1494 字
7 分钟
AWB 如何估计光源?从灰世界到可信像素筛选

AWB 看不到物体原本的颜色,只能看到“光源光谱 × 表面反射率 × 传感器响应”的结果。仅凭一张 RGB 图像同时求出光源和反射率,本质上是一个欠定问题;经典算法之所以可用,是因为它们额外加入了关于场景的统计假设。

Gray World:假设颜色在整体上互相抵消#

灰世界假设认为,一个颜色足够丰富的场景,其平均反射率接近中性。在线性 RGB 中计算均值 (Rˉ,Gˉ,Bˉ)(\bar R,\bar G,\bar B) 后,可令三个通道趋向同一目标:

gc=(Rˉ+Gˉ+Bˉ)/3cˉg_c=\frac{(\bar R+\bar G+\bar B)/3}{\bar c}

最后常再以绿色通道归一化增益。

Gray World:平均颜色真的是灰吗

灰世界假设认为足够丰富的场景长期平均应接近中性;当画面由单一物体颜色占据时,算法会把内容误当光源。

估计 R Gain1.10
G Gain1.00
估计 B Gain0.92
场景内容

森林场景会被错误补入洋红,日落可能被过度降温。现代 AWB 会结合中性候选、语义、肤色与先验光源模型。

这个方法的优势是简单、稳定且无需训练;它的弱点也来自同一个假设。森林、蓝天、水下、红色舞台和大面积彩色墙面并不满足“颜色丰富且均衡”,算法会把物体固有颜色误认为光源偏色。

White Patch 与中性点假设#

White Patch 假设场景中最亮、接近漫反射白的区域能够代表光源颜色。它在存在白纸、灰卡或高反射中性物体时很有效,但容易被灯具、镜面高光和通道饱和欺骗。

中性点方法不要求候选一定最亮,而是在颜色空间中寻找可能为灰色的像素。问题在于:经过未知光源照明后,中性物体本来就会偏离中性轴,筛选范围过窄会漏掉候选,过宽又会混入彩色物体。

因此实际系统往往组合多个估计器,而不是把所有场景交给单一规则。

先筛像素,再谈均值#

统计输入的质量通常比均值公式更重要。常见排除条件包括:

  • 过暗像素:通道比例容易受黑电平残差和读出噪声支配;
  • 饱和像素:至少一个通道已经裁剪,RGB 比例不再可信;
  • 高色度像素:更可能属于强色物体,而非中性候选;
  • 坏点、耀斑和镜面反射:会制造局部异常统计;
  • 面积过小的候选:可能只是噪声或偶然高光。

可以把亮度与色度条件写成一个明确的候选掩码。令

Yi=Ri+Gi+Bi3,χi=max(Ri,Gi,Bi)min(Ri,Gi,Bi)Yi+εY_i=\frac{R_i+G_i+B_i}{3},\qquad \chi_i=\frac{\max(R_i,G_i,B_i)-\min(R_i,G_i,B_i)}{Y_i+\varepsilon}

则一个简化的可信集合为

Ω={iYmin<Yi<Ymax,  max(Ri,Gi,Bi)<Smax,  χi<τχ}.\Omega=\left\{i\mid Y_{\min}<Y_i<Y_{\max},\; \max(R_i,G_i,B_i)<S_{\max},\;\chi_i<\tau_\chi\right\}.

YminY_{\min} 排除噪声主导的暗部,SmaxS_{\max} 排除接近裁剪的像素,τχ\tau_\chi 则限制候选色度。StatisticsMaskLab 展示的正是这三类门限之间的取舍。

统计区域决定 AWB 看见什么

饱和高光、深噪声、强物体色与人脸都不应被同等对待。候选筛选常比最后的增益公式更重要。

保留样本100%
色偏残差0.28
置信度0.32
统计策略

中性候选更可靠但数量少。工程上需要在样本覆盖率、噪声与先验偏差之间平衡,并对低置信度场景保守更新。

空间分块也很重要。直接汇总全图会让大面积背景支配结果;先在每个块内统计,再对有效块加权,可以保留场景分布信息,并为后续的混合光检测提供依据。

