一、 简介
图像识别允许计算机以一种类似于人类的方式识别图像。在过去,开发人员必须借助于模式识别这样复杂的图像识别技术与算法来实现这一目的。如今,借助于Google Vision API,程序员们可以直接使用这些现成工具中提供的图像识别功能。
本文将通过一个基于Ionic框架构建的JavaScript Web应用向你展示如何使用Google Vision API实现图片识别。
二、 开始工作
要想使用Google Vision API需要上传一个JSON文件,此文件中要包含想要检测的图像类型以及该图像的base64编码。你需要把这两部分信息上传到到Google Vision API端。
下面给出一个JSON文件的示例︰
- {
- "requests":[
- {
- "image":{
- "content":"base64-encoded-image"
- },
- "features":[
- {
- "type":"LABEL_DETECTION",
- "maxResults":1
- }
- ]
- }
- ]
- }
在此示例中,您必须使用图像的实际base64编码字符串来代替上面的base64-encoded-image部分。此外,你还需要在属性features处提供一个对象数组,该数组包含你想要检测的图像类型信息。其中,LABEL_DETECTION属性值的作用是通过指定一个标签或说明信息来对图像进行分类。
一旦从服务器端返回信息,那么返回信息的形式应当类似如下︰
- {
- "responses": [
- {
- "labelAnnotations": [
- {
- "mid": "/m/0bt9lr",
- "description": "dog",
- "score": 0.89208293
- }
- ]
- }
- ]
- }
因为在前面的请求格式中你指定了LABEL_DETECTION并给maxResults赋值为1;所以,在响应数组中返回的是单个对象。在上面的示例中,数组名是labelAnnotations。
除了使用前面例子中的LABEL_DETECTION外,你还可以使用如下枚举数据:
l FACE_DETECTION:检测照片中的人脸部分,返回相应的坐标值,用于根据检测到范围来绘制脸部分。
l LANDMARK_DETECTION:检测标志性建筑,例如悉尼的歌剧院或威尔特郡的巨石阵等。
l LOGO_DETECTION:检测不同的公司徽标。
l TEXT_DETECTION:采用光学字符识别(OCR)技术从图像中提取文本。
l SAFE_SEARCH_DETECTION:基于安全搜索参数对图像进行分类。这里提供的图像分类分为:成人类、恶搞类、医疗类和暴力类等。
三、 注册云Vision API
在本文写作的此时,谷歌云Vision API尚处于beta阶段,这意味着开发人员可以免费尝试使用。为此,你可以导航到谷歌云平台网站(https://cloud.google.com/vision/),点击按钮“try to free”进行操作。上述操作会把你导航到一个页面,询问为您的业务和信用信息;但别担心,谷歌不会收取你任何超过300美元费用的。
一旦上述操作完成,你就可以在谷歌控制台创建一个新的项目,并支持项目中进行付费,并启用云Vision API。你建议你跳过通常的操作过程,但使用选项“API Key”。请参考下面的图片:
四、 构建应用程序
现在,你已准备好要构建应用程序了。但首先,我想简要概述一下你要构建的应用程序。该应用程序提供了一个页面,其中包含与云Vision API进行交互所需的所有元素。其中,提供了一个下拉列表用于选择用户想使用哪种类型的图像检测,用于拍照的按钮,用于显示要拍的照片,一个标题部分用于描述显示的图片信息。
下面给出的是最终的应用程序的外观形式︰
你可以在GitHub网站上找到本示例工程的源码(https://github.com/sitepoint-editors/ionic-vision)。
(一) 安装依赖性
在你的工作目录中,打开一个新的终端窗口并建议通过如下方式安装Cordova和Ionic︰
- npm install -g cordova ionic
然后,通过如下命令使用空白模板创建一个新的Ionic项目︰
- ionic start ionic-vision blank
接下来,添加您想要使用的平台。我只想安装Android系统,但是这些代码应该也可以工作在iOS平台上。命令如下:
- ionic platform add android
接下来,你需要安装几个插件,以便与设备API进行交互,从而可以使用相机、文件和及上传文件等功能。相关命令如下:
- cordova plugin add cordova-plugin-camera
- cordova plugin add cordova-plugin-file
- cordova plugin add cordova-plugin-file-transfer
接下来再使用bower安装ngCordova:
- bower install ngCordova
注意:NgCordova库提供了针对要安装的插件的AngularJS包装器。这些包装器使得在一个Ionic应用程序中使用这些插件更为容易。
(二) 添加控制器
现在,打开目录www并在js目录下创建一个文件controllers/HomeController.js。最后添加如下代码:
- (function(){
- angular.module('starter')
- .controller('HomeController', ['$scope', '$ionicModal', '$cordovaFile', '$cordovaFileTransfer', '$cordovaCamera', HomeController]);
- function HomeController($scope, $ionicModal, $cordovaFile, $cordovaFileTransfer, $cordovaCamera){
- var me = this;
- me.current_image = 'img/koro-sensei.png';
- me.image_description = '';
- me.detection_type = 'LABEL_DETECTION';
- me.detection_types = {
- LABEL_DETECTION: 'label',
- TEXT_DETECTION: 'text',
- LOGO_DETECTION: 'logo',
- LANDMARK_DETECTION: 'landmark'
- };
- var api_key = 'your-google-api-key';
- $scope.takePicture = function(){
- var options = {
- destinationType: Camera.DestinationType.DATA_URL,
- sourceType: Camera.PictureSourceType.CAMERA,
- targetWidth: 500,
- targetHeight: 500,
- correctOrientation: true,
- cameraDirection: 0,
- encodingType: Camera.EncodingType.JPEG
- };
- $cordovaCamera.getPicture(options).then(function(imagedata){
- me.current_image = "data:image/jpeg;base64," + imagedata;
- me.image_description = '';
- me.locale = '';
- var vision_api_json = {
- "requests":[
- {
- "image":{
- "content": imagedata
- },
- "features":[
- {
- "type": me.detection_type,
- "maxResults": 1
- }
- ]
- }
- ]
- };
- var file_contents = JSON.stringify(vision_api_json);
- $cordovaFile.writeFile(
- cordova.file.applicationStorageDirectory,
- 'file.json',
- file_contents,
- true
- ).then(function(result){
- var headers = {
- 'Content-Type': 'application/json'
- };
- options.headers = headers;
- var server = 'https://vision.googleapis.com/v1/images:annotate?key=' + api_key;
- var filePath = cordova.file.applicationStorageDirectory + 'file.json';
- $cordovaFileTransfer.upload(server, filePath, options, true)
- .then(function(result){
- var res = JSON.parse(result.response);
- var key = me.detection_types[me.detection_type] + 'Annotations';
- me.image_description = res.responses[0][key][0].description;
- }, function(err){
- alert('An error occurred while uploading the file');
- });
- }, function(err){
- alert('An error occurred while trying to write the file');
- });
- }, function(err){
- alert('An error occurred getting the picture from the camera');
- });
- }
- }
- })();
现在,让我们来分片断介绍上面的代码。首先,创建控制器并导入需要的库:
- (function(){
- angular.module('starter')
- .controller('HomeController', ['$scope', '$cordovaFile', '$cordovaFileTransfer', '$cordovaCamera', HomeController]);
- function HomeController($scope, $cordovaFile, $cordovaFileTransfer, $cordovaCamera){
- ...
- }
在控制器中设置视图所需要的默认数据。这包括:要显示的图像的占位符,一个空的描述位置,默认的检测类型,等等。通常我们都使用LABEL_DETECTION这一选项,因为它相比于其他选项更具通用性。请参考如下代码:
- var me = this;
- me.current_image = 'img/koro-sensei.png';
- me.image_description = '';
- me.detection_type = 'LABEL_DETECTION';
接下来定义一个对象,它包含所有要检测的类型以及谷歌提供的API键:
- me.detection_types = {
- LABEL_DETECTION: 'label',
- TEXT_DETECTION: 'text',
- LOGO_DETECTION: 'logo',
- LANDMARK_DETECTION: 'landmark'
- };
- var api_key = 'your-google-api-key';
接下来,创建一个当按下相机按钮时要执行的方法,代码如下:
- $scope.takePicture = function(){
- ...
- };
在该方法中,首先声明相机插件有关的选项,把destinationType设置为Camera.DestinationType.DATA_URL。这意味着:一旦选中图片,回调函数中将会拥有图像的URI数据。因为此URI已经是base64编码的数据了,所以不再需要转换。
sourceType被指定为Camera.PictureSourceType.CAMERA,这样便可以使用照相机拍摄的图像作为数据源。然后,targetWidth和targetHeight两个值分别设置恰当的图像尺寸。correctOrientation值被设置为true,这样它会自动把图像的方向修改为纵向方式。把cameraDirection指定为0,这样便可以使用后置摄像头了。最后,把encodingType指定为Camera.EncodingType.JPEG,从而允许你把数据URI预置为data:image/jpeg;base64,从而显示图像。
- var options = {
- destinationType: Camera.DestinationType.DATA_URL,
- sourceType: Camera.PictureSourceType.CAMERA,
- targetWidth: 500,
- targetHeight: 500,
- correctOrientation: true,
- cameraDirection: 0,
- encodingType: Camera.EncodingType.JPEG
- };
通过调用$cordovaCamera.getPicture将打开设备上默认的相机应用程序。它使用options作为参数,然后调用then,并提供成功和错误操作对应的回调函数。同样的设计适用于后面你会使用的所有插件。
- $cordovaCamera.getPicture(options).then(function(imagedata){
- ...
- }, function(err){
- alert('An error occurred getting the picture from the camera');
- });
接下来,在成功操作回调函数中更新图像源(current_image)并把描述内容重置为一个空串:
- me.current_image = "data:image/jpeg;base64," + imagedata;
- me.image_description = '';
然后,使用URI从相机插件得到的数据URI和用户所选的检测类型(me.detection_type) 数据一个构建对象。然后,把该对象转换为一个字符串;这样一来,你就可以在发送到API的JSON文件中使用它作为内容数据。
- var vision_api_json = {
- "requests":[
- {
- "image":{
- "content": imagedata
- },
- "features":[
- {
- "type": me.detection_type,
- "maxResults": 1
- }
- ]
- }
- ]
- };
- var file_contents = JSON.stringify(vision_api_json);
接下来,使用Cordova文件插件把file_contents写到存储在应用程序沙箱根目录下的文件file.json中。另外,注意writeFile方法的第三个参数是一个布尔类型,用于指定如果文件不存在的话是否创建一个新文件:
- $cordovaFile.writeFile(
- cordova.file.applicationStorageDirectory,
- 'file.json',
- file_contents,
- true
- ).then(function(result){
- ...
- }, function(err){
- alert('An error occurred while writing to the file');
- });
当把内容写入到文件中时,需要声明文件传输插件所需要使用的变量。下面代码片断中的headers变量对应于请求的http头部。因为你发送一个JSON文件,您必须将Content-Type设置为application/json。另外,server中使用了一个完整路径形式的URL来向API发送请求; filePath中也使用了一个完整路径形式来指定要发送的JSON文件。
- var headers = {
- 'Content-Type': 'application/json'
- };
- options.headers = headers;
- var server = 'https://vision.googleapis.com/v1/images:annotate?key=' + api_key;
- var filePath = cordova.file.applicationStorageDirectory + 'file.json';
接下来,使用文件传输插件的upload方法将文件发送到服务器。这里,提供给upload方法的第四个参数是一个布尔值,用于设置是否接受来自所有主机的安全证书。一旦你得到一个服务器端的响应,便需要使用JSON.parse方法将其转换为JavaScript对象。通过串联当前的检测类型和Annotations一词来构建键(key)。这允许你形成字符串labelAnnotations,如果用户选择LABEL_DETECTION作为检测类型的话。然后,你可以使用此字符串提取图像的实际描述。
- $cordovaFileTransfer.upload(server, filePath, options, true)
- .then(function(result){
- var res = JSON.parse(result.response);
- var key = me.detection_types[me.detection_type] + 'Annotations';
- me.image_description = res.responses[0][key][0].description;
- }, function(err){
- alert('An error occured while uploading the file');
- });
(三) 添加视图
现在,需要创建文件template/home.html,并添加如下代码:
- <ion-view title="IonicVision" ng-controller="HomeController as home_ctrl">
- <header class="bar bar-header bar-stable">
- <h1 class="title">Ionic Vision</h1>
- </header>
- <ion-content class="has-header padding">
- <img src="{{ home_ctrl.current_image }}" class="picture">
- <h3 class="text-center" ng-show="home_ctrl.image_description">{{ home_ctrl.image_description }}</h3>
- <label class="item item-input item-select">
- <div class="input-label">
- Detection Type
- </div>
- <select ng-model="home_ctrl.detection_type">
- <option value="{{detection_type}}" ng-repeat="(detection_type, detection_type_value) in home_ctrl.detection_types">{{detection_type_value}}</option>
- </select>
- </label>
- <button class="button button-positive button-block" ng-click="takePicture()">
- Take Picture
- </button>
- </ion-content>
- </ion-view>
接下来,对上面的代码进行逐片分析。
首先,创建一个新的ion-view并指定要使用的控制器:
- <ion-view title="IonicVision" ng-controller="HomeController as home_ctrl">
- </ion-view>
在这个io-view里面是页眉部分(header)和ion-content。其中,ion-content是你在页眉部分下部要看到的UI元素部分。再往里面是图像、图像描述、检测类型列表和拍照按钮等信息。
- <header class="bar bar-header bar-stable">
- <h1 class="title">Ionic Vision</h1>
- </header>
- <ion-content class="has-header padding">
- <img src="{{ home_ctrl.current_image }}" class="picture">
- <h3 class="text-center" ng-show="home_ctrl.image_description">{{ home_ctrl.image_description }}</h3>
- <label class="item item-input item-select">
- <div class="input-label">
- Detection Type
- </div>
- <select ng-model="home_ctrl.detection_type">
- <option value="{{detection_type}}" ng-repeat="(detection_type, detection_type_value) in home_ctrl.detection_types">{{detection_type_value}}</option>
- </select>
- </label>
- <button class="button button-positive button-block" ng-click="takePicture()">
- Take Picture
- </button>
- </ion-content>
五、 格式化
大多数的样式化工作由Ionic自动完成,因此你仅需要声明一组样式即可。为此,需要把下面内容添加到css/style.css文件中:
- .text-center {
- text-align: center;
- }
- .picture {
- max-width: 100%;
- max-height: 100%;
- }
(一) 组合到一起
打开js/app.js文件,其中包含用于初始化Ionic和ngCordova的代码。如果您选择使用Ionic提供的空白启动模板,那么你会注意到大部分的代码已经填写了。你仅需要指定ngCordova的用途并编辑config方法的内容为指向文件home.html即可。
- angular.module('starter', ['ionic', 'ngCordova'])
- .run(function($ionicPlatform) {
- $ionicPlatform.ready(function() {
- if(window.cordova && window.cordova.plugins.Keyboard) {
- cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
- cordova.plugins.Keyboard.disableScroll(true);
- }
- if(window.StatusBar) {
- StatusBar.styleDefault();
- }
- });
- })
- .config(function($stateProvider, $urlRouterProvider) {
- $stateProvider
- .state('home', {
- url: '/home',
- templateUrl: 'templates/home.html'
- });
- $urlRouterProvider.otherwise('/home');
- });
接下来,打开文件index.html并链接到ng-cordova.js文件(接在文件ionic.bundle.js后面即可)。然后,在app.js文件的后面还要链接到文件HomeController.js。
别忘记把starter指定为ng-app的值,并在body标记的内部添加ion-nav-view,以便显示home.html视图。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
- <title></title>
- <link href="lib/ionic/css/ionic.css" rel="stylesheet">
- <link href="css/style.css" rel="stylesheet">
- <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
- <link href="css/ionic.app.css" rel="stylesheet">
- -->
- <!-- ionic/angularjs js -->
- <script src="lib/ionic/js/ionic.bundle.js"></script>
- <script src="lib/ngCordova/dist/ng-cordova.js"></script>
- <!-- cordova script (this will be a 404 during development) -->
- <script src="cordova.js"></script>
- <!-- your app's js -->
- <script src="js/app.js"></script>
- <script src="js/controllers/HomeController.js"></script>
- </head>
- <body ng-app="starter">
- <ion-nav-view></ion-nav-view>
- </body>
- </html>
六、 运行应用程序
现在,你可以在你的设备或者模拟器上运行上面的应用程序了,这只需要执行如下命令即可:
- ionic run android
七、 小结
在本教程中,你使用ionic并借助云Vision API构建了一个图像识别软件。其中,我讨论了使用不同的图像检测类型,例如标签、标志、徽标和文本检测等。但是,文章中我并没有涵盖人脸检测或安全搜索检测知识。不过,对于人脸检测技术,您可以使用像Fabric.js这种框架。此工具会把图像转换成一个画布(Canvas)对象并在检测到的脸上画圆。
有关云Vision API更多的知识,请自行阅读官方文档(https://cloud.google.com/vision/docs/)。当然,本人也非常希望了解到你的使用体验与思考结果。
原文标题:Image Recognition with the Google Vision API and Ionic
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】