坏点检测算法基础:邻域像素比较法、中底滤波法、梯度检测法

坏点检测,说白了就是在一张图像里找出那些「不对劲」的像素。我在刚入行时,总觉得这步很简单——不就是找几个亮点暗点吗?后来在量产项目中吃过亏,才发现坏点检测的水很深。今天咱们就把三种最基础的检测算法掰开揉碎讲清楚。

1. 邻域像素比较法

这是最直观的方法。它的核心逻辑很简单:如果一个像素跟它周围的邻居长得都不像,那它很可能就是坏点。

具体怎么做呢?我习惯用一个 3×3 的窗口,在图像上逐像素滑动。对每个中心像素,计算它和周围 8 个像素的差值。如果差值超过某个阈值,就标记为候选坏点。

关键公式:

|Pcenter - Pneighbor| > Threshold → 候选坏点

这里有个坑——阈值怎么设?设小了误检多,设大了漏检多。我在一个手机摄像头项目里,就因为这个阈值调了整整两天。后来总结出一套经验:

  • 亮场阈值:通常设为 40-60(8bit 数据),针对白色背景下的暗点
  • 暗场阈值:通常设为 20-40,针对黑色背景下的亮点
  • 自适应阈值:根据局部均值动态调整,效果最好但计算量大

邻域比较法有个明显的缺点——对边缘敏感。你想想看,图像边缘处的像素本来就和邻居差异大,很容易被误判为坏点。所以实际项目中,我一般会加一个边缘保护机制:先做边缘检测,边缘区域的像素不参与坏点判断。

2. 中值滤波法

这个方法很有意思。它的思路是:如果一个像素的值和中值差太多,那它就有问题。

具体流程是这样的:

  1. 取 3×3 或 5×5 的窗口
  2. 对窗口内所有像素排序,找到中值
  3. 计算中心像素与中值的差值
  4. 差值超过阈值 → 标记为坏点

为什么用中值而不是均值?我记得第一次做这个算法时,也想过用均值。后来发现均值容易被极端值拉偏——如果窗口里正好有两个坏点,均值可能就不准了。中值就稳定得多,它对 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)| 检测另一对角线方向坏点

取四个方向梯度的最大值,如果超过阈值,就判定为坏点。这样做的好处是:不管坏点出现在哪个方向,都能被检测到。

注意:梯度检测法对噪声很敏感。如果图像本身噪声较大,建议先做一次轻度的去噪处理,否则误检率会很高。我曾经在一个低光照项目中吃过这个亏,后来加了预处理才解决。

三种方法对比

我把这三种方法放在一起做了个对比,方便你根据实际场景选择:

方法 计算量 检测精度 抗噪能力 适用场景
邻域比较法 低 中 弱 简单场景、实时性要求高
中值滤波法 中 中高 强 孤立坏点、噪声环境
梯度检测法 高 高 弱 高精度要求、多方向坏点

三种方法的流程关系

下面这张图展示了三种检测方法的完整流程和它们之间的关系:

坏点检测算法流程对比图 坏点检测算法流程对比 输入图像 邻域像素比较法 3×3 窗口滑动 与 8 邻域差值比较 中值滤波法 窗口内像素排序 与中值比较 梯度检测法 四方向梯度计算 取最大梯度值 阈值判断 标记为坏点 保留为正常像素 三种方法可单独使用,也可组合使用以提高检测准确率

实际项目中的选择建议

说了这么多,到底该用哪种?我个人的经验是:

  • 如果项目周期紧、算力有限:用邻域比较法,简单粗暴,效果够用
  • 如果图像噪声大:用中值滤波法,抗噪能力强
  • 如果对坏点检测精度要求极高:用梯度检测法,或者三种方法组合使用

我的建议:在实际项目中,我通常先用邻域比较法做快速筛查,再用梯度检测法做精确确认。这样既保证了速度,又兼顾了精度。你可以试试这个组合方案。

嗯,坏点检测的基础算法就讲到这里。这三种方法虽然基础,但它们是后续所有高级算法的基石。你把这些吃透了,后面学自适应检测、机器学习检测就会轻松很多。