基于Google Vision API和Ionic实现Web开发中图像识别
创始人
2025-01-29 02:01:03
0次

一、 简介

图像识别允许计算机以一种类似于人类的方式识别图像。在过去,开发人员必须借助于模式识别这样复杂的图像识别技术与算法来实现这一目的。如今,借助于Google Vision API,程序员们可以直接使用这些现成工具中提供的图像识别功能。

本文将通过一个基于Ionic框架构建的JavaScript Web应用向你展示如何使用Google Vision API实现图片识别。

二、 开始工作

要想使用Google Vision API需要上传一个JSON文件,此文件中要包含想要检测的图像类型以及该图像的base64编码。你需要把这两部分信息上传到到Google Vision API端。

下面给出一个JSON文件的示例︰

  1. { 
  2.   "requests":[ 
  3.     { 
  4.       "image":{ 
  5.        "content":"base64-encoded-image" 
  6.       }, 
  7.       "features":[ 
  8.         { 
  9.           "type":"LABEL_DETECTION", 
  10.           "maxResults":1 
  11.         } 
  12.       ] 
  13.     } 
  14.   ] 
  15. } 

在此示例中,您必须使用图像的实际base64编码字符串来代替上面的base64-encoded-image部分。此外,你还需要在属性features处提供一个对象数组,该数组包含你想要检测的图像类型信息。其中,LABEL_DETECTION属性值的作用是通过指定一个标签或说明信息来对图像进行分类。

一旦从服务器端返回信息,那么返回信息的形式应当类似如下︰

  1. {  
  2.   "responses": [ 
  3.     { 
  4.       "labelAnnotations": [ 
  5.  
  6.         { 
  7.           "mid": "/m/0bt9lr", 
  8.           "description": "dog", 
  9.           "score": 0.89208293 
  10.         } 
  11.       ] 
  12.     } 
  13.  
  14.   ] 
  15.  
  16. } 

因为在前面的请求格式中你指定了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︰

 

  1. npm install -g cordova ionic 

然后,通过如下命令使用空白模板创建一个新的Ionic项目︰

 

  1. ionic start ionic-vision blank 

接下来,添加您想要使用的平台。我只想安装Android系统,但是这些代码应该也可以工作在iOS平台上。命令如下:

 

  1. ionic platform add android 

接下来,你需要安装几个插件,以便与设备API进行交互,从而可以使用相机、文件和及上传文件等功能。相关命令如下:

  1. cordova plugin add cordova-plugin-camera 
  2. cordova plugin add cordova-plugin-file  
  3. cordova plugin add cordova-plugin-file-transfer 

接下来再使用bower安装ngCordova:

 

  1. bower install ngCordova 

注意:NgCordova库提供了针对要安装的插件的AngularJS包装器。这些包装器使得在一个Ionic应用程序中使用这些插件更为容易。

(二) 添加控制器

