You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 04:40:23