4. RAW图预处理:Bayer格式解析、黑电平校正、LSC镜头阴影校正、坏点校正、白平衡预处理
各位同学,欢迎来到多帧HDR融合实战的第一道关卡——RAW图预处理。
说实话,很多做算法的人容易忽略这一步。他们觉得HDR融合的核心是“对齐”和“融合”,预处理嘛,随便调调库就行。但我得告诉你,这种想法在工程落地时往往会吃大亏。我在项目里见过太多次了——预处理没做好,后面融合出来的图像全是偏色、暗角、或者一堆闪烁的坏点。嗯,今天我们就来把这些坑一个一个填上。
4.1 Bayer格式解析:从Sensor拿到的第一手数据
你从摄像头Sensor直接读出来的数据,不是RGB,而是Bayer格式。说白了,每个像素只记录一种颜色——红、绿、蓝中的一个。最常见的排列是RGGB,也就是一个2x2的单元里,左上和右下是绿,右上红,左下蓝。
我刚开始做ISP时,犯过一个低级错误:直接把Bayer数据当成RGB去显示,结果图像全是马赛克。后来才明白,必须先做去马赛克(Demosaic),把缺失的颜色插值出来。
不过在我们HDR融合的场景里,预处理阶段通常不做Demosaic。为什么?因为融合需要在RAW域做,保持原始信息。你想想看,一旦插值成RGB,很多细节就丢了,后面再融合效果会打折扣。
| Bayer排列 | 常见Sensor | 特点 |
|---|---|---|
| RGGB | Sony IMX系列 | 最主流,绿色双倍采样 |
| BGGR | 部分OmniVision | 与RGGB只是顺序不同 |
| RCCC | 安防/车载 | 红色为主,低光性能好 |
4.2 黑电平校正:把“零”找回来
Sensor在完全无光的情况下,输出的像素值不是0。因为电路本身有暗电流,会有一个基础偏移量,这就是黑电平(Black Level)。
黑电平校正其实很简单:
// 伪代码示例
uint16_t black_level = 64; // 10-bit RAW常见值
for (int i = 0; i < width * height; i++) {
raw[i] = (raw[i] > black_level) ? (raw[i] - black_level) : 0;
}
但这里有个坑——不同通道的黑电平可能不一样。我记得有一次调试一个国产Sensor,红通道和蓝通道的黑电平差了8个DN(Digital Number)。如果统一减同一个值,暗部就会偏色。
4.3 LSC镜头阴影校正:消除暗角
镜头阴影(Lens Shading),说白了就是画面四周比中心暗。这是物理规律——镜头边缘进光量天生就少。再加上Sensor的微透镜角度匹配问题,四周的响应也会下降。
校正方法是用一个增益矩阵,对每个像素乘以一个系数。系数从中心到边缘逐渐增大。
// 简化的LSC校正
float gain = lens_shading_table[y][x]; // 查表得到增益
raw[y * width + x] = clamp(raw[y * width + x] * gain, 0, max_val);
实际工程中,LSC表是怎么来的?有两种方式:
- 标定法: 拍一张均匀光照的灰卡,然后反推每个像素需要的增益。这是最准的。
- 经验公式法: 用多项式拟合,比如中心增益为1.0,边缘增益为1.2~1.5。适合快速原型验证。
4.4 坏点校正:别让一个像素毁了整张图
Sensor的坏点分两种:
- 死点(Dead Pixel): 永远输出0或接近0,怎么都不亮。
- 亮点(Hot Pixel): 永远输出最大值,或者比正常值高很多。
坏点校正的核心思路是“用邻居的值来替代”。最简单的做法是中值滤波:
// 坏点检测与校正
if (is_defect_pixel(raw[y][x], neighbors)) {
raw[y][x] = median_filter(neighbors);
}
但这里有个关键问题——怎么判断一个像素是不是坏点?
我常用的方法是:
- 计算当前像素与周围8个像素的差值。
- 如果差值超过某个阈值(比如50个DN),就标记为候选坏点。
- 再检查这个像素在相邻帧中是否持续异常——如果是,才确定为坏点。
4.5 白平衡预处理:给颜色定调
白平衡(White Balance)的目的是让白色物体在任何光源下都呈现白色。在RAW域,我们通常用增益调整来实现:
// 白平衡增益应用
float r_gain = 1.8; // 红色通道增益
float b_gain = 1.4; // 蓝色通道增益
// 绿色通道通常保持1.0
for (int i = 0; i < width * height; i++) {
if (is_red_pixel(i)) {
raw[i] = clamp(raw[i] * r_gain, 0, max_val);
} else if (is_blue_pixel(i)) {
raw[i] = clamp(raw[i] * b_gain, 0, max_val);
}
}
增益怎么算?常见方法有:
- 灰度世界法: 假设场景中所有颜色的平均是灰色,然后调整增益使R、G、B均值相等。
- 白点法: 找到场景中最亮的区域(假设是白色),然后调整增益使该区域R=G=B。
但在HDR融合中,我建议不要做完整的白平衡。为什么?因为HDR融合需要多帧之间的颜色一致性。如果每帧都独立做白平衡,不同帧的增益可能不一样,融合后就会出现颜色闪烁。
4.6 本章知识体系总览
下面这张图总结了RAW图预处理的完整流程和各个模块的关系:
这五个步骤是串行执行的,顺序不能乱。Bayer解析是基础,黑电平校正是前提,LSC和坏点校正是质量保障,白平衡预处理是最后的调色准备。每一步都做扎实了,后面的HDR融合才能有好的数据基础。