4. 镜头阴影(Shading)校正:LSC原理、高通LSC tuning流程、网格点与增益计算、常见阴影问题修复
镜头阴影,说白了就是拍出来的照片四角发暗、中间亮。你拿手机对着白墙拍一张,如果四角明显比中心暗,那就是 shading。这个问题在广角镜头、大光圈镜头上尤其明显。我入行那会儿,第一次调 shading 时觉得不就是加个增益嘛,结果调完发现四角是亮了,但噪点也跟着炸了……嗯,从那以后我再也不敢小看 LSC 了。
4.1 镜头阴影的成因与分类
镜头阴影分两种:亮度阴影(Luma Shading)和颜色阴影(Color Shading)。亮度阴影是四角亮度下降,颜色阴影是四角偏色——通常是偏绿或偏紫。
为什么会这样?
- 亮度阴影:镜头的光学设计导致边缘光线入射角大,传感器接收到的光量减少。说白了就是镜头边缘的“集光能力”不如中心。
- 颜色阴影:不同波长的光在镜头中的折射率不同,导致 R/G/B 通道的衰减曲线不一致。结果就是四角颜色偏移。
我在项目中遇到过一款手机,广角端拍蓝天,四角直接偏紫。一开始以为是 sensor 问题,后来查了镜头 spec 才发现是红外滤光片和镜头的匹配没做好。所以 shading 问题不全是 ISP 能解决的,有时候得找镜头厂一起看。
核心要点:LSC 校正的本质是对每个像素位置施加不同的增益,补偿镜头的光学衰减。但增益不能乱加,否则会放大噪声。
4.2 LSC 校正原理
LSC 校正的基本思路很简单:测出每个位置的衰减量,然后乘上对应的增益。但实际实现时,ISP 不可能为每个像素单独存一个增益值——那样存储量太大了。所以高通的做法是用网格点(Mesh Grid)来近似。
具体来说:
- 把图像分成 M×N 个网格,每个网格的交点就是一个网格点。
- 每个网格点存一个增益值(R、G、B 各一个)。
- 网格点之间的像素,用双线性插值算出增益。
你想想看,如果网格点太稀疏,插值出来的增益曲线就不平滑,容易出现“网格痕迹”。如果网格点太密,存储和计算开销又大。高通平台一般推荐 9×13 或 13×17 的网格,具体看 sensor 分辨率和镜头特性。
我的经验:网格点数量不是越多越好。我曾经试过 17×21 的网格,结果 tuning 数据量翻倍,但画质提升几乎看不出来。后来我一般从 9×13 开始,如果发现 shading 曲线有高频波动再加密。
4.3 高通 LSC Tuning 流程
高通的 LSC tuning 流程,我总结下来分四步。每一步都有坑,我一个个说。
4.3.1 采集原始数据
你需要拍一张均匀光源下的灰卡或白墙。注意:光源要均匀,灰卡要干净。我见过有人用办公室的白墙做参考,结果墙上有污渍,调出来的 shading 曲线全是假的。
- 光源:D65 或 D50,色温要稳定。
- 灰卡:18% 灰卡最好,白卡也行但容易过曝。
- 格式:RAW 格式,关闭所有 ISP 处理(包括 AWB、CCM、Gamma)。
4.3.2 计算增益矩阵
用采集到的 RAW 图,计算每个像素位置的衰减量。公式很简单:
gain(x, y) = target_value / pixel_value(x, y)
其中 target_value 是图像中心区域的像素均值。然后对 R、G、B 三个通道分别计算。
高通平台有专门的工具(比如 Qualcomm Chromatix)来做这件事。你只需要导入 RAW 图,工具会自动生成增益矩阵。但工具生成的增益不一定最优——我习惯在工具输出后再手动检查一下边缘区域的增益值,防止工具被噪声带偏。
4.3.3 网格点拟合
把计算出的增益矩阵,拟合到 M×N 的网格点上。拟合算法一般是最小二乘法,但要注意:
- 网格点要覆盖整个图像区域,包括边缘。
- 拟合后的增益曲线要平滑,不能有突变。
- 如果镜头有“鱼眼”效应,网格点分布可能需要非均匀。
避坑指南:我曾经在拟合时发现边缘网格点的增益值异常高(超过 4.0)。查了半天,发现是 RAW 图边缘区域过暗,信噪比太低,导致计算出的增益值不可靠。后来我改用多帧平均的 RAW 图,问题就解决了。
4.3.4 验证与微调
把生成的 LSC 参数烧进 ISP,然后拍实景验证。验证时要注意:
- 拍白墙看均匀性。
- 拍自然场景看颜色一致性。
- 拍低照度场景看噪声是否被放大。
如果发现四角偏色,可以单独调整 R 或 B 通道的增益曲线。我一般先调 G 通道(亮度),再调 R/B 通道(颜色)。
4.4 网格点与增益计算详解
网格点的计算,很多人以为就是简单的除法。其实没那么简单。高通平台里,网格点的增益值是以 Q8 格式存储的——说白了就是定点数,1 表示 1.0 倍增益,256 表示 2.0 倍增益。
举个例子:
// 假设中心区域像素均值为 200
// 边缘某个像素值为 150
// 那么该位置的增益为 200 / 150 = 1.333
// 在 Q8 格式下,存储值为 1.333 * 256 ≈ 341
网格点之间的插值,高通用的是双线性插值。公式如下:
G(x, y) = (1 - dx) * (1 - dy) * G00 + dx * (1 - dy) * G10 + (1 - dx) * dy * G01 + dx * dy * G11
其中 G00、G10、G01、G11 是四个相邻网格点的增益值,dx、dy 是像素到左上角网格点的归一化距离。
这里有个细节:网格点的坐标是整数,但像素坐标是浮点数。所以插值时需要把像素坐标映射到网格坐标系。高通平台里,这个映射关系由 mesh_rolloff_size 和 mesh_rolloff_offset 两个参数控制。
我的习惯:在 tuning 时,我会把网格点的增益值打印出来,画成 3D 曲面图。如果曲面有“尖刺”或“凹陷”,说明某个网格点的增益值异常,需要手动修正。
4.5 常见阴影问题修复
在实际项目中,我遇到过各种各样的 shading 问题。下面列几个典型的,以及我的修复思路。
| 问题现象 | 可能原因 | 修复方法 |
|---|---|---|
| 四角明显偏暗 | LSC 增益不足,或网格点太稀疏 | 增加网格点密度,重新拟合增益曲线 |
| 四角偏绿/偏紫 | R/B 通道的增益曲线不匹配 | 单独调整 R 或 B 通道的增益,使颜色恢复中性 |
| 图像出现网格痕迹 | 网格点太稀疏,或插值算法精度不够 | 加密网格点,或改用更高精度的插值算法 |
| 低照度下噪声明显 | LSC 增益过大,放大了噪声 | 降低增益上限,或配合去噪算法一起调 |
| 不同色温下 shading 不一致 | 镜头对不同色温的光衰减不同 | 在多个色温下分别采集数据,生成多组 LSC 参数 |
我印象最深的一次,是某款手机在低照度下拍夜景,四角全是噪点。查了半天,发现是 LSC 增益在边缘区域达到了 3.5 倍,把 sensor 的暗电流噪声也放大了。后来我限制了增益上限(不超过 2.5 倍),同时配合高通的多帧降噪,才把问题解决。
注意:LSC 不是万能的。如果镜头本身的 shading 超过 50%(即边缘亮度不到中心的一半),靠 LSC 硬拉会带来严重的噪声和颜色失真。这时候应该先找镜头厂优化镜头设计,而不是在 ISP 端硬扛。
4.6 LSC 调试的 SV G 流程图
下面这张图是我自己总结的 LSC tuning 流程,每次做新项目我都会照着走一遍。
4.7 小结
LSC 校正看起来简单,但要做好其实不容易。我个人的经验是:数据质量决定 tuning 质量。如果 RAW 图拍得不好,后面再怎么调也是白费。另外,LSC 不是孤立存在的,它和 AWB、CCM、去噪都有耦合关系。调 LSC 时,最好先把其他模块关掉,等 LSC 调好了再逐步打开其他模块。
嗯,这一章就到这里。记住:shading 问题不可怕,可怕的是不知道 shading 从哪里来。