坏点检测算法基础:邻域像素比较法、中底滤波法、梯度检测法
坏点检测,说白了就是在一张图像里找出那些「不对劲」的像素。我在刚入行时,总觉得这步很简单——不就是找几个亮点暗点吗?后来在量产项目中吃过亏,才发现坏点检测的水很深。今天咱们就把三种最基础的检测算法掰开揉碎讲清楚。
1. 邻域像素比较法
这是最直观的方法。它的核心逻辑很简单:如果一个像素跟它周围的邻居长得都不像,那它很可能就是坏点。
具体怎么做呢?我习惯用一个 3×3 的窗口,在图像上逐像素滑动。对每个中心像素,计算它和周围 8 个像素的差值。如果差值超过某个阈值,就标记为候选坏点。
关键公式:
|Pcenter - Pneighbor| > Threshold → 候选坏点
这里有个坑——阈值怎么设?设小了误检多,设大了漏检多。我在一个手机摄像头项目里,就因为这个阈值调了整整两天。后来总结出一套经验:
- 亮场阈值:通常设为 40-60(8bit 数据),针对白色背景下的暗点
- 暗场阈值:通常设为 20-40,针对黑色背景下的亮点
- 自适应阈值:根据局部均值动态调整,效果最好但计算量大
邻域比较法有个明显的缺点——对边缘敏感。你想想看,图像边缘处的像素本来就和邻居差异大,很容易被误判为坏点。所以实际项目中,我一般会加一个边缘保护机制:先做边缘检测,边缘区域的像素不参与坏点判断。
2. 中值滤波法
这个方法很有意思。它的思路是:如果一个像素的值和中值差太多,那它就有问题。
具体流程是这样的:
- 取 3×3 或 5×5 的窗口
- 对窗口内所有像素排序,找到中值
- 计算中心像素与中值的差值
- 差值超过阈值 → 标记为坏点
为什么用中值而不是均值?我记得第一次做这个算法时,也想过用均值。后来发现均值容易被极端值拉偏——如果窗口里正好有两个坏点,均值可能就不准了。中值就稳定得多,它对 outlier 不敏感。
我的经验:中值滤波法在检测孤立坏点时效果极好,但对「坏点簇」(连续多个坏点)效果不佳。如果遇到坏点簇,建议把窗口扩大到 5×5 或 7×7。
代码实现也很简单,我贴一段核心逻辑:
// 3x3 中值检测伪代码
for each pixel (x, y) {
// 取 3x3 邻域
window = getNeighborhood(image, x, y, 3);
// 排序取中值
median = sort(window)[4]; // 3x3 共 9 个像素,中值是第 5 个
// 计算差值
diff = abs(image[x][y] - median);
// 阈值判断
if (diff > THRESHOLD) {
markAsBadPixel(x, y);
}
}
3. 梯度检测法
这个方法稍微复杂一点,但检测精度更高。它的核心思想是:坏点会在局部产生异常的梯度变化。
什么是梯度?说白了就是像素值的变化率。正常图像中,相邻像素的梯度是平滑的。但坏点会在它所在的位置产生一个「突变」——梯度值会异常大。
我常用的梯度检测方案是计算四个方向的梯度:
| 方向 | 梯度计算 | 特点 |
|---|---|---|
| 水平方向 | |P(x,y) - P(x-1,y)| + |P(x,y) - P(x+1,y)| | 检测水平条纹状坏点 |
| 垂直方向 | |P(x,y) - P(x,y-1)| + |P(x,y) - P(x,y+1)| | 检测垂直条纹状坏点 |
| 45° 方向 | |P(x,y) - P(x-1,y-1)| + |P(x,y) - P(x+1,y+1)| | 检测对角线方向坏点 |
| 135° 方向 | |P(x,y) - P(x-1,y+1)| + |P(x,y) - P(x+1,y-1)| | 检测另一对角线方向坏点 |
取四个方向梯度的最大值,如果超过阈值,就判定为坏点。这样做的好处是:不管坏点出现在哪个方向,都能被检测到。
注意:梯度检测法对噪声很敏感。如果图像本身噪声较大,建议先做一次轻度的去噪处理,否则误检率会很高。我曾经在一个低光照项目中吃过这个亏,后来加了预处理才解决。
三种方法对比
我把这三种方法放在一起做了个对比,方便你根据实际场景选择:
| 方法 | 计算量 | 检测精度 | 抗噪能力 | 适用场景 |
|---|---|---|---|---|
| 邻域比较法 | 低 | 中 | 弱 | 简单场景、实时性要求高 |
| 中值滤波法 | 中 | 中高 | 强 | 孤立坏点、噪声环境 |
| 梯度检测法 | 高 | 高 | 弱 | 高精度要求、多方向坏点 |
三种方法的流程关系
下面这张图展示了三种检测方法的完整流程和它们之间的关系:
实际项目中的选择建议
说了这么多,到底该用哪种?我个人的经验是:
- 如果项目周期紧、算力有限:用邻域比较法,简单粗暴,效果够用
- 如果图像噪声大:用中值滤波法,抗噪能力强
- 如果对坏点检测精度要求极高:用梯度检测法,或者三种方法组合使用
我的建议:在实际项目中,我通常先用邻域比较法做快速筛查,再用梯度检测法做精确确认。这样既保证了速度,又兼顾了精度。你可以试试这个组合方案。
嗯,坏点检测的基础算法就讲到这里。这三种方法虽然基础,但它们是后续所有高级算法的基石。你把这些吃透了,后面学自适应检测、机器学习检测就会轻松很多。