浏览器中的图像识别 API

4,399 阅读9分钟

前言

在这几年的前端发展中,Web 应用不断朝着 Native APP 的体验发展,比如在今年被谈及最多的 PWA,就连 Apple 都逐渐在自家浏览器 safari 中集成 Service Worker。在各大浏览器厂商的支持下,Web 逐渐拥有了更多的能力,同时随着硬件的一代代升级,前端应用中的体验也在逐渐提升。

然而很多时候,对于硬件底层的调用以及复杂运算上仍然需要 Native APP 的支持,在 Webview 环境中以 JSBridge 的形式提供给前端应用调用。这使得很许多前端应用只能依托于 Native APP 定制的 Webview。当然,浏览厂商也在不断跟进,把许多底层的硬件接口和系统层面的接口直接提供给 Web 使用,比如 Web Bluetooth API 、Web Share API、Shape Detection API 等等。

在本篇文章中,将介绍 Chrome 中集成的图形识别 API (Shape Detection API)。

图形识别

照片和图像是互联网构成中最大的部分,其中相当一部分包含了可识别的特征,比如人脸,二维码或者文本。可想而之,识别这些特征的计算开销非常大,但有些很有趣场景,比如在照片中自动标记人脸,或者根据图像中的 URL 进行重定向。硬件厂商从很久以前就已经开始支持这些特性,但 Web 应用迟迟未能很好地利用上这些硬件特性,必须借助一些难用的程序库才能达到目的。

由于图像识别需要系统层面的资源与计算能力,因此只有原生的底层 API 能够驾驭的住。在目前的 Web 应用中,涉及到图像识别的功能时,一般是将图片上传至服务器或者在 Webview 中通过 JSBridge 传给 Native APP ,在其计算出结果之后返回到 Web 中继续处理。对于 Web 来说,其能力则显得单薄,必须依托于服务端的处理或者是 JSBridge ,而如果对图像的处理能够成为 Web 的一个标准 API,那么其体验将会得到很大程度的提升。

在 Native 开发中,Android 和 IOS 平台都在系统层面直接提供给了应用开发识别图像的一些能力,比如对于二维码/条形码的识别,Android 可以使用 barcode API 、 iOS 可以使用 CIQRCodeFeature API

而在 Web 应用中为何就不能有一套标准的 js API 来调用系统底层的能力呢?

Chrome 团队在 16 年就尝试在浏览器中集成了直接提供给 Web 开发调用的 Shape Detection API 。目前图形识别 API 在 WICG 中还处于孵化和实验阶段,如果想开启该功能,需要下载 Canary 版本的 Chrome 浏览器(www.google.com/chrome/brow…),然后在地址栏输入 chrome://flags/#enable-experimental-web-platform-features ,在 Experimental Web Platform features 这一项点击 “启用” 来开启该实验性的功能。

接下来验证一下浏览器是否支持了该 API ,在 Console 中输入:

window.FaceDetector
window.BarcodeDetector
window.TextDetector

如果 LOG 出:

ƒ FaceDetector() { [native code] }
ƒ BarcodeDetector() { [native code] }
ƒ TextDetector() { [native code] }

则说明你已经可以在浏览器中调用 Shape Detection API 了。

虽然目前来说该 API 还处于实验阶段(实验阶段的功能是不稳定的,其最终并不一定会正式集成),但是作为新时代的前端开发者,我们还是愿意尝尝鲜的。

TIP:以下例子都需要下载 Canary 版本的 Chrome 浏览器,并且开启 Experimental Web Platform features 实验性功能。

API 能力

Shape Detection API 提供了三个接口可以调用:

  • FaceDetector: 人脸识别;
  • BarcodeDetector: 二维码/条形码 识别;
  • TextDetector: 文本识别;

1. 人脸识别

FaceDetector 是一个针对图像中的人脸进行识别的底层加速平台组件类,它接受一个配置参数 FaceDetectorOptions ,我们直接创造一个 FaceDetector 实例:

const faceDetector = new FaceDetector({
  fastMode: true,
  maxDetectedFaces: 10
});

