功能
我们可以利用face-api的人脸识别开源框架开发人脸识别的系统,本文是一个简单的示例,实现的功能一是可以实现对人脸的情绪识别,二是对识别的人脸打上情绪值得标签以及显示关键的识别点;功能如下所示:
所需要的相关知识
在这个示例中用到了Face-api开源框架的相关知识,HTML,JavaScript,NodeJS等,NodeJS主要功能提供本地Web访问。
Face-api开源框架的API
检测人脸
检测图像中的所有的人脸。
const detections = await faceapi.detectAllFaces(input)
默认情况下,detectAllFaces使用SSD Mobilenet V1 人脸检测。您可以通过传递相应的options对象来指定面部检测器:
const detections1 = await faceapi.detectAllFaces(input, new faceapi.SsdMobilenetv1Options())
检测68个人脸特征点
在人脸检测之后,我们还可以如下预测每个检测到的人脸的面部标记:
检测图像中的所有人脸 + 为每个检测到的人脸计算68个面部标记点。
const detectionsWithLandmarks = await faceapi.detectAllFaces(input).withFaceLandmarks()
识别面部表情
人脸表情识别可以对检测到的人脸执行如下操作:
检测图像中的所有人脸 + 识别每个人脸的面部表情。
const detectionsWithExpressions = await faceapi.detectAllFaces(input).withFaceLandmarks().withFaceExpressions()
人脸检测模型
SSD Mobilenet V1
对于人脸检测,本项目实现了一个基于MobileNetV1的SSD(单点多盒检测器Single Shot Multibox Detector)。神经网络将计算图像中每个人脸的位置,并返回边界框以及每个人脸的概率。该人脸检测器的目标是在检测人脸边界盒时获得较高的精度,而不是较低的推理时间。量化模型的大小约为5.4 MB(ssd_mobilenetv1_model)。
68点人脸标记检测模型
该软件包实现了非常轻巧、快速,但准确的68点面部标记检测器。 默认模型的大小仅为350kb( face_landmark_68_model ),微型模型的大小仅为80kb( face_landmark_68_tiny_model )。 两种模型都采用了深度可分离卷积以及紧密连接的块的思想。 这些模型已经在约有35,000张面部图像的数据集上进行了训练,这些数据用68个面部标点标记。
人脸识别模型
对于面部识别,实现了类似于ResNet-34的体系结构,以从任何给定的面部图像计算面部描述符(具有128个值的特征向量),该描述符用于描述人脸的特征。 该模型“不限于”用于训练的一组面部,这意味着您可以将其用于任何人(例如您自己)的面部识别。 您可以通过比较两个人脸的面部描述符来确定两个人脸的相似性,例如通过计算欧式距离或使用您选择的任何其他分类器。
神经网络等效于face-recognition.js中使用的FaceRecognizerNet和dlib人脸识别示例中使用的网络。 权重已通过davisking进行了训练,该模型在LFW基准上的脸部识别上达到了99.38%的预测准确性。量化模型的大小约为6.2 MB (face_recognition_model).
人脸表情识别模型
面部表情识别模型轻巧,快速,并提供合理的准确性。 该模型的大小约为310kb,采用深度可分离卷积和密集连接的块。 它已经过公开数据集上的各种图像以及从网络上抓取的图像的培训。 注意,戴眼镜可能会降低预测结果的准确性。
相关代码
服务器端
server.js
//定义变量
const express = require('express')
const path = require('path')
const { get } = require('request')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
const viewsDir = path.join(__dirname, 'views')
app.use(express.static(viewsDir))
//支持浏览器端以http://localhost 进行访问,跳转到webcam.html上来
app.get('/', (req, res) => res.redirect('/webcam'))
app.get('/webcam', (req, res) => res.sendFile(path.join(viewsDir, 'webcam.html')))
var server = app.listen(process.env.PORT || 3000, listen);
function listen() {
var host = server.address().address;
var port = server.address().port;
console.log('Server app listening at http://' + host + ':' + port);
}
人脸识别采集端
webcam.html
<!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>web 端的人脸识别</title>
<!--这里注意一下引用顺序,我们需要引入 face-api.min.js 这个依赖。只支持HTTP或HTTPS访问-->
<script defer src="face-api.min.js"></script>
<script defer src="script.js"></script>
<!--简单地给样式-->
<!--创建一个画布,绘制人脸识别框,这里我们创建一个 canvas 用于将识别出来数据绘制到视频上,canvas 可以用 js 动态创建-->
<style>
body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
canvas {
position: absolute;
}
</style>
</head>
<body>
<!--创建一个 video 标签来捕捉人脸
autoplay 属性规定一旦视频就绪马上开始播放。如果设置了该属性,视频将自动播放。
muted 属性设置或返回音频/视频是否应该被静音(关闭声音)。-->
<video id="video" width="720" height="560" autoplay muted></video>
</body>
</html>
Script.js
const video = document.getElementById('video')
let expression;
//导入训练好的模型,所有模型都加载完毕后再启动我们的视频
//通过 Promise 的 all 将这些文件同时进行异步加载,
//tinyFaceDetector 这是轻量级可以快速识别人脸的模型
//faceLandmark68Net 用于对人脸不同部位识别的模型
//faceRecognitionNet 识别出人脸的位置,和覆盖的范围
//faceExpressionNet 用于识别人的情绪
Promise.all([
faceapi.nets.ssdMobilenetv1.loadFromUri('/models'),
faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
faceapi.nets.faceExpressionNet.loadFromUri('/models'),
]).then (startVideo)
//通过摄像头捕捉视频
//这里我们使用 navigator 的 getUserMedia 获取设备的多媒体设备,传入 video 表示要获取视频流,然后将视频流传入到 video 标签来显示。
function startVideo(){
navigator.getUserMedia(
{ video:{} },
stream => video.srcObject = stream,
err => console.error(err)
)
}
//获取识别数据
//识别是个耗时的操作,所以用异步方法获取识别数据,调用 faceapi 的 detectAllFaces 方法,
//传入要识别的资源,也就是视频,然后我们要识别什么可以传入一个 options 告诉识别器我们要识
//别什么。打印识别出来的结果数据。
video.addEventListener('play',() => {
//faceapi.createCanvasFromMedia(video) 创建 canvas
const canvas = faceapi.createCanvasFromMedia(video)
document.body.append(canvas)
//让 canvas 与我们 vidoe 大小匹配
const displaysize = { width: video.width,height:video.height }
faceapi.matchDimensions(canvas,displaysize)
setInterval(async () => {
const expression = await faceapi.detectAllFaces(video,
new faceapi.SsdMobilenetv1Options()).withFaceLandmarks().withFaceExpressions()
//将我们测试的框结果与显示大小相匹配。
const resizedDetections = faceapi.resizeResults(expression,displaysize)
//清除上一次绘制的结果,下面就是将结果绘制到视频上
canvas.getContext('2d').clearRect(0,0,canvas.width,canvas.height)
faceapi.draw.drawDetections(canvas,resizedDetections)
faceapi.draw.drawFaceLandmarks(canvas,resizedDetections)
faceapi.draw.drawFaceExpressions(canvas,resizedDetections)
},100)
})
运行
1、git clone https://github.com/davidchenguang/facedetection.git
2、cd 命令转到相应目录下
3、node server.js
4、通过浏览器打开,http://localhost:3000 运行体验