052、黑电平校正(BLC)实战:暗电流补偿算法与温度自适应调优策略
一、一个让我熬夜三天的Bug
2018年夏天,某款旗舰手机项目,Sensor是IMX586,ISP用高通Spectra 380。整机在常温下拍照一切正常,但到了可靠性测试——高温65℃环境箱里,暗光场景下画面出现了明显的“紫边”和“偏绿”现象。更诡异的是,同一台机器放回常温半小时,问题自动消失。
当时团队里有人怀疑是镜头镀膜热胀冷缩,有人怀疑是Sensor的RGGB通道增益不一致。我花了三天时间,逐帧dump raw图,发现一个规律:温度升高后,Sensor输出的暗场像素值(遮光像素OB)整体抬升了约12个DN(10bit raw),但ISP的BLC模块还在用常温下标定的固定值做减法。这就是典型的黑电平校正失效——暗电流随温度漂移,而补偿值没跟上。
二、黑电平到底在补偿什么
很多人以为BLC就是“把全黑画面的像素值减到0”,这是错的。Sensor在完全无光条件下,像素依然会输出一个非零值,这个值由两部分组成:
- 固定模式噪声(FPN):每个像素的偏移量不同,但相对稳定,一次标定即可。
- 暗电流噪声:随温度指数级增长,每升高10℃,暗电流大约翻倍。这是BLC要动态补偿的核心对象。
Sensor设计时会在像素阵列边缘留出一圈“光学黑像素”(Optical Black,OB),这些像素被金属遮挡,永远接收不到光。OB像素的输出值,就是当前温度下暗电流的实时采样。BLC的数学本质很简单:
校正后像素值 = 原始像素值 - OB均值但实战中,这个减法远没有看起来那么简单。
三、OB采样策略:别被均值骗了
第一次写BLC代码时,我直接取所有OB像素的算术平均值,结果在低光场景下画面出现横向条纹。排查发现,OB行和有效像素行在读出时序上存在差异——Sensor的模拟读出电路在每行开始时有短暂的建立时间,导致前几行OB值偏高。
正确的做法:剔除OB区域的前N行(N取决于Sensor的读出建立时间,通常3-5行),只取稳定后的OB行做均值。这里踩过坑——某次换Sensor型号后忘了调整N值,暗角校正全乱套。
更精细的做法是分通道统计。RGGB四个通道的暗电流特性不同,B通道对温度最敏感(硅基材料对短波长的量子效率随温度变化更大),G通道次之,R通道最稳定。所以:
// 别这样写:所有通道共用一个OB均值blc_offset=mean(all_ob_pixels);// 应该这样写:分通道统计blc_offset_r=mean(ob_pixels_under_r_channel);blc_offset_gr=mean(ob_pixels_under_gr_channel);blc_offset_gb=mean(ob_pixels_under_gb_channel);blc_offset_b=mean(ob_pixels_under_b_channel);分通道补偿后,高温下的偏色问题能改善80%。剩下的20%,来自OB像素本身的热噪声方差——单帧OB均值不够稳定,需要多帧滤波。
四、温度自适应:从查表到在线学习
早期方案是查表法:在实验室用温箱标定-20℃到85℃的OB值,存成LUT。但有两个致命问题:
- 标定成本高:每个Sensor型号、每个增益档位都要标,一个项目光标定就要两周。
- 老化漂移:Sensor使用半年后,暗电流特性会变化,出厂LUT失效。
后来在车载项目上被逼出了新方案——在线自适应。核心思路:利用Sensor的OB区域做实时温度感知,同时用有效像素区域的“伪暗场”做校验。
具体实现分三步:
第一步:粗调——基于OB实时统计
每帧计算当前OB均值,与上一帧做IIR滤波(系数0.3-0.5,别用0.1以下,响应太慢)。滤波后的值作为当前帧的BLC偏移量。
第二步:细调——利用场景中的“真黑”区域
在画面中寻找亮度极低的像素块(比如暗光下的黑色物体),这些区域的理想值应该是0。如果经过粗调后,这些区域的平均值仍大于某个阈值(比如10个DN),说明OB统计存在偏差(比如OB区域被污染或Sensor读出异常),需要做二次补偿。
第三步:温度-增益联合补偿
暗电流不仅随温度变化,还随Sensor增益(Analog Gain)变化。增益越高,暗电流被放大的倍数越大。所以补偿公式应该是:
blc_final = blc_ob_mean * (1 + k * (gain - gain_ref))其中k是温度-增益耦合系数,需要在实验室标定一次,但比全温区标定简单得多。这里有个经验值:对于BSI工艺的Sensor,k大约在0.02-0.05之间;对于FSI工艺,k可能到0.1。
五、实战中的三个坑
坑一:OB区域被污染
某次量产发现,手机在强光下拍照,画面出现“黑斑”。排查发现,镜头边缘的杂散光照射到了OB区域,导致OB均值偏高,BLC过度补偿,有效像素被减到负值,ISP clamp后变成全黑。解决方案:在OB区域外围再加一圈“保护行”,这些行的像素值不参与统计,只作为光隔离带。
坑二:BLC与数字增益的时序冲突
ISP pipeline中,BLC通常在数字增益(Digital Gain)之前。但如果数字增益很大(比如暗光场景下增益到4x),BLC的微小误差会被放大。一个常见错误:先做BLC,再做数字增益,结果暗电流噪声被放大到肉眼可见。正确顺序应该是:BLC → 去噪 → 数字增益。去噪模块放在中间,可以抑制BLC残留的随机噪声。
坑三:HDR多帧合成的BLC一致性
在HDR模式下,短帧和长帧的曝光时间不同,暗电流积累量不同。如果每帧独立做BLC,合成时会出现亮度跳变。解决方案:以长帧的OB值为基准,短帧的BLC偏移量按曝光时间比例缩放。比如长帧曝光30ms,OB均值为50;短帧曝光5ms,OB均值应为50 * (5/30) ≈ 8.3。别直接用短帧自己的OB统计,因为短帧的OB信噪比太低,统计误差大。
六、调试工具与判断标准
在实验室调试BLC时,我习惯用三个指标:
- 暗场均匀性:全黑环境下,raw图各通道的均值应接近0,标准差应小于1个DN(10bit)。如果标准差大于2,说明BLC没做好,或者Sensor的FPN标定有问题。
- 温度漂移量:从25℃到65℃,OB均值变化应控制在3个DN以内。超过5个DN,说明温度自适应算法没生效。
- 极限场景鲁棒性:在-20℃低温下,OB值可能降到接近0,此时BLC不能过度补偿(不能把有效像素减到负值)。需要设置一个最小补偿阈值,比如至少保留2个DN的偏置,防止负值clamp导致细节丢失。
七、个人经验
做了十几年BLC,最大的感悟是:黑电平校正不是简单的减法,而是对Sensor物理特性的建模。每个Sensor型号的暗电流特性都不一样,甚至同一片wafer上不同die都有差异。量产时,最好在模组端做一次OB标定,把每个模组的OB基准值写入OTP,ISP在初始化时读取。
另外,别迷信“全自动自适应”。在极端场景下(比如Sensor温度从-20℃瞬间跳到60℃),OB统计的响应速度跟不上,需要配合硬件温度传感器做前馈补偿。我见过一个方案:在Sensor PCB上贴一个热敏电阻,温度变化超过5℃/s时,强制使用查表值,等OB统计稳定后再切回自适应模式。
最后说一句:BLC调好了,用户感知不到;调不好,所有后续的ISP模块(AWB、CCM、Gamma)都会跟着错。它就像地基,看不见但决定了整栋楼的高度。