手动白平衡是在已知光源或中性卡时设置通道增益;AWB(Auto White Balance)必须只根据当前图像判断:画面偏黄,究竟来自暖色光源,还是来自夕阳、木墙与黄色物体本身?
因此 AWB 不是一条“把 RGB 均值拉齐”的公式,而是一套带有不确定性的估计与控制系统。
一条完整的 AWB 链路
工程实现通常包含五个阶段:
- 从 RAW 或线性 RGB 中采集分块统计;
- 排除饱和、过暗、强色和其他不可信像素;
- 根据中性候选、颜色分布与场景先验估计光源;
- 把光源估计转换为白平衡增益,并联动 CCM 插值;
- 根据置信度、场景变化和历史状态平滑或冻结输出。
这条链路里,“测到了什么”和“是否相信测量”同样重要。单色墙、舞台灯、混合照明都可能让数学上稳定的统计给出语义上错误的答案。
光源估计与白平衡增益
若中性表面在当前光源下测得 ,一种以绿色通道为基准的增益写法是:
这说明 WB 与 AWB 的职责不同:WB 应用增益,AWB 决定应该使用哪组增益。
把像素写成列向量 ,最常见的教学模型是对角变换:
若候选集合 中确实包含中性表面,则校正后的通道应满足中性约束:
用候选均值 代入,就得到 、。下面的 NumPy 函数只实现这个数值内核,输入必须是已经完成黑电平校正、近似线性的 RGB;候选掩码如何产生,留给下一篇讨论。
import numpy as np
def diagonal_wb_gains(linear_rgb, neutral_mask, eps=1e-6): """由可信中性候选计算以 G 为锚点的 (gR, gG, gB)。""" rgb = np.asarray(linear_rgb, dtype=np.float64) mask = np.asarray(neutral_mask, dtype=bool) if rgb.ndim != 3 or rgb.shape[-1] != 3: raise ValueError("linear_rgb 必须是 H×W×3") if mask.shape != rgb.shape[:2] or not np.any(mask): raise ValueError("neutral_mask 必须匹配图像且至少包含一个候选")
mean_rgb = rgb[mask].mean(axis=0) if np.any(mean_rgb <= eps): raise ValueError("候选均值过暗,通道比不可信")
gains = mean_rgb[1] / mean_rgb gains /= gains[1] # 明确保持绿色通道为 1 return np.clip(gains, 0.25, 4.0) # 教学用安全范围对角模型假设同一组通道增益可以解释整幅图像。真实相机还需要传感器标定、光源轨迹、增益限幅,并让 CCM 随估计光源插值;窄带光源与混合光也不能仅靠一个全局对角矩阵完整校正。
色温与 Tint 是两条不同方向
色温主要沿蓝—黄轴变化,Tint 处理绿—洋红偏移。AWB 要估计的是光源,而不是让所有像素变成灰色。


实拍照片的冷暖变化用颜色叠层近似,仅用于观察校正方向;中性块与增益才对应简化通道模型,不等同于完整的 Planckian locus 或相机标定模型。
相关色温主要描述蓝—黄方向,Tint 补充绿—洋红方向,但它们仍不能完整表示任意光谱。窄带 LED、荧光灯和混合光可能在相同色温下产生不同的传感器响应,因此真实系统需要相机标定、光源模型和场景先验。
AWB 为什么必须输出置信度
灰世界、中性点和白点假设都只在部分场景成立。可靠 AWB 不应只输出 ,还应输出:
- 有效统计像素比例;
- 候选光源之间的一致性;
- 当前场景是否可能为单色或混合光;
- 与上一帧结果的变化幅度;
- 最终估计的置信度与锁定状态。
置信度低时,保持上一组可信增益通常比追逐噪声更安全。视频中的颜色闪烁,很多时候不是估计均值不准,而是状态机过度相信了每一帧。
AWB 与其他模块的边界
AWB 的输出常同时影响 WB 增益、CCM 选择和色调风格;AE 又会改变统计亮度、饱和比例和信噪比。因此 3A 必须交换状态,但不应让职责混在一起。
- AWB 估计光源,不负责修正镜头色差;
- CCM 修正传感器颜色响应,不能代替错误的光源估计;
- Tone Mapping 能改变观感,却不应成为线性 AWB 统计的输入;
- 局部色彩风格可以保留暖光氛围,不等于 AWB 估计失败。
最小实现骨架
stats = collect_linear_rgb_stats(raw, blocks=True)candidates = reject_unreliable(stats, dark=True, saturated=True, chromatic=True)illuminant, confidence = estimate_illuminant(candidates, scene_prior)
if confidence >= update_threshold: target_gains = illuminant_to_gains(illuminant, calibration) gains = temporal_filter(previous_gains, target_gains, scene_change)else: gains = previous_gains这段骨架有意把“统计”“估计”“决策”“时间控制”分开。这样的系统更容易记录中间状态,也更容易定位偏色究竟来自候选筛选、模型选择还是输出平滑。
后续两篇将分别深入经典统计方法,以及置信度、混合光与视频稳定问题。理解 AWB 的关键,是承认单帧图像无法总是唯一确定光源,并把这种不确定性显式带进系统。