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)

传感器设计时,会在像素阵列边缘留几行/几列被金属遮挡的像素。这些像素永远见不到光,专门用来测量暗电流。

流程很简单:

  1. 读出 OB 像素的平均值
  2. 用这个值作为当前帧的黑电平基准
  3. 所有有效像素减去这个基准值
// 伪代码: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 模块。

顺序是这样的:

  1. sensor 原始数据(RAW)
  2. 黑电平校正(BLC)
  3. 镜头阴影校正(LSC)
  4. 坏点校正(DPC)
  5. 去噪(NR)
  6. ...后续处理

为什么 BLC 要放在最前面?因为后面的 LSC、DPC、NR 都假设黑电平已经被校正到 0 附近。如果 BLC 没做好,后面的模块全都会算错。

BLC 在 ISP Pipeline 中的位置 Sensor RAW BLC 校正 LSC 校正 DPC 校正 ... 为什么 BLC 必须放在最前面? • LSC 校正依赖准确的黑色基准,BLC 不准会导致镜头阴影校正错误 • DPC 坏点检测需要知道正常像素的基线,BLC 偏移会误判坏点 • 去噪模块的阈值设定基于 0 黑电平,BLC 偏差会让去噪力度失准 • 一句话: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 就有问题。