4、白平衡校正:色温与光源、灰度世界假设、完美反射理论、色温估计方法、AWB算法实现

白平衡校正,说白了就是让相机在不同光线下都能把白色拍成白色。你想想看,白炽灯下拍的照片偏黄,日光灯下偏绿,阴天偏蓝——这些偏色就是色温捣的鬼。我入行那会儿,第一个独立负责的模块就是AWB,踩过的坑到现在还记得清清楚楚。

4.1 色温与光源:偏色的根源

色温不是温度,是光线的颜色属性。单位是开尔文(K)。数值越低,光越暖(偏红黄);数值越高,光越冷(偏蓝)。

光源类型 典型色温(K) 视觉感受
烛光 1500 - 2000 暖黄
白炽灯 2500 - 3000 暖白
日光(正午) 5000 - 5500 中性白
阴天 6000 - 7000 冷白偏蓝
蓝天阴影 8000 - 10000 深蓝

相机传感器本身没有色温概念,它只记录R、G、B三个通道的响应值。不同色温下,同一白色物体在传感器上的RGB比例完全不同。AWB要做的,就是把这个比例拉回到标准光源下的状态。

核心思路:找到场景中的“参考白”,然后调整R、G、B增益,让参考白的R=G=B。

4.2 灰度世界假设:最经典的起点

灰度世界假设认为:一张色彩丰富的自然图像,所有像素的R、G、B平均值应该趋于相等,即呈现灰色。

公式很简单:

R_gain = G_avg / R_avg
B_gain = G_avg / B_avg

然后对每个像素应用增益:

R_out = R_in * R_gain
B_out = B_in * B_gain
G_out = G_in  // G通道通常不动

我在项目中遇到过一个问题:当场景被大面积单色物体占据时(比如一片蓝天、一面红墙),灰度世界假设会彻底失效。整张图会被拉成灰色,偏色反而更严重。

避坑指南:我曾经在一个监控项目中,场景里80%是绿色草坪。灰度世界算法把整个画面拉成了品红色,甲方差点退货。后来我加了“色彩丰富度检测”,只有场景足够多彩时才信任灰度世界假设。

4.3 完美反射理论:找最亮的点

完美反射理论换个角度思考:图像中最亮的像素点,通常对应真实世界中的白色或镜面反射区域。这些点的R、G、B值应该相等。

实现步骤:

  1. 统计每个像素的亮度(比如取max(R,G,B)或Y分量)
  2. 选出亮度最高的前1%-5%的像素
  3. 计算这些像素的R、G、B平均值
  4. 用这个平均值计算增益
// 伪代码示例
bright_pixels = select_top_percent(image, 0.02)  // 取最亮2%
R_ref = mean(bright_pixels.R)
G_ref = mean(bright_pixels.G)
B_ref = mean(bright_pixels.B)

R_gain = G_ref / R_ref
B_gain = G_ref / B_ref

这个方法对高光区域敏感。如果场景里没有真正的白色物体,或者高光区域本身带颜色(比如彩色灯光),结果就会跑偏。

我的经验:实际工程中,我通常把灰度世界和完美反射两个结果做加权融合。权重根据场景统计动态调整——色彩丰富时多信任灰度世界,高光明显时多信任完美反射。

4.4 色温估计方法:从像素到色温

更高级的做法是直接估计场景色温,然后查表或计算对应的增益。常见方法有两种:

4.4.1 基于色温曲线的映射

提前标定不同色温下,标准白色在传感器上的R/G和B/G比值。形成一条色温曲线。运行时,统计图像中“疑似白色”区域的R/G和B/G,在曲线上找到最近的色温点。

4.4.2 基于色度空间的分类

把图像转换到色度空间(比如CbCr或u'v'),用统计方法判断主色温区域。我见过有的方案直接用CNN分类器,输入是小块图像,输出是色温类别。

方法 优点 缺点
灰度世界 简单、计算快 大色块场景失效
完美反射 对高光场景鲁棒 依赖白色参考点
色温曲线 物理意义明确 需要标定、泛化性一般
深度学习 精度高、适应性强 算力开销大、需要数据集

4.5 AWB算法实现:从理论到代码

下面是一个完整的AWB实现流程,我把它拆成几个清晰的步骤。这是我在一个手机ISP项目中实际用过的简化版本。

// 完整AWB流程(简化版)
// 输入:Bayer域或RGB域图像
// 输出:白平衡校正后的图像

Step 1: 统计图像统计量
  - 将图像分成MxN个块(比如16x16)
  - 对每个块计算R、G、B均值
  - 剔除过暗(噪声大)和过亮(可能饱和)的块

Step 2: 候选白色点检测
  - 对每个有效块,计算R/G和B/G
  - 如果R/G和B/G都在预设的“白色区域”内,标记为候选白点
  - 白色区域通常是一个多边形,由不同色温下的白点标定得到

Step 3: 色温估计
  - 对候选白点做聚类,找到最密集的色温区域
  - 或者直接取所有候选白点的R/G和B/G中位数

Step 4: 增益计算
  - 根据估计的色温,查表得到R_gain和B_gain
  - 或者直接用候选白点的统计值计算增益

Step 5: 增益应用
  - 对每个像素:R_out = R_in * R_gain, B_out = B_in * B_gain
  - G通道保持不变

Step 6: 后处理(可选)
  - 增益限幅,防止颜色过饱和
  - 空间平滑,避免块状效应

关键参数:块大小、候选白点阈值、增益限幅值。这些参数在不同传感器和镜头组合下需要重新调优。我建议在实验室用色卡标定,然后在真实场景中验证。

嗯,这里要注意:增益不能无限大。如果某个通道的增益超过2.0,说明场景色温极偏,或者算法估计有误。我一般会设一个上限,比如1.5到2.5之间,超出部分截断。

4.6 知识体系总览

下面这张图把本章的核心逻辑串起来了。从物理世界的色温光源,到两种经典假设,再到工程实现中的具体步骤。

白平衡校正知识体系 白平衡校正知识体系 色温与光源(物理根源) 灰度世界假设 完美反射理论 色温估计方法 AWB算法实现(6步流程) 校正后图像(R=G=B) 核心原则 找到场景中的参考白 → 计算R/G/B增益 → 让参考白的R=G=B

从这张图可以看得很清楚:物理世界的色温是源头,两种理论是两种不同的“找白”思路,色温估计是中间桥梁,最后落到具体的算法实现上。每一步都有坑,但每一步也都有成熟的应对方法。

工程建议:如果你刚开始做AWB,我建议先实现灰度世界+完美反射的加权版本。跑通之后,再逐步加入色温曲线和候选白点检测。一口吃不成胖子,AWB的调优往往要迭代好几个版本才能稳定。