1. 图像传感器与RAW图基础:Bayer阵列、黑电平、线性化、LSC镜头阴影校正

各位同学好,我是你们的ISP算法讲师。这一章咱们要聊的是整个ISP Pipeline的起点——RAW图。说白了,就是摄像头传感器刚把光信号转成电信号,还没经过任何美化处理的那个“素颜”数据。

我刚开始做ISP的时候,总觉得RAW图处理是“脏活累活”,不如后面的降噪、HDR炫酷。后来被现实狠狠教育了一顿——前面基础没打好,后面算法再牛也救不回来。你想想看,如果黑电平都没校准对,整个画面的暗部细节就全偏了,降噪算法再强也只能把噪声和信号一起抹掉。

好,咱们直接进入正题。

1.1 Bayer阵列——传感器的“像素棋盘”

大多数CMOS图像传感器,每个像素只能感知光的强度,分辨不出颜色。那彩色照片怎么来的?靠的是在像素表面覆盖一层彩色滤光片阵列(CFA)。最经典的就是Bayer阵列,也叫拜耳阵列。

Bayer阵列的排布规则很简单:

  • 50% 绿色(G)——人眼对绿色最敏感,所以绿色像素占一半
  • 25% 红色(R)
  • 25% 蓝色(B)

常见的排布是RGGB或BGGR。高通平台默认用BGGR居多,但这不是的,不同模组厂商可能不一样。

关键点:RAW图里每个像素只有一种颜色信息。要得到全彩图,必须做去马赛克(Demosaic),也就是用周围像素插值出缺失的颜色通道。这个咱们后面章节会细讲。

我在项目中遇到过一件事:某款模组的Bayer排布标称是RGGB,但实际产线上贴歪了,导致去马赛克后出现彩色条纹。排查了三天才发现是Bayer排布读错了。嗯,这里要注意——永远不要相信模组规格书上的Bayer顺序,一定要用工具实际抓一帧RAW图验证。

1.2 黑电平(Black Level)——把“零”找准

传感器在没有光照的时候,理论上输出应该是0。但实际因为暗电流、电路噪声等原因,输出会有一个偏移量。这个偏移量就是黑电平。

黑电平校准的目的很简单:把“真正的黑”拉到0。

高通平台上的黑电平处理流程:

  1. 传感器输出RAW图时,通常会在每行或每帧包含一些光屏蔽像素(Optical Black Pixels),这些像素被金属遮挡,接收不到光
  2. ISP读取这些光屏蔽像素的平均值,作为当前帧的黑电平估计值
  3. 从所有有效像素中减去这个黑电平值

个人经验:黑电平不是固定不变的。温度升高、曝光时间变长,黑电平都会漂移。我建议在长曝光场景(比如夜景模式)下,动态更新黑电平值,而不是用预设的固定值。

黑电平校准的数学表达很简单:

// 伪代码示例
uint16_t black_level = get_optical_black_average();
for (each pixel in RAW frame) {
    pixel = (pixel > black_level) ? (pixel - black_level) : 0;
}

注意:减完黑电平后可能会出现负值,一定要做截断到0。否则后续的线性化、增益处理会把负值放大,产生奇怪的伪影。

1.3 线性化——把传感器的“脾气”摸清楚

理想情况下,传感器输出的数字码值应该和入射光强成正比。但现实是,很多传感器(尤其是高增益或低端传感器)的输出并不是线性的。

线性化的目的:把非线性的传感器响应曲线,映射成一条直线。

为什么要做线性化?因为后续的降噪、HDR合成、颜色校正等算法,都假设输入数据是线性的。如果输入是非线性的,这些算法会出各种奇怪的问题。

线性化的典型做法:

  • 查表法(LUT):预先在实验室标定出传感器在不同光照下的响应曲线,生成一个映射表。运行时直接查表转换。
  • 分段线性拟合:把响应曲线分成若干段,每段用一条直线近似。适合资源受限的嵌入式平台。

高通平台通常使用LUT方式,在ISP的BPS(Bayer Processing Segment)模块中完成线性化。

方法 精度 资源消耗 适用场景
查表法(LUT) 高 较高(需要存储256/1024个entry) 高端平台、对画质要求高的场景
分段线性拟合 中等 低(只需存储几个断点和斜率) 低端平台、实时性要求高的场景
多项式拟合 中等 中等 需要连续曲线、可接受一定误差

我曾经踩过一个坑:某款传感器在低照度下响应曲线严重非线性,但模组厂给的线性化LUT只覆盖了正常光照范围。结果夜景模式下,暗部细节全部被压缩,降噪后出现明显的色块。后来我重新标定了全光照范围的LUT才解决。

1.4 LSC镜头阴影校正——把“暗角”抹平

镜头阴影(Lens Shading),俗称暗角。因为镜头的光学特性,边缘区域接收到的光强比中心区域少,导致画面四周偏暗。

LSC(Lens Shading Correction)就是通过增益补偿,把边缘像素的亮度提上来,让整个画面亮度均匀。

高通平台上的LSC实现方式:

  • 网格增益表(Mesh Gain Table):把图像分成M×N个网格,每个网格存储一个增益值。运行时通过双线性插值计算出每个像素的增益。
  • 增益值通常用Qx格式的定点数表示,比如Q4.8格式,表示4位整数+8位小数。

LSC校准的典型流程:

  1. 拍摄一张均匀光照下的灰卡(或白墙)
  2. 计算每个像素相对于中心区域的亮度衰减比例
  3. 生成增益网格表,使得边缘像素的增益大于中心
  4. 将增益表烧录到模组的OTP(一次性可编程存储器)中

重要提醒:LSC增益不能太大。如果边缘增益超过2.0(即6dB),说明镜头本身的光学素质太差,强行补偿会放大噪声和颜色偏差。我一般建议增益上限控制在1.5~1.8之间。

下面这张图展示了RAW图从传感器输出到完成LSC校正的完整流程:

RAW图预处理流程 RAW图预处理流程(Bayer → 黑电平 → 线性化 → LSC) 传感器原始输出 Bayer阵列排布 黑电平校正 线性化 LSC镜头阴影校正 预处理后RAW图 说明:高通ISP中,黑电平校正和线性化通常在BPS模块完成,LSC在IFE模块完成。 各模块之间通过DDR或内部总线传递RAW图数据。

1.5 四个步骤的依赖关系

这四个步骤的顺序不能乱。我见过有人把LSC放在黑电平前面做,结果边缘增益把黑电平偏移也放大了,暗部噪声爆炸。

正确的顺序是:

  1. Bayer阵列解析——先搞清楚每个像素是什么颜色
  2. 黑电平校正——把零位校准
  3. 线性化——把响应曲线拉直
  4. LSC校正——最后做亮度均匀性补偿

小技巧:在高通平台的tuning工具中,你可以分别开关每个模块来观察效果。我调试时习惯先关掉所有模块,从黑电平开始逐个打开,确保每一步的效果都是正确的。