4、坏点检测与校正:坏点分类、动态检测与插值补偿
坏点,说白了就是传感器像素阵列里的“瑕疵品”。
我刚开始做图像传感器时,觉得坏点不就是几个不亮的点嘛,补上就行了。后来发现,事情远没那么简单。坏点会随着温度、增益、曝光时间变化,甚至今天测是好的,明天就冒出来了。
这一章,我们就来彻底搞定坏点问题。
4.1 坏点分类:死点、亮点、热像素
坏点按表现行为,主要分三类。我习惯用一张表来区分它们:
| 类型 | 英文名 | 典型表现 | 成因 | 是否随温度变化 |
|---|---|---|---|---|
| 死点 | Dead Pixel | 输出始终为0或极低值 | 光电二极管损坏、电路断路 | 基本不变 |
| 亮点 | Stuck Pixel / Hot Pixel | 输出始终为饱和值或高值 | 电路短路、漏电流过大 | 轻微变化 |
| 热像素 | Hot Pixel / Warm Pixel | 暗场下输出随温度升高而增大 | 暗电流异常、杂质污染 | 显著变化 |
关键区分:死点和亮点是“硬故障”,出厂就定了。热像素是“软故障”,温度一高就冒出来,温度降下去又好了。这也是动态检测最难处理的地方。
我在项目中遇到过一种情况:客户反馈低温下图像完美,一到夏天就满屏“星星”。查了半天,就是热像素在作怪。所以,坏点检测必须覆盖全温度范围,不能只在实验室25℃下测。
4.2 动态坏点检测算法
静态坏点检测(比如出厂标定一张暗场图)只能对付死点和亮点。热像素怎么办?必须上动态检测。
动态检测的核心思路很简单:拿当前像素跟周围邻居比。如果它跟邻居差异太大,那它大概率有问题。
我常用的算法流程是这样的:
- 取窗口:以目标像素为中心,取5x5或3x3邻域。
- 计算统计量:计算邻域内像素的均值、中值或标准差。
- 设定阈值:根据传感器增益、ISO、温度查表得到动态阈值。
- 比较判决:如果目标像素值与邻域中值的偏差超过阈值,标记为坏点。
嗯,这里要注意阈值怎么设。设太严,好点被误杀;设太松,坏点漏检。我个人习惯用自适应阈值:
// 伪代码:自适应阈值动态坏点检测
uint8_t detect_bad_pixel(uint16_t center, uint16_t *neighbors, int size, float gain) {
// 1. 计算邻域中值
uint16_t median = quick_median(neighbors, size);
// 2. 计算邻域标准差
float std = calc_std(neighbors, size, median);
// 3. 自适应阈值 = 基础阈值 * 增益因子 + 噪声基底
float threshold = BASE_THRESHOLD * gain + 3.0f * std;
// 4. 判决
float diff = (float)abs((int)center - (int)median);
if (diff > threshold) {
return 1; // 坏点
}
return 0; // 好点
}
避坑指南:我曾经在低光照场景下,把好点误判为坏点。原因是邻域标准差太小,阈值被压得太低。后来我加了一个最小阈值保护,保证即使场景很平,阈值也不会低于某个下限。
4.3 坏点插值补偿技术
检测到坏点后,不能直接扔掉,得用周围好点的信息把它“补”回来。常用的补偿方法有几种:
4.3.1 邻域均值插值
最简单粗暴的方法。取坏点周围8个或4个邻居的平均值。优点是快,缺点是会模糊边缘。
4.3.2 中值插值
取邻域中值。对孤立坏点效果很好,而且能保留边缘。我比较推荐这个方法。
4.3.3 方向性插值
先判断边缘方向(水平、垂直、对角),然后只沿着边缘方向取邻居做插值。效果最好,但计算量也最大。
下面这张图展示了不同插值方法的效果对比:
4.4 实际工程中的坏点处理流程
在实际的ISP pipeline中,坏点校正通常放在黑电平校正之后、去马赛克之前。我总结了一个完整的处理流程:
- 出厂标定:在暗场和均匀光照下,生成静态坏点表(死点+亮点)。
- 温度补偿:根据温度传感器读数,从查找表中获取当前温度下的热像素阈值。
- 动态检测:逐帧扫描,用4.2节的算法检测新出现的坏点。
- 坏点合并:将动态检测到的坏点与静态坏点表合并。
- 插值补偿:对合并后的坏点列表,执行插值补偿。
- 结果校验:检查补偿后的图像是否出现新的异常。
重要提醒:动态检测不能每帧都做,太耗资源。我一般设置每30帧做一次全帧检测,或者只在场景切换、增益变化时触发检测。另外,检测到的坏点要加入临时坏点表,连续多帧都出现才确认为永久坏点,避免闪烁噪声误判。
4.5 性能权衡与选型建议
坏点校正的算法选择,本质上是在效果、速度、资源三者之间做权衡。我整理了一张选型表:
| 场景 | 推荐算法 | 原因 |
|---|---|---|
| 低端MCU、低帧率 | 静态坏点表 + 均值插值 | 资源占用极小,无动态检测开销 |
| 中端ISP、30fps | 动态检测 + 中值插值 | 平衡效果与性能,适合大多数场景 |
| 高端安防、车载 | 全帧动态检测 + 方向性插值 | 对坏点零容忍,需要最高质量 |
| 科研、医疗成像 | 多帧融合 + 机器学习检测 | 追求极致精度,可接受较大计算量 |
我个人建议,不要一上来就上最复杂的算法。先跑通静态坏点表+中值插值,看看效果。如果客户反馈有热像素问题,再逐步加入动态检测。这样开发周期短,风险也低。
一个小技巧:在调试阶段,可以把检测到的坏点标记成红色或绿色,输出到屏幕上。这样一眼就能看出哪些点被检测到了,有没有漏检或误检。我每次调试新传感器都会用这个办法,非常直观。