4、黑电平校正(BLC):从原理到实战
黑电平校正,圈里人常叫 BLC(Black Level Correction)。
说白了,就是告诉相机:“什么是真正的黑色”。
你想想看,如果传感器在完全无光的环境下,输出值不是 0,而是 16、32 甚至更高,那拍出来的画面就会发灰、发雾,暗部细节全糊在一起。BLC 要做的,就是把底噪抬起来的那个“假黑”给扣掉。
4.1 暗电流成因:为什么黑的不够黑?
传感器像素本质上是个光电二极管。光照进来,产生电子;没光照,理论上应该没电子。但现实不是这样的。
即使完全遮光,像素里依然会有电子产生。这些电子来自硅基材料的热激发——温度越高,电子越活跃。这就是暗电流。
暗电流的核心影响:
- 让黑色基准值上移,画面发灰
- 随温度升高呈指数增长(夏天和冬天差异很大)
- 不同像素的暗电流不一致,形成固定模式噪声(FPN)
我在项目中遇到过一台 IPC,白天画面正常,到了晚上红外模式下一片灰蒙蒙。查了半天,发现是传感器温度升到 60°C,暗电流飙到了 50 个 DN 以上。BLC 没跟上,黑电平全飘了。
4.2 BLC 校准方法:两种主流方案
校准黑电平,业内主要有两条路:OB 区域法和 PGA 法。我分别讲讲。
4.2.1 OB 区域法(Optical Black)
传感器设计时,会在像素阵列边缘留几行/几列被金属遮挡的像素。这些像素永远见不到光,专门用来测量暗电流。
流程很简单:
- 读出 OB 像素的平均值
- 用这个值作为当前帧的黑电平基准
- 所有有效像素减去这个基准值
// 伪代码:OB 区域法 BLC
uint16_t ob_sum = 0;
for (int i = 0; i < OB_LINE_COUNT; i++) {
for (int j = 0; j < OB_PIXEL_COUNT; j++) {
ob_sum += ob_buffer[i][j];
}
}
uint16_t black_level = ob_sum / (OB_LINE_COUNT * OB_PIXEL_COUNT);
// 逐像素校正
for (int y = 0; y < IMG_HEIGHT; y++) {
for (int x = 0; x < IMG_WIDTH; x++) {
pixel[y][x] = (pixel[y][x] > black_level) ?
(pixel[y][x] - black_level) : 0;
}
}
我的经验:OB 区域法最大的优势是实时跟踪温度变化。帧与帧之间暗电流波动,OB 值会跟着变,BLC 自动适应。但要注意 OB 像素本身也有噪声,建议做中值滤波后再取平均,别直接用原始值。
4.2.2 PGA 法(Programmable Gain Amplifier)
有些传感器没有 OB 区域,或者 OB 区域被裁掉了(比如某些宽动态 sensor)。这时候就得用 PGA 法。
PGA 法是在模拟域给信号加一个固定的偏置电压,让 ADC 转换后的黑电平落在目标值上。这个偏置值通过寄存器写入传感器。
| 对比项 | OB 区域法 | PGA 法 |
|---|---|---|
| 实时性 | 每帧自动更新 | 固定值,需定期校准 |
| 温度适应性 | 好,自动跟踪 | 差,温度变化需重新标定 |
| 硬件要求 | 需要 OB 像素区域 | 需要 PGA 寄存器支持 |
| 噪声影响 | OB 像素噪声会引入 | 无额外噪声 |
| 适用场景 | 主流安防 sensor | 宽动态、特殊 sensor |
4.3 BLC 校准流程:从产线到现场
实际项目中,BLC 校准分两步走:产线标定和现场自适应。
产线标定:
- 将 sensor 完全遮光(用遮光罩或暗箱)
- 采集多帧 OB 数据,取统计平均值
- 写入 sensor 的 BLC 寄存器或 ISP 的配置表
- 验证:全黑画面输出值应在目标值 ±2 DN 以内
现场自适应:
- ISP 每帧读取 OB 区域数据
- 做帧间平滑滤波,防止单帧噪声导致闪烁
- 动态调整减去的黑电平值
- 限制调整步长,避免画面突变
注意:产线标定和现场自适应不能互相替代。产线标定解决的是 sensor 个体差异(每颗 sensor 的暗电流不完全一样),现场自适应解决的是温度漂移。缺一个,画面都会出问题。
4.4 调试中的常见问题与避坑
做 BLC 调试这些年,踩过的坑不少。挑几个典型的说说。
问题一:画面发灰,暗部不黑
最常见的问题。BLC 值偏小,黑电平没扣干净。
我曾经调试一款 4K sensor,默认 BLC 值是 64,但实际暗电流到了 80。画面一直灰蒙蒙的,调了几天增益和曲线都没用。最后用示波器量了 OB 区域的输出,才发现是 BLC 值设低了。
问题二:暗部闪烁,帧与帧之间亮度跳动
这通常是 OB 区域噪声太大,或者帧间平滑没做好。
我的做法:对 OB 区域做 3x3 中值滤波,然后取 5 帧滑动平均。别用简单平均,单帧的随机噪声会直接反映到画面上。
问题三:画面出现竖条纹或横条纹
如果 OB 区域只有几行或几列,且这些像素本身有缺陷,校正后会把缺陷带入有效区域。
解决方案:在产线标定时,标记出 OB 区域中的坏像素,计算平均值时排除它们。
问题四:温度变化后画面偏色
暗电流对 RGB 通道的影响不一样。通常红色通道的暗电流最大,蓝色最小。如果 BLC 是全局统一减一个值,温度升高后画面会偏红。
我建议:如果 sensor 支持,做通道独立的 BLC。R、Gr、Gb、B 四个通道分别计算 OB 值,分别校正。
避坑指南:
- 产线标定时,sensor 必须充分预热(至少 5 分钟),否则标定值不准
- OB 区域不要只用一行,至少取 4-8 行做统计
- 现场自适应时,BLC 调整步长不要超过 1 DN/帧,否则画面会闪
- 如果画面出现黑切(黑色区域被切到 0),说明 BLC 过冲了,需要加保护逻辑
4.5 BLC 在 ISP Pipeline 中的位置
BLC 是 ISP 流水线的第一道工序。数据从 sensor 出来,经过 ADC 转换,第一个进的就是 BLC 模块。
顺序是这样的:
- sensor 原始数据(RAW)
- 黑电平校正(BLC)
- 镜头阴影校正(LSC)
- 坏点校正(DPC)
- 去噪(NR)
- ...后续处理
为什么 BLC 要放在最前面?因为后面的 LSC、DPC、NR 都假设黑电平已经被校正到 0 附近。如果 BLC 没做好,后面的模块全都会算错。
4.6 调试参数速查表
最后给一张我在项目中常用的 BLC 调试参数表,供参考。
| 参数 | 典型值 | 调试建议 |
|---|---|---|
| OB 行数 | 4-16 行 | 越多越稳定,但占用带宽 |
| OB 列数 | 8-32 列 | 建议左右各取对称区域 |
| 帧间平滑帧数 | 3-8 帧 | 场景变化快时减少帧数 |
| BLC 调整步长 | 0.5-1 DN/帧 | 步长过大导致闪烁 |
| 目标黑电平 | 0-4 DN | 保留少量余量防止黑切 |
| 通道独立 BLC | 开启/关闭 | 高精度场景建议开启 |
个人习惯:我调试 BLC 时,会先关掉所有其他 ISP 模块,只保留 BLC。然后对着全黑画面,看 RAW 数据的直方图。理想情况下,直方图应该是一个紧贴 0 的窄峰。如果峰偏了,或者峰太宽,BLC 就有问题。