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),这些像素被金属遮挡,永远收不到光。它们的输出值,就代表了当前环境下的黑电平。
我个人的习惯是:
- 从sensor的OB区域取一行或一列像素
- 计算这些像素的平均值
- 用这个平均值作为当前帧的黑电平
但要注意,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(自动白平衡),那个更有意思——你会发现,同一个白色物体,在不同光源下拍出来颜色完全不一样。嗯,到时候再细说。