Face-api.js 开发者教程:从入门到实战
目录
- 什么是 Face-api.js?
- 为什么选择 Face-api.js?
- 准备工作:环境搭建
- 创建项目
- 安装依赖
- 下载模型文件
- 核心概念:模型与 API
- 实战演练:构建你的第一个应用
- 加载模型
- 访问摄像头
- 进行人脸检测
- 检测面部特征点
- 估算年龄与性别
- 进阶:面部识别
- 完整代码示例
- 最佳实践与优化技巧
- 总结与资源
什么是 Face-api.js?
Face-api.js 是一个基于 TensorFlow.js 的 JavaScript 库,它允许你在浏览器端直接运行预训练的计算机视觉模型,而无需任何服务器端处理,这意味着你可以将面部识别、检测等功能直接集成到你的 Web 应用中,保护用户隐私,并提供即时响应。
它支持多种任务:
- 人脸检测:在图像或视频中定位人脸的位置。
- 面部标志点检测:找到脸上的 68 个关键点(如眼睛、鼻子、嘴唇的轮廓)。
- 面部识别:识别图像中的人是谁,需要先进行“注册”。
- 年龄与性别估算:估算人脸的年龄范围和性别。
- 表情识别:识别出人脸所表达的情绪(如开心、悲伤、惊讶)。
为什么选择 Face-api.js?
- 纯前端实现:所有计算都在用户的浏览器中完成,数据无需上传到服务器,隐私性极高。
- 易于集成:对 JavaScript 开发者非常友好,API 设计简洁。
- 基于 TensorFlow.js:利用了谷歌强大的机器学习框架,性能和准确性都有保障。
- 实时性:可以在视频流中进行实时检测,适用于直播、视频通话等场景。
准备工作:环境搭建
1 创建项目
创建一个新的项目目录,并初始化一个 package.json 文件。
mkdir face-api-demo cd face-api-demo npm init -y
2 安装依赖
我们需要安装 face-api.js 和一个用于简化视频处理的库 @tensorflow/tfjs-converter(虽然 face-api.js 通常会自动处理,但显式安装更稳妥)。
npm install face-api.js @tensorflow/tfjs
3 下载模型文件
这是最关键的一步!face-api.js 的所有功能都依赖于预训练好的模型文件,你需要从它的 GitHub 仓库中下载这些文件。
操作步骤:
- 访问 face-api.js 的 Releases 页面。
- 找到最新的稳定版本(
v0.22.2)。 - 在该版本的 Assets 中,下载
models-weights_manifest.json和face-api.js文件。 - 在你的项目根目录下,创建一个名为
public的文件夹,并将下载的这两个文件放入public文件夹中。 - 从 face-api.js 的
weights目录 下载所有模型文件(.bin和.json),并将它们也放入public文件夹。
你的项目结构应该看起来像这样:
face-api-demo/
├── node_modules/
├── public/
│ ├── age_gender_model-weights_manifest.json
│ ├── face_expression_model-weights_manifest.json
│ ├── face_landmark_68_model-weights_manifest.json
│ ├── face_landmark_68_point_model-weights_manifest.json
│ ├── face_recognition_model-weights_manifest.json
│ ├── face_detection_model-weights_manifest.json
│ ├── faceapi.min.js
│ ├── faceapi.js
│ ├── ... (所有 .bin 和 .json 权重文件)
├── package.json
└── ... (我们将创建的 HTML 和 JS 文件)
核心概念:模型与 API
face-api.js 的核心是加载不同的模型来执行不同的任务。
faceapi.nets.tinyFaceDetector.loadFromUri('/public'): 一个轻量级的人脸检测模型,速度快,但精度稍低,适合实时视频。faceapi.nets.ssdMobilenetv1.loadFromUri('/public'): 一个更精确的人脸检测模型,但速度较慢。faceapi.nets.faceLandmark68Net.loadFromUri('/public'): 用于检测 68 个面部标志点。faceapi.nets.faceRecognitionNet.loadFromUri('/public'): 用于面部识别,计算人脸的“特征向量”。faceapi.nets.ageGenderNet.loadFromUri('/public'): 用于估算年龄和性别。faceapi.nets.faceExpressionNet.loadFromUri('/public'): 用于识别表情。
工作流程:
- 在应用启动时,异步加载你需要的模型。
- 当用户授权摄像头后,获取视频流。
- 在一个
requestAnimationFrame循环中,不断从视频中捕获帧。 - 使用
detectAllFaces或detectSingleFace等方法对捕获的帧进行分析。 - 将返回的结果(如边界框、特征点等)绘制到
<canvas>上。
实战演练:构建你的第一个应用
我们将创建一个简单的 Web 页面,它能够打开摄像头,实时检测人脸,并在画布上绘制出边界框和特征点。
1 创建 HTML 文件
在 public 文件夹下创建 index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">Face-api.js Demo</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 20px;
}
#video, #canvas {
border: 2px solid black;
max-width: 100%;
}
#canvas {
position: absolute;
}
</style>
</head>
<body>
<h1>Face-api.js 实时人脸检测</h1>
<div style="position: relative;">
<video id="video" width="720" height="560" autoplay muted></video>
<canvas id="canvas"></canvas>
</div>
<button id="startBtn">开始检测</button>
<!-- 引入 face-api.js -->
<script src="faceapi.js" type="text/javascript"></script>
<!-- 引入我们自己的 JS 逻辑 -->
<script src="app.js" type="text/javascript"></script>
</body>
</html>
2 创建 JavaScript 逻辑文件
在 public 文件夹下创建 app.js,我们将在这里编写所有核心代码。
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const startBtn = document.getElementById('startBtn');
const displaySize = { width: video.width, height: video.height };
// 1. 加载模型
async function loadModels() {
// 使用 async/await 异步加载
await faceapi.nets.tinyFaceDetector.loadFromUri('/public');
await faceapi.nets.faceLandmark68Net.loadFromUri('/public');
await faceapi.nets.faceRecognitionNet.loadFromUri('/public');
await faceapi.nets.ageGenderNet.loadFromUri('/public');
await faceapi.nets.faceExpressionNet.loadFromUri('/public');
console.log('所有模型加载完成!');
}
// 2. 启动摄像头
async function startVideo() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: {} });
video.srcObject = stream;
// 等待视频元数据加载完成
return new Promise((resolve) => {
video.onloadedmetadata = () => {
resolve(video);
};
});
} catch (err) {
console.error("无法访问摄像头: ", err);
alert("请允许访问摄像头以使用此功能。");
}
}
// 3. 调整画布大小以匹配视频
function resizeCanvasToDisplaySize() {
displaySize.width = video.videoWidth;
displaySize.height = video.videoHeight;
canvas.width = displaySize.width;
canvas.height = displaySize.height;
}
// 4. 检测并绘制人脸
async function detect() {
// 清除上一帧的绘制
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 使用 tinyFaceDetector 进行检测
const detections = await faceapi
.detectAllFaces(video, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceExpressions()
.withAgeAndGender();
// 调整检测结果以匹配显示尺寸
const resizedDetections = faceapi.resizeResults(detections, displaySize);
// 绘制检测结果
faceapi.draw.drawDetections(canvas, resizedDetections);
faceapi.draw.drawFaceLandmarks(canvas, resizedDetections);
faceapi.draw.drawFaceExpressions(canvas, resizedDetections);
// 在每个检测到的人脸旁边绘制标签(年龄、性别等)
resizedDetections.forEach((detection) => {
const box = detection.detection.box;
const drawOptions = { anchor: [box.x + box.width + 10, box.y] };
const age = Math.round(detection.age);
const gender = detection.gender;
const genderProbability = Math.round(detection.genderProbability * 100);
const expression = Object.keys(detection.expressions).reduce((a, b) => detection.expressions[a] > detection.expressions[b] ? a : b);
const drawText = `${gender} (${genderProbability}%) - ${age} years - ${expression}`;
new faceapi.draw.DrawTextField([drawText], box.topRight, drawOptions).draw(canvas);
});
// 递归调用,实现实时检测
requestAnimationFrame(detect);
}
// 主函数
async function main() {
await loadModels();
await startVideo();
video.addEventListener('play', () => {
resizeCanvasToDisplaySize();
detect();
});
}
// 绑定按钮事件
startBtn.addEventListener('click', main);
3 运行你的应用
你可以启动一个简单的 HTTP 服务器来运行你的应用,因为浏览器出于安全考虑,不允许直接从 file:// 协议访问摄像头。
如果你安装了 http-server,可以直接运行:
npx http-server public
或者使用 Python:
# 确保你已安装 Python cd public python -m http.server 8000
然后在浏览器中打开 http://localhost:8000(或你看到的地址),点击“开始检测”按钮,允许摄像头权限,你就能看到神奇的效果了!
完整代码示例
上面的 app.js 和 index.html 就是完整的示例代码,你只需要将它们和下载好的模型文件放在正确的位置即可。
最佳实践与优化技巧
- 按需加载模型:不要一次性加载所有模型,根据你的应用需求,只加载必要的模型,可以显著减少初始加载时间。
- 选择合适的检测器:
TinyFaceDetector: 速度最快,适合实时视频。SsdMobilenetv1: 精度更高,适合静态图片或对精度要求高的场景。
- 性能优化:
- 降低检测频率:你不需要以 60fps 的速度进行检测,可以使用
setInterval或setTimeout来降低检测频率,例如每 200ms 检测一次。 - 缩小视频尺寸:在将视频帧送入模型之前,可以将其绘制到一个较小的离屏 canvas 上,然后再进行检测,这会大大减少计算量,但会牺牲一些精度。
- 使用
requestAnimationFrame:这是在浏览器中创建流畅动画的标准做法,可以确保你的绘制和检测与浏览器的刷新率同步。
- 降低检测频率:你不需要以 60fps 的速度进行检测,可以使用
- 错误处理:始终使用
try...catch块来处理摄像头访问失败或模型加载失败的情况,并向用户友好的提示。
总结与资源
恭喜!你已经学会了如何使用 Face-api.js 在浏览器中实现强大的人脸识别功能。
核心要点回顾:
- 环境搭建:安装库,下载模型文件。
- 加载模型:使用
await faceapi.nets.xxx.loadFromUri()异步加载。 - 获取视频:使用
navigator.mediaDevices.getUserMedia()。 - 检测循环:在
video.play事件中,使用requestAnimationFrame循环调用检测函数。 - 绘制结果:使用
faceapi.draw中的辅助函数将检测结果可视化。
进一步学习的资源:
- 官方 GitHub 仓库:https://github.com/justadudewhohacks/face-api.js
这里有最详细的 API 文档、示例和演示。
- TensorFlow.js 官方文档:https://www.tensorflow.org/js
了解底层的机器学习框架。
- MDN Web Docs:https://developer.mozilla.org/
学习关于 WebRTC、Canvas API 等浏览器 API 的知识。
你可以基于这个基础,尝试构建更复杂的应用,比如人脸解锁、表情互动游戏、或者一个简单的员工考勤系统,祝你编码愉快!
