黑电平校正原理:暗电流与光响应非均匀性
黑电平校正,简称BLC。说白了,就是让传感器在没光的时候,输出值归零。
你可能会问:传感器没光不就是全黑吗?输出应该是0才对啊。嗯,理想情况确实如此。但现实世界哪有这么完美?我做过这么多项目,还没见过哪颗传感器能在全黑下输出0的。
暗电流:传感器天生的"漏电"问题
先说说暗电流。这玩意儿是半导体器件的物理特性,没法完全消除。
每个像素点其实就是一个光电二极管。光照时产生光生电子,没光时呢?热激发也会产生电子。温度越高,热激发越强,暗电流就越大。
我在项目中遇到过这样的情况:夏天户外测试,传感器温度飙到60多度,暗电流直接翻了好几倍。画面暗部全是偏红的,校正参数完全失效。后来才意识到,暗电流是随温度变化的,不能用一个固定值去校正。
暗电流的几个特点:
- 温度敏感:每升高10度,暗电流大约翻一倍
- 曝光时间相关:曝光越长,积累的暗电荷越多
- 像素差异:不同像素的暗电流大小不一样
光响应非均匀性:像素之间的"性格差异"
光响应非均匀性,英文叫PRNU。这名字听着挺唬人,其实意思很简单:同样光照下,不同像素的输出值不一样。
为什么会这样?你想想看,一颗几百万像素的传感器,每个像素的尺寸、掺杂浓度、量子效率都不可能完全一致。就像同一批生产的灯泡,亮度也会有细微差别。
PRNU主要分两种:
- 固定模式噪声(FPN):每个像素的偏移量是固定的,不随光照变化
- 光响应非均匀性(PRNU):增益差异,光照越强越明显
黑电平校正主要处理的是FPN这部分。PRNU通常留给后面的增益校正去处理。
黑电平的数学模型
搞清楚了物理原理,咱们来看看数学怎么描述。
一个像素的输出值,可以拆解成三部分:
Pixel_out = Signal + Dark_current + FPN_offset
其中:
- Signal:真实的光信号,我们想要的部分
- Dark_current:暗电流贡献,与曝光时间和温度相关
- FPN_offset:固定模式噪声,每个像素独有的偏移
黑电平校正的目标,就是把Dark_current和FPN_offset去掉,只保留Signal。
实际工程中,我们通常用一个更简单的模型:
Pixel_corrected = Pixel_raw - BLC_value
这个BLC_value怎么来的?一般有两种方式:
- OB像素法:传感器边缘有被遮挡的像素,它们的输出就是黑电平参考值
- 暗场标定法:盖上镜头盖拍一张全黑图,统计平均值作为BLC
重要提醒:OB像素法更实用,因为它能实时跟踪温度变化。暗场标定法只适合实验室环境,温度一变就不准了。
校正的基本公式
好了,到了动手环节。黑电平校正的公式其实很简单:
// 全局校正:所有像素减去同一个值
for (int i = 0; i < width * height; i++) {
pixel[i] = pixel[i] - blc_value;
// 防止下溢
if (pixel[i] < 0) pixel[i] = 0;
}
这是最基础的版本。但我建议你别这么用,原因有二:
- 不同通道的BLC不一样:R、Gr、Gb、B四个通道,暗电流特性不同
- 不同位置的BLC也不一样:传感器边缘和中心的暗电流有差异
我个人习惯用通道独立的BLC:
// 通道独立的BLC校正
// blc_r, blc_gr, blc_gb, blc_b 分别对应四个通道
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int idx = y * width + x;
if ((y % 2 == 0) && (x % 2 == 0)) {
// R通道
pixel[idx] = pixel[idx] - blc_r;
} else if ((y % 2 == 0) && (x % 2 == 1)) {
// Gr通道
pixel[idx] = pixel[idx] - blc_gr;
} else if ((y % 2 == 1) && (x % 2 == 0)) {
// Gb通道
pixel[idx] = pixel[idx] - blc_gb;
} else {
// B通道
pixel[idx] = pixel[idx] - blc_b;
}
// 钳位到有效范围
pixel[idx] = CLAMP(pixel[idx], 0, max_value);
}
}
经验之谈:我曾经在调试一款手机摄像头时,发现画面偏绿。查了半天,原来是Gr和Gb的BLC值搞反了。这两个通道虽然都是绿色,但暗电流特性确实有差异,千万别偷懒用同一个值。
BLC与动态范围的关系
这个知识点容易被忽略,但它真的很重要。
动态范围,简单说就是传感器能同时记录的最亮和最暗的比值。BLC校正做不好,动态范围直接缩水。
举个例子:
| 场景 | BLC值 | 有效信号范围 | 动态范围损失 |
|---|---|---|---|
| 理想情况 | 0 | 0 ~ 1023 (10bit) | 0% |
| BLC偏大 | 64 | 0 ~ 959 | 6.25% |
| BLC偏小 | 32 | 0 ~ 991 | 3.125% |
看到没?BLC值越大,暗部被抬得越高,亮部的可用范围就越小。动态范围就这么被压缩了。
更严重的问题是什么?
- BLC偏大:暗部噪声被放大,画面发灰,对比度下降
- BLC偏小:暗部细节丢失,出现黑切现象
避坑指南:我曾经在一个安防项目中,为了追求暗部细节,把BLC值设得偏小。结果晚上监控画面暗部全是黑的,什么也看不清。后来才发现,BLC偏小导致暗部信号被截断了,信息全丢了。校正不是越小越好,要找到那个平衡点。
那怎么找到合适的BLC值?我的做法是:
- 先拍一张全黑图,统计每个通道的均值
- 再拍一张均匀灰卡,看校正后的线性度
- 微调BLC值,直到暗部噪声和动态范围达到平衡
嗯,这里要注意一点:BLC校正必须在RAW域进行,而且要在其他校正之前。顺序搞错了,后面的白平衡、伽马校正都会受影响。
最后总结一下我的经验:黑电平校正看似简单,就是个减法操作。但要做好,得理解暗电流的物理特性,得考虑温度和曝光时间的影响,还得平衡动态范围和噪声。别小看这一步,它直接决定了整个ISP pipeline的底子好不好。