用稳健统计限制离群值#

即使通过掩码,候选中仍可能混入彩色物体或镜面高光。与普通均值相比,截尾均值会先删除每个通道两端各 qq 比例的样本:

TMeanq(x)=1n2kj=k+1nkx(j),k=qn\operatorname{TMean}_q(x)= \frac{1}{n-2k}\sum_{j=k+1}^{n-k}x_{(j)}, \qquad k=\lfloor qn\rfloor

其中 x(j)x_{(j)} 是排序后的样本。下面代码把 Gray World、可信像素 mask 与 10% 截尾均值串成一个可运行的估计器,返回光源 RGB 色度而不是直接输出 WB 增益,以便与总览篇的“估计/应用”职责分离。

import numpy as np
def gray_world_illuminant(linear_rgb, dark=0.03, bright=0.92,
chroma_limit=0.35, trim=0.10):
"""从 [0, 1] 线性 RGB 估计归一化光源颜色。"""
rgb = np.asarray(linear_rgb, dtype=np.float64)
if rgb.ndim != 3 or rgb.shape[-1] != 3:
raise ValueError("linear_rgb 必须是 H×W×3")
y = rgb.mean(axis=-1)
peak = rgb.max(axis=-1)
chroma = (peak - rgb.min(axis=-1)) / np.maximum(y, 1e-6)
mask = (y > dark) & (y < bright) & (peak < 0.98) & (chroma < chroma_limit)
candidates = rgb[mask]
if len(candidates) < 32:
raise ValueError("可信候选不足,应降低置信度而不是强行更新")
k = int(len(candidates) * trim)
sorted_rgb = np.sort(candidates, axis=0)
3 collapsed lines
core = sorted_rgb[k:len(candidates) - k] if k else sorted_rgb
illuminant = core.mean(axis=0)
return illuminant / np.maximum(illuminant.sum(), 1e-6), mask

这里的阈值与 10% 截尾比例是教学默认值,不是跨相机通用标定。逐通道排序也会打散 RGB 样本对应关系;它适合演示稳健中心,不足以代替色度空间聚类、空间分块权重与相机光源轨迹约束。

统计必须处于合适的颜色域#

AWB 通常在线性 RAW 或近似线性 RGB 上统计。若直接平均 Gamma 编码后的像素,暗部被相对放大,均值不再与采集到的光子比例对应。

同时还要明确 BLC、LSC 与坏点校正的顺序:黑电平残差会污染暗部通道比,镜头阴影会让画面不同位置呈现不同颜色倾向,坏点则会影响小区域候选。统计模块依赖这些基础校正提供可信输入。

从候选分布得到光源#

筛选后不应只保留三个全局均值。更完整的调试数据包括:

stats = {
"block_rgb": block_rgb,
"valid_mask": valid_mask,
"candidate_count": candidate_count,
"chromaticity_histogram": uv_histogram,
"highlight_ratio": highlight_ratio,
}

候选在色度空间中聚成单一紧密峰,通常比散布在多处更可信。估计器可以把 Gray World、White Patch、已知光源轨迹和场景分类结果融合,并保留各自得分供决策层使用。

如何验证经典统计方法#

测试集不能只包含色卡和普通街景,还应覆盖:

  • 大面积单色物体与低颜色多样性场景;
  • 暖光、日光、荧光灯和窄带 LED;
  • 饱和灯具、镜面高光与深阴影;
  • 灰卡位于中心、边缘和不同亮度区间;
  • 多种肤色、天空、草地与水下场景;
  • 不同曝光量、模拟增益和传感器温度。

经典统计方法不是过时的“简单基线”。它们仍然提供可解释、低成本的观测量;真正的工程难点,是知道假设何时成立,并把候选质量交给后续置信度层判断。

AWB 如何估计光源?从灰世界到可信像素筛选
https://cloudsir.top/posts/how-awb-estimates-illuminants/
作者
CloudSir
发布于
2026-08-25
许可协议
CC BY-NC-SA 4.0
AWB 如何保持稳定?置信度、混合光与时域控制
AWB 自动白平衡系统:从光源估计到闭环控制