镜头阴影校正与坏点校正调试实战 - 第3节

亮度阴影校正原理:增益补偿模型

亮度阴影,说白了就是镜头中心亮、四周暗的现象。你拿手机对着白墙拍一张,如果四角发暗,那就是典型的亮度阴影。我刚开始做ISP调试时,第一件事就是先看raw图的四角亮度——这个习惯一直保留到现在。

校正的原理其实很简单:给暗的区域多补点增益,亮的区域少补或不补。这就是增益补偿模型的核心思想。

增益补偿模型

假设镜头中心亮度为1.0,四角亮度只有0.6。那校正时,中心增益设为1.0,四角增益设为1/0.6 ≈ 1.667。这样乘上去,整张图就均匀了。

数学表达就是:

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

其中 Gain(x, y) 是每个像素位置的补偿系数。这个系数怎么来?靠标定。

关键点:增益不能无限大。我曾经遇到过一款模组,四角亮度只有中心的40%,算下来增益要2.5倍。结果校正后四角噪声爆炸,暗部全是彩噪。所以硬件设计时就要控制好镜头阴影深度,一般建议四角不低于中心的50%。

标定流程

标定增益系数,通常分三步:

  1. 拍灰卡:用均匀光源照射灰卡,拍一张raw图
  2. 计算增益:以图像中心为基准,计算每个像素位置的补偿系数
  3. 生成LUT:把增益系数存成查找表,供ISP运行时调用

嗯,这里要注意:灰卡必须均匀,光源不能有暗区。我见过有人用手机闪光灯当光源,结果校正出来反而更不均匀——因为光源本身就不均匀。

网格(Mesh)校正原理

如果每个像素都存一个增益值,那LUT会非常大。比如200万像素的图像,每个像素存一个16位增益,光LUT就要4MB。这在嵌入式系统里根本扛不住。

所以实际工程中,我们不会逐像素存增益,而是用网格的方式。

什么是网格?

把图像分成M×N个网格,每个网格顶点存一个增益值。比如17×13的网格,总共221个顶点。存储量从4MB降到442字节,差了将近一万倍。

我习惯用17×13的网格,水平17个点,垂直13个点。为什么是这个数?因为大部分sensor的分辨率是4:3或16:9,17×13刚好能覆盖,而且网格密度够用。

网格规格 顶点数 存储量(16bit) 适用场景
9×7 63 126字节 低端芯片,性能受限
17×13 221 442字节 主流方案,平衡性能与精度
33×25 825 1650字节 高精度需求,如医疗影像

个人经验:网格太疏会校正不干净,太密又浪费资源。17×13是我试过的最优解。如果你用的是广角镜头,建议加到33×25,因为广角边缘的亮度变化更剧烈。

插值算法:双线性与双三次

网格只存了顶点的增益值,那网格内部的像素怎么办?插值。说白了就是根据周围四个顶点的值,算出当前像素的增益。

双线性插值

这是最常用的方法。原理很简单:

  1. 找到当前像素所在的网格
  2. 取四个顶点的增益值
  3. 按距离做两次线性插值(先水平,再垂直)

数学公式长这样:

G(x, y) = (1-Δx)(1-Δy)·G00 + Δx(1-Δy)·G10 + (1-Δx)Δy·G01 + Δx·Δy·G11

其中Δx、Δy是像素在网格内的归一化坐标,范围0~1。

双线性插值的优点是计算量小,硬件实现简单。大部分ISP芯片都硬支持这个算法。缺点呢?增益曲线不够平滑,在网格边界处可能会有肉眼可见的跳变。

避坑指南:我曾经在一个项目里发现,用双线性插值校正后,图像上出现了规则的条纹。查了两天才发现,是网格顶点增益标定不准,加上插值算法放大了误差。后来我把网格从17×13改成33×25,问题就解决了。所以网格密度不够时,别急着怪插值算法。

双三次插值

双三次插值用4×4=16个顶点来计算,而不是双线性的2×2=4个。它用三次多项式拟合增益曲面,结果更平滑。

优点很明显:

  • 增益曲线连续且一阶导数连续
  • 网格边界处没有跳变
  • 校正效果更自然

缺点也很明显:

  • 计算量是双线性的4倍以上
  • 硬件实现复杂,很多芯片不支持
  • 对噪声更敏感

我个人建议:除非你的芯片算力足够,或者对画质要求极高(比如专业相机),否则用双线性就够了。双三次带来的提升,在普通场景下肉眼几乎看不出来。

两种算法对比

对比项 双线性插值 双三次插值
计算量 低(4次乘加) 高(16次乘加+多项式)
平滑度 C0连续 C1连续
硬件支持 几乎所有ISP 仅高端ISP
适用场景 手机、安防、车载 专业相机、医疗影像

知识结构图

下面这张图把亮度阴影校正的完整流程串起来了:

亮度阴影校正知识结构 亮度阴影校正 增益补偿模型 网格(Mesh)校正 插值算法 拍灰卡标定 计算增益系数 M×N网格划分 顶点增益存储 双线性插值 双三次插值 输出:校正后均匀图像 核心思路 标定 → 网格化 → 插值 → 逐像素补偿 用少量存储换取全图均匀,是工程与画质的平衡

从图上你能看到,整个流程就是:先标定出增益系数,然后用网格压缩存储,最后通过插值还原到每个像素。每一步都有取舍,没有银弹。

调试建议:如果你刚接手一个项目,先别急着调算法参数。第一步应该是确认镜头阴影的原始数据——拍一张raw图,用工具看四角亮度比。如果比0.5还低,先找硬件改镜头,别指望算法能搞定一切。