4. 黑电平校正(BLC):BLC的作用、Offset校准方法、温度对BLC的影响
黑电平校正,圈里人常叫它BLC。这玩意儿看着不起眼,但你要是没处理好,整张图就废了。我刚开始调ISP那会儿,就吃过这个亏——画面暗部发紫,怎么调都调不回来,折腾了两天才发现是BLC的offset没设对。
说白了,BLC要解决什么问题?你想想看,传感器在完全无光的情况下,理论上应该输出0。但现实是,它总会输出一个非零的值。这个值就是黑电平。如果不把它减掉,暗部就会偏色,动态范围也会被压缩。
核心一句话:BLC就是找到传感器在“全黑”状态下的输出值,然后在每个像素上把它减掉。
4.1 BLC到底在干什么?
我习惯把BLC理解成“归零操作”。传感器每个像素都有暗电流,温度越高,暗电流越大。这个暗电流叠加在真实信号上,就像你称东西时秤没归零一样。
BLC的作用主要有三个:
- 消除暗电流偏移:把全黑条件下的输出拉回到0附近
- 保证暗部色彩准确:R、G、B三个通道的黑电平如果不一致,暗部就会偏色
- 释放动态范围:黑电平占用了ADC的码值,减掉后能多用几个bit
嗯,这里要注意一点。BLC不是简单减一个固定值。不同像素、不同增益、不同温度下,黑电平都不一样。所以校准是个细致活。
4.2 Offset校准方法——我常用的两种方式
Offset校准,说白了就是找到那个“减多少”的值。方法有很多,我挑两个最实用的讲。
方法一:OB像素校准法
现在的传感器都会留几行或几列被遮挡的像素,叫Optical Black(OB)区域。这些像素收不到光,它们的输出就是纯黑电平。
具体做法:
- 读取OB区域所有像素的值
- 计算平均值(或者中位数,看噪声情况)
- 用这个值作为当前帧的BLC offset
// 伪代码示例:OB像素校准
uint16_t blc_offset = 0;
uint32_t sum = 0;
int ob_pixel_count = 0;
for (int row = 0; row < OB_ROWS; row++) {
for (int col = 0; col < OB_COLS; col++) {
// 跳过坏像素
if (!is_defect_pixel(row, col)) {
sum += ob_buffer[row][col];
ob_pixel_count++;
}
}
}
blc_offset = sum / ob_pixel_count;
// 对每个有效像素做校正
for (int i = 0; i < TOTAL_PIXELS; i++) {
pixel_out[i] = (pixel_in[i] > blc_offset) ?
(pixel_in[i] - blc_offset) : 0;
}
我的经验:OB像素数量别太少,至少64个以上,不然噪声太大。我曾经在一个项目里只用了16个OB像素,结果每帧的offset都在跳,画面闪烁。后来改成128个,稳得很。
方法二:暗场校准法
有些场景下OB区域不可靠,或者你想做更精细的校准。那就拍一张全黑图——盖上镜头盖,在完全无光的环境下拍一帧。
步骤:
- 盖上镜头盖,设置目标增益和曝光时间
- 采集一帧或多帧图像
- 对每个像素(或每个通道)计算平均值
- 把这个值存成LUT,运行时查表校正
这个方法精度高,但麻烦。因为不同增益、不同曝光时间下黑电平不一样,你得拍很多组数据。
注意:暗场校准对环境要求极高。哪怕有一丝漏光,校准结果就废了。我建议在暗室做,用黑色绒布把镜头裹严实。
4.3 温度对BLC的影响——这个坑我踩过
温度对BLC的影响有多大?我直接说数据吧。
| 温度范围 | 黑电平偏移量(12bit ADC) | 影响程度 |
|---|---|---|
| -20°C ~ 0°C | +2 ~ +5 LSB | 轻微 |
| 0°C ~ 40°C | +5 ~ +15 LSB | 中等 |
| 40°C ~ 85°C | +15 ~ +50 LSB | 严重 |
你看,温度从25°C升到60°C,黑电平可能漂了20多个LSB。如果不做补偿,暗部直接偏绿或偏紫。
为什么会这样?因为暗电流随温度呈指数增长。传感器内部的热激发电子多了,黑电平自然就上去了。
我遇到过最头疼的一个案子:车载摄像头,夏天暴晒后车内温度能到70°C。BLC如果不做温度补偿,画面暗部全是噪点,颜色也偏得离谱。后来我们加了温度传感器,做了个简单的线性补偿模型:
// 温度补偿BLC示例
float temperature_coeff = 0.8; // 单位:LSB/°C
int reference_temp = 25; // 校准时的温度
int current_temp = read_temperature_sensor();
int temp_delta = current_temp - reference_temp;
uint16_t compensated_offset = blc_offset +
(int)(temp_delta * temperature_coeff);
// 用补偿后的offset做校正
for (int i = 0; i < TOTAL_PIXELS; i++) {
pixel_out[i] = (pixel_in[i] > compensated_offset) ?
(pixel_in[i] - compensated_offset) : 0;
}
避坑指南:温度系数不是线性的!高温区斜率更大。我建议分段线性拟合,或者直接用查表法。精度要求高的场景,可以考虑用多项式拟合。
4.4 知识体系总览
下面这张图是我自己整理的BLC知识结构,你看一眼就能明白整个逻辑。
这张图把BLC的三大作用、两种校准方法、以及温度影响和补偿方案串起来了。你调试的时候,按这个思路走,基本不会漏掉关键点。
最后说一句:BLC调好了,暗部细节就出来了。调不好,后面做再多AWB、CCM都是白搭。我见过太多人一上来就调颜色,结果暗部偏色怎么都救不回来——其实就是BLC没做对。