Skip to content
JoralmoPro
TwitterHomepage

Ionic + Cloud Vision de Google

IoT, IA, Cloud Vision, javascript, programación, Ionic1 min read

En está ocasión estaremos viendo como crear una imitación de la aplicación "Not hot dog app" que aparece en la famosa serie silycon valley, por si acaso no sabes cual es la aplicación te dejo un link para que le des un vistaso.

Para hacer posible la aplicación utilizaremos Ionic Framework y el Api de Google Cloud Vision, por lo tanto lo primero que debemos hacer es instalar Ionic e iniciar un nuevo proyecto, lo conseguimos de la siguiente manera (infiero que tienes instalado Node.js y npm)

1$ npm i ionic -g && ionic start hotDogoNo blank

El primer comando instalara ionic de manera global en el sistema, el segundo iniciara un nuevo proyecto de ionic llamado hotDogoNo y con la plantilla blank, acá pueden ver más al respecto.

Ahora de momento iremos a la pagina de Cloud Vision y activamos la Api y guardamos el Api Key.

Abrimos el proyecto de ionic en nuestro editor favorito, y nos centraremos en la carpeta /src/ y ahora especificamente en el archivo /src/app/app.modules.ts donde importaremos el modulo http de angular con el que realizaremos las peticiones y también el modulo de la cámara para poder tomar la foto desde el celular y colocamos los módulos dentro del array de imports y providers respectivamente.

Para instalar el modulo de la cámara

1$ ionic cordova plugin add cordova-plugin-camera
2$ npm install --save @ionic-native/camera

1import { BrowserModule } from '@angular/platform-browser';
2import { ErrorHandler, NgModule } from '@angular/core';
3import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
4import { SplashScreen } from '@ionic-native/splash-screen';
5import { StatusBar } from '@ionic-native/status-bar';
6import { HttpModule } from '@angular/http'; //HttpModule
7import { Camera } from '@ionic-native/camera'; //Camara
8
9import { MyApp } from './app.component';
10
11@NgModule({
12 declarations: [
13 MyApp
14 ],
15 imports: [
16 BrowserModule,
17 IonicModule.forRoot(MyApp),
18 HttpModule //Array de imporst
19 ],
20 bootstrap: [IonicApp],
21 entryComponents: [
22 MyApp
23 ],
24 providers: [
25 StatusBar,
26 SplashScreen,
27 {provide: ErrorHandler, useClass: IonicErrorHandler},
28 Camera // Array de providers
29 ]
30})
31export class AppModule {}

Por el momento es todo en este archivo.

Ahora vamos al archivo /src/ages/inicio/inicio.ts

Yo he eliminado la pagina "home" que viene por defecto y he creado la pagina "inicio"

En la pagina de inicio escribiremos el código necesario para la lógica de la aplicación, o sea, aquí capturamos la imagen y la enviamos a Cloud Vision para luego trabajar con el resultado que nos retorna, pero veamos y analicemos el código

Aquí pueden ver como es la estructura para enviar la petición a Cloud Vision

