3. 镜头阴影校正(LSC)调优

镜头阴影校正,简称 LSC。说白了,就是解决画面四周偏暗、偏色的问题。你想想看,镜头本身是个物理器件,光线从中心到边缘的路径不一样,衰减自然也不同。8K 传感器像素又密,这个问题会被放大得很明显。

我刚开始接触 ISP 时,觉得 LSC 不就是乘个增益嘛,有什么难的?后来在 8K 项目上被均匀性指标卡了整整两周……嗯,从那以后我再也不敢小看 LSC 了。

3.1 LSC 原理:为什么会有阴影?

镜头阴影主要分两类:

  • 亮度阴影(Luma Shading):边缘亮度比中心低,原因是余弦四次方定律和镜头物理遮挡。
  • 颜色阴影(Color Shading):边缘出现偏色,因为不同波长(R/G/B)的光在镜头不同位置的透过率不一致。

8K 传感器对角线更长,边缘光线入射角更大,阴影效应比 1080P 严重得多。我测过一颗 8K 模组,中心到角落的亮度差能到 40% 以上——不校正根本没法看。

核心公式(简化版):

校正后像素值 = 原始像素值 × 增益系数 (x, y)

增益系数由 LUT(查找表)提供,每个像素位置对应一个值。

3.2 LUT 生成方法:从标定到查表

LUT 怎么来的?不是拍脑袋写的。标准流程分三步:

  1. 采集均匀光源图像:用积分球或均匀面光源,拍一张 RAW 图。
  2. 计算增益矩阵:以图像中心为参考,计算每个像素需要的增益值。
  3. 压缩与存储:全分辨率增益矩阵太大(8K 下约 33M 个点),需要降采样成网格 LUT。

我个人习惯用 17×13 或 33×25 的网格。网格越密,校正精度越高,但存储和计算开销也越大。8K 实时处理时,我建议用 33×25,配合双线性插值,效果和全分辨率几乎没区别。

实战技巧:标定时一定要用 RAW 图,不要用已经做过任何处理的图像。我曾经因为用了带 AWB 的图做 LSC 标定,结果颜色阴影越校越偏……

3.3 LSC 对均匀性的影响

LSC 做得好不好,直接决定画面均匀性指标。我一般用两个指标衡量:

指标 定义 8K 目标值
亮度均匀性 四角亮度 / 中心亮度 ≥ 95%
颜色均匀性 四角 ΔE 相对于中心 ≤ 3

如果 LSC 参数不对,会出现:

  • 过校正:边缘出现亮环或偏色反转
  • 欠校正:阴影残留,四角依然偏暗
  • 网格效应:LUT 网格太粗,插值后出现可见的块状过渡

我记得有一次,客户反馈画面边缘有淡淡的粉色条纹。查了半天,发现是 LUT 网格在 Bayer 格式下对齐出了问题——R 通道和 B 通道的增益插值相位错了。

3.4 LSC 调优实战

调优 LSC,我有一套固定的流程:

  1. 粗调:用标准光源标定生成初始 LUT,验证均匀性是否在 90% 以上。
  2. 精调:针对不同色温(D65、D50、A 光源)分别微调,因为镜头阴影会随光谱变化。
  3. 边界检查:在极端场景(强逆光、低照度)下验证,防止 LSC 放大噪声。
  4. 硬件适配:确认 LUT 格式与 ISP 硬件匹配,包括位宽、网格坐标、插值方式。

避坑指南:我曾经在 8K 60fps 项目上,因为 LUT 加载时机不对,导致每帧切换场景时出现一帧未校正的原始图——画面闪了一下。后来加了双缓冲机制才解决。

下面是我常用的 LUT 生成代码片段(Python 示意):

import numpy as np

def generate_lsc_lut(raw_img, grid_size=(33, 25)):
    h, w = raw_img.shape[:2]
    center_val = np.mean(raw_img[h//2-10:h//2+10, w//2-10:w//2+10])
    
    # 计算每个网格点的增益
    grid_h = np.linspace(0, h-1, grid_size[1])
    grid_w = np.linspace(0, w-1, grid_size[0])
    
    lut = np.zeros(grid_size)
    for i, row in enumerate(grid_h):
        for j, col in enumerate(grid_w):
            local_val = np.mean(raw_img[int(row)-2:int(row)+2, 
                                        int(col)-2:int(col)+2])
            lut[i, j] = center_val / max(local_val, 1)
    
    # 限制增益范围,防止过校正
    lut = np.clip(lut, 0.8, 2.0)
    return lut

这段代码的核心是:用中心区域亮度做参考,计算每个网格点的增益。注意我加了 clip 限制——增益不能无限大,否则噪声会被放大到不可接受。

3.5 LSC 调优知识体系

我把 LSC 调优的核心逻辑画成了一张图,方便你理解整体流程:

LSC 调优知识体系 RAW 图像输入 均匀光源标定 → 计算增益矩阵 降采样 → 网格 LUT 生成 粗调:均匀性 ≥ 90% 精调:多色温微调 边界检查:噪声/过校正 最终 LUT → 硬件部署 注意:每个阶段都需要验证均匀性指标,否则返工成本很高

这张图把 LSC 调优分成了四个阶段:标定、LUT 生成、粗调/精调/边界检查、最终部署。每个阶段都有明确的输入输出,你照着这个流程走,基本不会漏掉关键步骤。

个人经验:8K 传感器因为像素尺寸小,对 LSC 精度要求更高。我建议在精调阶段,至少用 3 个色温点做标定,然后线性插值生成中间色温的 LUT。这样能保证不同光照下的均匀性一致性。