
本文介绍如何使用 html5 video 和 canvas api 实现持续、稳定的实时摄像头黑白化处理,通过 javascript 对每一帧执行阈值二值化(rgb 平均亮度 > x → 白,否则黑),并修复常见崩溃与性能问题。
要实现真正可持续的实时黑白视频流(如来自用户摄像头),关键在于:✅ 正确初始化媒体流、✅ 避免重复创建 captureStream() 导致资源泄漏、✅ 优化像素处理逻辑、✅ 合理使用 requestAnimationFrame 循环。原始代码崩溃的核心原因有三:
- videoElement.srcObject = canvas.captureStream() 在每帧中反复调用 —— 每次都会创建新 MediaStream,旧流未释放,引发内存溢出与浏览器卡死;
- canvas.width/height 在 processFrame() 内动态设置 —— 视频尺寸在 play 事件触发时尚未就绪(videoWidth/videoHeight 为 0),导致 getImageData 失败;
- 未等待视频实际可播放(canplay 或 loadeddata)即启动处理循环,造成早期空帧或异常。
以下是生产就绪的完整实现方案:
实时黑白摄像头流
⚠️ 注意事项与进阶建议:
-
性能瓶颈:纯 JS 像素遍历在高分辨率(如 1280×720)下易掉帧。推荐升级方案:
- ✅ 使用 WebGL(通过 glfx.js 或自定义 shader)实现 GPU 加速二值化;
- ✅ 或将计算移至 Web Worker,避免阻塞主线程(需传递 ImageBitmap);
- 阈值自适应:固定 threshold=120 依赖光照条件。可结合 ctx.getImageData() 计算整帧平均亮度,动态调整阈值(Otsu 算法简化版);
- 兼容性:captureStream() 在 Safari 中需开启实验性功能(chrome://flags/#unsafely-treat-insecure-origin-as-secure),生产环境建议搭配 HTTPS;
- 关闭清理:页面卸载前应调用 stream.getTracks().forEach(t => t.stop()) 释放摄像头。
通过以上结构化实现,你将获得一个低延迟、不崩溃、可持续运行的实时黑白视频流——既是计算机视觉入门实践,也是 Web 媒体处理的典型范式。