FaceDetectorOptions 中的参数:

  • fastMode: [Boolean] ,表示是否开启速度优先(于精确度)模式,将通过更小的比例尺(更靠近目标图形)或寻找更大的目标图形的办法进行识别;
  • maxDetectedFaces: [Number] ,当前场景中已识别的人脸数的最大值;

FaceDetector 类有一个方法 detect ,接受一个图片的 Image 或者 Blob 对象,用来检测该图片中的人脸,同时返回一个 Promise 对象:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Shape Detection API Demo</title>
  <style>
  * {
    box-sizing: border-box;
    padding: 0;
    margin: 0;
  }
  </style>
</head>
<body>
  <img
    id="face-image"
    src="//opsqe9du9.bkt.clouddn.com/1.jpeg" alt="image"
    crossorigin="anonymous"
    style="width: 100%;"
  />
<script type="text/javascript">
window.onload = main();
function main () {
  const faceDetector = new FaceDetector({fastMode: true, maxDetectedFaces: 10});

  const image = document.getElementById('face-image');

  faceDetector.detect(image)
    .then(detectedFaces => {
      console.log(detectedFaces);
    })
    .catch((e) => {
      console.error("Face Detection failed, boo.", e);
    });
}
</script>
</body>
</html>

以上例子中:在 HTML 中创建了一个 img 标签(这里需要注意一点,如果图片来自跨域,那么需要设置crossorigin="anonymous"),之后获取到 Image 对象,调用 faceDetector.detect 来检测图片中的人脸,在识别成功后打印出 detectedFaces 得到:

(5) [DetectedFace, DetectedFace, DetectedFace, DetectedFace, DetectedFace]
0: DetectedFace
  boundingBox: DOMRect
    bottom: 275
    height: 44
    left: 710
    right: 754
    top: 231
    width: 44
    x: 710
    y: 231
  landmarks: Array(3)
    0:
      location: {x: 729, y: 246}
      type: "eye"
    1: {location: {…}, type: "eye"}
    2: {location: {…}, type: "mouth"}
    length: 3
1: DetectedFace {boundingBox: DOMRect, landmarks: Array(3)}
2: DetectedFace {boundingBox: DOMRect, landmarks: Array(3)}
3: DetectedFace {boundingBox: DOMRect, landmarks: Array(3)}
4: DetectedFace {boundingBox: DOMRect, landmarks: Array(3)}
length: 5

可以看到,这里识别到了 5 个人脸,返回了一个 length === 5 的数组,每个数组元素都是一个 DetectedFace 对象,包含了两个属性:

  • boundingBox: DOMRect 对象,包含了该识别区域的位置(bottom、top、left、right、x、y)、大小信息(width、height);
  • landmarks: 为一个数组,包含了其脸部的一些特性信息,比如眼睛(eye)、嘴巴(mouth),及其位置信息(x、y);

完整 Demo:tongchengqiu.github.io/mixin-demo/…

2. 二维码/条形码识别

BarcodeDetector 是一个针对图像中的二维码或条形码进行识别的底层加速平台组件类,我们直接创建其实例:

const barcodeDetector = new BarcodeDetector();

和 FaceDetector 一样,使用 detect 函数来检测图片,该方法同样接受一个图片的 Image 或者 Blob 对象,同时返回一个 Promise 对象:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Shape Detection API Demo</title>
  <style>
  * {
    box-sizing: border-box;
    padding: 0;
    margin: 0;
  }
  </style>
</head>
<body>

<img id="qrcode-image" crossorigin="anonymous" src="//opsqe9du9.bkt.clouddn.com/img-2.png" alt="QRCODE">

<script type="text/javascript">
window.onload = main;

function main () {
  const barcodeDetector = new BarcodeDetector();

  const image = document.getElementById('qrcode-image');

  barcodeDetector.detect(image)
    .then(detectedCodes => {
      console.log(detectedCodes);
    })
    .catch((e) => {
      console.error("Barcode Detection failed, boo.", e);
    })
}
</script>
</body>
</html>

和上述例子一样,打印出检测获取到的 detectedCodes

[DetectedBarcode]
0: DetectedBarcode
    boundingBox: DOMRect
      bottom: 375.4765348434448
      height: 362.06744384765625
      left: 9.409090042114258
      right: 371.47656440734863
      top: 13.409090995788574
      width: 362.0674743652344
      x: 9.409090042114258
      y: 13.409090995788574
    cornerPoints: Array(4)
      0: {x: 9.52997875213623, y: 13.529980659484863}
      1: {x: 370.59088134765625, y: 13.409090995788574}
      2: {x: 371.4765625, y: 375.4765319824219}
      3: {x: 9.409090042114258, y: 374.5908508300781}
      length: 4
    rawValue: "https://qiutc.me/"
length: 1

获取到的数组中每个元素是一个识别到的二维码的 DetectedBarcode 对象,包含了三个属性:

  • DetectedBarcode: 二维码的位置信息;
  • cornerPoints: 一串已识别条形码的顶点序列;
  • rawValue: 该二维码表示的真实值,是一个 String 值;

完整 Demo:tongchengqiu.github.io/mixin-demo/…

3. 文字识别

TextDetector 是一个针对图像中的文本进行识别的底层加速平台组件,我们直接创建其实例:

const textDetector = new TextDetector();

和 FaceDetector 一样,使用 detect 函数来检测图片,该方法同样接受一个图片的 Image 或者 Blob 对象,同时返回一个 Promise 对象:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Shape Detection API Demo</title>
  <style>
  * {
    box-sizing: border-box;
    padding: 0;
    margin: 0;
  }
  </style>
</head>
<body>
<img id="text-image" crossorigin="anonymous" src="//opsqe9du9.bkt.clouddn.com/img-3.png" alt="TEXT">
<script type="text/javascript">
window.onload = main;
function main () {
  const textDetector = new TextDetector();
  const image = document.getElementById('text-image');
  textDetector.detect(image)
    .then(detectedTexts => {
      console.log(detectedTexts);
    })
    .catch((e) => {
      console.error("Text Detection failed, boo.", e);
    })
}
</script>
</body>
</html>

和上述例子一样,打印出检测获取到的 detectedTexts

(12) [DetectedText, DetectedText, DetectedText, DetectedText, DetectedText, DetectedText, DetectedText, DetectedText, DetectedText, DetectedText, DetectedText, DetectedText]
0: DetectedText
  boundingBox: DOMRect {x: 190.78125, y: 42.1875, width: 1527.984375, height: 31.21875, top: 42.1875, …}
  cornerPoints: (4) [{…}, {…}, {…}, {…}]
  rawValue: ""
1: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
2: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
3: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
4: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
5: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
6: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
7: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
8: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
9: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
10: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
11: DetectedText {rawValue: "", boundingBox: DOMRect, cornerPoints: Array(4)}
length: 12

获取到的数组中每个元素是一个识别到的文字的 DetectedText 对象,包含了三个属性:

  • DetectedBarcode: 文字的位置信息;
  • cornerPoints: 顶点位置信息;
  • rawValue: 文字真实值,从 demo 中我们发现这里为空,应该是该功能还未被实现完全;

完整 Demo:tongchengqiu.github.io/mixin-demo/…

总结

从目前来看,Shape Detection API 还处于测试实验阶段,其功能也不尽完善,但是相信在未来的几年,该功能会逐渐被完善并且应用于生产环境。

有了 Shape Detection API ,在很多场景下都可以很大程度地降低应用的复杂性,并且使得 Web 应用更加具有独立性。

  • 应用人脸识别,我们能在用户处理图片的时候更精确的标识出人脸,给予更精确的建议;
  • 应用 二维码/条形码 识别,配合摄像头的调用,可以直接在前端层面获取扫描信息,进行支付、跳转、添加好友等操作;
  • 应用文字识别,我们能够直接在用户端实现 OCR 的功能;

从目前来看,越来越多的底层 API 可以直接在浏览器环境中使用,前端应用能够直接使用更多的系统资源,调用更多的硬件接口。这也是未来的一个趋势,当浏览器赋予了 Web 更多的能力,Web 也将可以提供给用户更优秀的体验。

参考