3、RAW域预处理:黑电平校正、镜头阴影校正、坏点校正、增益与白平衡

各位同学,欢迎来到RAW域预处理这一章。说实话,这是整个ISP流水线里最“脏”最“累”的活,但也是最能体现功力的地方。你想想看,传感器拿到的原始数据,说白了就是一堆带着各种噪声和偏差的电压值。如果不把这些“底子”清理干净,后面做再多 fancy 的增强算法都是白搭。

我个人习惯把预处理比作“打地基”。地基没打好,楼盖得再高也得塌。今天我们就来聊聊这四个最关键的预处理步骤:黑电平校正、镜头阴影校正、坏点校正,还有增益与白平衡。

核心观点: RAW域预处理的目标只有一个——让传感器输出的原始数字信号,尽可能真实地反映场景中的物理光强分布。每一步校正都是在消除一个特定的“系统误差”。

3.1 黑电平校正(Black Level Correction)

先说说黑电平。什么是黑电平?说白了,就是传感器在全黑环境下(比如盖上镜头盖),理论上应该输出0,但实际上它会输出一个非零的数值。这个数值就是黑电平。

为什么会这样?因为传感器电路本身有暗电流,ADC也有一个偏置。我记得在项目中遇到过一款老式的CCD传感器,它的黑电平居然有64个DN(Digital Number)之多。如果不减掉这个偏移量,你拍出来的黑色物体就会发灰,暗部细节全被淹没了。

校正方法其实很简单:

  • 全局减固定值: 从每个像素值中减去一个全局的黑电平值。比如传感器标定黑电平为64,那就每个像素减64。
  • 行/列自适应: 有些传感器不同行或不同列的黑电平不一样。这时候需要逐行或逐列减去对应的黑电平值。
  • OB(Optical Black)像素法: 传感器边缘有一圈被遮挡的像素,它们永远接收不到光。直接用这些像素的平均值作为当前帧的黑电平。
我的经验: 千万别小看黑电平校正。有一次我在调试夜景模式,发现暗部总是偏紫。查了半天,原来是黑电平没校正好,导致暗部R通道和B通道的偏移量不一致。减掉正确的黑电平后,颜色一下就正了。

3.2 镜头阴影校正(Lens Shading Correction)

接下来是镜头阴影。你想想看,镜头是一个凸透镜,光线从中心到边缘的路径长度不一样,而且边缘的光线入射角更大,所以边缘的进光量天然就比中心少。这就导致了照片中心亮、边缘暗的现象,也就是“暗角”。

校正方法通常是这样的:

  1. 标定增益图: 在均匀光照下(比如对着一个均匀亮度的白板)拍一张RAW图。然后计算每个像素位置相对于中心亮度的增益系数。
  2. 存储增益矩阵: 把增益系数存成一个查找表(LUT),通常是一个二维数组。
  3. 逐像素乘增益: 对每个像素,根据它的坐标查表得到增益值,然后乘上去。

这里有个坑要注意——增益不能太大。我曾经在调试一个超广角镜头时,边缘的增益系数达到了4.0以上。结果边缘的噪声被放大了4倍,暗角是没了,但噪点惨不忍睹。所以实际工程中,我们通常会设置一个最大增益限制,比如2.0,剩下的暗角留给后面的算法去处理。

避坑指南: 镜头阴影校正的增益图一定要在多个色温下标定。因为不同波长的光在镜头中的折射率不同,导致R、G、B三个通道的阴影分布不一样。只用D65光源标定,到了白炽灯下颜色就会偏。

3.3 坏点校正(Bad Pixel Correction)

坏点,就是传感器上那些“不听话”的像素。它们要么永远亮着(亮点),要么永远暗着(暗点),要么响应不正常。每个传感器出厂时都会有一张坏点列表,但使用过程中还会产生新的坏点。

校正策略分两种:

类型 检测方法 校正方法
静态坏点 出厂标定,存储在OTP中 直接替换为相邻像素均值
动态坏点 实时检测:当前像素与邻域像素差异超过阈值 中值滤波或插值替换

动态坏点检测是我觉得最有意思的部分。算法逻辑大概是这样的:

// 伪代码:动态坏点检测
for each pixel (x, y):
    // 计算周围8邻域的均值
    mean = average(neighbors)
    // 计算当前像素与均值的差异
    diff = abs(pixel - mean)
    // 如果差异超过阈值,判定为坏点
    if diff > threshold:
        pixel = mean  // 替换为邻域均值

阈值怎么设?这就有讲究了。设得太小,会把正常的纹理细节当成坏点给抹掉;设得太大,坏点又检测不出来。我一般会根据传感器的噪声水平来动态调整阈值——噪声大的区域阈值放宽,噪声小的区域阈值收紧。

我的习惯: 在做坏点校正时,我会把R、G、B三个通道分开处理。因为不同通道的坏点特性不一样,B通道的坏点通常比R通道多。分开处理能更精准地保留细节。

3.4 增益与白平衡(Gain & White Balance)

最后一步是增益和白平衡。这两个东西经常放在一起做,因为它们的数学形式是一样的——都是对每个通道乘一个系数。

增益是用来调整整体亮度的。比如在暗光环境下,传感器信号太弱,我们就需要放大信号。但放大信号的同时也会放大噪声,所以增益不能乱用。

白平衡则是为了消除不同光源色温带来的颜色偏差。你想想看,在日光灯下拍的白纸,和在白炽灯下拍的白纸,颜色肯定不一样。白平衡的目的就是让白色在任何光源下都看起来是白色。

白平衡的数学表达很简单:

R_out = R_in * gain_R
G_out = G_in * gain_G
B_out = B_in * gain_B

其中gain_R、gain_G、gain_B就是白平衡增益。通常我们会固定G通道的增益为1.0,然后调整R和B的增益。比如在日光下,gain_R和gain_B可能都在1.0附近;在钨丝灯下,gain_R会变大(因为红光少),gain_B会变小(因为蓝光多)。

这里有一个关键点——增益的顺序。是先做白平衡还是先做增益?我个人建议先做白平衡,再做增益。因为白平衡调整的是颜色比例,增益调整的是整体亮度。先调颜色再调亮度,逻辑上更清晰,也更容易调试。

注意: 增益和白平衡的系数不能太大。如果某个通道的增益超过了4.0,说明当前场景的光照条件已经超出了传感器的设计范围。这时候强行提亮只会得到一张满是噪点的废片。该补光就补光,该换传感器就换传感器,别跟物理规律较劲。

3.5 预处理流程总览

好了,四个步骤都讲完了。我们来画一张图,把整个预处理流程串起来。

RAW域预处理流程图 RAW域预处理流程 传感器 RAW 数据 ① 黑电平校正 ② 镜头阴影校正 ③ 坏点校正 ④ 增益与白平衡 预处理后 RAW 数据 注意顺序 黑电平 → 镜头阴影 → 坏点 → 增益白平衡 顺序不可颠倒 关键参数 增益上限:≤4.0 白平衡:R/G/B独立 坏点阈值:动态调整

这张图把整个流程串起来了。你注意看,顺序是固定的——先做黑电平,再做镜头阴影,然后是坏点,最后才是增益和白平衡。为什么是这个顺序?因为每一步都在为下一步做准备。黑电平校正让数据归零,镜头阴影校正让亮度均匀,坏点校正去掉异常值,最后再做颜色和亮度的调整。顺序乱了,结果就会出问题。

好了,RAW域预处理的四个核心步骤就讲到这里。这些内容看起来简单,但每一个步骤都有很多工程细节。我在项目中踩过的坑,今天都分享给你们了。希望大家在实际工作中能少走一些弯路。