阶段 7 · 视频帧基础24 分钟
Canvas 视频处理:读取、改写与重新输出像素
drawImage、ImageData、像素循环与成本
把生成的视频帧绘制到 Canvas,实时做亮度分级和扫描线效果,观察像素级处理的成本。
LEARNING GOALS
先明确本课目标
1
从视频帧绘制到 Canvas
2
用 ImageData 修改像素
3
理解读回、分辨率和帧率的性能乘法
MENTAL MODEL · 再建立心智模型
视频元素负责解码,Canvas 像一个可读写的帧缓冲;drawImage 把当前帧拷入,getImageData 才把像素搬到 JavaScript。
MINIMAL EXAMPLE
哪一步真正把像素暴露给 JavaScript?
drawImage 可以留在浏览器优化的图像路径中;getImageData 会创建包含 RGBA 字节的 ImageData,使 JavaScript 能逐像素读取和改写。
javascriptcontext.drawImage(video, 0, 0, width, height);
const frame = context.getImageData(0, 0, width, height);
for (let i = 0; i < frame.data.length; i += 4) {
const y = 0.2126 * frame.data[i] +
0.7152 * frame.data[i + 1] +
0.0722 * frame.data[i + 2];
frame.data[i] = frame.data[i + 1] = frame.data[i + 2] = y;
}
context.putImageData(frame, 0, 0);- 先绘制当前帧 drawImage 把媒体的当前画面缩放到处理尺寸。
- 读取 RGBA 字节 每个像素占连续四个通道,循环步长通常是 4。
- 写回处理结果 修改 data 后用 putImageData 重新写入 Canvas。
你能任意改写像素,同时也能从循环规模直观看到高分辨率处理的成本。
OPTIONAL · 按需查阅完整术语表与概念边界遇到陌生术语时再展开,不打断主线实验。
展开⌄
音视频基础Video Frame带尺寸、时间戳和颜色信息的一张视频画面,可来自解码器、视频元素、Canvas 或 WebCodecs。音视频原理PixelPixel(picture element,图像元素)是二维图像网格中的一个采样位置,保存的颜色分量由 Pixel Format 决定。音视频基础Canvas 2D浏览器 CanvasRenderingContext2D 的二维绘图接口,可把视频帧绘入画布并读取或修改像素。音视频基础drawImageCanvas 2D 把图片、视频或画布源缩放并绘制到目标画布的方法;视频源会使用调用时可用的当前帧。音视频基础ImageDataCanvas 2D 中保存宽度、高度和 RGBA 像素数组的数据对象,常配合 getImageData 与 putImageData 使用。音视频基础Pixel Processing逐像素读取并变换颜色数值的处理方式;在 CPU 上处理高分辨率视频时容易受内存带宽和帧预算限制。音视频基础Frame Budget为维持目标帧率,一帧从输入到输出可使用的最大时间;例如 60 FPS 的理论预算约为 16.7 ms。
LIVE EXPERIMENT · 先获得反馈
边改边运行
浏览器加载后会激活代码编辑器、独立运行环境与实时输出。
本课挑战
加入自动降分辨率策略,使处理耗时始终低于每帧预算的一半。
回到原理,解释刚才发生了什么
先用结果建立反馈,再按运行流程、核心原理和知识关系逐层深入。
CORE IDEA
核心讲解
像素循环的成本会相乘
每帧像素数 × 帧率 × 每像素操作量决定 CPU 压力。先降低处理尺寸,通常比微调循环语法更有效。
避免不必要的 CPU 往返
只需缩放或合成时直接 drawImage;只有算法必须读取像素时才调用 getImageData。更重的处理可考虑 Worker、WebGL 或 WebGPU。
OPTIONAL · 迁移时查阅Web 与原生实现对照主线实验完成后,再用完整映射处理跨平台或跨 API 迁移。
展开⌄
浏览器解码帧很高效,把全部像素读进 JavaScript 则会引入明显成本。
WebGL
getImageData 暴露每个像素,灵活但增加读回、内存带宽与 JavaScript 循环。
WebGPU
drawImage 让浏览器在内部路径完成缩放、裁剪与合成,适合大多数画面组合。
先缩小处理分辨率,再决定是否真的需要读回像素。