0
雷锋网按:本文为雷锋字幕组编译的技术博客,原标题 face-api.js — JavaScript API for Face Recognition in the Browser with tensorflow.js,作者为 Vincent Mühler 。
翻译 | 王飞 赵朋飞 整理 | MY
我可以很激动地说,我们终于有可能在浏览器中运行人脸识别程序了!在这篇文章中,我会给大家介绍一个基于 TensorFlow.js 核心的 JavaScript 模块,这个模块叫做 face-api.js。为了实现人脸检测、人脸识别以及人脸特征点检测的目的,该模块分别实现了三种类型的卷积神经网络。
和往常一样,我们先看一个简单一点的代码实例,用几行的代码以便能够让大家可以直接开始使用这个包。我们开始吧!
第一个 face-recognition.js,那么现在还有其他包吗?
如果你有阅读过我的另外一篇关于 nodejs 进行人脸识别方面的文章:Node.js+face-recognition.js: Simple and Robust Face Recognition using Deep Learning , 你可能会意识到,一段时间以前,我构建过一个相似的包。比方说三个 face-recognition.js,将人脸识别功能引入 nodejs 当中。
起初,我没有想到在 javascript 社区中对脸部识别软件包的需求如此之高。对于很多人来说,face-recognition.js 似乎是一个很不错的免费软件包了,另外也有像微软和亚马逊提供的付费软件包。但是,一直有人问我能否在浏览器中完整地运行整个人脸识别的流程
最后的答案是肯定的,多亏了 tensorflow.js,利用好 tfjs-core, 我成功实现了部分相似的工具,这些小工具能够让你得到和使用 face-recognition.js 几乎相似的运行结果,并且是在浏览器中。而且最棒的一点是你不需要再安装任何依赖项,它可以直接运行。额外的好处是它还支持 GPU 加速,在 WebGL 上运行操作。
这足让我相信 JavaScript 社区需要这样的浏览器软件包!接下来就是发挥你自己的想象力,你可以用这个来构建各种各样的应用程序。:)
如何用深度学习来解决人脸识别的问题
如果你是那种想要尽快开始的人(或妹子),你可以跳过这一部分并直接跳到代码部分。但为了更好地理解 face-api.js 中用于实现人脸识别的方法,我强烈建议你按照步骤来,因为我经常被问到这一部分的问题。
为了简单起见,我们实际想要实现的是给定一个人的脸部图像然后对他/她进行识别,给定的图像即输入图像。我们解决这个问题的方法是为每个我们想要识别的人提供一个(或多个)图像,并用人名称标记,即参考数据。现在我们将输入图像与参考数据进行比较,并找到最相似的参考图像。如果两个图像足够相似,那我们就输出人名,否则我们输出'未知'。
听起来像是个不错的计划!但是这里仍存在两个问题。首先,如果我们有一张显示多个人的图像,并且我们想要识别所有这些图像,那该怎么办呢?其次,我们还需要能够获得度量两张人脸图像的相似性的量,以便进行比较。
人脸检测
第一个问题的答案是人脸检测。简单地说,我们首先找到输入图像中的所有的人脸。对于人脸检测,face-api.js 实现了 SSD(Single Shot Multibox Detector),它基本上是一个基于 MobileNetV1 的 CNN,在网络顶部叠加了一些额外的预测层。
这个网络返回包围每张脸的 bounding box,以及其对应的分数,即每个 boundingbox 中包含人脸的概率。这里的分数用于过滤边界框,因为图像中可能根本不包含人脸。另外要注意的是,即使图像中只有一个人,为了得到 boundingbox,也应该首先进行人脸检测这一步骤。
人脸特征点检测与人脸对齐
第一个问题解决了 但是,我想指出我们接下来要对齐边界框,在将它们传递到面部识别网络之前,为每个框提取以面部为中心的图像,因为这样可以使面部识别更准确!
针对这个目标。face-api.js 已经实现了一个简单的 CNN,这个网络能够返回给定人脸图片的 68 个脸部特征点。
根据特征点的位置,boundingbox 可以被确定在脸部的中心。下面显示的是人脸检测的结果(左)以及人脸对齐后的结果(右)。
人脸识别
现在我们可以将提取和对齐的人脸图像提供给人脸识别网络,该网络基于类似 ResNet-34 的体系结构,基本上与 dlib 中实现的体系结构相对应。该网络已经被训练,能够学习将人脸的特征映射到一个人脸描述器上(具有 128 个值的特征向量),这一过程通常也被称为面部嵌入。
现在回到我们最开始比较两张脸的这个问题上:我们将使用每个提取的面部图像的面部描述符,并将它们与参考数据的面部描述符进行比较。更确切地说,我们可以计算两个面部描述符之间的欧氏距离,并基于阈值判断两个面是否相似(对于 150×150 大小的面部图像来说,0.6 是比较好的阈值)。使用欧几里德距离的效果非常好,但当然你也可以使用你选择的任何类型的分类器。以下 gif 可视化了两张图片通过欧几里德距离进行比较的过程。
现在,让我们消化一下人脸识别的理论,接下来用代码来编写一个例子吧。
编码时间!
在这个简短的例子中,我们将逐步了解如何在以下输入图像中识别多个人脸:
包含脚本
首先,从 dist/face-api.js 获取最新的编译,或者 从 dist/face-api.min.js 获取修订版,并将脚本包含进来:
如果使用 npm:
加载模型数据
根据您的应用程序的需求,您可以专门加载您需要的模型,但是要运行一个完整的端到端示例,我们需要加载人脸检测、 脸部特征点和人脸识别模型。模型文件可以在 repo 或点击这里获取。
模型的权重已经被量化,与原始模型相比,将模型文件的大小减少了 75%,以允许您的客户只加载所需的最少数据。此外,模型权重被分割成最大 4 MB 的块,允许浏览器缓冲这些文件,以便这些文件只被加载一次。
模型文件可以简单的被当做浏览器的静态资源,或者你可以在其他地方托管它们,并可以通过特定的路由或 URL 加载这些文件。假设你将它们和你的其他资源一起放到模型目录下(public/models):
或者,如果你仅仅想加载特定的模型:
从输入图像中获得对所有面孔的完整描述
神经网络接受 HTML 图像、画布、视频或者张量等形式的输入。使用 score > minScore 检测面部边界框,我们简单的说:
完整的面部描述包括检测结果(边界框+分值),脸部特征,以及计算描述符。正如你所看到的,在前面的讨论中 faceapi.allFaces 在后台做了所有的工作。然而,你也可以手动获取脸部位置和特征点。如果你以此为目标的话,可以在 github repo 找到很多例子。
注意,边界框和特征点位置依赖于原始图像/媒体的大小。如果显示的图像大小与原始图像大小不一致,您可以简单地调整大小:
我们可以通过将边界框绘制到画布上来可视化检测结果 :
脸部特征点可以如下方式显示:
通常,我所做的是将一个绝对定位的画布叠加在 img 元素的顶部,它们的宽度和高度是相同的(可以查看 github 上的示例了解更多信息)
面部识别
现在我们知道了如何检索输入图像中所有人脸的位置和描述了,我们将从一些图像中指出每个人脸并计算出人脸的描述符。这些描述符将会是我们的参考数据。
假设我们有一些可用的示例图像,我们首先从一个 url 获取图像,并使用 faceapi.bufferToImage 从数据缓冲区中创建 HTML 图像元素:
接下来,对于每一个图像,我们定位主题并计算面部描述符,就像我们之前对输入图像所做的操作:
现在,我们要做的所有事情都是循环遍历我们输入图像的面部描述,并找到与参考数据距离最小的描述符:
正如前面提到的,我们使用欧氏距离度量相似度,结果证明它是有效的。我们最终得到了在输入图像中检测到的每个面孔的最佳匹配。
最后,我们可以将边界框和它们的标签一起绘制到画布上,以显示结果:
好了!到目前为止,我希望您已经了解了如何使用这个 api。另外,我还建议您看一下 repo 的其他例子。现在尽情享受这个软件包吧!
如果你喜欢这篇文章,欢迎点赞并在 medium 或 twitter 上关注我。也欢迎在 github repository 上评价。请继续关注更多教程!
雷锋网雷锋网
雷峰网原创文章,未经授权禁止转载。详情见转载须知。