4. BLC(黑电平校正):把“纯黑”还给图像
各位做 ISP 的同行,咱们今天聊聊 BLC。黑电平校正,名字听着挺学术,说白了就是——让相机在完全没光的时候,输出值归零。
你可能会想:“这有什么难的?没光不就是 0 吗?” 嗯,现实没这么简单。传感器在暗场下,由于暗电流、读出噪声、ADC 偏移等因素,输出的原始数据并不是 0,而是一个正数。这个正数,就是黑电平(Black Level)。如果不把它减掉,整张画面就像蒙了一层灰雾,暗部细节全被埋没了。
4.1 BLC 的原理:暗电流与 ADC 偏移
我刚开始做 ISP 时,对 BLC 的理解就是“减一个固定值”。后来踩了坑才明白,这个“固定值”其实并不固定。它受温度、增益、曝光时间影响很大。
传感器内部通常有两种方式产生黑电平:
- 光学黑像素(OB, Optical Black): 传感器边缘有一圈被金属遮挡的像素,它们永远接收不到光。这些像素的输出值,就代表了当前条件下的黑电平。
- ADC 偏移: 模数转换器本身会有一个固定的偏移量,通常由硬件寄存器控制。
实际的黑电平 = OB 像素平均值 + ADC 偏移量。我们做 BLC 校准,就是要精确测量这个值。
4.2 BLC 校准方法:三步走
校准 BLC 其实不复杂,但步骤必须严谨。我个人习惯按下面三步走:
- 采集暗场数据: 盖上镜头盖,确保完全遮光。用目标增益和曝光时间拍一张 raw 图。注意,环境温度要稳定,最好在 25°C 恒温箱里做。
- 计算 OB 均值: 从 raw 图中提取 OB 区域(通常是前几行或左右边缘),计算每个通道(R/Gr/Gb/B)的平均值。
- 写入寄存器或 LUT: 将计算出的偏移量写入传感器的 BLC 寄存器,或者在 ISP 的 BLC 模块中配置减去的值。
下面是一个简单的校准流程示意图:
4.3 BLC 对暗部细节的影响
这个影响太大了。我直接说结论:BLC 不准,暗部细节要么被裁切,要么被噪声淹没。
咱们分两种情况看:
| BLC 状态 | 现象 | 对暗部的影响 |
|---|---|---|
| BLC 偏大(减多了) | 暗部发黑,细节丢失 | 本来有微弱信号的像素被减到 0 以下,被 clamp 掉,细节永久丢失 |
| BLC 偏小(减少了) | 画面发灰,对比度低 | 暗部残留了本应减掉的偏移量,噪声被放大,信噪比下降 |
| BLC 准确 | 暗部纯净,细节丰富 | 微弱信号被保留,噪声水平最低,动态范围最大化 |
4.4 BLC 调试实战:从寄存器到图像
好了,理论说完了,咱们上手。假设你拿到一颗新的 sensor,怎么调 BLC?
第一步,先看 datasheet。大部分 sensor 会给出推荐的 BLC 寄存器值。但别全信,我建议你用自己的暗场数据验证一遍。
第二步,写一个简单的校准脚本。下面是一个伪代码示例:
// 伪代码:BLC 校准
uint16_t ob_avg_r = 0, ob_avg_gr = 0, ob_avg_gb = 0, ob_avg_b = 0;
int ob_pixel_count = 0;
// 遍历 OB 区域(假设 raw 图前 4 行是 OB)
for (int row = 0; row < 4; row++) {
for (int col = 0; col < width; col++) {
uint16_t pixel = raw_image[row][col];
// 根据 Bayer 模式累加
if (is_red(row, col)) ob_avg_r += pixel;
else if (is_green_red(row, col)) ob_avg_gr += pixel;
else if (is_green_blue(row, col)) ob_avg_gb += pixel;
else if (is_blue(row, col)) ob_avg_b += pixel;
ob_pixel_count++;
}
}
// 计算均值
ob_avg_r /= (ob_pixel_count / 4);
ob_avg_gr /= (ob_pixel_count / 4);
ob_avg_gb /= (ob_pixel_count / 4);
ob_avg_b /= (ob_pixel_count / 4);
// 写入寄存器(假设 sensor 支持逐通道 BLC)
sensor_write_register(BLC_R, ob_avg_r);
sensor_write_register(BLC_GR, ob_avg_gr);
sensor_write_register(BLC_GB, ob_avg_gb);
sensor_write_register(BLC_B, ob_avg_b);
第三步,验证。拍一张暗场图,用工具(比如 Imatest 或 Python)看直方图。理想情况下,暗场直方图的峰值应该在 0 附近,且没有明显的拖尾。
4.5 多增益下的 BLC 补偿
前面提到,BLC 会随增益变化。现代 sensor 通常支持多增益下的 BLC 自动补偿,但有些低端 sensor 需要你自己做。
怎么做?很简单,在不同增益下分别采集暗场,建立一张 增益 vs. BLC 偏移 的查找表(LUT)。
| 模拟增益 (dB) | R 通道 BLC (DN) | Gr 通道 BLC (DN) | Gb 通道 BLC (DN) | B 通道 BLC (DN) |
|---|---|---|---|---|
| 0 | 64 | 63 | 63 | 65 |
| 6 | 68 | 67 | 67 | 69 |
| 12 | 76 | 74 | 75 | 78 |
| 18 | 92 | 89 | 90 | 95 |
你看,增益每增加 6dB,BLC 偏移大约增加 4-6 个 DN。如果不做补偿,高增益下暗部偏色会非常明显。
嗯,BLC 这块内容差不多就这些。它虽然基础,但直接影响暗部画质。很多图像问题,比如暗部偏色、噪点异常、动态范围不足,追根溯源往往就是 BLC 没调好。下次遇到这类问题,不妨先从 BLC 查起。