4. 白平衡(AWB):灰度世界法、完美反射法、色温估计、增益计算

白平衡这东西,说白了就是让白色物体在照片里看起来是白的。你想想看,人眼有很强的色彩恒常性,不管在钨丝灯下还是阴天,看白纸都是白的。但传感器没这个本事,它老老实实地记录光谱能量分布,结果就是——偏色。

我在项目里遇到过最头疼的一次,是某款手机在商场暖色灯光下拍人像,人脸直接变成了「黄脸婆」。用户投诉一大堆。后来查出来,就是 AWB 在混合光源场景下崩了。所以这一章,咱们把 AWB 的几板斧彻底讲透。

4.1 灰度世界法(Gray World)

这是最经典的假设:一幅色彩丰富的图像,其 R、G、B 三个通道的平均值应该趋于相等。换句话说,整个场景的「平均颜色」是灰色的。

算法步骤很简单:

  1. 计算全图 R、G、B 各自的均值:R_avg、G_avg、B_avg
  2. 计算灰色参考值:Gray = (R_avg + G_avg + B_avg) / 3
  3. 计算各通道增益:R_gain = Gray / R_avg,G_gain = Gray / G_avg,B_gain = Gray / B_avg
  4. 对每个像素应用增益:R_out = R_in * R_gain,以此类推

关键点:灰度世界法对场景内容非常敏感。如果画面里有一大片蓝色天空或绿色草地,均值就会严重偏离灰色,导致校正过度。

我曾经在一个户外监控项目里用过它。晴天效果还行,一到阴天或者黄昏,画面就偏得离谱。后来我加了一个「场景内容检测」——如果某个通道的方差明显偏小,说明该颜色占主导,就降低它的权重。嗯,算是打了个补丁。

4.2 完美反射法(Perfect Reflector / White Patch)

这个方法的思路是:图像中最亮的像素点,应该对应场景中的白色反射面。所以只要找到这些「最亮点」,用它们的颜色来估计光源色温。

具体做法:

  1. 遍历所有像素,计算每个像素的亮度(比如 Y = 0.299*R + 0.587*G + 0.114*B)
  2. 选出亮度最高的前 1%~5% 的像素
  3. 计算这些像素的 R、G、B 均值:R_max、G_max、B_max
  4. 增益计算:R_gain = 255 / R_max,G_gain = 255 / G_max,B_gain = 255 / B_max

注意:如果场景里根本没有白色物体(比如夜景、暗光环境),完美反射法会直接失效。它会错误地把噪点或高光溢出点当作白色参考,结果就是画面偏紫或偏绿。

我个人习惯把灰度世界法和完美反射法结合起来用。怎么结合?看场景。如果画面整体偏暗,我倾向于用完美反射法;如果画面色彩丰富且均匀,灰度世界法更稳。但大多数时候,我会取两者的加权平均——权重根据场景统计信息动态调整。

4.3 色温估计

色温估计是 AWB 的核心。它要回答一个问题:当前场景的光源色温是多少?

常用的方法有两种:

方法 原理 优点 缺点
基于色温曲线 在 R/G 和 B/G 色度空间上,预标定不同色温下的白点轨迹 物理意义明确,实现简单 需要提前标定,对混合光源不友好
基于学习的方法 用大量标定数据训练一个回归模型,输入图像统计特征,输出色温 适应性强,能处理复杂场景 计算量大,需要维护数据集

在实际工程中,我更喜欢用色温曲线法。为什么?因为它可解释性强,出了问题能快速定位。我曾经在调试一款安防相机时,发现它在荧光灯下总是偏绿。查了半天,原来是标定用的色温曲线在 4000K 附近有个拐点没处理好。重新标定后,问题就解决了。

色温估计的流程大致如下:

  1. 将图像从 RGB 转换到 R/G、B/G 色度空间
  2. 剔除过暗、过亮、饱和度太高的像素(这些点不靠谱)
  3. 在色温曲线上寻找与当前色度点最接近的色温值
  4. 如果找不到单一色温(比如混合光源),就取多个候选色温的加权平均

小技巧:在剔除异常像素时,我一般用「亮度范围 + 饱和度阈值」双重过滤。亮度太低的像素噪声大,亮度太高的可能已经饱和了。饱和度太高的像素(比如纯红、纯绿)对色温估计没有贡献,反而会引入偏差。

4.4 增益计算

色温估计出来之后,下一步就是计算增益。增益计算的本质是:把当前色温下的白点,映射到标准光源(D65,6500K)下的白点。

假设我们估计出的色温是 T,对应的白点在 R/G-B/G 空间中的坐标为 (rg_T, bg_T)。标准 D65 的白点坐标为 (rg_D65, bg_D65)。那么增益就是:

R_gain = rg_D65 / rg_T
G_gain = 1.0  // 通常固定 G 通道,调整 R 和 B
B_gain = bg_D65 / bg_T

但这里有个坑:增益不能无限大。如果色温极低(比如 2000K 的烛光),B 通道的增益可能会超过 4.0。这么大的增益会放大 B 通道的噪声,导致暗部出现彩色噪点。

我一般会做两件事:

  • 增益限幅:把 R 和 B 的增益限制在 [0.5, 3.0] 范围内
  • 增益平滑:帧与帧之间的增益变化不能太剧烈,否则画面会闪烁。我会用一阶低通滤波做平滑

下面这张图展示了 AWB 的整体流程:

AWB 白平衡处理流程 输入 RAW/RGB 图像 统计信息提取(均值、最亮点) 色温估计(曲线匹配 / 学习) 增益计算 + 限幅 + 平滑 输出白平衡校正图像 常见问题 • 大色块场景:灰度世界法失效 • 无白色物体:完美反射法失效 • 混合光源:色温估计不准 • 增益过大:暗部噪声放大

4.5 实战中的避坑指南

做了这么多年 ISP,AWB 的坑我踩过不少。挑几个典型的说说:

  • 场景切换时的色温跳变:从室内走到室外,色温从 3000K 跳到 6000K。如果增益直接跳变,画面会「闪」一下。我的做法是:检测到色温变化超过阈值时,用多帧渐进过渡,每帧只调整 10%~20%。
  • 人脸偏色问题:很多人脸在暖光下会偏黄。用户对肤色非常敏感。我一般会加一个人脸检测模块,如果检测到人脸,就用人脸区域的色温估计结果来主导全局 AWB。效果立竿见影。
  • 低照度场景:暗光下信噪比低,统计信息不可靠。这时候我倾向于「保守策略」——增益变化幅度减小,甚至固定在一个中间色温(比如 5000K),等光照条件改善后再恢复自适应。

总结一下:AWB 没有银弹。灰度世界法和完美反射法是基础,但实际工程中需要根据场景动态选择或融合。色温估计是核心,增益计算是执行。每一步都有坑,但每一步也都有对应的工程技巧。

我个人最深的体会是:不要迷信算法,要相信数据。每次遇到偏色问题,我都会先抓一帧 RAW 图,在 PC 上手动分析 R/G、B/G 分布,看看问题出在统计环节还是增益环节。定位清楚了,改起来就快了。