ISP核心模块:黑电平校正、镜头阴影校正、坏点校正的原理与调优

图像传感器拍出来的原始数据,说白了就是一堆「带病」的RAW图。直接拿去做后续处理,效果肯定惨不忍睹。今天咱们聊聊ISP流水线最前面的三个模块——BLC、LSC、DPC。这三个家伙负责把RAW图从「能用」变成「好用」。

我个人习惯把这三个模块称为「预处理三件套」。它们解决的问题各不相同,但目标一致:让传感器数据尽可能真实地反映外界光线。

核心观点: BLC、LSC、DPC 是 ISP 的「地基」。地基没打好,后面的 AWB、CCM、Gamma 调得再好也是白费功夫。

2.1 黑电平校正(BLC)

先说说黑电平。你想想看,传感器在完全无光的环境下,理论上应该输出0。但实际呢?它会输出一个非零的数值。这个数值就是黑电平。

为什么会这样?传感器电路本身有暗电流,ADC转换也有偏移。这些因素叠加起来,就形成了黑电平。如果不校正,暗部区域会发灰,对比度也会受影响。

2.1.1 原理与实现

BLC的原理很简单:减去一个固定的偏移量。但具体怎么减,有讲究。

// 最简单的全局BLC
pixel_out = pixel_in - blc_offset;

// 带饱和保护的BLC
pixel_out = (pixel_in > blc_offset) ? (pixel_in - blc_offset) : 0;

我在项目中遇到过一个问题:有些传感器不同通道的黑电平不一样。R、Gr、Gb、B四个通道各有各的偏移。这时候就得用通道独立的BLC。

BLC模式 适用场景 精度 硬件开销
全局BLC 低端传感器,暗电流均匀 低 1个减法器
通道独立BLC 主流CMOS传感器 中 4个减法器
动态BLC 温度变化大的场景 高 查表+减法器

2.1.2 调优要点

调BLC的时候,我建议你关注两个点:

  • 暗场采集:盖上镜头盖,拍一张全黑图。取平均值作为blc_offset。注意要拍多帧取平均,消除随机噪声。
  • 温度补偿:黑电平会随温度漂移。我曾经在户外测试时发现,中午和晚上的黑电平能差3-5个DN。如果产品工作温度范围大,建议做温度查表补偿。
小技巧: 调BLC时,可以观察RAW图的直方图。校正后,暗部峰值应该落在0附近,但不能大量裁切到0。如果裁切太多,说明减多了,暗部细节丢了。

2.2 镜头阴影校正(LSC)

镜头阴影,也叫亮度衰减。说白了就是画面四周比中心暗。这是光学系统的物理特性,没法完全避免,但可以通过数字手段补偿。

你想想看,镜头中心的光线是垂直入射的,边缘的光线是斜入射的。斜入射的光路更长,衰减更严重。再加上镜头本身的渐晕效应,就形成了阴影。

2.2.1 原理与实现

LSC的核心思路是:给边缘像素乘以一个大于1的增益。增益的大小取决于像素到中心的距离。

// 基于网格的LSC
// 预先存储一个增益网格,例如 17x13 个网格点
// 运行时通过双线性插值计算每个像素的增益
gain = bilinear_interpolation(grid, x, y);
pixel_out = pixel_in * gain;

我记得第一次做LSC时,用了最简单的多项式模型。结果发现边缘偏色严重。后来才意识到,不同颜色通道的衰减曲线不一样。R通道衰减最快,B通道次之,G通道最慢。所以LSC必须分通道处理。

注意: LSC增益不能太大。如果边缘增益超过4倍,噪声会被放大到不可接受的程度。这时候应该考虑光学设计,而不是全靠数字补偿。

2.2.2 调优流程

调LSC,我一般按这个步骤来:

  1. 拍灰卡:用均匀光源照射灰卡,拍一张RAW图。
  2. 分析衰减曲线:提取中心到边缘的亮度变化曲线。
  3. 生成增益网格:根据衰减曲线反推增益值。
  4. 验证校正效果:校正后,画面亮度均匀性应该达到95%以上。
  5. 检查偏色:如果边缘偏色,调整各通道的增益比例。

