如何用faceapi.js从Base64数据检测人脸?视频帧捕获后检测失败求助
问题描述
我想要使用faceapi.js从视频帧中检测人脸、捕获图像并检查捕获图像中的人脸位置。目前已成功实现视频帧的人脸检测与图像捕获,但无法在捕获的图像中检测人脸。
JS代码
const video = document.getElementById('video') Promise.all([ faceapi.nets.tinyFaceDetector.loadFromUri('/models'), faceapi.nets.faceLandmark68Net.loadFromUri('/models'), faceapi.nets.faceRecognitionNet.loadFromUri('/models'), faceapi.nets.faceExpressionNet.loadFromUri('/models'), faceapi.nets.ssdMobilenetv1.loadFromUri('/models') ]).then(startVideo) function startVideo() { navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; if (navigator.getUserMedia) { navigator.getUserMedia({ audio: false, video: {} }, function(stream) { var video = document.querySelector('video'); video.srcObject = stream; video.onloadedmetadata = function(e) { video.play(); }; }, function(err) { console.log("The following error occurred: " + err.name); } ); } else { console.log("getUserMedia not supported"); } } video.addEventListener('play', () => { const canvas = faceapi.createCanvasFromMedia(video) const area = document.getElementById('container') area.append(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().withFaceExpressions() const count = await faceapi .detectAllFaces(video, new faceapi.TinyFaceDetectorOptions()) .withFaceLandmarks() if(count.length>1){ alert("There are multiple faces in the frame. Please keep only one face"); } else{ const resizedDetections = faceapi.resizeResults(detections, displaySize) canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height) var frame_height = resizedDetections[0].detection._box._height var frame_width = resizedDetections[0].detection._box._width var frame_x = resizedDetections[0].detection._box._x var frame_y = resizedDetections[0].detection._box._y const button = document.getElementById('button') if (((frame_height>=160 && frame_height<=270) && (frame_width>=180 && frame_width<=270)) && ((frame_x>=100 && frame_x<=195) && (frame_y>=80 && frame_y<=190))) { button.disabled = false button.onclick = async function(){ button.disabled = true await CaptureImage() }; } else{ button.disabled = true } } }, 100) }) async function CaptureImage(){ document.querySelectorAll("#screenshot img") .forEach(img => img.remove()); const canvas = document.createElement('canvas'); canvas.width = 239; canvas.height = 306; canvas.getContext('2d').drawImage(video, 0, 0, 239, 306); const img = new Image() img.src = canvas.toDataURL('image/png', 1.0) document.getElementById('screenshot').appendChild(img) // 此处检测失败 const detections = await faceapi.detectAllFaces(img, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceExpressions() }
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>Document</title> <script defer src="face-api.min.js"></script> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="jquery.facedetection.min.js"></script> <script defer src="script.js"></script> <style> #container { margin: 0; padding: 0; width: 500px; height: 375px; display: flex; justify-content: center; align-items: center; } canvas { position: absolute; } #box { width: 239px; height: 306px; position: absolute; background-image: url("paper.png"); background-repeat: no-repeat; } </style> </head> <body> <div> <div id="container"> <div id="box"></div> <video id="video" width="500" height="375" autoplay muted></video> </div> <button type="button" id="button" disabled>Click to take picture</button> </div> <div id="screenshot"> </div> </body> </html>
解决方案
问题出在CaptureImage函数中:创建Image实例并赋值src后,立即调用faceapi的检测方法,但此时图像还未加载完成,faceapi无法读取到有效的图像数据,导致检测失败。
修改CaptureImage函数,通过Promise封装图像加载过程,等待图像加载完成后再执行人脸检测:
async function CaptureImage(){ document.querySelectorAll("#screenshot img") .forEach(img => img.remove()); const canvas = document.createElement('canvas'); canvas.width = 239; canvas.height = 306; canvas.getContext('2d').drawImage(video, 0, 0, 239, 306); const img = new Image() // 用Promise等待图像加载完成 await new Promise((resolve, reject) => { img.onload = resolve; img.onerror = reject; img.src = canvas.toDataURL('image/png', 1.0); }); document.getElementById('screenshot').appendChild(img) // 图像加载完成后再检测 const detections = await faceapi.detectAllFaces(img, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceExpressions() // 可在此处理检测结果,比如打印或业务逻辑使用 console.log(detections); }
这样就能确保faceapi在图像完全加载后进行检测,解决检测失败的问题。
内容的提问来源于stack exchange,提问作者Aloukik Roy
相关产品推荐
相关产品推荐

