基于faceapi的Web端人脸识别:仅显示摄像头前人员姓名
解决方案
关键修改点
- 移除加载标签图片时的批量控制台输出
- 在页面添加用于显示问候语的元素
- 仅在识别到当前摄像头前的人脸时,输出对应问候语并更新页面显示
修改后的代码
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Face Detection on the browser</title> <script defer src="face-api.min.js"></script> <script defer src="script.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <video id="video" width="600" height="450" autoplay></video> <!-- 添加用于显示问候语的元素 --> <div id="greeting" style="margin-top: 10px; font-size: 24px; font-weight: bold;"></div> </body> </html>
JS代码
const video = document.getElementById("video"); // 获取问候语显示元素 const greetingElement = document.getElementById("greeting"); Promise.all([ faceapi.nets.ssdMobilenetv1.loadFromUri("./models"), faceapi.nets.faceRecognitionNet.loadFromUri("./models"), faceapi.nets.faceLandmark68Net.loadFromUri("./models"), ]).then(startWebcam); function startWebcam() { navigator.mediaDevices .getUserMedia({ video: true, audio: false, }) .then((stream) => { video.srcObject = stream; }) .catch((error) => { console.error(error); }); } function getLabeledFaceDescriptions() { const labels = ["Bibinur", "Emunrich", "Mukthar", "NursultanAhmetsha"]; return Promise.all( labels.map(async (label) => { const descriptions = []; for (let i = 1; i <= 2; i++) { const img = await faceapi.fetchImage(`./labels/${label}/${i}.png`); const detections = await faceapi .detectSingleFace(img) .withFaceLandmarks() .withFaceDescriptor(); descriptions.push(detections.descriptor); // 移除加载标签时的批量输出 } return new faceapi.LabeledFaceDescriptors(label, descriptions); }) ); } video.addEventListener("play", async()=>{ const labeledFaceDescriptors = await getLabeledFaceDescriptions(); const faceMatcher = new faceapi.FaceMatcher(labeledFaceDescriptors); const canvas = faceapi.createCanvasFromMedia(video); document.body.append(canvas); const displaySize = {width: video.width, height: video.height}; faceapi.matchDimensions(canvas, displaySize); // 记录上一次识别的姓名,避免重复输出 let lastRecognizedName = ""; setInterval(async ()=>{ const detections = await faceapi .detectAllFaces(video) .withFaceLandmarks() .withFaceDescriptors(); const resizedDetections = faceapi.resizeResults(detections, displaySize) canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); const results = resizedDetections.map((d) => { return faceMatcher.findBestMatch(d.descriptor); }); // 清空之前的问候语 greetingElement.textContent = ""; if(results.length > 0){ const result = results[0]; const name = result.label; // 仅当识别结果变化时输出并更新页面 if(name !== lastRecognizedName){ lastRecognizedName = name; const greeting = `Hello ${name}`; console.log(greeting); greetingElement.textContent = greeting; } } else { // 未检测到人脸时重置记录 lastRecognizedName = ""; } results.forEach((result, i) => { const box = resizedDetections[i].detection.box; const drawBox = new faceapi.draw.DrawBox(box, { label: result, }); drawBox.draw(canvas); }); }, 100); });
修改说明
- 移除冗余输出:删除
getLabeledFaceDescriptions内的批量控制台输出,避免加载标签图片时重复打印所有人名。 - 添加页面显示区域:在HTML中新增问候语容器,用于在视频下方展示识别结果。
- 精准输出逻辑:在人脸识别循环中,仅当检测到的人脸姓名发生变化时,才输出
Hello 姓名到控制台并更新页面内容,避免重复刷屏。
内容的提问来源于stack exchange,提问作者user11130151
相关产品推荐
相关产品推荐

