TensorFlow.js实战:移动端实时人脸检测与高性能贴纸叠加
126
0
0
0
前言
想象一下,你的网页应用能像Snapchat或TikTok一样,实时识别人脸并叠加各种有趣的贴纸或特效,是不是很酷炫?TensorFlow.js让这一切成为了可能。本文将带你一步步实现这个功能,并针对移动设备进行性能优化,确保流畅的用户体验。
技术栈
- TensorFlow.js: 用于在浏览器中运行机器学习模型的库。
- Face Detection Model (例如:BlazeFace, MediaPipe FaceMesh): 预训练的人脸检测模型,用于识别视频流中的人脸。
- HTML5 Canvas: 用于绘制视频帧和叠加贴纸/特效。
- JavaScript: 用于控制整个流程。
步骤详解
环境搭建:
引入TensorFlow.js库:
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.18.0/dist/tf.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/face-detection@1.0.4/dist/face-detection.min.js"></script>创建HTML元素:
<video id="video" width="640" height="480" autoplay muted></video> <canvas id="canvas" width="640" height="480"></canvas>
获取视频流:
使用
getUserMediaAPI访问摄像头:async function setupCamera() { const video = document.getElementById('video'); const stream = await navigator.mediaDevices.getUserMedia({ 'audio': false, 'video': {facingMode: 'user'}, }); video.srcObject = stream; return new Promise((resolve) => { video.onloadedmetadata = () => { resolve(video); }; }); }
加载人脸检测模型:
选择合适的模型(例如BlazeFace),并加载:
async function loadFaceDetectionModel() { const model = await faceDetection.createDetector(faceDetection.SupportedModels.MediaPipeFaceMesh, { runtime: 'tfjs', modelType: 'mediapipe_face_mesh', maxFaces: 1, // 限制检测的人脸数量,提高性能 flipHorizontal: true, }); return model; }
实时人脸检测:
从视频流中获取帧,并使用模型进行人脸检测:
async function detectFaces(model, video) { const predictions = await model.estimateFaces(video); return predictions; }
贴纸/特效叠加:
获取人脸关键点(例如眼睛、鼻子、嘴巴等),并根据这些关键点的位置和大小,将贴纸或特效绘制到Canvas上:
function drawOverlay(predictions, canvas, video) { const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); predictions.forEach(prediction => { const keypoints = prediction.scaledMesh; // 获取人脸关键点 // 示例:在鼻子位置绘制一个简单的圆形贴纸 const nose = keypoints[4]; // 鼻子关键点索引 const x = nose[0]; const y = nose[1]; const stickerSize = 50; // 贴纸大小 ctx.beginPath(); ctx.arc(x, y, stickerSize / 2, 0, 2 * Math.PI); ctx.fillStyle = 'red'; ctx.fill(); }); }
性能优化:
模型选择: 选择轻量级的模型,例如BlazeFace,牺牲一定的精度来换取更快的速度。
降低分辨率: 降低视频流的分辨率,减少计算量。
限制检测人脸数量:
maxFaces: 1只检测一张人脸,减少计算负担。帧率控制: 不必每帧都进行检测,可以隔几帧检测一次。例如,每秒检测15帧:
let lastTime = 0; const fps = 15; // 每秒15帧 function shouldDetect(currentTime) { const interval = 1000 / fps; if (currentTime - lastTime >= interval) { lastTime = currentTime; return true; } return false; }硬件加速: 确保TensorFlow.js使用WebGL后端,利用GPU进行加速。
代码优化: 避免在循环中创建对象,尽量复用对象。
主循环:
将上述步骤整合到主循环中:
async function main() { const video = await setupCamera(); const model = await loadFaceDetectionModel(); const canvas = document.getElementById('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; function render(currentTime) { if (shouldDetect(currentTime)) { detectFaces(model, video).then(predictions => { drawOverlay(predictions, canvas, video); }); } requestAnimationFrame(render); } render(0); } main();
完整代码示例
<!DOCTYPE html>
<html>
<head>
<title>TensorFlow.js Face Detection</title>
<style>
body {
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
}
#container {
position: relative;
}
#canvas {
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<h1>TensorFlow.js 实时人脸检测</h1>
<div id="container">
<video id="video" width="640" height="480" autoplay muted></video>
<canvas id="canvas" width="640" height="480"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.18.0/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/face-detection@1.0.4/dist/face-detection.min.js"></script>
<script>
async function setupCamera() {
const video = document.getElementById('video');
const stream = await navigator.mediaDevices.getUserMedia({
'audio': false,
'video': {facingMode: 'user'},
});
video.srcObject = stream;
return new Promise((resolve) => {
video.onloadedmetadata = () => {
resolve(video);
};
});
}
async function loadFaceDetectionModel() {
const model = await faceDetection.createDetector(faceDetection.SupportedModels.MediaPipeFaceMesh, {
runtime: 'tfjs',
modelType: 'mediapipe_face_mesh',
maxFaces: 1,
flipHorizontal: true,
});
return model;
}
async function detectFaces(model, video) {
const predictions = await model.estimateFaces(video);
return predictions;
}
function drawOverlay(predictions, canvas, video) {
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
predictions.forEach(prediction => {
const keypoints = prediction.scaledMesh;
const nose = keypoints[4];
const x = nose[0];
const y = nose[1];
const stickerSize = 50;
ctx.beginPath();
ctx.arc(x, y, stickerSize / 2, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
});
}
let lastTime = 0;
const fps = 15;
function shouldDetect(currentTime) {
const interval = 1000 / fps;
if (currentTime - lastTime >= interval) {
lastTime = currentTime;
return true;
}
return false;
}
async function main() {
const video = await setupCamera();
const model = await loadFaceDetectionModel();
const canvas = document.getElementById('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
function render(currentTime) {
if (shouldDetect(currentTime)) {
detectFaces(model, video).then(predictions => {
drawOverlay(predictions, canvas, video);
});
}
requestAnimationFrame(render);
}
render(0);
}
main();
</script>
</body>
</html>
总结
通过以上步骤,你就可以使用TensorFlow.js实现一个简单的实时人脸检测和贴纸叠加功能。记住,性能优化是关键,尤其是在移动设备上。选择合适的模型、控制帧率、利用硬件加速等手段,可以显著提高用户体验。快去尝试一下,打造你自己的酷炫应用吧!