4、镜头阴影校正:LSC原理、增益矩阵、AI自适应校正
镜头阴影校正,英文叫 Lens Shading Correction,简称 LSC。说白了,就是解决照片四周发暗、发偏色的问题。你拿手机拍一张纯色的白墙,如果发现中间亮、四周暗,或者中间白、四周发绿发红,那就是镜头阴影在作怪。
我刚开始做 ISP 的时候,觉得这玩意儿不就是乘个系数嘛,有啥难的?后来真上手调了才发现,坑多着呢。不同镜头、不同光圈、不同焦距,阴影表现完全不一样。今天咱们就把这块彻底讲透。
4.1 镜头阴影是怎么产生的?
镜头阴影主要分两种:亮度阴影和颜色阴影。
- 亮度阴影(Luma Shading):也叫 vignetting。光线从镜头中心进入和从边缘进入,路径长度不一样,边缘的光线衰减更严重。再加上镜头本身的机械遮挡,边缘亮度自然就低了。
- 颜色阴影(Color Shading):这个更麻烦。不同波长的光(红绿蓝)通过镜头时,折射角度不同,导致 sensor 不同位置对颜色的响应不一致。结果就是,边缘区域偏色了。
我记得有一次调试一个广角镜头,拍出来的天空,中间是蓝的,四周居然发紫。一开始我还以为是 sensor 坏了,后来一查,就是颜色阴影没校正好。
核心结论:镜头阴影是光学系统的固有缺陷,不是 sensor 的问题。校正的目标就是补偿这种不均匀性。
4.2 LSC 的经典实现:增益矩阵
最传统的做法,就是给每个像素乘一个增益系数。但这个系数不是随便给的,得根据像素在图像中的位置来查表。
具体流程是这样的:
- 采集参考图:用均匀光源拍一张灰卡或白墙,得到一张 raw 图。
- 计算增益:以图像中心为基准,计算每个像素位置需要的补偿增益。
- 生成增益矩阵:通常是一个二维网格,比如 16x16 或者 32x32 的网格,每个网格点存一个增益值。
- 插值应用:实际运行时,对不在网格点上的像素,用双线性插值算出它的增益,然后乘上去。
代码实现大概长这样:
// 假设 gain_grid 是 16x16 的增益矩阵,img_w, img_h 是图像尺寸
// 对每个像素 (x, y) 计算增益
float grid_step_x = img_w / 16.0f;
float grid_step_y = img_h / 16.0f;
int gx = (int)(x / grid_step_x);
int gy = (int)(y / grid_step_y);
float fx = (x - gx * grid_step_x) / grid_step_x;
float fy = (y - gy * grid_step_y) / grid_step_y;
// 双线性插值
float gain = (1-fx)*(1-fy)*gain_grid[gy][gx]
+ fx*(1-fy)*gain_grid[gy][gx+1]
+ (1-fx)*fy*gain_grid[gy+1][gx]
+ fx*fy*gain_grid[gy+1][gx+1];
pixel_out = pixel_in * gain;
嗯,这里要注意:增益矩阵的精度很关键。我见过有人用 8bit 存增益,结果校正完出现明显的带状条纹。建议至少用 12bit 定点数或者 float16。
4.3 增益矩阵的标定流程
标定这一步,很多人觉得简单,其实最容易翻车。我分享一个我踩过的坑:
我曾经用普通的 LED 灯箱做标定光源,结果拍出来的参考图本身就有不均匀性。校正完反而把灯箱的不均匀性"补偿"进去了,照片出现奇怪的光斑。后来改用积分球才解决。
正确的标定流程应该是:
| 步骤 | 操作 | 注意事项 |
|---|---|---|
| 1 | 准备均匀光源(积分球或均匀面光源) | 光源均匀性 < 1%,色温稳定 |
| 2 | 拍摄多张 raw 图,取平均降噪 | 至少 16 张,消除随机噪声 |
| 3 | 计算每个像素的增益 | 增益 = 中心亮度 / 当前亮度 |
| 4 | 下采样生成增益网格 | 网格密度要匹配镜头阴影的平滑度 |
| 5 | 验证校正效果 | 用另一组光源拍摄验证,看均匀性 |
你想想看,如果光源本身就不均匀,那标定出来的增益矩阵就是错的。所以第一步的硬件条件,千万别省。
4.4 传统方法的局限性
增益矩阵方法虽然成熟,但有几个硬伤:
- 对焦依赖:镜头阴影会随着对焦距离变化。变焦镜头更麻烦,不同焦段阴影完全不同。
- 温度漂移:sensor 温度变化时,颜色阴影会漂移。我实测过,温度升高 10 度,边缘的红色增益需要调整 2%-3%。
- 个体差异:同一批镜头,每颗的阴影曲线都不一样。量产时如果共用一套参数,效果参差不齐。
说白了,传统方法是一个"静态"的校正方案。它假设镜头阴影是固定不变的,但现实世界不是这样。
4.5 AI 自适应校正:让算法学会"看情况"
那怎么解决动态变化的问题?我的思路是:让算法自己判断当前场景需要什么样的校正。
AI 自适应校正的核心思想是:不依赖预标定的增益矩阵,而是根据图像内容实时预测校正参数。
具体做法有两种主流方案:
- 参数预测网络:输入 raw 图的一些统计特征(比如各通道的亮度分布),输出一组增益网格参数。网络很小,几万参数就够了。
- 端到端校正网络:直接输入 raw 图,输出校正后的 raw 图。这个方案效果最好,但计算量也最大。
我个人更倾向于第一种方案。为什么呢?因为增益网格是 ISP 硬件直接支持的,你只需要替换网格参数,不需要改硬件流水线。部署起来方便很多。
小技巧:训练数据可以用不同镜头、不同温度、不同对焦距离下采集的 raw 图。我建议至少采集 5000 组数据,覆盖各种极端情况。数据不够的话,可以用仿真生成,但仿真和真实数据之间总有 gap,需要小心。
4.6 知识体系总览
下面这张图,把镜头阴影校正的完整知识结构画出来了。从问题根源到解决方案,再到 AI 进阶,一目了然。
4.7 落地时的一些经验
最后分享几个我在实际项目中踩过的坑和总结的经验:
- 增益不要太大:边缘增益超过 2.5 倍时,噪声会被严重放大。这时候要考虑是不是镜头本身太差了,该换镜头而不是硬调算法。
- 颜色阴影要分通道处理:R、G、B 三个通道的阴影曲线不一样,不能共用一套增益。我见过有人偷懒只做亮度校正,结果颜色偏得更厉害了。
- AI 模型要量化:ISP 通常跑在 DSP 或者 NPU 上,浮点模型跑不动。我建议训练时就用 QAT(量化感知训练),直接输出 int8 模型。
- 别忘了验证:校正完一定要用真实场景验证,别只看实验室数据。户外自然光、室内暖光灯、夜景,每种场景都要测。
一句话总结:镜头阴影校正,传统方法靠标定,AI 方法靠学习。但不管哪种方法,理解物理原理永远是第一步。没有光学基础,再牛的 AI 也救不了。