色彩校正基础:白平衡原理、色温与色调、灰度世界假设、完美反射假设

色彩校正,说白了就是让相机看到的世界,跟你人眼看到的世界一样。我刚开始做图像处理那会儿,总觉得白平衡是个小问题——不就是把白色调白嘛。直到有一次在户外拍产品,阳光透过树叶洒下来,整张图偏绿得一塌糊涂,我才意识到:白平衡搞不定,后面所有色彩工作都是白搭。

这一章,咱们把白平衡的底牌翻个底朝天。

白平衡到底在平衡什么?

先问一个问题:为什么人眼看白纸永远是白的?

因为人脑有色彩恒常性。不管在日光灯下、蜡烛光下、还是阴天户外,大脑会自动把光源颜色“扣除”,让你觉得白纸还是白纸。但相机没这个本事——它老老实实地记录所有光线。所以,当光源偏蓝时,整张图就偏蓝;光源偏黄时,整张图就偏黄。

白平衡要做的,就是模拟人脑的这个“扣除”过程。

核心公式(简化版):

校正后像素 = 原始像素 × (白点参考值 / 当前通道均值)

说白了,就是找到场景中“本该是白色”的那个点,然后按它的比例把其他颜色拉回来。

色温与色调:两个容易搞混的概念

我见过不少工程师把色温和色调混着用。其实它们是完全不同的两回事。

概念 物理含义 对图像的影响 典型场景
色温 光源的冷暖程度(开尔文 K) 低色温偏黄/红,高色温偏蓝 烛光 2000K,日光 5500K,阴天 7000K
色调 色彩在色环上的偏移方向 偏绿或偏品红 荧光灯下偏绿,LED 混光偏品

色温是一条直线——从黄到蓝。色调是垂直于这条直线的另一个维度——从绿到品红。两个维度合在一起,才能完整描述一个光源的颜色。

我的经验:调试时先调色温,再调色调。顺序反了,你会陷入死循环。我曾经在一个项目里先调了色调,结果色温一变,色调又得重来,浪费了两天时间。

灰度世界假设:最朴素的白平衡方法

这个假设很简单:一张色彩丰富的自然图像,所有颜色的平均值应该是灰色。

为什么?因为自然界中红绿蓝的分布大致均匀,平均下来就是中性灰。既然平均是灰的,那如果图像偏色,就说明光源颜色没有被扣除。

算法步骤:

  1. 计算整张图像 R、G、B 三个通道的平均值
  2. 找到三个平均值的最大值(或设定一个目标灰值)
  3. 分别计算每个通道的增益:增益 = 目标值 / 通道平均值
  4. 用增益校正每个像素
// 灰度世界假设的简单实现(伪代码)
float avgR = mean(image[:,:,0]);
float avgG = mean(image[:,:,1]);
float avgB = mean(image[:,:,2]);

float target = (avgR + avgG + avgB) / 3.0;

float gainR = target / avgR;
float gainG = target / avgG;
float gainB = target / avgB;

image_corrected[:,:,0] = image[:,:,0] * gainR;
image_corrected[:,:,1] = image[:,:,1] * gainG;
image_corrected[:,:,2] = image[:,:,2] * gainB;

注意:灰度世界假设有个致命弱点——如果场景本身就不是“色彩丰富”的,比如一片蓝天、一片草地、或者一个全是红色包装的货架,那平均值根本不是灰色。强行校正会得到灾难性的结果。

我曾经在拍红色包装的产品时用过这个方法,结果整张图变成了青色。嗯,从那以后我再也不敢无脑用灰度世界了。

完美反射假设:另一种思路

这个假设跟灰度世界正好相反。它不看平均值,而是找图像中最亮的点——认为这些点应该是白色或镜面反射点。

你想想看,如果场景中有一个白色物体,它反射了所有波长的光,那它就应该是最亮的。如果这个最亮点偏色了,说明光源颜色污染了它。

算法步骤:

  1. 找出图像中最亮的若干像素(比如前 1%)
  2. 计算这些像素的 R、G、B 平均值
  3. 以这些平均值为“白点”参考
  4. 计算增益并校正全图

两种假设的对比:

方法 适用场景 失效场景
灰度世界 色彩丰富的自然场景 单色场景、大面积纯色
完美反射 场景中有白色或高光区域 无高光、过曝或欠曝严重

知识结构图:白平衡方法全景

下面这张图把本章的核心逻辑串起来了。你可以看到,白平衡不是单一方法,而是一套从假设到校正的完整链路。

白平衡方法全景图 白平衡方法全景图 白平衡校正 灰度世界假设 完美反射假设 计算通道均值 求目标灰值 计算增益 提取最亮像素 计算白点均值 计算增益 像素级增益校正 校正后图像 ⚠ 注意 单色场景下两种假设均可能失效 建议结合场景选择或混合使用

实际项目中的选择策略

你可能会问:那我到底该用哪个?

我的建议是——别死磕一个。实际项目中,我通常这样做:

  • 先判断场景:如果场景色彩丰富,优先灰度世界;如果场景中有明显白色区域,优先完美反射。
  • 混合使用:有些算法把两种假设加权平均,比如 70% 灰度世界 + 30% 完美反射。效果往往比单一方法好。
  • 加个保护:计算增益时设置上下限,防止某个通道增益过大导致噪声爆炸。

一个小技巧:调试时可以在图像上画一个 ROI(感兴趣区域),只对 ROI 内的像素做白平衡统计。比如拍人脸时,只取皮肤区域做灰度世界,效果比全图好很多。我在一个人脸识别项目里用过这招,白平衡准确率从 72% 提到了 91%。

色温与色调的联合调试

最后聊一下实际调试中的操作。很多相机 SDK 会提供色温和色调两个滑块。你调色温时,图像在黄-蓝轴上移动;调色调时,在绿-品红轴上移动。

调试步骤:

  1. 放一张标准灰卡或白卡在场景中
  2. 用示波器或直方图看 RGB 三个通道的分布
  3. 先调色温,让 R 和 B 通道的峰值对齐
  4. 再调色调,让 G 通道与 R、B 对齐
  5. 微调直到三个通道的直方图基本重合

嗯,这里要注意:不要只看屏幕上的颜色“感觉对了”。人眼会自适应,感觉往往不准。一定要看数据——直方图和波形图才是你的好朋友。