3. 实现自动白平衡灰度世界算法
任务目标
本案例基于灰度世界假设(Gray World Assumption)实现自动白平衡:统计图像RGB三通道的平均值,以三通道均值的均值为基准计算各通道增益,对每个像素进行增益校正,从而消除环境光源造成的色偏。输入为普通RGB图像(如偏黄或偏蓝的室内照片),输出为校正后的图像。
核心原理
灰度世界假设认为:一幅色彩丰富的自然图像,其RGB三通道的平均值应趋于同一灰度值。若图像存在色偏,则三通道均值不相等。算法通过计算各通道增益,将三通道均值拉平到同一水平:
- 计算全图R、G、B通道均值
meanR, meanG, meanB - 计算灰度基准
gray = (meanR + meanG + meanB) / 3 - 各通道增益:
gainR = gray / meanR,gainG = gray / meanG,gainB = gray / meanB - 校正:
out = clamp(pixel * gain),像素值限制在[0, 255]
完整实现(Python + OpenCV)
import cv2
import numpy as np
def gray_world_awb(img):
"""
灰度世界自动白平衡
img: BGR图像 (H, W, 3), dtype=uint8
返回: 校正后的BGR图像 (H, W, 3), dtype=uint8
"""
# 转换为float避免溢出
img_f = img.astype(np.float32)
# 1. 计算各通道均值
mean_b = np.mean(img_f[:, :, 0])
mean_g = np.mean(img_f[:, :, 1])
mean_r = np.mean(img_f[:, :, 2])
# 2. 灰度基准
gray = (mean_r + mean_g + mean_b) / 3.0
# 3. 各通道增益(防止除零)
eps = 1e-6
gain_r = gray / (mean_r + eps)
gain_g = gray / (mean_g + eps)
gain_b = gray / (mean_b + eps)
# 4. 像素校正并裁剪到[0,255]
out = np.zeros_like(img_f)
out[:, :, 0] = np.clip(img_f[:, :, 0] * gain_b, 0, 255) # B通道
out[:, :, 1] = np.clip(img_f[:, :, 1] * gain_g, 0, 255) # G通道
out[:, :, 2] = np.clip(img_f[:, :, 2] * gain_r, 0, 255) # R通道
return out.astype(np.uint8)
# 最小调用入口
if __name__ == "__main__":
# 读取图像(请替换为实际路径)
img = cv2.imread("input.jpg")
if img is None:
print("错误:无法读取图像,请检查路径")
exit(1)
# 执行白平衡
result = gray_world_awb(img)
# 保存结果
cv2.imwrite("output.jpg", result)
print("处理完成,结果已保存为 output.jpg")
运行方式
- 安装依赖:
pip install opencv-python numpy - 将待校正图像命名为
input.jpg放在脚本同目录 - 运行:
python awb_gray_world.py
验证方法
通过以下两种方式验证算法是否生效:
- 视觉检查:打开
output.jpg,观察原本偏黄(暖色)或偏蓝(冷色)的图像是否恢复为中性色调,白色物体应呈现为白色。 - 数值验证:在代码中增加以下统计,观察校正前后三通道均值是否趋近相等:
# 验证辅助代码(可临时追加到main中)
mean_before = img.reshape(-1, 3).mean(axis=0)
mean_after = result.reshape(-1, 3).mean(axis=0)
print("校正前BGR均值:", mean_before)
print("校正后BGR均值:", mean_after)
通过条件:校正后三通道均值之间的最大差值小于5(例如B=120.1, G=121.3, R=119.8),且图像无明显色偏。
常见问题
- 图像整体偏暗或过曝:灰度世界算法只做颜色校正,不调整亮度。若校正后亮度异常,说明原图本身曝光有问题,需先做曝光校正。
- 大面积单色场景失效:若画面被单一颜色主导(如纯蓝天、纯红墙),灰度世界假设不成立,校正结果可能偏色。此时可改用更鲁棒的算法(如完美反射法),但不在本案例范围内。
- 增益过大导致过曝:当某通道均值极低时,增益会很大,导致该通道像素被裁剪到255。这是灰度世界算法的已知局限,可通过限制最大增益(如不超过3.0)缓解。