vue 使用 face-api.js 实现人脸识别

HTML 代码如下

<div class="videoBox" id="videoBox">
  <video ref="videoPlayer" width="800" height="600" autoplay muted playsinline></video>
  <canvas ref="overlay"></canvas>
</div>

把模型放到 public 文件夹内的 models 文件夹内

模型下载地址:
GitHub
蓝奏云

引入 face-api.min.js

face-api 地址:
GitHub
蓝奏云

import "./assets/js/face-api.min.js";

在 created 方法内加载模型

Promise.all([
  // 用于人脸检测的高精度模型
  faceapi.nets.ssdMobilenetv1.loadFromUri("./models"),
  // 用于人脸检测的小型模型,速度快但精度略低
  // faceapi.nets.tinyFaceDetector.loadFromUri("./models"),
  // 用于检测 68 个面部特征点
  faceapi.nets.faceLandmark68Net.loadFromUri("./models"),
  // 用于检测 68 个面部特征点的小型模型
  // faceapi.nets.faceLandmark68TinyNet.loadFromUri("./models"),
  // 用于人脸识别
  faceapi.nets.faceRecognitionNet.loadFromUri("./models"),
  // 用于估计年龄和性别
  faceapi.nets.ageGenderNet.loadFromUri("./models"),
  // 用于检测面部表情(如快乐、悲伤、愤怒等)
  faceapi.nets.faceExpressionNet.loadFromUri("./models"),
])
  .then(() => {
    this.$nextTick(() => {
      this.startVideo();
    });
  })
  .catch((err) => {
    console.error("Error loading models:", err);
  });

methods 内的 startVideo 方法

/**
 * 初始化视频播放并启动面部检测。
 * 此函数旨在开始播放视频,并使用faceapi库对视频中的面部进行检测和标注。
 * 它首先获取用户媒体流,然后在视频元素上设置这个流,以便开始播放。
 * 随后,它监听视频的播放事件,以便在视频播放时进行面部检测。
 */
startVideo() {
  // 获取视频播放器的引用
  const videoEl = this.$refs.videoPlayer;
  // 请求用户摄像头的媒体流
  navigator.mediaDevices.getUserMedia({ video: {} }).then((stream) => {
    // 将媒体流设置到视频元素,开始播放
    videoEl.srcObject = stream;
  });
  // 在视频开始播放时执行的操作
  videoEl.addEventListener("play", () => {
    // 获取覆盖层canvas的引用,用于绘制面部检测的结果
    const canvas = this.$refs.overlay;
    // 获取视频元素的显示尺寸
    const displaySize = { width: videoEl.width, height: videoEl.height };
    // 调整canvas的尺寸以匹配视频的显示尺寸
    faceapi.matchDimensions(canvas, displaySize);
    // 每隔100毫秒进行一次面部检测和绘制
    setInterval(async () => {
      const options = new faceapi.SsdMobilenetv1Options({
        minConfidence: 0.9,
        maxResults: 3,
        inputSize: 128,
      });
      // 使用faceapi检测视频中的所有面部,并获取面部标志点
      const detections = await faceapi.detectAllFaces(videoEl, options).withFaceLandmarks().withAgeAndGender().withFaceExpressions().withFaceDescriptors();
      if (detections.length == 0) {
        console.log("未检测到人脸");
      } else if (detections.length == 1) {
        console.log("检测到一张人脸,置信度:" + detections[0].detection.score);
      } else if (detections.length > 1) {
        console.log("检测到多张人脸");
      }
      // 将检测结果调整到与视频相同的尺寸,以便正确绘制
      const resizedDetections = faceapi.resizeResults(detections, displaySize);
      // 清空canvas以准备新的绘制
      canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
      // 在canvas上绘制面部检测的结果,包括面部边界和标志点
      faceapi.draw.drawDetections(canvas, resizedDetections);
      faceapi.draw.drawFaceLandmarks(canvas, resizedDetections);

      // 如果不带以下重绘的代码,则仅提示人脸识别的置信度
      // 遍历每一次检测的结果,这些结果包含了人脸的年龄、性别、表情等信息
      resizedDetections.forEach((detection) => {
        // 解构赋值,提取人脸的年龄、性别、性别概率和表情信息
        const { age, gender, genderProbability, expressions } = detection;
        // 提取人脸检测框的位置信息
        const box = detection.detection.box;
        // 创建一个新的DrawBox实例,用于在画布上绘制人脸检测框
        // 这里通过设置label属性,指定了绘制在检测框周围的文本内容
        const drawBox = new faceapi.draw.DrawBox(box, {
          label: `
           ${faceapi.utils.round(age, 0)} years
           ${gender} (${faceapi.utils.round(genderProbability)})
           ${Object.entries(expressions).sort((a, b) => b[1] - a[1])[0][0]}
         `,
        });
        // 绘制人脸检测框
        drawBox.draw(canvas);
      });
    }, 100);
  });
},