我曾经在一个项目中,LSC调了整整两周。问题出在光源不均匀上。灰卡拍出来本身就不均匀,导致增益网格全是错的。后来换了积分球光源,一次就调好了。

2.3 坏点校正(DPC)

坏点,就是传感器上那些「不听话」的像素。有的永远亮着(亮点),有的永远暗着(暗点),有的忽亮忽暗(闪烁点)。

坏点分两种:静态坏点和动态坏点。静态坏点是出厂就有的,位置固定。动态坏点是使用过程中产生的,受温度、电压影响。

2.3.1 原理与实现

DPC的基本思路是:检测坏点,然后用周围像素的值替换它。

// 简单的坏点检测与校正
// 检测:当前像素与周围8邻域的差值超过阈值
if (abs(pixel_center - pixel_neighbor) > threshold) {
    // 校正:用中值或均值替换
    pixel_out = median_filter(neighbors);
} else {
    pixel_out = pixel_in;
}

这里有个坑:阈值设得太小,会把正常细节误判为坏点;设得太大,又漏检。我建议用自适应阈值,根据局部亮度动态调整。

坏点类型 检测方法 校正方法 适用场景
静态亮点 暗场检测 查表替换 出厂标定
静态暗点 亮场检测 查表替换 出厂标定
动态坏点 邻域比较 中值滤波 实时处理

2.3.2 调优要点

调DPC,我总结了几条经验:

  • 静态坏点用查表法:出厂时做一次坏点标定,把坏点坐标存到OTP里。运行时直接查表替换,效率最高。
  • 动态坏点要防误判:纹理丰富的区域容易误检。我习惯在检测前先算局部方差,方差大的区域放宽阈值。
  • 校正后要平滑:替换后的像素可能与周围不连续,造成「斑点」。建议做一次3x3均值平滑。
避坑指南: 我曾经在调试时发现,DPC把星空的星星当成坏点给抹掉了。后来加了「星点保护」逻辑——如果检测到的「坏点」数量超过一定比例,就认为是场景特征,不做校正。

2.4 三个模块的协同关系

BLC、LSC、DPC在ISP流水线中的顺序是固定的:BLC → DPC → LSC。为什么是这个顺序?

先做BLC,把黑电平归零,后续的增益计算才准确。再做DPC,因为坏点校正依赖邻域像素,如果先做LSC,增益会把坏点放大,影响检测。最后做LSC,因为增益计算需要准确的像素值。

下面这张图展示了三个模块在ISP流水线中的位置和关系:

ISP预处理三件套流水线 ISP预处理三件套流水线 RAW输入 BLC 黑电平校正 DPC 坏点校正 LSC 镜头阴影校正 输出 为什么是这个顺序? BLC先归零 → DPC避免增益放大坏点 → LSC最后做精确增益补偿 顺序错了,校正效果会大打折扣

2.5 实战调优建议

最后,给几个实战中的调优建议:

  • 先调BLC,再调LSC,最后调DPC。BLC不准,LSC的增益计算就是错的。LSC没调好,DPC的坏点检测阈值就不好设。
  • 用工具看RAW图。我习惯用ImageJ或者Python的rawpy库,直接看校正前后的RAW数据。只看JPEG是看不出问题的。
  • 留余量。BLC的偏移量不要减到0,留1-2个DN的余量。LSC的增益不要超过3倍。DPC的阈值设得宽松一点,宁可漏检也不要误判。
重要提醒: 这三个模块的调优,一定要在最终的光学系统下进行。换了镜头、换了传感器、甚至换了镜头和传感器之间的距离,都要重新调。我曾经吃过这个亏,换了镜头没重新调LSC,结果画面边缘偏色严重,被客户投诉了。

好了,预处理三件套就聊到这儿。这三个模块虽然基础,但调好了能让后续的ISP处理事半功倍。记住一句话:地基不牢,地动山摇。