现在,打开目录www并在js目录下创建一个文件controllers/HomeController.js。最后添加如下代码:

  1. (function(){ 
  2.     angular.module('starter') 
  3.     .controller('HomeController', ['$scope', '$ionicModal', '$cordovaFile', '$cordovaFileTransfer', '$cordovaCamera', HomeController]); 
  4.     function HomeController($scope, $ionicModal, $cordovaFile, $cordovaFileTransfer, $cordovaCamera){ 
  5.         var me = this; 
  6.         me.current_image = 'img/koro-sensei.png'; 
  7.     me.image_description = ''; 
  8.         me.detection_type = 'LABEL_DETECTION';
  9.         me.detection_types = { 
  10.  
  11.           LABEL_DETECTION: 'label', 
  12.  
  13.           TEXT_DETECTION: 'text', 
  14.  
  15.           LOGO_DETECTION: 'logo', 
  16.  
  17.          LANDMARK_DETECTION: 'landmark' 
  18.         }; 
  19.         var api_key = 'your-google-api-key';  
  20.         $scope.takePicture = function(){ 
  21.             var options = { 
  22.                 destinationType: Camera.DestinationType.DATA_URL,  
  23.                 sourceType: Camera.PictureSourceType.CAMERA, 
  24.                  targetWidth: 500,  
  25.               targetHeight: 500, 
  26.               correctOrientation: true, 
  27.                 cameraDirection: 0, 
  28.                 encodingType: Camera.EncodingType.JPEG  
  29.             }; 
  30.             $cordovaCamera.getPicture(options).then(function(imagedata){ 
  31.                 me.current_image = "data:image/jpeg;base64," + imagedata;
  32.                 me.image_description = '';
  33.                 me.locale = ''; 
  34.                 var vision_api_json = { 
  35.  
  36.                   "requests":[ 
  37.  
  38.                     { 
  39.                       "image":{ 
  40.  
  41.                       "content": imagedata 
  42.  
  43.                       }, 
  44.                       "features":[ 
  45.  
  46.                       { 
  47.                           "type": me.detection_type, 
  48.  
  49.                           "maxResults": 1 
  50.  
  51.                         } 
  52.                       ] 
  53.                     } 
  54.                   ] 
  55.                 }; 
  56.                 var file_contents = JSON.stringify(vision_api_json); 
  57.               $cordovaFile.writeFile( 
  58.  
  59.                     cordova.file.applicationStorageDirectory, 
  60.                     'file.json', 
  61.  
  62.                     file_contents, 
  63.  
  64.                     true 
  65.                 ).then(function(result){ 
  66.                     var headers = { 
  67.                         'Content-Type': 'application/json' 
  68.  
  69.                     }; 
  70.                     options.headers = headers; 
  71.                    var server = 'https://vision.googleapis.com/v1/images:annotate?key=' + api_key; 
  72.                     var filePath = cordova.file.applicationStorageDirectory + 'file.json'; 
  73.                     $cordovaFileTransfer.upload(server, filePath, options, true)  
  74.                      .then(function(result){ 
  75.                             var res = JSON.parse(result.response); 
  76.  
  77.                             var key = me.detection_types[me.detection_type] + 'Annotations'; 
  78.                             me.image_description = res.responses[0][key][0].description; 
  79.                       }, function(err){ 
  80.                         alert('An error occurred while uploading the file'); 
  81.                       }); 
  82.                 }, function(err){ 
  83.                     alert('An error occurred while trying to write the file'); 
  84.                 }); 
  85.             }, function(err){ 
  86.  
  87.               alert('An error occurred getting the picture from the camera'); 
  88.  
  89.             }); 
  90.         } 
  91.     } 
  92. })(); 

