光学基础:镜头的光学特性、渐晕效应与色彩偏移原理

做图像处理这些年,我越来越觉得:不懂光学,ISP 调得再好也是空中楼阁。你想想看,传感器前面那个镜头,才是决定图像质量的第一个关卡。今天我们就来聊聊镜头的光学特性,以及它带来的两个经典问题——渐晕和色彩偏移。

镜头的光学特性

镜头不是完美的。它由多组透镜组成,目的是把光线汇聚到传感器上。但在这个过程中,有几个物理限制是绕不开的。

1. 光圈与进光量

光圈控制进光量,这个大家都懂。但有个细节:光圈越大(F 值越小),边缘光线入射角度越大,渐晕和色彩偏移就越明显。我在项目中遇到过一款手机镜头,F1.6 大光圈,拍出来的照片四角发暗、偏紫,后来不得不把光圈缩到 F2.0 才勉强压住。

2. 焦距与视场角

焦距越短,视场角越大,边缘光线入射角也越大。广角镜头是渐晕和色彩偏移的重灾区。超广角镜头(比如 12mm 等效焦距)的边缘入射角能到 30° 以上,这时候传感器上的微透镜都开始「吃不到」光线了。

3. 镜头镀膜与透过率

不同波长的光在镜头镀膜上的透过率不一样。一般来说,蓝光透过率最低,红光最高。这就导致了色彩偏移——镜头中心到边缘,色温会发生变化。

核心结论: 镜头的光学特性决定了图像的非均匀性。渐晕是亮度不均匀,色彩偏移是颜色不均匀。两者往往同时出现,互相纠缠。

渐晕效应(Vignetting)

说白了,渐晕就是照片四角比中心暗。原因很简单:边缘光线走的路更长,被镜头遮挡了一部分。

渐晕的三种类型

类型 成因 特点
光学渐晕 镜头镜筒遮挡边缘光线 与光圈大小相关,大光圈更明显
自然渐晕 余弦四次方定律 与入射角相关,广角镜头更严重
像素渐晕 传感器微透镜效率下降 与像素位置相关,边缘像素更暗

我刚开始做 ISP 时,以为渐晕只是亮度问题,用个简单的增益补偿就行。后来发现,渐晕还伴随着色彩偏移——四角不仅暗,还偏色。这时候只做亮度补偿是不够的。

渐晕的数学模型

理想情况下,渐晕可以用一个径向衰减函数来描述:

# 渐晕补偿模型
def vignetting_correction(image, center, coefficients):
    """
    image: 输入图像
    center: 光轴中心坐标 (cx, cy)
    coefficients: 多项式系数 [a0, a1, a2, ...]
    """
    h, w = image.shape[:2]
    cx, cy = center
    result = image.copy()
    
    for y in range(h):
        for x in range(w):
            # 计算径向距离
            r = np.sqrt((x - cx)**2 + (y - cy)**2)
            # 计算增益
            gain = 1.0
            for i, coeff in enumerate(coefficients):
                gain += coeff * (r ** (i+1))
            # 应用增益
            result[y, x] = np.clip(image[y, x] * gain, 0, 255)
    
    return result

这个模型虽然简单,但实际项目中够用了。我一般用 4 阶多项式,系数通过标定板拟合得到。

实战技巧: 标定渐晕时,记得用均匀光照的灰卡。我踩过坑——用白墙标定,结果白墙本身就不均匀,补偿后反而更糟。

色彩偏移原理

色彩偏移,也叫 Color Shading。它和渐晕是「孪生兄弟」。渐晕是亮度问题,色彩偏移是颜色问题。两者都源于镜头的光学特性。

为什么会有色彩偏移?

原因有两个:

  1. 镜头镀膜的波长依赖性: 不同波长的光在镜头中的折射率不同。蓝光折射率大,红光折射率小。边缘光线经过更多透镜,蓝光被「甩」得更远。
  2. 传感器微透镜的入射角敏感性: 微透镜对不同角度入射光的收集效率不同。大角度入射时,蓝光通道的收集效率下降最快。

我记得有一次,客户反馈某款手机拍出来的照片,四角偏紫红色。我一看就知道是色彩偏移。中心色温 5000K,四角色温能偏到 4500K 以下。这就是典型的「红蓝通道增益不匹配」。

色彩偏移的两种模式

模式 表现 成因
Luma Shading 四角偏暗,色温不变 主要是自然渐晕
Color Shading 四角色温偏移 镀膜 + 微透镜共同作用

实际项目中,两者往往混合出现。我习惯先做 Luma Shading 补偿,再做 Color Shading 补偿。顺序不能乱——先调亮度,再调颜色。

色彩偏移的补偿思路

补偿色彩偏移,本质上是对 R、G、B 三个通道分别做渐晕补偿,但补偿系数不同。比如:

# 色彩偏移补偿
def color_shading_correction(image, center, r_gain, b_gain):
    """
    r_gain, b_gain: 与位置相关的增益矩阵
    """
    # 分离通道
    r, g, b = cv2.split(image)
    
    # 分别补偿
    r_corrected = r * r_gain
    b_corrected = b * b_gain
    # G 通道通常不做补偿,或者做少量补偿
    
    # 合并
    result = cv2.merge([r_corrected, g, b_corrected])
    return result

这里有个坑:R 和 B 的增益矩阵不能独立标定。我试过分别标定,结果补偿后 G 通道反而偏了。后来改用联合标定——同时拍摄灰卡,同时拟合 R、G、B 三个通道的增益。

注意: 色彩偏移补偿不能过度。补偿太多会引入噪声,尤其是暗角区域的蓝色通道。我一般限制最大增益不超过 2.0。

知识结构总览

下面这张图,是我自己总结的镜头阴影与色彩偏移的知识框架。每次做项目前,我都会对照着梳理一遍。

镜头阴影与色彩偏移知识结构 镜头阴影与色彩偏移知识结构 镜头光学特性 渐晕效应 色彩偏移 光学渐晕 自然渐晕 像素渐晕 Luma Shading Color Shading 镀膜影响 微透镜影响 补偿策略:先 Luma Shading,后 Color Shading 联合标定 R、G、B 三通道增益

实战中的避坑指南

做镜头阴影校正这些年,我踩过不少坑。挑几个典型的说说:

  • 标定板要均匀: 我曾经用一块不均匀的灰板标定,结果补偿后图像出现「环形伪影」。后来改用积分球光源,问题才解决。
  • 温度影响: 镜头镀膜对温度敏感。冬天和夏天的标定结果不一样。我建议在常温下标定,然后做温度补偿。
  • 不要过度补偿: 四角增益太大,噪声会被放大。我一般限制最大增益 1.5 倍,超过的部分用平滑过渡。
  • 注意镜头模组公差: 同一批镜头,每颗的光学特性都有差异。量产时最好每颗单独标定,或者至少抽检。
我的习惯: 每次拿到新镜头模组,先拍一张均匀灰卡,用 3D 曲面拟合出渐晕和色彩偏移的分布。然后把这个分布存成 LUT,运行时直接查表补偿。效率高,效果也稳定。

好了,光学基础就聊到这儿。记住一句话:镜头阴影和色彩偏移是物理限制,我们只能补偿,不能消除。理解了这个,后面的校正算法才能用得得心应手。