4. RAW域处理:黑电平校正(BLC)、镜头阴影校正(LSC)、坏点校正(DPC)
各位同学,今天我们进入RAW域处理的第一个实战环节。说白了,RAW域就是传感器最原始的“底片”,还没经过任何美化。你想想看,如果底片本身就有问题,后面再怎么调也是白搭。所以,黑电平校正、镜头阴影校正、坏点校正,这三板斧必须打好。
4.1 黑电平校正(BLC)——把“零”找准
什么是黑电平?简单说,就是传感器在全黑环境下,理论上应该输出0,但实际会输出一个非零值。这个值就是黑电平。为什么会有这个值?因为传感器电路本身有暗电流,还有ADC的偏置。嗯,这里要注意,不同温度下黑电平还会漂移。
我在项目中遇到过最头疼的事:夏天车停在户外暴晒,黑电平直接飘了十几个DN(数字码值)。如果不校正,整个画面会偏绿,暗部细节全没了。
校正原理:
- 传感器通常会在像素阵列边缘预留一些“光学黑像素”(OB,Optical Black),这些像素被金属遮挡,不感光。
- 我们取这些OB像素的平均值,作为当前帧的黑电平值。
- 然后从每个有效像素中减去这个值。
代码实现其实很简单:
// 假设OB区域有N个像素,计算平均值
uint32_t sum_ob = 0;
for (int i = 0; i < N; i++) {
sum_ob += ob_buffer[i];
}
uint16_t black_level = sum_ob / N;
// 对每个有效像素做减法,并钳位到0
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int32_t val = raw_image[y][x] - black_level;
raw_image[y][x] = (val < 0) ? 0 : (uint16_t)val;
}
}
4.2 镜头阴影校正(LSC)——把“暗角”抹平
镜头阴影,说白了就是画面四周比中心暗。为什么会这样?两个原因:一是镜头的光学特性,边缘进光量天生比中心少;二是传感器本身对斜入射光的响应效率下降。
你想想看,车载摄像头视角通常很广(120°甚至190°),边缘阴影特别明显。如果不校正,晚上开车时画面四周黑乎乎的,行人或障碍物根本看不清。
校正方法:
- 我们预先在实验室拍一张均匀光照的灰卡,得到每个像素的增益系数。
- 增益系数 = 中心亮度 / 该像素亮度。
- 运行时,每个像素乘以对应的增益系数。
但这里有个坑——增益系数表太大了。一个200万像素的传感器,如果每个像素存一个16位增益值,那就是4MB。对于嵌入式系统来说,太奢侈了。
实际做法:
- 用网格方式存储增益系数。比如每32x32像素一个网格点,中间的点用双线性插值计算。
- 网格点通常用8位或10位定点数表示,精度够用。
我曾经在一个项目中,为了省成本用了便宜的塑料镜头,阴影特别严重。中心增益是1.0,边缘增益到了2.8。结果校正后噪声被放大了,画面边缘全是噪点。后来我加了噪声抑制,才勉强可用。所以,硬件选型真的很重要。
4.3 坏点校正(DPC)——把“死像素”修掉
坏点,就是传感器上那些“不听话”的像素。有的永远亮着(亮点),有的永远黑着(暗点),有的忽亮忽暗(闪烁点)。
车载摄像头对坏点特别敏感。为什么?因为一个坏点可能被误识别为“小目标”,比如远处的行人或障碍物。自动驾驶系统如果基于这个错误信息做决策,后果不堪设想。
坏点检测方法:
- 静态检测:出厂时记录坏点位置,存到OTP(一次性可编程存储器)里。运行时直接查表替换。
- 动态检测:运行时实时检测。比较当前像素与周围8个邻域像素的差异,如果差异超过阈值,就判定为坏点。
我个人习惯两种方法结合。静态检测处理固定坏点,动态检测处理温度变化导致的新坏点。
坏点校正方法:
- 最简单的:用周围像素的中值或平均值替换。
- 好一点的:用周围像素的梯度方向插值。比如水平方向梯度小,就用左右像素平均;垂直方向梯度小,就用上下像素平均。
代码示例(中值替换):
// 假设检测到坏点位置 (cx, cy)
// 取3x3邻域,排除坏点本身
uint16_t neighbors[8];
int idx = 0;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
if (dx == 0 && dy == 0) continue;
neighbors[idx++] = raw_image[cy+dy][cx+dx];
}
}
// 排序取中值
sort(neighbors, neighbors + 8);
raw_image[cy][cx] = neighbors[3]; // 8个元素的中值是第4个
4.4 三个校正的顺序
这三个校正的顺序不能乱。我的建议是:
- 先做BLC:把黑电平减掉,让数据归零。否则后面的校正都会带上偏置误差。
- 再做DPC:坏点校正应该在增益放大之前做。因为坏点被放大后,会变得更明显,更难修复。
- 最后做LSC:镜头阴影校正是乘性增益,放在最后。这样坏点不会被增益放大,噪声也只在最后一步被放大一次。
你想想看,如果先做LSC再做DPC,坏点被增益放大后,周围像素的差异会更大,检测阈值就不好设了。这个顺序是我踩过坑之后才确定的。
| 处理步骤 | 作用 | 注意事项 |
|---|---|---|
| BLC | 消除暗电流偏置 | 温度变化时需动态更新 |
| DPC | 修复坏点 | 阈值要自适应,避免误判 |
| LSC | 补偿镜头阴影 | 增益系数用网格+插值,节省存储 |
好了,这一章的内容就到这里。RAW域处理是ISP流水线的基石,这三步做不好,后面的所有处理都是空中楼阁。下一章我们讲去噪和去马赛克,那是真正让画面“变清晰”的关键步骤。