1import { SplashScreen } from '@ionic-native/splash-screen';
2import { Component } from '@angular/core';
3import { IonicPage, NavController, NavParams } from 'ionic-angular';
4import { Http } from '@angular/http';
5import { LoadingController } from 'ionic-angular/components/loading/loading-controller';
6import { Camera, CameraOptions } from '@ionic-native/camera';
7import { ToastController } from 'ionic-angular/components/toast/toast-controller';
8// imports necesarios
9
10@IonicPage({
11 //Lazy loading
12 name: "inicio"
13})
14@Component({
15 selector: 'page-inicio',
16 templateUrl: 'inicio.html',
17})
18export class InicioPage {
19 //Variables utilizadas en la aplicación
20
21 //Apikey de google cloud vision
22 googleCloudVisionAPIKey = "TUAPIKEY";
23 //Para obtener las respuestas de google cloud vision
24 labels: any[] = [];
25 //Para dar vista previa a la imgen
26 imagen: any = null;
27 //Respuesta de google cloud vison
28 resultado: any = null;
29 //variable de control de si es o no es hotdog
30 es: boolean = false;
31
32 constructor(public navCtrl: NavController, public navParams: NavParams, public splashScreen: SplashScreen, public http: Http, public loader: LoadingController, private camera: Camera, public toast: ToastController) {
33 //Objetos necesarios, necesarios tambien agregarlos en el app.module.ts
34 }
35
36 ionViewDidLoad() {
37 //Para ocultar el splash de ionic
38 this.splashScreen.hide();
39 }
40
41
42 //Funcion para hacer la petición a google cloud vision, estructura necesaria para la petición segun la documentación
43 getLabels(base64) {
44 const body = {
45 "requests": [
46 {
47 "image": {
48 "content": base64
49 },
50 "features": [
51 {
52 "type": "LABEL_DETECTION"
53 }
54 ]
55 }
56 ]
57 }
58 //Retornar la respuesta
59 return this.http.post(`https://vision.googleapis.com/v1/images:annotate?key=${this.googleCloudVisionAPIKey}`, body)
60 }
61
62 //Funcion para abrir la camara y procesar la imagen
63 tomarFoto() {
64 //Crear loader
65 let loader = this.loader.create({
66 content: 'Ejecutando analisis...'
67 });
68 //Mostrar loader
69 loader.present();
70 //Opciones para abrir la camara
71 const opciones: CameraOptions = {
72 //Calidad de la imagen
73 quality: 100,
74 //Alto de la imagen
75 targetHeight: 500,
76 //Ancho de la imagen
77 targetWidth: 500,
78 //Tip de respuesta (base64 en este caso)
79 destinationTyp-e: this.camera.DestinationType.DATA_URL,
80 //Tipo png
81 encodingType: this.camera.EncodingType.PNG,
82 mediaType: this.camera.MediaType.PICTURE,
83 //Abrir desde la camara (se puede tambien desde la galeria)
84 sourceType: this.camera.PictureSourceType.CAMERA
85 }
86 //Abirmos la camara pasando las opciones antes estipuladas
87 this.camera.getPicture(opciones).then((img) => {
88 this.labels = [];
89 this.es = false;
90 //Hacemos la petición a google cloud vision
91 this.getLabels(img).subscribe((resultados) => {
92 //Hacemos la variable imagen igual a la imagen obtenida por la camara para mostrar la vista previa
93 this.imagen = img;
94 //Obtenemos los resultados que nos da google
95 this.resultado = resultados.json().responses;
96 //Recorremos las etiquetas de la respuesta con map()
97 this.resultado[0].labelAnnotations.map(obj => {
98 //Guardamos las etiquetas en la variable labels
99 this.labels.push(obj.description);
100 //Si algunas de las etiquetas es "hot dog" entonces es un hot dog
101 if (obj.description == "hot dog") this.es = true;
102 });
103 //Quitamos el loader
104 loader.dismiss();
105 }, err => {
106 //Por si acaso ocurre un error
107 loader.dismiss();
108 this.mostrarToast(err.message, 5000);
109 });
110 }, err => {
111 //Por si acaso ocurre un error
112 loader.dismiss();
113 this.mostrarToast(err.message, 5000);
114 });
115 }
116
117 //Funcion para mostrar mensaje de error recibe mensaje de error y la duración de el mensaje
118 mostrarToast(mensaje: string, duracion: number) {
119 this.toast.create({
120 message: mensaje,
121 duration: duracion
122 }).present();
123 }
124
125}

El anterior es el código de toda la lógica de la aplicación, bastante optimízable por cierto pero por cuestiones del tutorial lo escribí así.

Ahora en el archivo /src/ages/inicio/inicio.html tendremos los siguiente

1<ion-header>
2 <!-- Color rojo de el navbar -->
3 <ion-navbar color="danger">
4 <ion-title>¿Hog dog o no?</ion-title>
5 </ion-navbar>
6</ion-header>
7
8<ion-content padding>
9 <ion-row margin>
10 <ion-card>
11 <!-- Si la imagen existe, mostramos su vista previa -->
12 <img *ngIf="imagen" [src]="'data:image/png;base64,' + imagen" />
13 </ion-card>
14 </ion-row>
15
16 <!-- Si existe ya un resultado, mostraremos lo siguiente -->
17 <ion-col *ngIf="resultado">
18
19 <!-- Si la variable "es" esta en true, mostramos que es un hotdog, de lo contrario pues mostramos que no es hotdog -->
20 <button *ngIf="es" color="secondary" ion-button full>
21 ¡Es un Hotdog!
22 </button>
23
24 <button *ngIf="!es" color="danger" ion-button full>
25 ¡No es Hotdog!
26 </button>
27
28 <!-- Si no es hotdog mostramos las etiquetas de lo que posiblemente está en la imagen -->
29 <div *ngIf="!es">
30 <h3>Posiblemente sea</h3>
31
32 <!-- Recorremos la variable labels -->
33 <ion-chip color="secondary" *ngFor="let label of labels">
34
35 <!-- Mostramos una por una -->
36 <ion-label>{{ label }}</ion-label>
37
38 </ion-chip>
39 </div>
40
41 </ion-col>
42 <!-- Boton flotante que ejecuta la funcion tomarFoto() -->
43 <ion-fab bottom right>
44 <button color="danger" ion-fab (click)="tomarFoto()">
45 <ion-icon name="camera"></ion-icon>
46 </button>
47 </ion-fab>
48</ion-content>

Y ahora veamos un poquito la aplicación funcionando

IMAGE ALT TEXT HERE

Mis disculpas por la alerta molestosa que sale al grabar el mi celular xD

Código en gitlab

Cualquier duda o sugerencia estoy en las redes como @JoralmoPro

Nos vemos en linea