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 完美反射假设
这个假设认为:图像中最亮的那个点,应该是纯白色的。换句话说,场景中总有一个物体能完美反射光源的颜色。
算法步骤:
- 找到图像中最亮的像素点(通常是R+G+B最大的那个)
- 把这个点的RGB值作为参考白点
- 计算各通道增益,使这个点变成纯白
代码实现:
// 找到最亮像素
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
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
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 算法流程总览
下面这张图把整个白平衡算法的流程串起来了:
3.7 实战中的取舍
说了这么多理论,最后聊点实际的。在白平衡调试中,我总结了几条经验:
- 不要迷信单一假设:灰度世界和完美反射各有优劣,最好做加权融合。我常用的权重是0.6:0.4。
- 注意场景切换:从室内到室外,色温可能从3000K跳到6000K。这时候增益平滑系数要动态调整,否则画面会卡顿。
- 保留一点偏色:有时候完全校正到中性白反而不好看。比如拍夕阳,稍微保留一点暖色调更有氛围。我一般会加一个色温偏移量,让用户自己调节。