ISP管线基础:从RAW图到RGB图
各位同学,今天我们来聊聊ISP管线里最核心的一段——从RAW图到RGB图的转换。说白了,就是让相机传感器看到的原始数据,变成我们人眼能理解的彩色图像。
我刚开始接触ISP时,总觉得这步很简单,不就是把拜耳阵列转成RGB嘛。后来真做项目才发现,这里面的坑一个接一个。嗯,咱们今天就把这些模块拆开揉碎了讲。
RAW图到底是什么?
先搞清楚一件事:相机传感器拍到的RAW图,不是我们平时看到的照片。它每个像素只记录一种颜色——红、绿或蓝。这就是拜耳阵列(Bayer Pattern)。
关键点:RAW图是单通道的,每个像素只有亮度值,没有颜色信息。颜色是靠相邻像素猜出来的。
常见的拜耳阵列有RGGB、BGGR、GRBG等。我个人习惯用RGGB,因为大部分传感器厂商默认就是这个排列。
| 拜耳类型 | 排列顺序 | 常见传感器 |
|---|---|---|
| RGGB | 红-绿-绿-蓝 | Sony IMX系列 |
| BGGR | 蓝-绿-绿-红 | 部分OmniVision |
| GRBG | 绿-红-蓝-绿 | 三星部分型号 |
避坑指南:我曾经在项目里搞错过拜耳排列顺序,结果去马赛克后图像全是紫绿色的。排查了两天才发现是配置写反了。所以拿到RAW图第一件事,先确认拜耳类型。
去马赛克(Demosaic)——猜颜色的艺术
去马赛克,说白了就是根据周围像素猜出每个像素缺失的颜色。比如一个红色像素,它缺绿色和蓝色,我们就用相邻的绿色和蓝色像素插值出来。
常用的方法有几种:
- 双线性插值:最简单,取周围像素的平均值。速度快,但边缘会有锯齿和伪色。
- 边缘导向插值:先判断边缘方向,再沿边缘插值。效果比双线性好,但计算量翻倍。
- 自适应插值:根据局部纹理复杂度动态选择插值方式。我项目里常用这个,效果和性能比较平衡。
我的经验:如果你做深度学习降噪,建议去马赛克放在降噪之后做。因为RAW域的噪声是高斯分布的,去马赛克后噪声会变成空间相关的,更难处理。
白平衡(AWB)——让白色真的白
你想想看,同一张白纸,在日光下是白的,在钨丝灯下是黄的,在荧光灯下是蓝的。人眼会自动校正,但相机不会。白平衡就是干这个的。
白平衡的核心是估计光源色温,然后对RGB三个通道分别乘一个增益系数。
// 白平衡增益计算示例
float r_gain = 1.8; // 红色通道增益
float g_gain = 1.0; // 绿色通道保持
float b_gain = 1.4; // 蓝色通道增益
// 应用增益
pixel.r = pixel.r * r_gain;
pixel.g = pixel.g * g_gain;
pixel.b = pixel.b * b_gain;
常见的白平衡算法有:
- 灰度世界法:假设场景平均颜色是灰色,然后调整增益使RGB均值相等。
- 完美反射法:找到图像中最亮的点,假设它是白色,然后以此校正。
- 色温估计法:通过统计R/G和B/G的比值来估计色温。
注意:白平衡做不好,后面Gamma校正和色彩矩阵都会跟着偏。我曾经在一个夜景项目里,白平衡没调好,结果整个画面偏蓝,客户直接打回重做。
Gamma校正——亮度的秘密
Gamma校正,说白了就是做两件事:一是补偿显示器的非线性响应,二是把12bit或14bit的RAW数据压缩到8bit。
人眼对暗部细节更敏感,对亮部不敏感。Gamma曲线就是让暗部保留更多细节,亮部压缩一些。
// Gamma校正标准公式
float gamma = 1.0 / 2.2;
output = pow(input, gamma);
// 实际项目中常用分段函数
if (input <= 0.0031308) {
output = 12.92 * input;
} else {
output = 1.055 * pow(input, 1.0/2.4) - 0.055;
}
这里要注意,Gamma校正是在线性域做的。也就是说,去马赛克和白平衡之后,图像还是线性的,然后做Gamma,最后输出到8bit。
重要:如果你要做深度学习降噪,一定要在Gamma校正之前做。因为Gamma会改变噪声的分布,让高斯噪声变成非均匀的,模型很难学。
ISP管线完整流程
好了,我们把这几个模块串起来,看看完整的ISP管线长什么样。
各模块对噪声的影响
做深度学习降噪,必须知道每个模块怎么影响噪声。我整理了一张表,方便大家对照。
| 模块 | 对噪声的影响 | 降噪建议 |
|---|---|---|
| 黑电平校正 | 基本不影响噪声分布 | 可放在降噪前或后 |
| 去马赛克 | 使噪声空间相关,产生伪色 | 建议降噪在去马赛克前做 |
| 白平衡 | 放大某些通道的噪声 | 降噪必须在白平衡前 |
| Gamma校正 | 使暗部噪声放大,亮部压缩 | 降噪必须在Gamma前 |
| 色彩矩阵 | 线性变换,噪声仍保持高斯 | 可放在降噪后 |
我的建议:如果你只能选一个位置做降噪,我推荐放在去马赛克之前,也就是RAW域。这时候噪声还是独立同分布的高斯噪声,模型最好学。我曾经在RGB域做过降噪,效果差了一大截,后来改回RAW域才解决问题。
实战中的注意事项
最后聊几个我在项目中踩过的坑:
- 位宽问题:RAW图通常是12bit或14bit,但深度学习模型一般处理8bit或16bit。我习惯先转成16bit浮点,避免精度损失。
- 拜耳排列:不同传感器排列不同,模型输入时要做相应处理。我一般把拜耳图拆成4个通道(R、G1、G2、B),这样模型不用关心排列。
- 黑电平:RAW图的黑电平不是0,一般是64或128。降噪前要先把黑电平减掉,否则模型会学到偏移。
- 归一化:我习惯把RAW数据归一化到[0,1]再送模型,这样训练更稳定。
再次提醒:ISP管线里的每个模块都不是孤立的。你改了一个模块,后面所有模块的输出都会变。所以做深度学习降噪时,一定要考虑整个管线的耦合关系。我曾经只优化了降噪模型,没调白平衡参数,结果图像整体偏色,客户不认账。