今天给大家分享的内容是纯 javascript 实现的人脸识别。希望体验一下今天 web 端技术的飞速发展。
简单创建一个项目,引入两个关键文件和文件夹
- models 是训练出来模型,这些模型是通过大量图片训练出来的。
- face-api.min.js 引入依赖文件
创建一个 video 标签来捕捉我这张老脸。
<video id="video" width="720" height="560" autoplay muted></video>
简单地给样式
<style>
body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<script defer src="./face-api.min.js"></script>
<script defer src="./app.js"></script>
这里注意一下引用顺序,我们需要引入 face-api.min.js 这个依赖。
通过摄像头捕捉视频
function startVideo(){
navigator.getUserMedia(
{video:{}},
stream => video.srcObject = stream,
err => console.log(err)
)
}
startVideo();
这里我们使用 navigator 的 getUserMedia 获取设备的多媒体设备,传入 video 表示要获取视频流,然后将视频流传入到 video 标签来显示。
导入训练好的模型
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
faceapi.nets.faceExpressionNet.loadFromUri('/models'),
]).then(startVideo());
通过 Promise 的 all 将这些文件同时进行异步加载,
- tinyFaceDetector 这是轻量级可以快速识别人脸的模型
- faceLandmark68Net 用于对人脸不同部位识别的模型
- faceRecognitionNet 识别出人脸的位置,和覆盖的范围
- faceExpressionNet 用于识别人的情绪,是高兴呀还是高兴呀 呵呵
所有模型都加载完毕后再启动我们的视频
获取识别数据
video.addEventListener('play',()=>{
setInterval(async()=>{
const detections = await faceapi.detectAllFaces(video,
new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
// .withFaceExpressions()
console.log(detections);
},100)
})
-
识别是个耗时的操作,所有用异步方法获取识别数据,调用 faceapi 的 detectAllFaces 方法,传入要识别的资源,也就是视频,然后我们要识别什么可以传入一个 options 告诉识别器我们要识别什么。打印识别出来的结果数据。
绘制人脸识别框
这里我们创建一个 canvas 用于将识别出来数据绘制到视频上,canvas 可以用 js 动态创建
canvas {
position: absolute;
top: 0;
left: 0;
}
这里需要给 canvas 一个绝对定位,以便和我们视频对其。
const canvas = faceapi.createCanvasFromMedia(video);
document.body.appendChild(canvas);
const displaySize = { width: video.width, height: video.height};
- faceapi.createCanvasFromMedia(video) 创建 canvas
video.addEventListener('play',()=>{
const canvas = faceapi.createCanvasFromMedia(video);
document.body.appendChild(canvas);
const displaySize = { width: video.width, height: video.height};
faceapi.matchDimensions(canvas,displaySize);
setInterval(async()=>{
const detections = await faceapi.detectAllFaces(video,
new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
const resizedDetections = faceapi.resizeResults(detections,displaySize)
canvas.getContext('2d').clearRect(0,0,canvas.width,canvas.height);
faceapi.draw.drawDetections(canvas,resizedDetections);
// .withFaceExpressions()
// console.log(detections);
},100)
})
const displaySize = { width: video.width, height: video.height}
让 canvas 与我们 vidoe 大小匹配
const resizedDetections = faceapi.resizeResults(detections,displaySize)
将我们测试的框结果与显示大小相匹配。
canvas.getContext('2d').clearRect(0,0,canvas.width,canvas.height);
清除上一次绘制的结果,下面就是讲结果绘制到视频上
faceapi.draw.drawDetections(canvas,resizedDetections);