转《在浏览器中使用tensorflow.js进行人脸识别的JavaScript API》
作者 | Vincent Mühle
编译 | 姗姗
出品 | 人工智能头条(公众号ID:AI_Thinker)
【导读】随着深度学习方法的应用,浏览器调用人脸识别技术已经得到了更广泛的应用与提升。在实际过程中也具有其特有的优势,通过集成与人脸检测与识别相关的API,通过更为简单的coding就可以实现。今天将为大家介绍一个用于人脸检测、人脸识别和人脸特征检测的 JavaScript API,通过在浏览器中利用 tensorflow.js 进行人脸检测和人脸识别。大家不仅可以更快速学习这个,对有人脸识别技术需求的 JS 开发者来说更是一件值得开心的事。
▌前言
对于 JS 开发者来说这将是一件很开心的事,那就是终于可以在浏览器中进行人脸识别了!通过接下来的这篇文章,将为大家介绍 face-api.js,一个构建在 tensorflow.js core 上的 javascript 模块,实现了人脸检测、人脸识别和人脸特征检测三种 CNNs (卷积神经网络)。
我们将通过研究一个简单的代码示例,只用几行代码就可以试着使用这个包。
▌第一个人脸识别包 face-recognition.js,现在又来了一个包?
如果读过我的另一篇关于人脸识别的文章 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 几乎相同的结果,但,是在浏览器中实现的!而最棒的一点是,它不需要设置任何外部依赖关系,就可以直接使用。还有一个意外的奖励 —— 在 WebGL 上运行操作 ,GPU 的加速。
这足以让我相信,javascript 社区需要这样一个包!这也将留给你们足够的想象空间,你们可以用它来构建各种各样的应用。
▌如何用深度学习解决人脸识别问题
如果你是希望尽快开始,你可以跳过这一部分,直接跳到编码中。但是为了更好地理解 face-api.js 使用的方法。要实现人脸识别,强烈建议参与一起学习,因为我经常会被问到这个问题。
简单来说,我们实际上想要实现的是,识别给出的一个人的面部图像,用作输入图像(input image)。
我们的方法是,给出想识别的那个人的一张或多张图片,并给此人的名字打上标签,用作参考数据(reference data)。现在将输入图片与引用数据进行对比并找出最相似的参考图片。如果两个图像足够相似,我们将会输出此人的名字,否则我们输出结果为 “unknow”。
听起来不错吧!然而这其中还存在两个问题。首先,如果一张照片中有多人并且我们想把所有人都识别出来该怎么办?其次,我们需要能够计算出两张人脸图像的相似度度量,以便比较它们。
▌人脸检测
对于第一个问题的答案是通过人脸检测来解决。简单地说,我们首先定位输入图像中的所有面孔。人脸检测,face-api.js 实现了一个 SSD 算法,它基本上是基于 MobileNetV1 的 CNN,在网络的顶部有一些额外的盒预测层。
网络返回每张面孔的边界框与相应的分数,即显示面孔的每个边界框的概率。这些分数用于筛选边界区域,因为图像中可能根本不包含任何面孔。注意,即使只有一个人要检索边界框,人脸检测也应该执行。
▌人脸特征检测和人脸对齐
第一个问题解决了!但是,我们想要对齐边界框,这样我们就可以在传递给人脸识别网络之前,在每个区域的人脸中心提取出图像,这将使人脸识别更加准确!
为此 face-api.js 实现了一个简单的 CNN 网络,此网络返回给定人脸图像的 68 个点的面部特征。
根据特征点的位置,边界区域可以集中在面部中心。在下图中你可以看到人脸检测的结果(左)与对齐的人脸图像(右)
▌人脸识别
现在我们可以将提取和对齐的人脸图像输入到人脸识别网络中,该网络是基于类似 ResNet-34 的架构,基本上对应于 dlib 中实现的架构。该网络已经被训练学习将人脸的特征映射到人脸描述符(一个有128个值的矢量)中,通常也被称为人脸嵌入。
现在回到比较两个人脸时的原始问题:我们将使用提取的每张人脸图像的描述符,并将它们与参考数据的人脸描述符进行比较。更准确地说,我们可以计算两张人脸描述符之间的欧式距离,根据阈值判断两个人脸是否相似(对于 150×150 幅人脸图像,0.6 是一个很好的阈值)。使用欧几里得距离方法非常有效,当然你也可以选择任意类型的分类器。下面的 gif 图像例子就是通过欧几里得距离来比较的两张人脸图像:
在学过了人脸识别的理论之后,我们开始 coding ~~
▌编码
在这个简短的示例中,我们将逐步看到如何在下面这张多人的输入图像上进行人脸识别:
▌脚本
首先,从 dist / face - api .js上或者 dist/face-ap.min.js 的minifed版本中获取 latest build ,包括脚本:
<script src="face-api.js"></script>
如果用 npm :
npm i face-api.js
▌加载模型数据
根据你的应用需求,可以专门加载需要的模型,但是要运行一个完整的端到端示例,我们需要加载人脸检测、人脸特征检测和人脸识别这三个模型。模型文件在 repo 上可用,可在此找到。
链接:
https://github.com/justadudewhohacks/faceapi.js/tree/master/weights
和原始模型相比,已经量化了模型的权重,模型文件大小减少了75%,以允许客户端只加载所需要的最小数据。此外,模型的权重被分割成最大 4 MB的组块,使浏览器可以缓存这些文件,这样只需要加载一次。
模型文件可以作为静态资源来提供在给 web 应用程序,也可以在其他地方托管它们,通过指定文件的路径或 url 来加载它们。假设在 public/models 下一个模型目录中提供它们。
const MODEL_URL = '/models'await faceapi.loadModels(MODEL_URL)
如果你只想加载特殊模块:
const MODEL_URL = '/models'
await faceapi.loadFaceDetectionModel(MODEL_URL)
await faceapi.loadFaceLandmarkModel(MODEL_URL)
await faceapi.loadFaceRecognitionModel(MODEL_URL)
▌从输入图像接收所有面孔的完整描述
神经网络接受 HTML 图像、画布或视频元素作为输入。简单地说,要检测输入的人脸的边界,只需使 Score > minScore
const minConfidence = 0.8const fullFaceDescriptions = await faceapi.allFaces(input, minConfidence)
完整的脸部描述包含检测结果(边界框+分数)、脸部特征和计算描述符。faceapi.js 做了之前讨论所有的问题。也可以手动获取人脸位置和特征。github repo上有这样的示例。
注意,边界和特征与原始图像/媒体大小相关。如果显示的图像大小与原始图像大小不一致,可以调整它们的大小:
const resized = fullFaceDescriptions.map(fd => fd.forSize(width, height))
可以通过画出边界区域来可视化检测结果
fullFaceDescription.forEach((fd, i) => { faceapi.drawDetection(canvas, fd.detection, { withScore: true })})
人间特征按照下面的方法显示出来
fullFaceDescription.forEach((fd, i) => {
faceapi.drawLandmarks(canvas, fd.landmarks, { drawLines: true })
})
▌人脸识别
知道了如何在输入图像中检索所有人脸的位置和描述符,我们将得到一些分别显示一个人的图像,并计算人脸描述符。这些描述符就是我们的参考数据。
假设我们有一些示例图像,我们首先用 url 获取图像。
然后使用 faceapi.bufferToImage 从数据缓存区中创建 HTML 图像元素:
// fetch images from url as blobsconst blobs = await Promise.all( ['sheldon.png' 'raj.png', 'leonard.png', 'howard.png'].map( uri => (await fetch(uri)).blob() ))// convert blobs (buffers) to HTMLImage elementsconst images = await Promise.all(blobs.map( blob => await faceapi.bufferToImage(blob)))
接下来,对于每个图像,定位被试的脸并计算面部描述符,就像之前对输入图像所做的处理那样:
const refDescriptions = await Promsie.all(images.map(
img => (await faceapi.allFaces(img))[0]
))
const refDescriptors = refDescriptions.map(fd => fd.descriptor)
现在,剩下要做的就是循环遍历输入图像的人脸描述,找到与参考数据欧式距离最小的描述符:
const sortAsc = (a, b) => a - bconst labels = ['sheldon', 'raj', 'leonard', 'howard']const results = fullFaceDescription.map((fd, i) => { const bestMatch = refDescriptors.map( refDesc => ({ label: labels[i], distance: faceapi.euclideanDistance(fd.descriptor, refDesc) }) ).sort(sortAsc)[0] return { detection: fd.detection, label: bestMatch.label, distance: bestMatch.distance }})
正如前面讲到的,在这里用效果很好的欧氏距离作为相似度度量。最终得到了在输入图像中每个人的最佳匹配。
最后可以将边界框和它们的标签一起画出来并显示结果:
// 0.6 is a good distance threshold value to judge
// whether the descriptors match or not
const maxDistance = 0.6
results.forEach(result => {
faceapi.drawDetection(canvas, result.detection, { withScore: false })
const text = `${result.distance < maxDistance ? result.className : 'unkown'} (${result.distance})`
const { x, y, height: boxHeight } = detection.getBox()
faceapi.drawText(
canvas.getContext('2d'),
x,
y + boxHeight,
text
)
})
这就是这次的学习之旅!至此希望大家已经学会如何使用这个 api,并且建议大家看一下 repo 中的其他示例。
——【完】——
转《在浏览器中使用tensorflow.js进行人脸识别的JavaScript API》的更多相关文章
- face-api.js:一个在浏览器中进行人脸识别的 JavaScript 接口
Mark! 本文将为大家介绍一个建立在「tensorflow.js」内核上的 javascript API——「face-api.js」,它实现了三种卷积神经网络架构,用于完成人脸检测.识别和特征点检 ...
- TensorFlow.js之安装与核心概念
TensorFlow.js是通过WebGL加速.基于浏览器的机器学习js框架.通过tensorflow.js,我们可以在浏览器中开发机器学习.运行现有的模型或者重新训练现有的模型. 一.安装 ...
- 在Java中直接调用js代码(转载)
http://blog.csdn.net/xzyxuanyuan/article/details/8062887 JDK1.6版添加了新的ScriptEngine类,允许用户直接执行js代码. 在Ja ...
- 第十一章:WEB浏览器中的javascript
客户端javascript涵盖在本系列的第二部分第10章,主要讲解javascript是如何在web浏览器中实现的,这些章节介绍了大量的脚本宿主对象,这些对象可以表示浏览器窗口.文档树的内容.这些章节 ...
- 在Java中直接调用js代码
JDK1.6版添加了新的ScriptEngine类,允许用户直接执行js代码. 在Java中直接调用js代码 不能调用浏览器中定义的js函数,会抛出异常提示ReferenceError: “alert ...
- TensorFlow.js入门(一)一维向量的学习
TensorFlow的介绍 TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理.Tensor(张量)意味着N维数组,Flow(流)意味着 ...
- JavaScript权威指南--WEB浏览器中的javascript
知识要点 1.客户端javascript window对象是所有客户端javascript特性和API的主要接入点.它表示web浏览器的一个窗口或窗体,并且可以用window表示来引用它.window ...
- 解决webkit浏览器中js方法中使用window.event提示未定义的问题
这实际上是一个浏览器兼容性问题,根源百度中一大堆,简要说就是ie中event对象是全局变量,所以哪里都能使用到,但是webkit内核的浏览器中却不存在这个全局变量event,而是以一个隐式的局部变量的 ...
- JS Date当前时间:获取日期时间方法在各浏览器中的差异
转自:http://www.feiesoft.com/00047/<script type="text/javascript"> // JS Date当前时间获取方法在 ...
随机推荐
- go语言中如何模拟100个IP同时并发访问服务器,每个ip要重复访问1000次。每个Ip一分钟之内只能访问一次
package main import ( "time" "sync" "fmt" "sync/atomic" ) ty ...
- AJAX方式发送远程请求报错:No 'Access-Control-Allow-Origin' header
AJAX GET方式发送远程请求,chrome开发者工具console中报错:XMLHttpRequest cannot load http://www.shikezhi.com/ajax/getDa ...
- jenkins使用2----基本实例
一.配置 1.点击新建,选择构建自由风格 2.剩下的都不动,来到构建步骤,新增一个输出hell world 3.保存后点击立即构建 二.查看日志 4.点击构建历史,再点击控制台输出 5.第三行显示 临 ...
- linux注释多行
方法一:使用可视化模块添加实现多行注释 1.打开文件/etc/password进行测试: vim /etc/password 2.进入到视图模式:按ctrl+v 1 root:x:0:0:root:/ ...
- 随机产生1-12的整数 , 根据产生整数输出一下该月份的季节信息(Math.random()和if语句的应用)
package com.summer.cn; /** * @author Summer *随机产生1-12的整数 , 根据产生整数输出一下该月份的季节信息 */ public class Test04 ...
- Spark笔记-repartition和coalesce
窄依赖.宽依赖以及stage的划分依据:https://www.cnblogs.com/itboys/p/6673046.html 参考: http://blog.csdn.net/u01268493 ...
- Google Protocol Buffers学习
参考资料:http://www.cnblogs.com/royenhome/archive/2010/10/29/1864860.html 参考资料:http://www.jianshu.com/p/ ...
- Gym101237C The Palindrome Extraction Manacher、SAM、倍增
传送门 假设字符串\(B,D\)满足\(|B| \geq |D|\),那么一定会有\(B=rev(D)+T\),其中\(T\)是一个回文串. 考虑枚举回文串\(T\)的中心\(p\),找到以\(p\) ...
- Windows Community Toolkit 3.0 - InfiniteCanvas
概述 InfiniteCanvas 是一个 Canvas 控件,它支持无限画布的滚动,支持 Ink,文本,格式文本,画布缩放操作,撤销重做操作,导入和导出数据. 这是一个非常实用的控件,在“来画视频” ...
- plw的晚餐(毒瘤题害我暴0)
题意 描述 plw吃完午饭之后,马上又觉得肚子饿了.他决定马上从美食区离开,赶往下一个吃饭地点"香香鸡".但是在plw离开离开美食区之前,需要按美食区的规矩画一个特殊符号,并且如果 ...