Ionic + Cloud Vision de Google
— IoT, IA, Cloud Vision, javascript, programación, Ionic — 1 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-camera2$ 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'; //HttpModule7import { Camera } from '@ionic-native/camera'; //Camara8
9import { MyApp } from './app.component';10
11@NgModule({12 declarations: [13 MyApp14 ],15 imports: [16 BrowserModule,17 IonicModule.forRoot(MyApp),18 HttpModule //Array de imporst19 ],20 bootstrap: [IonicApp],21 entryComponents: [22 MyApp23 ],24 providers: [25 StatusBar,26 SplashScreen,27 {provide: ErrorHandler, useClass: IonicErrorHandler},28 Camera // Array de providers29 ]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 necesarios9
10@IonicPage({11 //Lazy loading12 name: "inicio"13})14@Component({15 selector: 'page-inicio',16 templateUrl: 'inicio.html',17})18export class InicioPage {19 //Variables utilizadas en la aplicación20
21 //Apikey de google cloud vision22 googleCloudVisionAPIKey = "TUAPIKEY";23 //Para obtener las respuestas de google cloud vision24 labels: any[] = [];25 //Para dar vista previa a la imgen26 imagen: any = null;27 //Respuesta de google cloud vison28 resultado: any = null;29 //variable de control de si es o no es hotdog30 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.ts34 }35
36 ionViewDidLoad() {37 //Para ocultar el splash de ionic38 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ón43 getLabels(base64) {44 const body = {45 "requests": [46 {47 "image": {48 "content": base6449 },50 "features": [51 {52 "type": "LABEL_DETECTION"53 }54 ]55 }56 ]57 }58 //Retornar la respuesta59 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 imagen63 tomarFoto() {64 //Crear loader65 let loader = this.loader.create({66 content: 'Ejecutando analisis...'67 });68 //Mostrar loader69 loader.present();70 //Opciones para abrir la camara71 const opciones: CameraOptions = {72 //Calidad de la imagen73 quality: 100,74 //Alto de la imagen75 targetHeight: 500,76 //Ancho de la imagen77 targetWidth: 500,78 //Tip de respuesta (base64 en este caso)79 destinationTyp-e: this.camera.DestinationType.DATA_URL,80 //Tipo png81 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.CAMERA85 }86 //Abirmos la camara pasando las opciones antes estipuladas87 this.camera.getPicture(opciones).then((img) => {88 this.labels = [];89 this.es = false;90 //Hacemos la petición a google cloud vision91 this.getLabels(img).subscribe((resultados) => {92 //Hacemos la variable imagen igual a la imagen obtenida por la camara para mostrar la vista previa93 this.imagen = img;94 //Obtenemos los resultados que nos da google95 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 labels99 this.labels.push(obj.description);100 //Si algunas de las etiquetas es "hot dog" entonces es un hot dog101 if (obj.description == "hot dog") this.es = true;102 });103 //Quitamos el loader104 loader.dismiss();105 }, err => {106 //Por si acaso ocurre un error107 loader.dismiss();108 this.mostrarToast(err.message, 5000);109 });110 }, err => {111 //Por si acaso ocurre un error112 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 mensaje118 mostrarToast(mensaje: string, duracion: number) {119 this.toast.create({120 message: mensaje,121 duration: duracion122 }).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
Mis disculpas por la alerta molestosa que sale al grabar el mi celular xD
Cualquier duda o sugerencia estoy en las redes como @JoralmoPro
Nos vemos en linea