核心是将视频流渲染到Canvas并逐帧处理像素,需稳定低延迟:先用getUserMedia获取流并绑定video(设autoplay、muted、playsinline及显式宽高),监听loadeddata后用requestAnimationFrame绘制;滤镜通过getImageData读取、计算、putImageData写回,可降采样或WebWorker优化;基础效果优先用CSS filter。

核心是把视频流画到 Canvas 上,再逐帧读取、修改像素数据,最后写回显示——整个过程必须稳定、低延迟,且兼顾性能。
正确获取并绑定视频流
调用 navigator.mediaDevices.getUserMedia({ video: true }) 获取摄像头权限,拿到 MediaStream 后赋给 <video> 的 srcObject。关键设置不能少:
- autoplay 和 muted:绕过浏览器自动播放策略(尤其移动端)
- playsinline:防止 iOS 强制全屏,确保 canvas 能正常捕获画面
-
显式设置 width 和 height 属性(如
width="640" height="480"):避免因 CSS 缩放导致像素错位或失真 - 监听 loadeddata 或 canplay 事件后再开始绘制:否则首几帧可能是黑屏
用 requestAnimationFrame 稳定采集帧
不用 setInterval,改用 requestAnimationFrame 驱动绘制循环,与屏幕刷新率同步,更流畅也不丢帧。
- 在回调中调用
ctx.drawImage(video, 0, 0, canvas.width, canvas.height) - 如只需处理局部(比如人脸区域),可传入 video 的源坐标和尺寸参数裁剪绘制
- 为减轻压力,可加帧率限制:例如每 3 帧处理一次,用计数器或
performance.now()判断时间间隔
像素级滤镜实现与优化
滤镜逻辑集中在三步:读取 → 计算 → 写回。
立即学习“前端免费学习笔记(深入)”;
-
ctx.getImageData(0, 0, canvas.width, canvas.height)返回 ImageData,其.data是Uint8ClampedArray,按 R-G-B-A 四字节顺序排列 - 灰度化示例:
let avg = (r + g + b) / 3; data[i] = data[i+1] = data[i+2] = avg; - 反色示例:
data[i] = 255 - data[i];(对 R/G/B 分别操作) - 提前缓存
data.length,避免循环中反复访问;用位运算| 0替代Math.round加速计算 - 大画布(如 1280×720)频繁调用
getImageData/putImageData易卡顿,可降采样处理,或用 Web Workers 拆分计算,甚至迁移到 WebGL 加速
轻量效果优先用 CSS filter
若只需亮度、对比度、饱和度、模糊等基础效果,直接给 <video> 设置 CSS filter 更简单高效。
- 例如:
filter: brightness(1.3) contrast(1.1) saturate(0.9); - 用 JavaScript 动态更新
video.style.filter,注意每次赋值要覆盖完整字符串,别遗漏已有效果 - 需局部增强(如仅人脸)时,可用容器 +
::before伪元素叠加backdrop-filter



















