Canvas边缘检测通过三步实现:先将视频帧绘制到canvas并转为灰度图,再用Sobel算子计算水平与垂直梯度并合成幅值,最后映射为灰度像素渲染边缘图,需在requestAnimationFrame中循环执行以实现实时效果。

Canvas 实现边缘检测,核心是逐像素计算梯度强度,关键在三步:把视频或图像帧转为灰度图、用 Sobel 算子算出水平和垂直方向梯度、合并梯度幅值并阈值化生成边缘图。
获取并转为灰度图像
先将画面(比如 video 元素)绘制到 canvas 上,再提取像素数据:
- 调用 ctx.drawImage(video, 0, 0) 把当前帧渲染进 canvas
- 用 ctx.getImageData(0, 0, width, height) 拿到 RGBA 像素数组
- 遍历 data 数组,每 4 个元素一组(R、G、B、A),按加权公式 0.299×R + 0.587×G + 0.114×B 算灰度值,存入新的一维灰度数组(长度 = width × height)
应用 Sobel 卷积计算梯度
Sobel 使用两个 3×3 卷积核,分别提取横向与纵向边缘响应:
- Gx 核:[−1, 0, 1; −2, 0, 2; −1, 0, 1];Gy 核:[−1, −2, −1; 0, 0, 0; 1, 2, 1]
- 对每个非边界像素 (i, j),取它周围 3×3 区域,分别与 Gx、Gy 做点积,得到 Gx 和 Gy 值
- 梯度幅值 = Math.sqrt(Gx * Gx + Gy * Gy),这是边缘强度的衡量
- 边界像素(第一/最后一行、列)可跳过,或简单设为 0
映射结果并渲染边缘图
把梯度强度转成可视化的灰度像素,写回 canvas:
- 新建 ImageData 对象,宽高同原图
- 遍历每个位置,取对应梯度值 val,映射为显示灰度:val = Math.min(255, Math.floor(val))
- 设置该像素的 R=G=B=val,A=255(不透明)
- 最后用 ctx.putImageData(imageData, 0, 0) 渲染出来
整个过程需放在 requestAnimationFrame 循环中持续执行,才能形成实时边缘检测效果。注意控制帧率,避免频繁 getImageData / putImageData 影响性能。


















