首先,要理解我们的目标,我们将实时获取视频中的面部区域并将其周围的内容转为不透明以制造出弹幕的“遮挡效应”。
步骤一:环境准备
我们将使用 TensorFlow.js 的 Body-segmentation 库来完成面部识别部分,并使用 OffscreenCanvas 来绘制更新后的图像。
安装相关库:
npm install @tensorflow-models/body-segmentation
步骤二:使用 body-segmentation 检测脸部
首先,我们需要导入所需的库并配置我们的模型。
import { createSegmenter, SupportedModels } from "@tensorflow-models/body-segmentation";
import type { Ref } from "vue";
const model = SupportedModels.MediaPipeSelfieSegmentation;
const segmenterConfig = {
runtime: "mediapipe",
solutionPath: "https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation",
modelType: "general"
}
const segmenter = await createSegmenter(model, segmenterConfig);
接下来,我们会定期从视频流中获取图像,然后使用 segmenter.segmentPeople(videoEl)
对其进行处理。
步骤三:使用 OffscreenCanvas 进行绘制
我们接下来要创建一个 worker,并将画布对象和 mask 图像传给它。在 worker 端,我们会从 mask 图像中剔除人脸部分,然后在这部分绘制白色,产生弹幕的“遮挡效应”。 注意转移权移动给worker。
const worker = new Worker("/src/assets/pull/worker.ts");
let offscreen;
export async function detect(videoEl: HTMLVideoElement, canvas: Ref<HTMLCanvasElement>) {
if (!offscreen) {
offscreen = canvas.value.transferControlToOffscreen();
}
const segmentation = await segmenter.segmentPeople(videoEl);
const mask = await segmentation[0].mask.toCanvasImageSource();
worker.postMessage({ canvas: offscreen, mask: mask }, [offscreen]);
window.setTimeout(() => detect(videoEl, canvas), 66);
}
步骤四:Worker中绘制图像
在 worker 中,我们需要接收主线程传来的信息,并进行绘制。然后我们将绘制后的结果发送回主线程。
self.onmessage = function (event) {
const offscreen = event.data.canvas;
const mask = event.data.mask;
const context = offscreen.getContext('2d');
const reader = new FileReaderSync();
// ... 清空画布,并绘制图像操作
offscreen
.convertToBlob({type: 'image/png', quality: 0 })
.then((blob: Blob) => {
const dataURL = reader.readAsDataURL(blob);
self.postMessage({ msgType: 'mask', val: dataURL });
})
.catch(console.error);
};
经过以上步骤,我们成功制造了弹幕的“遮挡效应”。