现在,让我们来分片断介绍上面的代码。首先,创建控制器并导入需要的库:

  1. (function(){ 
  2.     angular.module('starter') 
  3.     .controller('HomeController', ['$scope', '$cordovaFile', '$cordovaFileTransfer', '$cordovaCamera', HomeController]); 
  4. function HomeController($scope, $cordovaFile, $cordovaFileTransfer, $cordovaCamera){ 
  5. ... 
  6. } 

在控制器中设置视图所需要的默认数据。这包括:要显示的图像的占位符,一个空的描述位置,默认的检测类型,等等。通常我们都使用LABEL_DETECTION这一选项,因为它相比于其他选项更具通用性。请参考如下代码:

  1. var me = this; 
  2.  
  3. me.current_image = 'img/koro-sensei.png'; 
  4.  
  5. me.image_description = ''; 
  6.  
  7. me.detection_type = 'LABEL_DETECTION'; 

接下来定义一个对象,它包含所有要检测的类型以及谷歌提供的API键:

  1. me.detection_types = { 
  2.  
  3.   LABEL_DETECTION: 'label', 
  4.  
  5.   TEXT_DETECTION: 'text', 
  6.  
  7.   LOGO_DETECTION: 'logo', 
  8.  
  9.   LANDMARK_DETECTION: 'landmark'  
  10. }; 
  11. var api_key = 'your-google-api-key'; 

接下来,创建一个当按下相机按钮时要执行的方法,代码如下:

  1. $scope.takePicture = function(){ 
  2.     ... 
  3. }; 

在该方法中,首先声明相机插件有关的选项,把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,从而显示图像。

  1. var options = { 
  2.     destinationType: Camera.DestinationType.DATA_URL, 
  3.     sourceType: Camera.PictureSourceType.CAMERA, 
  4.     targetWidth: 500, 
  5.     targetHeight: 500, 
  6.     correctOrientation: true, 
  7.     cameraDirection: 0, 
  8.     encodingType: Camera.EncodingType.JPEG 
  9. }; 

通过调用$cordovaCamera.getPicture将打开设备上默认的相机应用程序。它使用options作为参数,然后调用then,并提供成功和错误操作对应的回调函数。同样的设计适用于后面你会使用的所有插件。

  1. $cordovaCamera.getPicture(options).then(function(imagedata){ 
  2.  ... 
  3. }, function(err){ 
  4.  
  5.     alert('An error occurred getting the picture from the camera'); 
  6. }); 

接下来,在成功操作回调函数中更新图像源(current_image)并把描述内容重置为一个空串:

  1. me.current_image = "data:image/jpeg;base64," + imagedata; 
  2.  
  3. me.image_description = ''; 

然后,使用URI从相机插件得到的数据URI和用户所选的检测类型(me.detection_type) 数据一个构建对象。然后,把该对象转换为一个字符串;这样一来,你就可以在发送到API的JSON文件中使用它作为内容数据。

  1. var vision_api_json = { 
  2.  
  3.   "requests":[ 
  4.  
  5.     { 
  6.       "image":{ 
  7.         "content": imagedata 
  8.     }, 
  9.       "features":[ 
  10.         { 
  11.           "type": me.detection_type, 
  12.  
  13.           "maxResults": 1 
  14.         } 
  15.       ] 
  16.     } 
  17.   ] 
  18. }; 
  19. var file_contents = JSON.stringify(vision_api_json); 

接下来,使用Cordova文件插件把file_contents写到存储在应用程序沙箱根目录下的文件file.json中。另外,注意writeFile方法的第三个参数是一个布尔类型,用于指定如果文件不存在的话是否创建一个新文件:

  1. $cordovaFile.writeFile( 
  2.     cordova.file.applicationStorageDirectory, 
  3.  
  4.     'file.json', 
  5.  
  6.     file_contents, 
  7.  
  8.     true 
  9. ).then(function(result){ 
  10.    ... 
  11. }, function(err){ 
  12.     alert('An error occurred while writing to the file'); 
  13. }); 

当把内容写入到文件中时,需要声明文件传输插件所需要使用的变量。下面代码片断中的headers变量对应于请求的http头部。因为你发送一个JSON文件,您必须将Content-Type设置为application/json。另外,server中使用了一个完整路径形式的URL来向API发送请求; filePath中也使用了一个完整路径形式来指定要发送的JSON文件。

  1. var headers = { 
  2.  
  3.     'Content-Type': 'application/json' 
  4.  
  5. };   
  6. options.headers = headers; 
  7. var server = 'https://vision.googleapis.com/v1/images:annotate?key=' + api_key; 
  8.  
  9. var filePath = cordova.file.applicationStorageDirectory + 'file.json'; 

接下来,使用文件传输插件的upload方法将文件发送到服务器。这里,提供给upload方法的第四个参数是一个布尔值,用于设置是否接受来自所有主机的安全证书。一旦你得到一个服务器端的响应,便需要使用JSON.parse方法将其转换为JavaScript对象。通过串联当前的检测类型和Annotations一词来构建键(key)。这允许你形成字符串labelAnnotations,如果用户选择LABEL_DETECTION作为检测类型的话。然后,你可以使用此字符串提取图像的实际描述。

  1. $cordovaFileTransfer.upload(server, filePath, options, true) 
  2.  
  3.     .then(function(result){ 
  4.         var res = JSON.parse(result.response); 
  5.  
  6.         var key = me.detection_types[me.detection_type] + 'Annotations'; 
  7.  
  8.         me.image_description = res.responses[0][key][0].description; 
  9. }, function(err){ 
  10.     alert('An error occured while uploading the file'); 
  11.  
  12. }); 

(三) 添加视图

现在,需要创建文件template/home.html,并添加如下代码:

  1.  
  2.  
  3.      
  4.  
  5.         Ionic Vision 
  6.  
  7.      
  8.      
  9.          
  10.  
  11.         {{ home_ctrl.image_description }} 
  12.          
  13.            
  14.             Detection Type 
  15.           
 
  •            
  •  
  •             {{detection_type_value}} 
  •            
  •          
  •          
  •         Take Picture 
  •  
  •          
  •      
  •  
  •  
  • 接下来,对上面的代码进行逐片分析。

    首先,创建一个新的ion-view并指定要使用的控制器:

    1.  
    2.  
    3.  

    在这个io-view里面是页眉部分(header)和ion-content。其中,ion-content是你在页眉部分下部要看到的UI元素部分。再往里面是图像、图像描述、检测类型列表和拍照按钮等信息。

    1.  
    2.  
    3.     Ionic Vision 
    4.  
    5.  
    6.  
    7.      
    8.  
    9.     {{ home_ctrl.image_description }} 
    10.  
    11.      
    12.  
    13.        
    14.  
    15.         Detection Type 
    16.       
     
  •  
  •        
  •         {{detection_type_value}} 
  •      
  •      
  •      
  •     Take Picture 
  •      
  •  
  • 五、 格式化

    大多数的样式化工作由Ionic自动完成,因此你仅需要声明一组样式即可。为此,需要把下面内容添加到css/style.css文件中:

    1. .text-center { 
    2.     text-align: center; 
    3. }   
    4.  
    5. .picture { 
    6.   max-width: 100%; 
    7.    max-height: 100%; 
    8. } 

    (一) 组合到一起

    打开js/app.js文件,其中包含用于初始化Ionic和ngCordova的代码。如果您选择使用Ionic提供的空白启动模板,那么你会注意到大部分的代码已经填写了。你仅需要指定ngCordova的用途并编辑config方法的内容为指向文件home.html即可。

    1. angular.module('starter', ['ionic', 'ngCordova']) 
    2. .run(function($ionicPlatform) { 
    3.  
    4.   $ionicPlatform.ready(function() { 
    5.  
    6.     if(window.cordova && window.cordova.plugins.Keyboard) {
    7.  
    8.     cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); 
    9.  
    10.      cordova.plugins.Keyboard.disableScroll(true); 
    11.  
    12.     } 
    13.     if(window.StatusBar) { 
    14.  
    15.       StatusBar.styleDefault(); 
    16.     } 
    17.  
    18.   }); 
    19.  
    20. })
    21. .config(function($stateProvider, $urlRouterProvider) { 
    22.  
    23.   $stateProvider  
    24.   .state('home', { 
    25.  
    26.     url: '/home', 
    27.  
    28.     templateUrl: 'templates/home.html' 
    29.  
    30.   });  
    31.   $urlRouterProvider.otherwise('/home'); 
    32.  
    33. }); 

    接下来,打开文件index.html并链接到ng-cordova.js文件(接在文件ionic.bundle.js后面即可)。然后,在app.js文件的后面还要链接到文件HomeController.js。

    别忘记把starter指定为ng-app的值,并在body标记的内部添加ion-nav-view,以便显示home.html视图。

    1.  
    2.  
    3.  
    4.    
    5.      
    6.      
    7.      
    8.      
    9.      
    10.     
    11.      
    12.      
    13.      
    14.      
    15.      
    16.      
    17.      
    18.     
    19.    
    20.  
    21.    
    22.  
    23.      
    24.  
    25.    
    26.  
    27.  

    六、 运行应用程序

    现在,你可以在你的设备或者模拟器上运行上面的应用程序了,这只需要执行如下命令即可:

     

    1. 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】

    相关内容

    热门资讯

    PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
    网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
    各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
    粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
    如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
    什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
    全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
    如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
    只需三步,让你掌握阿尔法路由器... 请参照以下阿尔法路由器设置方法,通过浏览器进入及设置宽带路由器。经过这三个步骤的设置,基本上能够熟悉...
    30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...