CSS

.videoBox {
  width: 600px;
  height: 500px;
  position: relative;
}
canvas {
  position: absolute;
  top: 0;
  left: 0;
}

请添加图片描述

请添加图片描述

其他说明

其中 startVideo方法中的 faceapi内容说明

const options = new faceapi.SsdMobilenetv1Options({
  minConfidence: 0.9,
  maxResults: 3,
  inputSize: 128,
});
// 使用faceapi检测视频中的所有面部,并获取面部标志点
const detections = await faceapi.detectAllFaces(videoEl, options).withFaceLandmarks().withAgeAndGender().withFaceExpressions().withFaceDescriptors();
if (detections.length == 0) {
  console.log("未检测到人脸");
} else if (detections.length == 1) {
  console.log("检测到一张人脸,置信度:" + detections[0].detection.score);
} else if (detections.length > 1) {
  console.log("检测到多张人脸");
}

构造函数调用

faceapi.SsdMobilenetv1Options()

用于配置 SSD MobileNet V1 模型的选项,主要用于人脸检测
需要载入以下模型,用于人脸检测的高精度模型:faceapi.nets.ssdMobilenetv1.loadFromUri("./models")

faceapi.TinyFaceDetectorOptions()

用于配置 Tiny Face Detector 模型的选项。这是一个更轻量级且速度更快的模型,但精度可能略低于 SSD MobileNet V1
需要载入模型,用于人脸检测的小型模型,速度快但精度略低:faceapi.nets.tinyFaceDetector.loadFromUri("./models")

可选配置项
  1. minConfidence
    作用: 控制人脸检测或识别的结果质量。设置较高的 minConfidence 可以确保只有那些模型非常确信的检测结果被接受,从而提高结果的准确性。
    取值范围: 通常在 0 到 1 之间,其中 1 表示完全确信,0 表示没有信心。
  2. maxResults
    作用: 设置返回的最大检测结果数量。当检测到多个人脸时,可以限制返回的最大结果数。
    取值范围: 通常是一个正整数,表示返回的最大检测结果数量。
  3. inputSize
    作用: 设置输入图像的大小。较大的输入图像通常可以提供更高的检测精度,但会增加计算成本。
    取值范围: 通常是一个整数,表示图像的宽度和高度(如 128、224、416 等)。
  4. scoreThreshold(没测出来怎么用)
    作用: 设置检测结果的分数阈值。分数表示模型对每个检测结果的置信度得分,低于此阈值的结果可能会被过滤掉。
    取值范围: 通常是一个介于 0 到 1 之间的数值,表示分数的最低接受阈值。
const options = new faceapi.SsdMobilenetv1Options({
  minConfidence: 0.9,
  maxResults: 5,
  inputSize: 128,
});

方法调用

withFaceLandmarks()

用于在检测到的人脸上标记关键点,如眼睛、鼻子、嘴巴等。它在检测人脸位置的基础上,进一步识别面部特征点
需要载入以下模型,用于检测 68 个面部特征点:faceapi.nets.faceLandmark68Net.loadFromUri("./models")或用于检测 68 个面部特征点的小型模型:faceapi.nets.faceLandmark68TinyNet.loadFromUri("./models")

withAgeAndGender()

用于在检测到的人脸上预测年龄和性别。它会返回每个人脸的年龄、性别和性别概率
需要载入以下模型,用于估计年龄和性别:faceapi.nets.ageGenderNet.loadFromUri("./models")

withFaceExpressions()

用于在检测到的人脸上识别情绪表达。它会返回每个人脸的表情及其对应的概率,如快乐、悲伤、愤怒等
需要载入以下模型,用于检测面部表情(如快乐、悲伤、愤怒等):faceapi.nets.faceExpressionNet.loadFromUri("./models")

withFaceDescriptors()

用于提取人脸特征描述符。这些描述符是用于人脸识别的关键数据,可以与已知人脸进行对比,以识别人脸的身份
需要载入以下模型,用于人脸识别:faceapi.nets.faceRecognitionNet.loadFromUri("./models")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值