3、白平衡算法原理:灰度世界假设、完美反射假设、色温估计与增益计算

白平衡算法,说白了就是让相机在不同光源下都能把白色拍成白色。你想想看,在暖色灯光下拍的白纸,如果不做处理,照片会偏黄。算法要做的,就是把这个偏色拉回来。

我刚开始调ISP的时候,觉得白平衡不就是乘几个增益嘛,简单。后来踩了坑才发现,这里面的门道深着呢。今天咱们就把三个核心假设掰开揉碎了讲。

3.1 灰度世界假设

这个假设很直观:一张色彩丰富的自然图像,所有像素的RGB平均值应该趋于灰色。也就是说,R、G、B三个通道的均值应该相等。

公式很简单:

R_avg = G_avg = B_avg

如果实际图像中R_avg偏大,说明图像偏红,那就需要降低R通道的增益。具体计算:

Gain_R = G_avg / R_avg
Gain_G = 1.0
Gain_B = G_avg / B_avg

这里我习惯把G通道作为参考,因为人眼对绿色最敏感。当然你也可以用三个通道的平均值做参考,效果差不多。

实战经验: 灰度世界假设在色彩丰富的场景下效果很好。但如果你拍的是大片蓝天或者一整面红墙,这个假设就失效了。我曾在拍日落时吃过这个亏,整张图被拉成了灰蒙蒙的。

3.2 完美反射假设

这个假设认为:图像中最亮的那个点,应该是纯白色的。换句话说,场景中总有一个物体能完美反射光源的颜色。

算法步骤:

  1. 找到图像中最亮的像素点(通常是R+G+B最大的那个)
  2. 把这个点的RGB值作为参考白点
  3. 计算各通道增益,使这个点变成纯白

代码实现:

// 找到最亮像素
max_val = 0
for each pixel (r, g, b):
    sum = r + g + b
    if sum > max_val:
        max_val = sum
        ref_r = r
        ref_g = g
        ref_b = b

// 计算增益
Gain_R = 255 / ref_r
Gain_G = 255 / ref_g
Gain_B = 255 / ref_b
注意: 如果场景中有高光过曝的区域,这个假设会出问题。过曝像素的RGB值都接近255,会被误判为白点。我曾经在调试车载摄像头时遇到过这个问题——车灯过曝区域把整个画面的白平衡带偏了。

3.3 两种假设的对比

特性 灰度世界假设 完美反射假设
适用场景 色彩丰富的自然场景 有高光反射的场景
失效场景 单色场景(蓝天、红墙) 过曝、无高光场景
计算复杂度 低(只需统计均值) 中(需要找最亮点)
鲁棒性 对噪声敏感 对过曝敏感

实际工程中,我很少只用一种假设。通常会把两者结合起来,根据场景自适应切换。比如室内灯光下偏重灰度世界,室外阳光下偏重完美反射。

3.4 色温估计

色温估计是白平衡的核心。说白了,就是判断当前光源是偏暖(低色温)还是偏冷(高色温)。

常用的方法是通过R/G和B/G的比值来估算:

ratio_rg = R_avg / G_avg
ratio_bg = B_avg / G_avg

这两个比值可以映射到色温曲线上。比如:

  • 低色温(~3000K):ratio_rg > 1.2,ratio_bg < 0.8
  • 标准色温(~5500K):ratio_rg ≈ 1.0,ratio_bg ≈ 1.0
  • 高色温(~7000K):ratio_rg < 0.8,ratio_bg > 1.2
关键点: 色温估计的精度直接影响最终白平衡效果。我建议在调试时先标定好传感器的色温响应曲线,而不是用通用参数。每个传感器的RGB滤镜响应都不一样。

3.5 增益计算与限制

有了色温估计,增益计算就水到渠成了。但这里有个坑——增益不能无限大。

我一般会设置增益上限:

Gain_R = clamp(Gain_R, 0.5, 2.0)
Gain_G = 1.0
Gain_B = clamp(Gain_B, 0.5, 2.0)

为什么?因为增益太大会放大噪声。我曾经在低光环境下把B通道增益拉到3.0,结果蓝色通道的噪声全出来了,图像花得没法看。

另外,增益计算后还要考虑色温连续性。如果相邻两帧的色温跳变太大,画面会闪烁。我习惯加一个低通滤波器:

Gain_R_smooth = alpha * Gain_R_current + (1 - alpha) * Gain_R_previous

alpha一般取0.3~0.5,既能快速响应光源变化,又不会让画面抖动。

3.6 算法流程总览

下面这张图把整个白平衡算法的流程串起来了:

白平衡算法核心流程 原始RAW图像 统计R/G/B均值 计算R_avg, G_avg, B_avg 色温估计 计算R/G和B/G比值 增益计算 Gain_R = G_avg / R_avg 白平衡校正后图像 输入要求 • 线性RAW数据 • 未做Gamma校正 • 无过曝/欠曝区域 输出限制 • 增益范围[0.5, 2.0] • 帧间平滑滤波 • 防止色温跳变

3.7 实战中的取舍

说了这么多理论,最后聊点实际的。在白平衡调试中,我总结了几条经验:

  • 不要迷信单一假设:灰度世界和完美反射各有优劣,最好做加权融合。我常用的权重是0.6:0.4。
  • 注意场景切换:从室内到室外,色温可能从3000K跳到6000K。这时候增益平滑系数要动态调整,否则画面会卡顿。
  • 保留一点偏色:有时候完全校正到中性白反而不好看。比如拍夕阳,稍微保留一点暖色调更有氛围。我一般会加一个色温偏移量,让用户自己调节。
避坑指南: 我曾经在调试一款手机摄像头时,发现白平衡在荧光灯下总是偏绿。查了很久才发现,是荧光灯的频闪导致统计值不准。后来加了多帧平均才解决。所以,白平衡调试不能只看算法,还要考虑硬件和环境的干扰。