数学模型:Lens Shading 的增益模型与多项式拟合原理
镜头阴影校正,说白了就是给图像四角「补光」。但怎么补?补多少?这背后得有一套数学模型撑着。我早年刚接触 ISP 时,以为直接乘个固定系数就行,结果校正出来的图像中间亮、四周暗,或者出现一圈圈的光晕——嗯,那画面简直没法看。
后来我才明白,镜头阴影的衰减规律是有数学描述的。你只要找到这个规律,就能精确地算出每个像素该补多少。这一章,我们就来拆解这个数学模型。
镜头阴影的物理本质
先想一个问题:为什么镜头边缘进光少?
原因有两个:
- 余弦四次方定律:光线从镜头中心到边缘,入射角度变大,传感器接收到的光强按 cos⁴θ 衰减。θ 是光线与光轴的夹角。
- 机械遮挡:镜头镜筒、滤镜支架等结构,会遮挡一部分边缘光线,尤其是大光圈时更明显。
这两个因素叠加,就形成了我们看到的亮度从中心到边缘逐渐下降的「阴影」。
关键结论:镜头阴影的衰减曲线,在径向方向上近似一个平滑的、中心对称的曲面。这个曲面可以用多项式来拟合。
增益模型:从衰减到补偿
校正的思路很简单:
- 测量出每个像素位置的衰减系数。
- 计算一个增益值,让衰减后的像素恢复到目标亮度。
- 把这个增益值乘到原始像素上。
用公式表达就是:
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 个字节。
拟合过程:从数据到系数
拟合的步骤其实不复杂:
- 采集数据:拍一张均匀灰卡,提取每个像素的亮度值。
- 计算增益:中心亮度除以每个像素的亮度,得到增益样本。
- 建立方程:把每个像素的 r 值和增益值代入多项式,得到超定方程组。
- 求解系数:用最小二乘法求解多项式系数。
代码实现大概是这样的:
// 伪代码:径向多项式拟合
// 输入:像素坐标 (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 阶多项式在边缘区域的变化很剧烈,如果标定数据有噪声,拟合出来的曲线会「抖」得很厉害。所以,不是阶数越高越好。
增益模型的知识结构
下面这张图,把整个增益模型的逻辑串起来了:
实际项目中的注意事项
讲完了理论,说几个我在项目中踩过的坑:
- 归一化要统一:r 的计算必须用归一化距离,否则不同分辨率的传感器拟合出来的系数没法通用。我习惯把最长边的一半作为归一化因子。
- 增益不能无限大:边缘增益太大,会放大噪声。我一般限制最大增益不超过 2.5 倍,超过的部分用边缘截断处理。
- 不同通道分开拟合:R、G、B 三个通道的衰减曲线不一样。我曾经偷懒只拟合一个通道,结果校正后图像偏色严重。后来老老实实每个通道单独拟合。
- 温度影响:镜头阴影会随温度漂移。我遇到过夏天标定的系数,冬天用就偏暗了。如果产品工作温度范围大,建议做温度补偿。
一个小技巧:拟合完成后,用肉眼检查一下增益曲面。画一个 3D 曲面图,看它是不是平滑的。如果有凸起或凹陷,说明标定数据有问题,或者阶数选错了。
好了,这一章的内容就到这里。增益模型是整个镜头阴影校正的核心,理解了它,后面的校正算法就水到渠成了。