4、BLC(黑电平校正):黑电平产生原因、BLC校正原理、BLC调试方法、BLC对暗部细节的影响

各位同学,今天我们聊聊BLC——黑电平校正。

说实话,这个模块在ISP pipeline里看着不起眼,但你要是调不好它,暗部细节全完蛋。我见过不少新手,花大把时间调AEC、调降噪,结果图像暗部一片死黑,最后发现是BLC没弄对。嗯,咱们今天就把它彻底讲透。

4.1 黑电平是怎么来的?

先问一个问题:为什么sensor在完全无光的环境下,输出的像素值不是0?

你想想看,理论上没光就没电荷,ADC转换出来应该是0。但实际测一下,你会发现输出值可能是16、32,甚至64。这就是黑电平(Black Level)。

产生原因主要有三个:

  • 暗电流:半导体本身的热激发会产生电子,温度越高越明显。我在夏天调试户外摄像头时,黑电平能比冬天高出一大截。
  • ADC偏移:模数转换器本身有固定的偏置电压,这个偏移量会叠加到所有像素上。
  • 电路噪声:电源纹波、读出电路的不一致性,都会引入一个固定的直流分量。

关键认知:黑电平是一个固定的偏移量,它和信号无关。也就是说,暗处的像素和亮处的像素,都被加上了同一个底数。

4.2 BLC校正原理

说白了,BLC就是做减法。

校正公式很简单:

校正后像素值 = 原始像素值 - 黑电平值

但这里有个坑——黑电平值怎么取?

sensor通常会在像素阵列的边缘设置一些光学黑像素(Optical Black Pixels),这些像素被金属遮挡,永远收不到光。它们的输出值,就代表了当前环境下的黑电平。

我个人的习惯是:

  1. 从sensor的OB区域取一行或一列像素
  2. 计算这些像素的平均值
  3. 用这个平均值作为当前帧的黑电平

但要注意,OB像素本身也有噪声。所以我一般会做中值滤波,去掉异常值再平均。

小技巧:有些sensor支持动态BLC,每帧自动更新黑电平。但如果你发现画面有闪烁,建议锁定BLC值,用固定值校正。

4.3 BLC调试方法

调试BLC,我一般分三步走:

第一步:标定黑电平

盖上镜头盖,确保sensor完全无光。抓一帧raw图,统计所有像素的直方图。

正常情况下,直方图应该是一个窄峰。峰值对应的像素值,就是当前的黑电平。

# 伪代码示例
raw_data = read_raw_image("dark_frame.raw")
hist = calculate_histogram(raw_data)
black_level = find_peak(hist)  # 找到峰值位置
print(f"标定黑电平: {black_level}")

第二步:验证校正效果

用标定好的黑电平做减法,然后检查暗帧的均值是否接近0。

我曾经遇到过一个sensor,标定出来黑电平是64,但校正后暗帧均值还有2。查了半天,发现是sensor的OB区域有坏点,污染了平均值。后来改用中位数,问题解决。

第三步:检查暗部细节

拍一张低照度场景(比如室内灯光下),观察暗部区域。

  • 如果暗部发灰、发雾,说明BLC减多了(过校正)
  • 如果暗部死黑、细节丢失,说明BLC没减够(欠校正)

避坑指南:我曾经在调试一款高灵敏度sensor时,发现暗部有紫色条纹。排查了三天,最后发现是BLC校正后出现了负值,被后续模块截断成了0。解决方案是加一个clamp操作,把负值钳位到0。

4.4 BLC对暗部细节的影响

这个影响比你想象的要大得多。

我们来看一个具体的数据:

场景 原始像素值 黑电平 校正后值 信噪比
暗部细节A 68 64 4
暗部细节B 72 64 8
暗部细节C 80 64 16

你看,暗部细节A和B之间,原始值只差了4个DN。校正后,这个差值被保留了下来。但如果黑电平标定不准,比如你用了62而不是64,那校正后A就变成了6,B变成了10,差值还是4——但整体偏移了2个DN。

这2个DN的偏移,在后续的Gamma校正和LCE(局部对比度增强)中会被放大,最终导致暗部出现色偏或断层。

所以我的建议是:

  • 精度优先:黑电平标定要精确到0.1个DN级别
  • 温度补偿:如果sensor工作温度变化大,要做温度-黑电平的查找表
  • 增益联动:模拟增益增大时,黑电平也会被放大,需要做增益补偿

总结一句话:BLC调好了,暗部细节是细腻的、有层次的;调不好,暗部要么死黑一片,要么灰蒙蒙像蒙了一层雾。这是ISP调试中最基础、也最容易出问题的一环。

好了,BLC的内容就讲到这里。下一章我们聊AWB(自动白平衡),那个更有意思——你会发现,同一个白色物体,在不同光源下拍出来颜色完全不一样。嗯,到时候再细说。