声如洪钟 發表於 2025-4-19 23:52:00

视频解析图片识别人脸采集并切图video-clip-images,face-api.js

<h1 id="video-clip-images">video-clip-images</h1>
<h2 id="采集视频中的人脸并截取">采集视频中的人脸并截取</h2>
<ul>
<li>本<code>Demo</code>是通过face-api实现的。具体内容可前往Github:face-api</li>
<li>注: 返回大部分使用的都是<code>base64</code></li>
<li><code>Demo</code>地址放在了码云上:video-clip-images</li>
</ul>
<h2 id="目录结构">目录结构</h2>
<pre><code>video-clip-images/
├── face-api.js-master/
│   ├── weights/ 模型
│   │   └── ...
├── js/ 脚本
│   └── ...
└── index.html
</code></pre>
<h3 id="第一步加载模型">第一步加载模型</h3>
<pre><code>await faceapi.nets.tinyFaceDetector.loadFromUri(
    "./face-api.js-master/weights"
);
</code></pre>
<h3 id="第二步-通过传入的url-获取每一秒的图片">第二步 通过传入的url 获取每一秒的图片</h3>
<pre><code>async getVideoFace(url) {
    const video = document.createElement("video");
    const canvas = document.createElement("canvas");
    video.src = url;
    await new Promise((resolve) =&gt; {
      video.addEventListener("loadedmetadata", () =&gt; {
      resolve();
      });
    });
    const duration = video.duration;
    const ctx = canvas.getContext("2d");
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    const frameData = [];
    for (let i = 0; i &lt; duration; i++) {
      video.currentTime = i;
      await new Promise((resolve) =&gt; {
      video.addEventListener("seeked", function handler() {
          video.removeEventListener("seeked", handler);
          ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
          const base64 = canvas.toDataURL("image/jpeg");
          frameData.push({
            base64,
            second: i,
          });
          resolve();
      });
      });
    }

    return frameData;
}
</code></pre>
<h3 id="第三步-处理每一秒的图片并裁剪">第三步 处理每一秒的图片并裁剪</h3>
<ul>
<li><code>detectFrame</code>获取人物在图中的位置</li>
<li><code>getClipImage</code>获取裁剪后的图片<pre><code>getClipImage(box, image) {
const newCanvas = document.createElement("canvas");
const newCtx = newCanvas.getContext("2d");
newCanvas.width = box.width;
newCanvas.height = box.height;
newCtx.drawImage(
    image,
    box.x,
    box.y,
    box.width,
    box.height,
    0,
    0,
    box.width,
    box.height
);
const base64Data = newCanvas.toDataURL("image/png");
let img = document.createElement("img");
img.src = base64Data;
return base64Data;
}
</code></pre>
</li>
<li>通过第二步获取的<code>data</code>使用<code>detectFrame</code>获取<code>box</code></li>
<li>通过<code>filter</code>过滤<code>box</code>为空也就是没有获取到人脸。</li>
<li>最后使用<code>getClipImage</code>获取到裁剪后的图片</li>
</ul>
<pre><code>async install(url) {
    let data = await this.getVideoFace(url);
    const detectFrame = async (img) =&gt; {
      let box;
      const detections = await faceapi.detectAllFaces(
      img,
      new faceapi.TinyFaceDetectorOptions()
      );
      detections.forEach((detection) =&gt; {
      box = detection.box;
      });
      return box;
    };
    data = data.map((item) =&gt; {
      return new Promise((resolve, reject) =&gt; {
      let img = new Image();
      img.onload = async () =&gt; {
          item.box = await detectFrame(img);
          item.img = img;
          resolve(item);
      };
      img.src = item.base64;
      });
    });
    data = await Promise.all(data);
    console.log(`本次处理耗时:${this.numb}秒`);
    clearInterval(this.time);
    return data
      .filter((i) =&gt; Boolean(i.box))
      .map((item) =&gt; {
      item.clipImage = this.getClipImage(item.box, item.img);
      return item;
      });
}
</code></pre>
<h3 id="报告菜坤后端要blob">报告!菜坤后端要<code>Blob</code></h3>
<ul>
<li>把<code>它</code>工资分我一份!!!!!</li>
<li>处理裁剪好的base64<code>base64ToBlob(item.clipImage)</code><pre><code>new ClipImages("./2025419-450082.mp4").then((data) =&gt; {
      data.forEach((item) =&gt; {
      let img = document.createElement("img");
      img.src = item.clipImage;
      document.body.appendChild(img);
      item.clipImageBlob = base64ToBlob(item.clipImage)
      });
      console.log(data);
});
</code></pre>
</li>
<li>base64ToBlob代码片段<pre><code>function base64ToBlob(base64, contentType = "image/png") {
// 去掉 Base64 编码字符串的前缀
const sliceIndex = base64.indexOf(",") + 1;
const base64Data = base64.slice(sliceIndex);

// 解码 Base64 数据
const binary = atob(base64Data);
const length = binary.length;
const buffer = new ArrayBuffer(length);
const view = new Uint8Array(buffer);

// 将二进制字符串转换为 Uint8Array
for (let i = 0; i &lt; length; i++) {
      view = binary.charCodeAt(i);
}

// 创建 Blob 对象
return new Blob(, { type: contentType });
}
</code></pre>
</li>
</ul>
<h3 id="效果图">效果图</h3>
<p><img src="https://img2024.cnblogs.com/blog/2042148/202504/2042148-20250419235215102-1109505011.png" alt="效果图" loading="lazy"></p>


</div>
<div id="MySignature" role="contentinfo">
    有问题联系QQ1291481728或在下方评论,会在第一时刻处理。<br><br>
来源:https://www.cnblogs.com/ooo51o/p/18836320
頁: [1]
查看完整版本: 视频解析图片识别人脸采集并切图video-clip-images,face-api.js