数学模型:Lens Shading 的增益模型与多项式拟合原理

镜头阴影校正,说白了就是给图像四角「补光」。但怎么补?补多少?这背后得有一套数学模型撑着。我早年刚接触 ISP 时,以为直接乘个固定系数就行,结果校正出来的图像中间亮、四周暗,或者出现一圈圈的光晕——嗯,那画面简直没法看。

后来我才明白,镜头阴影的衰减规律是有数学描述的。你只要找到这个规律,就能精确地算出每个像素该补多少。这一章,我们就来拆解这个数学模型。

镜头阴影的物理本质

先想一个问题:为什么镜头边缘进光少?

原因有两个:

  • 余弦四次方定律:光线从镜头中心到边缘,入射角度变大,传感器接收到的光强按 cos⁴θ 衰减。θ 是光线与光轴的夹角。
  • 机械遮挡:镜头镜筒、滤镜支架等结构,会遮挡一部分边缘光线,尤其是大光圈时更明显。

这两个因素叠加,就形成了我们看到的亮度从中心到边缘逐渐下降的「阴影」。

关键结论:镜头阴影的衰减曲线,在径向方向上近似一个平滑的、中心对称的曲面。这个曲面可以用多项式来拟合。

增益模型:从衰减到补偿

校正的思路很简单:

  1. 测量出每个像素位置的衰减系数。
  2. 计算一个增益值,让衰减后的像素恢复到目标亮度。
  3. 把这个增益值乘到原始像素上。

用公式表达就是:

I_corrected(x, y) = I_raw(x, y) × G(x, y)

其中 G(x, y) 就是我们要找的增益。它和衰减系数是倒数关系:

G(x, y) = 1 / attenuation(x, y)

衰减系数怎么来?靠标定。你拍一张均匀亮度的灰卡,然后看每个像素的亮度值。中心最亮,边缘最暗。中心亮度除以边缘亮度,就是该位置的衰减系数。

我的经验:标定时千万别用纯白纸。我踩过这个坑——白纸的纹理和反光不均匀,标定出来的增益曲线全是毛刺。后来改用专业积分球或均匀光源,数据才干净。

多项式拟合:用数学描述衰减

直接存储每个像素的增益值?太浪费了。一个 1200 万像素的传感器,光增益表就要几十 MB。而且不同镜头、不同光圈、不同焦距,增益表都不一样。

所以,我们用多项式来拟合这个增益曲面。常用的模型有两种:

模型类型 公式形式 适用场景
径向多项式 G(r) = 1 + a₁r² + a₂r⁴ + a₃r⁶ 中心对称的镜头阴影
二维多项式 G(x,y) = 1 + b₁x² + b₂y² + b₃x²y² + ... 非对称或传感器倾斜的情况

其中 r 是像素到图像中心的归一化距离,范围 0~1。为什么只用偶次项?因为镜头阴影是中心对称的,奇次项会引入不对称,反而破坏校正效果。

我个人习惯用径向多项式,参数少、计算快。你看,只需要 3 个系数(a₁, a₂, a₃),就能描述整个增益曲面。存储成本从几十 MB 降到 12 个字节。

拟合过程:从数据到系数

拟合的步骤其实不复杂:

  1. 采集数据:拍一张均匀灰卡,提取每个像素的亮度值。
  2. 计算增益:中心亮度除以每个像素的亮度,得到增益样本。
  3. 建立方程:把每个像素的 r 值和增益值代入多项式,得到超定方程组。
  4. 求解系数:用最小二乘法求解多项式系数。

代码实现大概是这样的:

// 伪代码:径向多项式拟合
// 输入:像素坐标 (x, y),增益值 gain
// 输出:多项式系数 a1, a2, a3

for each pixel (x, y):
    r = sqrt(x*x + y*y) / max_radius
    // 构建矩阵 A 和向量 b
    A[i][0] = r*r      // r² 项
    A[i][1] = r*r*r*r  // r⁴ 项
    A[i][2] = r*r*r*r*r*r // r⁶ 项
    b[i] = gain - 1

// 最小二乘法求解 A * coeffs = b
coeffs = (A^T * A)^(-1) * A^T * b

注意:拟合时一定要剔除异常点。我曾经遇到过传感器上有灰尘,拟合出来的曲线在灰尘位置出现尖峰,校正后图像上多了一个亮斑。后来我加了中值滤波预处理,把异常点先抹掉。

多项式阶数的选择

阶数越高,拟合越精确,但计算量也越大。而且阶数过高会过拟合——把噪声也拟合进去了。

我一般这样选:

  • 2 阶(r² 项):简单镜头,或者对精度要求不高的场景。计算量最小。
  • 4 阶(r² + r⁴):大多数消费级镜头。我项目里 80% 的情况用这个。
  • 6 阶(r² + r⁴ + r⁶):广角镜头或高精度校正。注意防止过拟合。

你想想看,6 阶多项式在边缘区域的变化很剧烈,如果标定数据有噪声,拟合出来的曲线会「抖」得很厉害。所以,不是阶数越高越好。

增益模型的知识结构

下面这张图,把整个增益模型的逻辑串起来了:

镜头阴影增益模型知识结构 物理成因 余弦四次方定律 机械遮挡效应 数学模型 径向多项式 G(r) 二维多项式 G(x,y) 拟合算法 最小二乘法 异常点剔除 输出:多项式系数 (a₁, a₂, a₃) 应用:逐像素增益计算 + 校正 核心思路:物理衰减 → 数学拟合 → 系数存储 → 实时校正 存储成本从几十 MB 降到 12 字节,计算量仅需 3 次乘加

实际项目中的注意事项

讲完了理论,说几个我在项目中踩过的坑:

  • 归一化要统一:r 的计算必须用归一化距离,否则不同分辨率的传感器拟合出来的系数没法通用。我习惯把最长边的一半作为归一化因子。
  • 增益不能无限大:边缘增益太大,会放大噪声。我一般限制最大增益不超过 2.5 倍,超过的部分用边缘截断处理。
  • 不同通道分开拟合:R、G、B 三个通道的衰减曲线不一样。我曾经偷懒只拟合一个通道,结果校正后图像偏色严重。后来老老实实每个通道单独拟合。
  • 温度影响:镜头阴影会随温度漂移。我遇到过夏天标定的系数,冬天用就偏暗了。如果产品工作温度范围大,建议做温度补偿。

一个小技巧:拟合完成后,用肉眼检查一下增益曲面。画一个 3D 曲面图,看它是不是平滑的。如果有凸起或凹陷,说明标定数据有问题,或者阶数选错了。

好了,这一章的内容就到这里。增益模型是整个镜头阴影校正的核心,理解了它,后面的校正算法就水到渠成了。