canvas中用动态阈值将图片转为黑白扫描件,先灰度化(gray=0.299r+0.587g+0.114b),再以15×15窗口算局部均值并减去30~60偏移量得阈值,最后二值化,兼顾边缘清晰与噪点抑制。

在 Canvas 中用动态阈值把普通图片转成清晰的黑白扫描件效果,核心不是固定一个数(比如 128),而是根据图像局部明暗自动调整分界线。这样签名、手写文字边缘更干净,纸面噪点被压平,整体接近专业扫描仪输出。
先转灰度,再算局部平均亮度
彩色图直接二值化容易失真,得先统一到灰度空间:
- 用标准加权公式计算每个像素灰度:gray = 0.299×R + 0.587×G + 0.114×B,赋给 R/G/B 三个通道
- 不操作 alpha 通道,保持透明区域不变(如有)
- 灰度图生成后,不再需要原始颜色信息,后续只处理单通道强度值
用滑动窗口统计邻域亮度均值
全局阈值对光照不均的图片(如侧光拍摄的签名)效果差;动态阈值按小块分别计算,更贴合实际纸面反差:
- 选 15×15 或 21×21 像素为一个局部区域(太大则丢失细节,太小则易受噪点干扰)
- 遍历每个像素时,取其周围邻域内所有灰度值求平均,得到该点的“背景亮度”
- 为避免边界越界,只处理距边缘 ≥ 窗口半径的像素;边缘区域可沿用最近有效阈值或简单填充
设定偏移量生成动态阈值并二值化
单纯用邻域均值做阈值仍会把浅色字迹误判为背景,需加入经验性衰减:
- 对每个像素,最终阈值 = 邻域均值 − C,C 通常取 30~60(数值越大,留下的墨迹越多)
- 若当前灰度 ≥ 阈值 → 设为纯白(255,255,255);否则 → 设为纯黑(0,0,0)
- 跳过 alpha 通道赋值,保持原透明度;若图无透明通道,第四字节可设为 255
性能优化要点
实时处理或大图批量转换时,这些细节能明显提速:
- 复用 getImageData 返回的 data 数组,不要每帧新建 ImageData 对象
- 用 Uint8ClampedArray 直接操作像素,避免 Math.round 等浮点运算
- 对高清图(如 >1200px 宽),可先缩放到 800px 再处理,最后 canvas.drawImage 放大显示
- 视频流场景下,务必设置 video.crossOrigin = "anonymous",否则 getImageData 报跨域错误
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











