4. 镜头阴影校正(LSC):从物理成因到高通实战

镜头阴影校正,英文叫 Lens Shading Correction,简称 LSC。这是 RAW 域处理里非常基础、但又极其关键的一环。你想想看,一颗再好的镜头,物理上也不可能做到中心和边缘进光量完全一致。这个不一致,就是我们今天要解决的「阴影」问题。

我个人习惯把镜头阴影分成两类来理解:亮度阴影(Luma Shading)和颜色阴影(Color Shading)。前者是亮度不均匀,后者是颜色偏了。很多刚入行的工程师只关注亮度,忽略了颜色,结果图像边缘总是偏色,怎么调都调不好。嗯,这里我们先从根上把成因讲清楚。

4.1 阴影是怎么来的?

先说 Luma Shading。说白了,就是镜头的光学特性导致的。光线从镜头中心进入 sensor 和从边缘进入,光程不一样,入射角度也不一样。根据余弦四次方定律,边缘的照度会自然衰减。再加上镜头本身的渐晕效应,边缘亮度就更低了。

我在项目中遇到过一款广角镜头,中心到边缘的亮度差能达到 40% 以上。如果不做校正,拍出来的照片就像戴了个暗角滤镜,非常难看。

再说 Color Shading。这个稍微复杂一点。不同波长的光(红、绿、蓝)在镜头中的折射率不同,导致它们到达 sensor 不同像素位置时的光程差也不一样。结果就是:镜头中心和边缘的颜色响应不一致。通常表现为边缘偏绿或偏紫。

关键区别:
  • Luma Shading:亮度不均匀,整体变暗,中心亮边缘暗。
  • Color Shading:颜色偏移,边缘出现色偏,与亮度无关。

4.2 LSC 算法原理:网格增益校正

校正的思路其实很直接。既然阴影是空间位置相关的,那我们就针对每个像素位置,乘上一个对应的增益值,把衰减补回来。这就是网格增益校正(Grid Gain Correction)的核心思想。

为什么不直接给每个像素一个增益?因为 sensor 的像素动辄几千万,存一张全尺寸的增益表,内存吃不消。所以工程上采用网格法:把图像分成 M×N 个网格,每个网格顶点存一个增益值。中间像素的增益通过双线性插值算出来。

我建议你记住这个流程:

  1. 标定阶段:拍摄均匀光源(如积分球),计算每个网格点的理想增益。
  2. 存储阶段:将增益表写入 sensor 的 OTP 或系统参数文件。
  3. 运行阶段:ISP 硬件读取增益表,对 RAW 图逐像素插值并乘增益。
我的经验:网格密度很关键。网格太稀疏,校正后会出现块状伪影;网格太密,标定和存储成本都高。一般 16×16 或 32×32 是比较常见的折中方案。高通平台默认是 16×16。

下面是 LSC 校正的典型流程,我画了一张图帮你理解:

LSC 网格增益校正流程 输入 RAW 图 网格增益表 (16×16) 双线性插值 逐像素增益计算 输出校正 RAW 说明:网格增益表在标定时生成,存储在 sensor OTP 或系统参数中。 运行时 ISP 硬件自动完成插值和增益乘法,不占用 CPU。

4.3 高通平台 LSC 标定与参数加载

在高通平台上,LSC 的标定和参数加载有一套成熟的工具链。我做过几次完整的标定,这里把关键步骤和注意事项分享给你。

4.3.1 标定流程

标定的核心目标是生成准确的网格增益表。高通推荐使用积分球作为均匀光源,但实际产线上常用灯箱配合灰卡。我个人建议,如果条件允许,尽量用积分球,数据更干净。

步骤 操作 注意事项
1 搭建均匀光源环境 光源色温要覆盖目标场景(如 D65、A 光源)
2 拍摄多帧 RAW 图 取平均降噪,避免单帧噪声影响增益计算
3 计算每个网格点的增益 增益 = 中心亮度 / 当前网格亮度
4 生成增益表并写入 OTP 注意数据格式对齐高通要求
5 验证校正效果 拍摄均匀图,检查中心和边缘亮度差 < 2%
我曾经踩过的坑:标定时光源不均匀,导致增益表里包含了光源本身的亮度分布。结果校正后反而引入了新的阴影。所以标定前一定要确认光源均匀性,最好用均匀性 > 98% 的积分球。

4.3.2 参数加载与调试

在高通 ISP 的驱动层,LSC 参数通常通过 chromatix 库加载。你需要把标定好的增益表填入对应的 XML 或二进制文件中。我记得高通平台有一个专门的工具叫 LSC_Tuning_Tool,可以可视化查看增益分布。

下面是一个简化的参数加载示例,展示增益表在代码中的结构:

// 高通平台 LSC 增益表结构示例
typedef struct {
    uint16_t grid_width;    // 网格宽度,通常为 16
    uint16_t grid_height;   // 网格高度,通常为 16
    uint16_t gain_r[16][16]; // R 通道增益
    uint16_t gain_gr[16][16];// Gr 通道增益
    uint16_t gain_gb[16][16];// Gb 通道增益
    uint16_t gain_b[16][16]; // B 通道增益
} lsc_gain_table_t;

// 加载函数调用
lsc_gain_table_t *table = lsc_load_table("sensor_lsc.bin");
isp_set_lsc_gain(table);

这里要注意,高通平台对 R、Gr、Gb、B 四个通道是分别存储增益的。因为 Color Shading 的存在,不同通道的衰减曲线不一样。如果你只用一个增益表,颜色阴影就校正不了。

调试技巧:在调试阶段,我习惯先关掉 Color Shading 校正,只调 Luma Shading。等亮度均匀了,再单独调 Color Shading。这样问题定位更清晰,不会两个问题搅在一起。

4.4 实战中的常见问题

做 LSC 校正,有几个问题几乎每次都会遇到。我列出来,你以后碰到了可以快速排查。

  • 校正后出现网格状伪影:通常是网格密度不够,或者插值算法精度不足。试试增加网格数,或者检查插值系数是否溢出。
  • 边缘颜色校正过度:Color Shading 的增益不要给太猛。我曾经遇到过边缘增益超过 2.0 的情况,结果边缘噪声被放大,反而更难看。建议限制最大增益在 1.5 以内。
  • 不同色温下效果不一致:Color Shading 与光源色温强相关。建议至少标定 D65 和 A 光源两组参数,运行时根据 AWB 结果动态切换。