视频解析人脸实时追加框,框出人脸video-rect-images,face-api.js

video-rect-images

采集视频中的人脸并框出

  • Demo是通过face-api实现的。具体内容可前往Github:face-api
  • 注: 返回大部分使用的都是base64
  • Demo地址放在了码云上:video-rect-images

目录结构

video-rect-images/
├── face-api.js-master/
│   ├── weights/ 模型
│   │   └── ...
├── js/ 脚本
│   └── ...
└── index.html

最后的效果图

效果图

一起来看看AI生成的文档

视频人脸检测项目说明

{"type":"load_by_key","key":"banner_image_0","image_type":"search"}

一、项目概述

该项目实现了一个在网页上对视频进行人脸检测的功能,通过使用 face-api.js 库,能够检测视频中的人脸,并在视频上绘制人脸检测框,同时将检测到的人脸区域截取并以图片形式展示在页面上。

二、HTML 结构

页面标题与样式

<head> 部分,设置页面标题为 “视频人脸检测”。

定义了一些 CSS 样式,包括:

视频容器 #videoContainer 的样式,设置为相对定位;

视频 #video 和画布 #canvas 的样式,设置为绝对定位,并且 #canvas 禁止指针事件;

播放按钮 #playBtn 的样式;

展示截取人脸图片的区域 #show-people 中图片的样式。

页面内容

<body> 部分:

有一个播放按钮 <button id="playBtn">点击播放并开始检测</button>

视频容器 <div id="videoContainer"> 内包含:

一个 <video> 元素,用于播放视频,视频源为 ./2025419-450082.mp4,并提供了不支持视频标签时的提示信息;

一个 <canvas> 元素,用于绘制人脸检测框;

一个 <div id="show-people"></div> 用于展示截取的人脸图片。

三、JavaScript 代码功能

获取 DOM 元素

使用 document.getElementById 获取页面上的视频元素 video、画布元素 canvas 和播放按钮元素 playBtn

**截取人脸图片函数 **getImage

该函数接受一个表示人脸检测框的 box 对象作为参数,具体步骤如下:

创建一个新的画布 newCanvas 和其 2D 上下文 newCtx

根据 box 的尺寸设置新画布的宽度和高度;

从原始视频中绘制人脸区域到新画布上;

将新画布的内容导出为 Base64 编码的图像数据;

创建一个新的 <img> 元素,设置其 src 为 Base64 数据,并将其添加到 #show-people 元素中展示。

**初始化函数 **init

使用 await faceapi.nets.tinyFaceDetector.loadFromUri("./face-api.js-master/weights") 加载人脸检测模型;

设置画布的高度和宽度与视频的高度和宽度一致。

**开始检测函数 **startDetection

获取画布的 2D 上下文 ctx

使用 requestAnimationFrame 实现流畅的检测循环;

在每一帧中,检测视频中的所有人脸,得到 detections

清空画布,然后遍历 detections,为每个人脸绘制检测框,并调用 getImage 函数截取人脸图片。

播放按钮点击事件处理

当点击播放按钮时:

尝试播放视频,并调用 startDetection 开始检测;

如果播放失败,弹出错误提示;

同时隐藏播放按钮。

页面加载时初始化

使用 window.onload = init; 在页面加载完成后调用 init 函数进行初始化操作。

四、依赖项

face-api.js** 库**:通过 <script src="./js/face-api.min.js"></script> 引入,用于实现人脸检测功能。

人脸检测模型文件:位于 ./face-api.js-master/weights 目录下,由 faceapi.nets.tinyFaceDetector.loadFromUri 加载。

五、注意事项

确保视频文件 ./2025419-450082.mp4 存在且路径正确。

确保 face-api.js 库和人脸检测模型文件的路径正确,否则可能导致人脸检测功能无法正常工作。

部分浏览器可能对视频自动播放有限制,若视频无法自动播放,可能需要用户手动交互(如点击页面)来触发播放。

最终代码片段

<!DOCTYPE html>
<html>
  <head>
    <title>视频人脸检测</title>
    <style>
      #videoContainer {
        position: relative;
        /* max-width: 800px; */
      }
      #video,
      #canvas {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: auto;
      }
      #canvas {
        pointer-events: none;
      }
      /* 添加播放按钮样式 */
      #playBtn {
        padding: 12px 24px;
        background: #4caf50;
        color: white;
        border: none;
        cursor: pointer;
        margin: 10px;
      }
      #show-people img {
        display: inline-block;
      }
    </style>
  </head>
  <body>
    <button id="playBtn">点击播放并开始检测</button>
    <div id="videoContainer">
      <video id="video" controls muted>
        <source src="./2025419-450082.mp4" type="video/mp4" />
        您的浏览器不支持视频标签
      </video>
      <canvas id="canvas"></canvas>
      <hr />
      <div id="show-people"></div>
    </div>

    <!-- 引入face-api.js -->
    <script src="./js/face-api.min.js"></script>

    <script>
      const video = document.getElementById("video");
      const canvas = document.getElementById("canvas");
      const playBtn = document.getElementById("playBtn");

      function getImage(box) {
        // 创建新的画布
        const newCanvas = document.createElement("canvas");
        const newCtx = newCanvas.getContext("2d");

        // 设置新画布的尺寸为截取区域的大小
        newCanvas.width = box.width;
        newCanvas.height = box.height;

        // 从原始画布上绘制截取区域到新画布
        newCtx.drawImage(
          video,
          box.x,
          box.y,
          box.width,
          box.height,
          0,
          0,
          box.width,
          box.height
        );

        // 导出为 Base64 编码的图像数据
        const base64Data = newCanvas.toDataURL("image/png");

        // 在图像元素中显示截取的图像
        // outputImage.src = base64Data;
        let showPeople = document.getElementById("show-people");
        let img = document.createElement("img");
        img.src = base64Data;
        showPeople.append(img);
        // console.log("Base64 数据:", base64Data);
      }

      // 初始化函数
      async function init() {
        // 加载人脸检测模型
        await faceapi.nets.tinyFaceDetector.loadFromUri(
          "./face-api.js-master/weights"
        );

        // 设置视频尺寸同步到canvas
        canvas.height = video.videoHeight;
        canvas.width = video.videoWidth;
      }

      // 开始检测
      async function startDetection() {
        const ctx = canvas.getContext("2d");

        // 使用requestAnimationFrame实现流畅检测
        const detectFrame = async () => {
          if (!video.paused && !video.ended) {
            // 检测人脸
            const detections = await faceapi.detectAllFaces(
              video,
              new faceapi.TinyFaceDetectorOptions()
            );

            // 清空画布
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            // console.log(detections)
            // 绘制检测框

            detections.forEach((detection) => {
              const box = detection.box;
              // console.log(box);

              ctx.save(); // 保存当前上下文状态
              ctx.beginPath();
              ctx.rect(box.x, box.y, box.width, box.height);
              ctx.strokeStyle = "#ff0000";
              ctx.lineWidth = 1;
              ctx.stroke();
              ctx.restore(); // 恢复之前保存的上下文状态

              getImage(box);
            });
          }
          requestAnimationFrame(detectFrame);
        };
        detectFrame();
      }

      // 播放按钮点击事件
      playBtn.addEventListener("click", async () => {
        try {
          await video.play();
          startDetection();
          playBtn.style.display = "none"; // 隐藏按钮
        } catch (err) {
          alert("视频播放失败: " + err.message);
        }
      });

      // 初始化
      window.onload = init;
    </script>
  </body>
</html>

posted @ 2025-04-20 00:57  小泽沐优声  阅读(195)  评论(1)    收藏  举报