一、黑电平校正(BLC)原理

黑电平校正,简称BLC,是ISP流水线的第一关。

说白了,传感器在完全无光的情况下,输出的像素值不应该是0。为什么?因为传感器本身有暗电流,还有读出电路的偏置。我刚开始做ISP时,就被这个坑过——拿到的raw图整体偏绿,怎么调白平衡都不对,后来才发现是黑电平没校正好。

1.1 黑电平是怎么产生的

传感器每个像素,即使没有光子入射,也会产生微弱的电流。这叫暗电流。温度越高,暗电流越大。另外,读出电路也有固定的偏置电压。这两者叠加,就形成了黑电平。

你可以把黑电平理解成传感器的「底噪」。它是个固定的偏移量,通常在16到64之间(12bit raw数据)。

核心公式:

校正后的像素值 = 原始像素值 - 黑电平值

如果结果小于0,就截断到0。

1.2 为什么需要BLC

不校黑电平,后面所有处理都会出问题。举个例子:

  • 自动曝光(AE)会误判场景亮度
  • 白平衡(AWB)会引入色偏
  • 去马赛克(Demosaic)会产生伪色

我见过一个产品,BLC没做好,暗光下整张图发紫。折腾了两周,最后发现就是黑电平参数没更新。

二、硬件架构设计

BLC的硬件实现,其实不复杂。但要做好,得考虑几个关键点。

2.1 整体架构

我习惯把BLC模块分成三个子模块:

  1. 统计模块:收集暗像素区域的统计值
  2. 计算模块:根据统计值算出当前帧的黑电平
  3. 校正模块:对每个像素做减法运算

下面这张图,是我自己画的BLC硬件架构:

BLC硬件加速器架构图 Raw数据输入 校正模块 (减法器阵列) 校正后数据 统计模块 (暗像素累加) 计算模块 (均值/中值) 控制模块 (参数更新) 数据流 校正模块 统计模块 计算模块 控制模块

2.2 暗像素区域的选择

传感器通常会在边缘预留一些被遮挡的像素。这些像素收不到光,理论上就是纯黑。我们拿它们来算黑电平。

但要注意:

  • 暗像素区域要避开边缘效应
  • 一般取4行×4列到16行×16列
  • 不同颜色通道要分开统计

我的经验:暗像素区域不要选在角落。角落的像素受工艺影响大,统计值不稳定。我一般选在传感器上边缘中间位置,取8行×8列。

三、流水线实现

BLC的流水线设计,核心是处理好时序。

3.1 单帧流水线

对于每一帧图像,BLC的处理流程是这样的:

  1. 帧起始:加载上一帧计算好的黑电平参数
  2. 行处理:对每个像素做减法,同时统计暗像素值
  3. 帧结束:根据统计值计算当前帧的黑电平,供下一帧使用

这里有个关键点:当前帧用的是上一帧的黑电平参数。为什么?因为统计和计算需要时间,没法做到「当前帧统计、当前帧校正」。

注意:如果场景变化剧烈,这种「滞后校正」会出问题。比如从暗室突然走到阳光下,前几帧的黑电平可能不准。我遇到过这种情况,后来加了帧间滤波才解决。

3.2 硬件流水线级数

我一般把BLC设计成3级流水线:

流水线级 操作 延迟
第1级 读取像素值,减去黑电平 1个时钟
第2级 判断是否为暗像素,累加统计值 1个时钟
第3级 输出校正结果,更新计数器 1个时钟

这样设计,每个时钟周期可以处理一个像素。对于1080p@30fps的传感器,完全够用。

四、参数自适应更新策略

黑电平不是一成不变的。温度变了、增益变了、甚至传感器老化,都会影响黑电平。所以参数必须自适应更新。

4.1 更新策略

我常用的策略是「帧间滑动平均」:

// 伪代码:黑电平自适应更新
blc_new = (blc_old * 7 + blc_current) / 8;

这样既跟得上变化,又不会因为单帧噪声导致参数抖动。

4.2 不同增益下的处理

传感器增益变化时,黑电平也会跟着变。我一般会做一张查找表:

增益倍数 黑电平偏移量
1x 0
2x +2
4x +6
8x +14

这张表需要在实验室标定。我建议标定三个温度点:0°C、25°C、60°C,然后线性插值。

4.3 异常处理

有时候暗像素区域会被强光照射到(比如镜头漏光)。这时候统计值会异常偏高。

我的做法是加一个阈值判断:如果当前帧的统计值比上一帧大了50%以上,就认为异常,保持上一帧的参数不变。

避坑指南:我曾经遇到过一个case,暗像素区域被灰尘遮挡,导致黑电平统计值一直偏低。后来我加了「暗像素有效性检测」——如果连续5帧的统计值都低于某个下限,就报警并恢复默认参数。

五、总结

BLC看起来简单,就是个减法。但要做好,得考虑统计、计算、更新三个环节。硬件设计上,3级流水线足够;参数更新上,滑动平均加异常检测是标配。

嗯,这一章就到这里。记住一句话:BLC是ISP的基石,基石不稳,后面全白搭。


专注资料整理