4、镜头阴影校正(LSC):从物理成因到工程实现

镜头阴影校正,英文叫 Lens Shading Correction,简称 LSC。说白了,就是解决照片四周变暗、偏色的问题。你拿手机拍一张纯白墙壁,如果发现中间亮、四角暗,那就是镜头阴影在作怪。

我最早接触这个模块是在做一款安防摄像头的时候。当时 ISP 调完,画面中心亮度正常,但四个角明显发暗,客户直接打回。嗯,从那以后,我再也不敢小看 LSC 了。

4.1 镜头阴影的成因

镜头阴影不是单一原因造成的。它主要来自两个物理效应:

  • 光晕衰减(Cos⁴ Law):镜头中心到边缘的光程不同,边缘光线入射角大,到达传感器的光强按 cos⁴θ 衰减。说白了,边缘收到的光就是少。
  • 微透镜效率下降:传感器每个像素上方都有微透镜,边缘像素的微透镜收集光线的效率比中心低。尤其是大光圈镜头,这个问题更明显。

这两个效应叠加,结果就是:中心亮、边缘暗,而且不同颜色通道的衰减程度还不一样——这就导致了边缘偏色。

关键指标:镜头阴影通常用中心与边缘的亮度比值来衡量。一般要求 < 10% 的亮度差异,高端方案要求 < 5%。

4.2 LSC 校正原理

校正思路其实很简单:给每个像素乘一个增益系数。中心区域增益接近 1.0,边缘区域增益大于 1.0,把暗的地方补亮。

但这里有个坑——你不能只做亮度校正。不同通道的衰减曲线不同,R、G、B 通道需要独立的增益。否则亮度是均匀了,颜色却偏了。

我见过一个项目,工程师只做了亮度 LSC,结果画面四周发绿。为什么?因为绿色通道的衰减比红色慢,统一增益把绿通道补过了。所以,LSC 必须是多通道独立的。

个人习惯:我一般先做亮度校正,再做颜色校正。分两步走,调试时更容易定位问题。

4.3 增益矩阵的生成

实际工程中,我们不会为每个像素单独存一个增益值。那样太费内存了。常用的做法是:生成一个稀疏的增益网格,然后插值得到每个像素的增益。

增益矩阵的生成流程如下:

  1. 采集均匀光源下的 RAW 图:拍一张纯灰卡或积分球图像。
  2. 分块统计均值:把图像分成 M×N 个网格,统计每个网格内各通道的像素均值。
  3. 计算增益系数:以中心网格为参考,每个网格的增益 = 中心均值 / 当前网格均值。
  4. 存储增益网格:将 M×N 个增益值存入 LUT(查找表)。
网格尺寸 内存占用(单通道) 精度 适用场景
8×8 64 个 float 低 低端摄像头、快速调试
16×16 256 个 float 中 主流手机、安防
32×32 1024 个 float 高 专业相机、医疗影像

网格尺寸的选择是个权衡。网格太粗,校正后会有块状伪影;网格太细,内存和计算量都上去了。我个人习惯从 16×16 起步,看效果再调整。

4.4 增益插值方法

有了稀疏的增益网格,接下来就是插值。常用的插值方法有三种:

  • 最近邻插值:直接取最近的网格增益。速度快,但会有明显的块状边界。
  • 双线性插值:用周围 4 个网格点做线性加权。效果好,计算量适中,是工程中最常用的。
  • 双三次插值:用周围 16 个点做三次曲线拟合。平滑度最好,但计算量大,一般用在高端方案。

避坑指南:我曾经在 8×8 网格上用双线性插值,结果画面边缘出现明显的阶梯状亮度变化。后来换成 16×16 网格,问题就解决了。网格密度不够,再好的插值也救不了。

下面是一个双线性插值的简化实现:

// 双线性插值计算像素增益
float interpolate_gain(float x, float y, float* grid, int grid_w, int grid_h) {
    int ix = (int)x;
    int iy = (int)y;
    float fx = x - ix;
    float fy = y - iy;
    
    float g00 = grid[iy * grid_w + ix];
    float g10 = grid[iy * grid_w + ix + 1];
    float g01 = grid[(iy + 1) * grid_w + ix];
    float g11 = grid[(iy + 1) * grid_w + ix + 1];
    
    float g0 = g00 * (1 - fx) + g10 * fx;
    float g1 = g01 * (1 - fx) + g11 * fx;
    
    return g0 * (1 - fy) + g1 * fy;
}

4.5 LSC 校正流程总览

我把整个 LSC 校正的流程画成了一张图,方便你理解各模块的关系:

LSC 校正流程总览 RAW 图像输入 分块统计均值 计算增益系数 存储增益网格 插值 + 像素校正 注意事项 • 各通道独立计算增益 • 网格尺寸 16×16 起步 • 双线性插值最常用 常见问题 • 网格太粗 → 块状伪影 • 通道不独立 → 边缘偏色

4.6 工程实现中的几个关键点

理论讲完了,聊聊实际干活时要注意的事。

第一,增益上限要钳位。边缘增益不能无限大,否则会放大噪声。我一般把增益上限设在 2.0~3.0 之间,具体看 sensor 的噪声水平。

第二,温度漂移要补偿。镜头阴影会随温度变化,尤其是塑料镜头。高端方案会做温度查表,低端方案至少要在产线做多温度标定。

第三,不同色温要分开标定。D65 和 A 光源下的阴影曲线不一样。我见过一个项目只标了 D65,结果在室内暖光下边缘偏红。后来加了多色温 LUT,问题才解决。

总结一下:LSC 校正的核心就三件事——分块统计、独立通道、合理插值。网格尺寸选 16×16,插值用双线性,增益上限钳位,多色温标定。做到这几点,镜头阴影基本就能压到 5% 以内。