4. 坏像素校正(BPC)

坏像素校正,英文叫 Bad Pixel Correction,简称 BPC。说白了,就是 sensor 上有些像素点「坏了」——要么永远亮着(白点),要么永远黑着(黑点),要么响应不正常。这些点如果不处理,拍出来的照片上就会有一堆固定位置的亮点或暗点,看着特别碍眼。

我刚开始做 ISP 调试那会儿,遇到过一块 sensor,出厂就有 200 多个坏点。当时我心想,这 sensor 质量也太差了。后来才知道,其实每颗 sensor 都有坏点,只是多少的问题。关键是怎么把它们找出来,然后悄无声息地修掉。

核心要点:坏点校正分为两大类——静态坏点检测(出厂标定)和动态坏点检测(实时检测)。两者缺一不可。

坏像素校正(BPC)知识体系 坏像素校正 静态坏点检测 动态坏点检测 出厂标定 坏点表存储 插值校正 中值替换 邻域检测 阈值判断 自适应校正 边缘保护 静态 + 动态 = 完整坏点校正方案

4.1 静态坏点检测与校正

静态坏点检测,说白了就是「出厂前先摸清 sensor 的底细」。每颗 sensor 在出厂时都会做一次全黑和全白测试,把那些响应异常的像素坐标记录下来,存成一个坏点表(Defect Pixel Table)。

我个人习惯把静态坏点分成三类:

坏点类型 表现 成因
亮点(Hot Pixel) 暗场下像素值异常高 暗电流过大,漏电
暗点(Dead Pixel) 亮场下像素值异常低 光电二极管损坏
响应异常点 增益响应曲线偏离正常 制造工艺偏差

校正方法其实不复杂。找到坏点坐标后,用周围正常像素的值把它替换掉。常用的有:

  • 邻域均值插值:取上下左右四个像素的平均值。简单,但容易模糊边缘。
  • 中值滤波:取 3x3 邻域的中值。对孤立坏点效果很好。
  • 方向插值:先判断边缘方向,再沿边缘方向插值。效果最好,但计算量大。

我的经验:静态坏点表一定要在 sensor 工作温度稳定后采集。我遇到过一批 sensor,常温下标定只有 50 个坏点,一上 60°C 直接飙到 300 多个。后来我们改成了在 60°C 下标定,问题才解决。

4.2 动态坏点检测算法

静态坏点表能解决大部分问题,但还不够。为什么?因为有些坏点是「间歇性」的——温度变化、电压波动、老化,都可能导致新的坏点出现。这时候就需要动态坏点检测。

动态检测的核心思路很简单:如果一个像素的值和周围像素差异太大,那它很可能就是坏点。

我常用的动态检测流程是这样的:

  1. 计算邻域统计量:取 3x3 或 5x5 窗口,计算均值、中值、标准差。
  2. 计算偏差:中心像素值与邻域中值的差值。
  3. 阈值判断:如果偏差超过预设阈值,标记为坏点。
  4. 校正:用邻域中值或均值替换。

这里有个关键问题——阈值怎么设?设小了容易误检,把正常细节当成坏点;设大了又漏检。我一般用自适应阈值:

// 动态坏点检测伪代码
for each pixel (x, y) {
    // 取 3x3 邻域
    window = getNeighborhood(image, x, y, 3);
    median = getMedian(window);
    stddev = getStdDev(window);
    
    // 自适应阈值:基于局部噪声水平
    threshold = K * stddev + base_threshold;
    
    diff = abs(image[x][y] - median);
    
    if (diff > threshold) {
        // 标记为坏点,用中值替换
        image[x][y] = median;
    }
}

注意:动态检测最怕的就是把图像细节误判为坏点。比如一根细电线、一颗星星、一个高光点,它们的像素值和周围差异也很大。我建议在检测前先做边缘判断——如果中心像素位于边缘上,就放宽阈值或者跳过检测。

4.3 校正效果评估与调优

坏点校正做得好不好,不能光靠眼睛看。我一般用以下几个指标来评估:

评估指标 计算方法 目标值
坏点检出率 检出的坏点数 / 实际坏点数 > 95%
误检率 误检的像素数 / 总像素数 < 0.01%
PSNR 损失 校正前后图像的 PSNR 差值 < 0.5 dB
主观视觉 观察是否有残留亮点/暗点 无可见瑕疵

调优的时候,我习惯按这个顺序来:

  • 先调静态:确保坏点表准确,校正算法在平坦区域不引入伪影。
  • 再调动态:从宽松阈值开始,逐步收紧,观察误检和漏检的平衡点。
  • 最后做场景测试:拍夜景(暗场)、拍白墙(亮场)、拍纹理丰富的场景,看有没有问题。

避坑指南:我曾经在调动态坏点检测时,把阈值设得太低,结果拍星空时把星星全当成坏点给抹掉了。后来我加了一个「高亮保护」逻辑——如果中心像素值远高于邻域均值,且邻域方差也很大,就认为是真实细节,不处理。这才把问题解决。

4.4 静态与动态的协同工作

在实际工程中,静态和动态是配合使用的。我一般这样设计流程:

  1. 先查静态坏点表,如果当前像素在表中,直接校正。
  2. 如果不在表中,再跑动态检测。
  3. 动态检测发现的坏点,可以实时校正,也可以记录下来,后续更新到静态坏点表中。

这样做的好处是:静态检测快、准、省资源;动态检测灵活、能应对突发情况。两者互补,才能做到万无一失。

嗯,坏像素校正这块,说白了就是「先摸清家底,再实时盯防」。静态坏点表是基础,动态检测是补充。调优的关键在于平衡检出率和误检率,千万别为了追求零坏点而把图像细节也抹掉了。