2. 光源估计

光源估计,说白了就是猜出当前场景下光源的颜色。你想想看,一张白纸在日光灯下发青,在白炽灯下发黄,但人眼总能认出它是白的。相机不行,它得靠算法去猜。这一章我们就来聊聊三种最经典的光源估计方法。

核心思路: 光源估计的目标是找到图像中“应该为白色”的区域,然后反推出光源的 RGB 分量。有了光源颜色,我们才能做后续的白平衡校正。

2.1 灰度世界法(Gray World)

这个方法的名字很直白——它假设整个世界是灰色的。什么意思呢?就是认为一张色彩丰富的自然图像,所有像素的 R、G、B 通道平均值应该相等,都趋向于一个共同的灰度值。

我个人习惯用这个算法做快速预调。它简单到令人发指:

// 伪代码:灰度世界法
avgR = mean(image[:,:,0])
avgG = mean(image[:,:,1])
avgB = mean(image[:,:,2])

// 计算各通道增益
gainR = avgG / avgR
gainB = avgG / avgB

// 校正后的图像
output[:,:,0] = image[:,:,0] * gainR
output[:,:,1] = image[:,:,1] * 1.0
output[:,:,2] = image[:,:,2] * gainB

我在项目中遇到过一个问题:如果场景里大面积都是同一种颜色,比如一片蓝天或一片绿草地,灰度世界法就会翻车。它会强行把蓝色或绿色拉成灰色,结果整张图都偏色了。

避坑指南: 我曾经在一个户外航拍项目里直接用灰度世界法,结果天空被拉成了灰白色,地面植被也失去了饱和度。后来我加了预处理——先检测图像是否包含大面积单色区域,如果是,就切换到其他方法。
优点 缺点
计算极快,适合实时处理 大面积单色场景会失效
实现简单,三行代码搞定 对暗部噪声敏感
对色彩丰富的场景效果不错 无法处理多光源混合场景

2.2 完美反射法(White Patch)

这个方法又叫“白点法”。它的假设是:图像中一定存在某个区域是纯白色的,或者至少是接近白色的。找到这个最亮的点,把它当作光源颜色的参考。

嗯,这里要注意:完美反射法找的不是整张图最亮的像素,而是每个通道最亮的像素。我刚开始做的时候也犯过这个错——直接找 RGB 总和最大的像素,结果经常找到的是过曝的灯泡。

// 伪代码:完美反射法
// 取每个通道前 1% 最亮像素的平均值
sortedR = sort(image[:,:,0].flatten())
sortedG = sort(image[:,:,1].flatten())
sortedB = sort(image[:,:,2].flatten())

topPercent = 0.01
whiteR = mean(sortedR[-int(len(sortedR)*topPercent):])
whiteG = mean(sortedG[-int(len(sortedG)*topPercent):])
whiteB = mean(sortedB[-int(len(sortedB)*topPercent):])

// 计算增益
gainR = max(whiteG, whiteB) / whiteR
gainG = max(whiteR, whiteB) / whiteG
gainB = max(whiteR, whiteG) / whiteB
经验之谈: 我建议取前 0.5%~1% 的最亮像素做平均,而不是直接用最大值。这样可以避免单个坏点或噪点对结果的影响。另外,如果场景里根本没有白色物体(比如拍一片红枫叶),这个方法也会失效。

完美反射法的好处是它对色彩偏差的纠正很彻底,尤其是当场景里确实有白色参考物时。但它的缺点也很明显——如果场景整体偏暗,或者高光区域很少,结果就会很不稳定。

2.3 Shades of Grey 方法

这个方法可以看作是灰度世界法和完美反射法的“混血儿”。它引入了一个参数 p,通过调整 p 的值,可以在两种极端之间平滑过渡。

说白了,灰度世界法用的是 p=1 的 Minkowski 范数(均值),完美反射法用的是 p=∞ 的 Minkowski 范数(最大值)。Shades of Grey 则允许 p 取其他值,比如 p=6 或 p=12。

// 伪代码:Shades of Grey 方法
p = 6  // 常用值,可根据场景调整

// 计算每个通道的 p-范数
normR = (mean(image[:,:,0]**p))**(1/p)
normG = (mean(image[:,:,1]**p))**(1/p)
normB = (mean(image[:,:,2]**p))**(1/p)

// 计算增益
gainR = normG / normR
gainB = normG / normB
p 值 对应方法 适用场景
p=1 灰度世界法 色彩丰富的自然场景
p=6~12 Shades of Grey 大多数室内外场景
p→∞ 完美反射法 有明确白色参考物的场景
关键洞察: p 值越大,算法越倾向于寻找“最亮”的区域;p 值越小,算法越倾向于统计全局平均。我在实际项目中通常从 p=6 开始试,然后根据效果微调。

2.4 三种方法的对比与选择

这三种方法没有的好坏,关键看场景。我整理了一个对比表格,方便你快速决策:

方法 计算量 鲁棒性 适用场景
灰度世界法 极低 中等 色彩丰富、光照均匀的场景
完美反射法 低 较低 有白色参考物、高光充足的场景
Shades of Grey 中等 较高 大多数通用场景,可调参数

我个人习惯在工程中这样选:如果是移动端实时预览,用灰度世界法,速度快;如果是拍照后处理,用 Shades of Grey 加 p=6;如果是专业摄影后期,我会结合完美反射法做二次校验。

注意: 这三种方法都假设场景是单光源。如果遇到混合光源(比如室内日光灯加窗外阳光),它们都会失效。这种情况需要更高级的方法,我们后面章节会讲。

2.5 本章知识结构图

下面这张图帮你理清三种方法的关系和适用边界:

光源估计方法对比图 光源估计三大经典方法 光源估计 灰度世界法 p=1,均值假设 Shades of Grey p=6~12,可调参数 完美反射法 p→∞,最亮区域 优点 计算极快 适合实时处理 优点 鲁棒性较高 参数可调 优点 有白色参考时精准 校正彻底 选择建议:场景复杂用 Shades of Grey,简单场景用灰度世界
实战建议: 如果你刚开始接触白平衡,我建议先从灰度世界法入手,跑通流程后再尝试 Shades of Grey。调参时注意观察 p 值变化对结果的影响——p 越大,校正力度越强,但也越容易过冲。