4. 镜头阴影校正(LSC):解决四角发暗问题
镜头阴影,说白了就是拍出来的照片四周比中间暗。你拿手机对着白墙拍一张,如果四角明显发灰,那就是阴影。这问题在广角镜头、大光圈镜头上尤其明显。我刚开始调ISP时,第一版样机拍出来的照片,四角暗得跟戴了墨镜似的——嗯,从那以后我就把LSC当成必调项了。
4.1 阴影是怎么来的?
镜头阴影主要分两种:
- 亮度阴影(Luma Shading):镜头边缘进光量天生比中心少,这是物理规律。说白了,光线斜着进入镜头,有效通光面积变小了。
- 色彩阴影(Color Shading):不同波长的光在镜头边缘折射角度不同,导致R/G/B通道衰减不一致。结果就是四角不光暗,还偏色。
我在项目中遇到过一款手机镜头,四角偏紫得厉害。一开始以为是传感器问题,后来一测,是红外滤光片和镜头的配合出了问题。色彩阴影比亮度阴影更难调,因为它跟波长、镀膜、CRA(主光线角)都有关。
4.2 基于网格的增益补偿:主流方案
现在主流做法是网格增益补偿。为什么不用全局公式?因为镜头阴影不是均匀的,它跟像素位置、镜头型号、光圈大小都有关系。你想想看,用一个固定公式去拟合所有情况,误差太大了。
网格补偿的思路很简单:
- 把图像分成M×N个网格(常见16×16或32×32)
- 在每个网格顶点存一个增益值
- 对网格内部的像素,用双线性插值算出增益
- 每个像素乘以对应的增益,完成校正
我个人习惯用32×32的网格。网格太粗(比如8×8),阴影补偿不平滑,会出现块状痕迹;网格太细(比如64×64),校准表太大,占用存储和带宽。32×32是个不错的平衡点。
// 伪代码:网格增益插值
float lsc_gain(int x, int y, float grid[GRID_H][GRID_W]) {
// 计算网格坐标
float gx = (float)x / IMG_W * (GRID_W - 1);
float gy = (float)y / IMG_H * (GRID_H - 1);
// 取四个顶点
int ix = (int)gx;
int iy = (int)gy;
float fx = gx - ix;
float fy = gy - iy;
// 双线性插值
float g00 = grid[iy][ix];
float g10 = grid[iy][ix+1];
float g01 = grid[iy+1][ix];
float g11 = grid[iy+1][ix+1];
float g0 = g00 + fx * (g10 - g00);
float g1 = g01 + fx * (g11 - g01);
return g0 + fy * (g1 - g0);
}
4.3 校准流程:从灰卡到增益表
增益表怎么来的?不是拍脑袋写的,是拍出来的。标准流程如下:
| 步骤 | 操作 | 注意事项 |
|---|---|---|
| 1 | 拍摄均匀灰卡(DNP或X-Rite) | 光照均匀度>98%,避免反光 |
| 2 | 采集RAW图像 | 关闭所有ISP模块,只取原始数据 |
| 3 | 计算每个网格的平均值 | 排除坏点和边缘像素 |
| 4 | 以中心网格为基准,计算增益 | 增益 = 中心值 / 当前值 |
| 5 | 平滑增益表 | 去除噪声,避免补偿过度 |
| 6 | 量化并写入ISP寄存器 | 注意位宽和精度 |
我曾经在实验室里折腾了一整天,发现校准出来的增益表怎么都不对。后来才发现,是灰卡没放平,有一点点倾斜。你想想看,灰卡倾斜5度,四角反射的光就不均匀了,校准出来的增益表自然不准。所以,校准环境比算法本身更重要。
4.4 色彩阴影的单独处理
亮度阴影好办,R/G/B三个通道用同一套增益就行。但色彩阴影不行——每个通道的衰减曲线不一样。我建议的做法是:
- G通道:作为亮度参考,单独生成增益表
- R和B通道:分别生成增益表,或者生成相对于G的比值表
比值表的好处是,亮度变化不影响色差。比如R/G比值在中心是1.0,在四角可能变成1.15,那就把四角的R通道增益调低,让比值回到1.0。这样,即使场景亮度变化,色彩阴影也能稳定校正。
4.5 实战中的坑
调LSC这么多年,踩过的坑不少。列几个典型的:
- 网格边界不连续:增益表在网格边界跳变,导致图像出现网格状条纹。解决办法是增加网格密度,或者用更高阶的插值(比如三次样条)。
- 过补偿:四角增益太大,把噪声也放大了。我建议设置增益上限,比如最大2.0倍。超过这个值,说明镜头阴影太严重,应该先优化镜头。
- 温度漂移:镜头阴影会随温度变化。我在一个项目中遇到过,手机发热后四角又暗了。后来加了温度补偿表,不同温度区间用不同的增益表。
- 变焦镜头:不同焦距下阴影曲线不同。需要为每个焦距段单独校准,或者用插值方式生成中间焦距的增益表。
4.6 知识结构图
下面这张图总结了LSC的核心流程和关键点:
4.7 性能与资源权衡
LSC在硬件实现时,有几个资源消耗点需要注意:
| 资源项 | 32×32网格 | 64×64网格 | 说明 |
|---|---|---|---|
| 增益表存储 | 3KB(单通道) | 12KB(单通道) | 三通道×3 |
| 插值计算 | 4次乘法+2次加法 | 4次乘法+2次加法 | 计算量相同 |
| 补偿精度 | 良好 | 优秀 | 64×64更平滑 |
| 校准工作量 | 低 | 高 | 网格越多,校准越耗时 |
我个人建议,移动端用32×32就够了。如果是高端相机或者安防监控,可以考虑64×64。但别忘了,网格越密,校准时的光照均匀度要求越高——你想想看,64×64网格意味着4096个点,每个点的光照偏差都要控制在1%以内,这可不是闹着玩的。