首页 > 教程攻略 > ai资讯 >纯前端 AI 视频特效实践:在浏览器中完成实物识别与动态描边

纯前端 AI 视频特效实践:在浏览器中完成实物识别与动态描边

来源:互联网 时间:2026-08-02 12:02:58

标题:

纯前端 AI 视频特效实践:在浏览器中完成实物识别与动态描边

在 Timeline Studio 这个项目里,实现了一套完全在浏览器本地运行的实物描边功能。它能识别商品、鞋子、玩具这些物体,生成 Alpha 蒙版,然后在图片或视频里渲染出可调节的描边效果。

项目完整代码已开源,放在 GitHub 上:

https://github.com/MartinDelophy/ai-video-editor

整个过程都在浏览器内完成,不需要把用户素材上传到任何服务器。

整体实现思路

说到实物描边,很多人第一反应是边缘检测,但这招其实不太灵。边缘检测会同时提取人物、背景和纹理,根本没法确定用户到底想处理哪个物体。

所以,项目把处理流程拆成了四个阶段:

目标检测↓
目标身份锁定↓
提示式物体分割↓
描边材质渲染


简单来说,目标检测负责找到画面里有哪些可能的“参赛选手”,提示式分割负责给真正的目标画一个像素级的蒙版。对于视频,还需要通过光流传播和稀疏锚点分析来保持前后帧的稳定。

使用 Worker 执行目标检测

模型推理这事儿,放在 Web Worker 里做,避免阻塞 React 界面和时间线的交互。主线程这边只需要发送待分析画面就行:

worker.postMessage({ requestId,type: "detect",blob,scoreThreshold: 0.24,
});


Worker 在初始化 ONNX Runtime 会话时,会优先尝试 WebGPU,如果不行,就回退到 WASM:

async function createSession(modelBytes) { if (na vigator.gpu) {   try { 
return await ort.InferenceSession.create(modelBytes, { 
executionProviders: ["webgpu"],
graphOptimizationLevel: "all",
});  } catch (error) { 
console.warn("WebGPU 初始化失败,回退 WASM");  }}
return ort.InferenceSession.create(modelBytes, {   executionProviders: ["wasm"],  graphOptimizationLevel: "all",});
}


这样做的好处是,既能充分利用支持 WebGPU 的设备,也能兼容那些普通浏览器环境。

锁定用户真正想处理的物体

检测模型可能会同时返回好几个候选框。项目没有直接选择置信度最高的那个,而是综合计算了多个因素:

  • 检测置信度
  • 物体面积
  • 物体是否靠近画面中心
  • 与上一帧目标的重叠程度
  • 前后帧类别是否一致

排序代码简化后是这样的:

function calculateRank(item, previous) { const area = getArea(item.box);const centerScore = getCenterScore(item.box);const previousIoU = boxIoU(item.box, previous?.box);const identityBonus =  previous?.label === item.label ? 0.5 : 0;
return (  item.score * 0.55 +  Math.min(area, 0.25) +  centerScore * 0.2 +  previousIoU * 1.2 +  identityBonus);
}


在视频中,上一帧的目标会被赋予更高的权重,这样就能避免其他物体突然进入画面后发生错误切换。

从检测框生成物体 Alpha

目标确定之后,系统会根据物体的中心生成一个提示点,然后调用提示式分割模型:

const result = segmenter.segment(image, { keypoint: {   x: clamp(point.x, 0, 1),  y: clamp(point.y, 0, 1),},
});

const mask = result.confidenceMasks.at(-1);
const probabilities = mask.getAsFloat32Array();


置信度结果会转换成 0~255 的 Alpha 值:

const alpha = new Uint8ClampedArray(probabilities.length);

for (let i = 0; i < probabilities.length; i++) { const probability = clamp(probabilities[i], 0, 1);
alpha[i] = probability >= threshold  ? Math.round(probability * 255)  : 0;
}


得到 Alpha 之后,还得做一个保守的质量检查。如果蒙版出现以下情况,系统就不会直接接受:

  • 蒙版越过了目标区域
  • 出现了多个明显的连通区域
  • 混入了其他物体或背景
  • 面积相对上一帧异常变化
  • 目标身份发生了跳变

相比之下,修复一个已经错误的蒙版代价太大,直接跳过那些不可靠的帧反而更安全。

视频使用稀疏锚点和光流传播

如果每帧都执行完整的检测和分割,计算开销会非常大。所以视频分析采用了稀疏锚点策略。

const needsAnchor =index === 0 ||index - lastAnchorIndex >= anchorInterval ||!trackedMaskBox;

if (needsAnchor) { currentAlpha = await analyzeObjectAnchor(frame);lastAnchorIndex = index;
} else { currentAlpha = await propagateAlphaWithFlow(  previousFrame,  currentFrame,  currentAlpha,);
}


只有首帧、固定间隔或者目标丢失时,才会重新执行完整的分析。中间帧则通过光流来传播 Alpha。

传播完成后,还会检查面积变化是否合理:

const ratio = nextArea / trackedArea;

if (!nextBox || ratio < 0.35 || ratio > 2.8) { currentAlpha = null;trackedMaskBox = null;
}


一旦传播结果不可信,系统就会重新检测目标,而不是继续传播错误的蒙版。

分离 AI 分析与视觉样式

模型分析只负责生成可复用的 Alpha。描边的颜色、宽度、阴影和材质,这些都属于独立的效果状态:

const objectOutline = { targetKind: "object",outline: {   color: "#f3efe4",  width: 12,  opacity: 1,  glow: 0.35,},material: {   id: "paper",  edgeDensity: 0.5,  shadowDepth: 0.32,},
};


用户调整样式时,只需要重新合成画面,不需要再次运行检测和分割模型。

同一份 Alpha 同时用于编辑器预览和最终导出,这样可以保证两条渲染链路的效果完全一致。

总结

浏览器本地实物描边的核心,其实不依赖于某一个模型,而是一整套处理策略:

  • Worker 隔离模型推理
  • WebGPU 与 WASM 兼容回退
  • 检测与提示式分割组合
  • 目标身份锁定
  • 保守的蒙版质量门槛
  • 稀疏锚点与光流传播
  • AI 分析和视觉渲染解耦