2. 光源估计
光源估计,说白了就是猜出当前场景下光源的颜色。你想想看,一张白纸在日光灯下发青,在白炽灯下发黄,但人眼总能认出它是白的。相机不行,它得靠算法去猜。这一章我们就来聊聊三种最经典的光源估计方法。
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
完美反射法的好处是它对色彩偏差的纠正很彻底,尤其是当场景里确实有白色参考物时。但它的缺点也很明显——如果场景整体偏暗,或者高光区域很少,结果就会很不稳定。
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→∞ | 完美反射法 | 有明确白色参考物的场景 |
2.4 三种方法的对比与选择
这三种方法没有的好坏,关键看场景。我整理了一个对比表格,方便你快速决策:
| 方法 | 计算量 | 鲁棒性 | 适用场景 |
|---|---|---|---|
| 灰度世界法 | 极低 | 中等 | 色彩丰富、光照均匀的场景 |
| 完美反射法 | 低 | 较低 | 有白色参考物、高光充足的场景 |
| Shades of Grey | 中等 | 较高 | 大多数通用场景,可调参数 |
我个人习惯在工程中这样选:如果是移动端实时预览,用灰度世界法,速度快;如果是拍照后处理,用 Shades of Grey 加 p=6;如果是专业摄影后期,我会结合完美反射法做二次校验。
2.5 本章知识结构图
下面这张图帮你理清三种方法的关系和适用边界: