<译> How to detect human faces in JavaScript

翻译系列第五篇,怎样用JS检测人脸(或其他形状),原文地址

Google认为web完全可以和本地应用程序相媲美。多年来,本地应用程序优于web应用程序的一个领域是检测图像中的形状,直到最经几年才能完成诸如面部识别这样的任务,但是情况不再是这样了!

形状检测API

WICG(Web Platform Incubator Community Group)最近提出了一项新的标准提案:形状检测API(Shape Detection API)。它允许检测图像中的两种类型的形状:

  • 面部
  • 条码和二维码

目前,这两个检测器都能在chrome内部实现。默认启用的是条码检测,面部检测是后面的标识(chrome://flags#enable-experimental-web-platform-features)。还有另外一个定义文本检测API的规范,允许检测文本。这些检测器都共享相同的API:

1
2
const detector = new FaceDetector( optionalOptions );
const results = await detector.detect( imageBitmap );

有三个全局可用的接口(在页面和在Web工作线程内部):

  • FaceDetector
  • BarcodeDetector
  • TextDetector

optionalOptions 参数是一个对象,其中包含检测器的附加配置。每个形状检测器都有自己的一组选项,但是在大多数情况下你也可以完全省略这个参数,通常默认值就足够了。

构造检测器之后,你就可以用它的异步方法detect()来检测图像中的形状,该方法返回一个带有图像中形状的坐标和关于该形状的其他信息的对象。例如TextDetector API中识别的文本或FaceDetector API中的眼睛或鼻子等面部特定部位的坐标

imageBitmap 参数是要分析的图像,作为imageBitmap实例传递

备注:为什么这个ImageBitmap 不只是一个img元素或简单的Blob?这是因为形状检测器也可以在workers内部使用,在这里不能访问DOM。使用ImageBitmap 对象可以解决这个问题。此外,它们允许使用更多的图像源,比如画布元素(包括屏幕外的)甚至视频

基本上就是这样!

简单应用

好吧,让我们看看新知识如何应用到实践中去。让我们准备一个示例web应用程序,它将允许使用所提议的API检测形状

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
28
29
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shape Detection API demo</title>
</head>
<body>
<h1>Shape Detection API</h1>

<h2>Face detection</h2>
<label>Choose an image file:
<input type="file" accept="image/*" data-type="face">
</label>

<h2>Barcode detection</h2>
<label>Choose an image file:
<input type="file" accept="image/*" data-type="barcode">
</label>

<h2>Text detection</h2>
<label>Choose an image file:
<input type="file" accept="image/*" data-type="text">
</label>

<script type="module">
</script>
</body>
</html>

该文件包含三个input[type=file]元素,它们将是要分析的图像的来源。它们都有一个[data-type]属性,通知脚本要检索哪个形状。还有一个script[type=module]元素,它将包含处理输入元素所需的代码

1
2
3
4
5
6
7
8
9
import detectShape from './detector.mjs'; // 1

document.body.addEventListener( 'change', async ( { target } ) => { // 2
const [ image ] = target.files; // 3

const detected = await detectShape( image, target.dataset.type ); // 4

console.log( detected ); // 5
} );

首先,从检测器导入detectShape()函数。detector.mjs这个函数可以完成所有的工作

然后将更改事件侦听器绑定到文档。由于有了事件委托机制,它将对输入元素中的所有更改做出反应

另外,侦听器是异步的,因为检测器也是异步的,我希望在可能的情况下使用async / await语法

还有一个解构语句,用于只获取传递给侦听器的事件对象的目标属性,从而只获取触发事件的元素

幸运的是,下一行没有那么拥挤,它基本上获取用户选择的文件并将其保存到image 变量

当你获得图像时,您可以将它与从[data-type]属性(4)获取的检测器类型一起传递给detectShape()函数

最后将获取的结果打印在控制台

JavaScript

去看看detector.mjs文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const options = { // 5
face: {
fastMode: true,
maxDetectedFaces: 1
},
barcode: {},
text: {}
}
async function detectShape( image, type ) {
const bitmap = await createImageBitmap( image ); // 2
const detector = new window[ getDetectorName( type ) ]( options[ type ] ); //3
const detected = await detector.detect( bitmap ); // 6

return detected; // 7
}

function getDetectorName( type ) {
return `${ type[ 0 ].toUpperCase() }${ type.substring( 1 ) }Detector`; // 4
}

export default detectShape; // 1

该文件只有一个detectShape()函数导出,这个函数转换传递的文件,使用createImageBitmap()全局函数生成所需的ImageBitmap,然后创建一个适当的检测器

构造函数名称派生自type 参数。它的第一个字母更改为大写,并添加Detector 后缀

每一种检测器都有一个包含选项的对象。条形码和文本检测器都将使用默认选项,但是对于人脸检测器,有两个选项

  • fastMode 开启不太准确的检测(这将识别更多的面孔,但也会增加误报的数量)
  • maxDetectedFaces 设置为1只检测一张脸

创建形状检测器后,可以调用它的detect()方法并等待结果。当获取结果时,将其返回

运行程序

编码已经完成,但是,如果直接从该目录启动应用程序,它将无法正常工作。这主要是因为代码使用了受CORS规则约束的ES模块。解决这些问题有两种方法

  • 切换回旧的——非模块JavaScript一点都不cool
  • 开一个本地静态资源服务器——非常的cooooooooool

幸运的是,使用本地web服务器非常简单,只需在应用程序所在的目录中运行以下命令

1
npx http-server ./

(注:作者后面这里稍微解释了一下http-server的下载使用啥的,其实简单而言就目标目录,一行命令:

1
hs -a [IPv4] -p [port]

就是这样!有了新的形状检测api,至少在Chrome中检测图像中的某些形状是相当容易的。我们需要等待,看看其他浏览器是否会跟进

源码和案例

该应用程序的完整代码可在GitHub上获得。还有一个稍微增强和样式化的实时文本、条形码和人脸检测演示供您使用。它的源代码也可以在GitHub上找到。不幸的是,在撰写本文时,Linux上还不支持形状检测

接下来,人脸检测最重要的应用之一就是人脸识别。这项技术将从图像或视频帧中检测到的人脸与人脸数据库进行匹配。与其他生物识别技术一样,它可以用于认证用户、与计算机、智能手机或其他机器人系统交互、自动索引图像或用于视频监控目的