2、传统ISP流水线深度解析:从Bayer到YUV,逐级拆解黑电平校正、去马赛克、白平衡、Gamma校正等模块。
好,我们直接进入正题。传统ISP流水线,说白了就是把CMOS传感器吐出来的原始Bayer数据,一步步加工成人眼看着舒服的YUV图像。这个过程我做了十几年,每个模块都踩过坑。今天咱们就把它拆开揉碎了讲。
先看整体流程,心里有个地图:
2.1 黑电平校正(Black Level Correction)
传感器在完全无光照的情况下,输出的像素值并不是0。为什么?因为电路本身有暗电流和偏置电压。这个非零的底值,就是黑电平。
校正方法很简单:
// 伪代码示例
pixel_out = pixel_raw - black_level;
if (pixel_out < 0) pixel_out = 0;
但实际工程里有个坑。我记得有一次调试一款手机传感器,发现暗部偏绿。查了半天,原来是R、G、B通道的黑电平不一致。不同通道的暗电流不一样,必须分别校正。
2.2 去马赛克(Demosaic)
Bayer格式每个像素只记录一种颜色。去马赛克的任务,就是通过插值把缺失的另外两个颜色算出来。最常见的Bayer模式是RGGB。
插值算法有很多种,我列个对比:
| 算法 | 复杂度 | 画质 | 典型场景 |
|---|---|---|---|
| 双线性插值 | 低 | 差(伪彩色多) | 低端摄像头、预览模式 |
| 边缘导向插值 | 中 | 较好 | 主流手机ISP |
| 自适应插值(如AHD) | 高 | 优秀 | 高端相机、医疗影像 |
我个人习惯用边缘导向插值。它先判断当前像素是在水平边缘还是垂直边缘,然后沿着边缘方向插值。这样能有效减少锯齿和伪彩色。
2.3 白平衡(White Balance)
白平衡的本质,是让白色物体在任何光源下都呈现为白色。不同光源的色温不同,传感器对RGB的响应也不同。白平衡就是给R和B通道乘上不同的增益,把色差拉回来。
经典做法是灰度世界法:假设场景中所有颜色的平均值是灰色。那么:
R_gain = G_avg / R_avg
B_gain = G_avg / B_avg
但这个方法有个致命缺陷——如果场景里大面积是单一颜色(比如蓝天、绿草地),白平衡就会完全跑偏。
你想想看,一片蓝天里,蓝色通道的平均值远高于红绿,按灰度世界法算出来,蓝增益会很小,结果天空被拉成了灰色。这显然不对。
2.4 Gamma校正
Gamma校正有两个目的:一是补偿显示设备的非线性响应(CRT时代留下的遗产),二是把人眼敏感的暗部细节拉开。
标准Gamma曲线:
// sRGB标准Gamma
if (linear <= 0.0031308)
gamma = 12.92 * linear;
else
gamma = 1.055 * pow(linear, 1/2.4) - 0.055;
嗯,这里要注意。Gamma校正是在线性光域做的。也就是说,去马赛克和白平衡的输出必须是线性数据,做完Gamma再转到非线性域。顺序不能乱。
我见过有人把Gamma放在白平衡前面做,结果色彩完全不对。因为Gamma是非线性变换,会改变RGB之间的比例关系,白平衡的增益就失效了。
2.5 色彩空间转换与YUV输出
Gamma校正之后,数据还是RGB格式。但显示、编码、传输通常用YUV。Y是亮度,UV是色度。人眼对亮度更敏感,对色度不敏感,所以UV可以降采样,节省带宽。
标准转换矩阵(BT.601):
Y = 0.299*R + 0.587*G + 0.114*B
Cb = -0.169*R - 0.331*G + 0.500*B + 128
Cr = 0.500*R - 0.419*G - 0.081*B + 128
到这里,传统ISP流水线就走完了。从Bayer Raw到YUV,每一步都有它的物理意义和工程考量。