
044、白平衡算法演进灰度世界、色温估计与AI自适应校正去年夏天我在产线上盯一个安防摄像头的白平衡调试画面里是一片绿油油的菜地结果算法硬生生把绿色拉成了灰蓝色。产线工人问我“这摄像头是不是色盲”我盯着log看了半天发现灰度世界假设在纯色场景下彻底翻车了。这种问题干过影像系统的人多少都遇到过——白平衡调好了叫“色彩还原”调不好就是“色偏灾难”。白平衡的本质是让相机在不同光源下把白色还原成白色。听起来简单但真实场景里光源色温从2000K的烛光到10000K的阴天阴影中间还夹杂着混合光源和物体本身反射特性的干扰。今天这篇笔记我从灰度世界讲起一路聊到AI自适应校正重点放在那些容易踩坑的地方。灰度世界假设简单但脆弱灰度世界假设认为一幅图像中所有颜色的平均反射率是灰色的。换句话说R、G、B三个通道的平均值应该相等。基于这个假设算法计算每个通道的增益把平均值拉到同一水平。代码实现看起来干净利落defgray_world_awb(img):# 这里踩过坑直接对整图求均值会引入大面积纯色区域的偏差avg_rnp.mean(img[:,:,0])avg_gnp.mean(img[:,:,1])avg_bnp.mean(img[:,:,2])# 别这样写直接用全局均值做除法遇到大面积蓝天或草地直接翻车gain_ravg_g/avg_r gain_bavg_g/avg_b img_balancedimg.copy()img_balanced[:,:,0]np.clip(img[:,:,0]*gain_r,0,255)img_balanced[:,:,2]np.clip(img[:,:,2]*gain_b,0,255)returnimg_balanced这段代码在实验室的灰卡测试下表现完美但一上真实场景就露怯。我见过最离谱的一次是在一个满是红色花朵的花园里灰度世界算法把整个画面拉成了青色——因为红色通道均值太高算法强行压低红色结果绿色和蓝色通道相对突出。灰度世界假设的致命弱点在于它假设场景中所有颜色的分布是均匀的。现实世界偏偏不按这个剧本走。大面积单色物体、天空、草地、室内墙壁都会让这个假设失效。完美反射假设另一种极端完美反射假设认为图像中最亮的像素点应该是白色的。算法找到这些“白点”用它们的RGB值来估计光源色温。defperfect_reflector_awb(img,percentile95):# 这里踩过坑percentile选太高容易受噪点影响选太低又找不到真正的白点# 我一般用95%但遇到高光过曝的场景要降到90%r_channelimg[:,:,0]g_channelimg[:,:,1]b_channelimg[:,:,2]# 别这样写直接取最大值一个热噪点就能毁掉整张图max_rnp.percentile(r_channel,percentile)max_gnp.percentile(g_channel,percentile)max_bnp.percentile(b_channel,percentile)gain_rmax_g/max_r gain_bmax_g/max_b img_balancedimg.copy()img_balanced[:,:,0]np.clip(img[:,:,0]*gain_r,0,255)img_balanced[:,:,2]np.clip(img[:,:,2]*gain_b,0,255)returnimg_balanced这个方法在室内灯光场景下表现不错因为灯光的反射点往往是白色的。但遇到室外强光下的金属反光、水面反光算法会把非白色的高亮区域误判为白点结果就是色偏。我调试过一个车载摄像头在雨天路面反光时完美反射算法把路面积水反光当成了白点整个画面偏蓝。后来加了饱和度阈值过滤才勉强压住这个问题。色温估计从经验到模型灰度世界和完美反射都是基于图像统计的“盲”方法。色温估计则更进一步它试图直接推断光源的色温值。传统色温估计方法基于一个观察不同色温下同一物体的RGB比值会呈现规律性变化。比如低色温暖光下红色通道相对增强高色温冷光下蓝色通道相对增强。defcolor_temperature_estimation(img):# 这里踩过坑直接对全图做色温估计混合光源场景会算出个不存在的中间值# 我的做法是先做区域分割对每个区域独立估计avg_rnp.mean(img[:,:,0])avg_gnp.mean(img[:,:,1])avg_bnp.mean(img[:,:,2])# 别这样写直接用固定公式不同sensor的响应曲线差异很大# 这个公式是从某款CMOS的标定数据拟合来的换sensor要重新标定r_g_ratioavg_r/avg_g b_g_ratioavg_b/avg_g# 经验公式色温 常数 / (b_g_ratio - r_g_ratio 偏移)# 实际项目中这个公式的参数需要从标定数据中拟合color_temp4500/(b_g_ratio-r_g_ratio0.5)returncolor_temp色温估计的精度取决于两个因素一是sensor的光谱响应曲线是否标定准确二是场景中是否有足够多的中性色物体。我在手机影像项目中做过一组对比实验在D65光源下色温估计误差在±200K以内但在混合光源场景比如室内日光灯窗外自然光误差能到±800K。白点检测与置信度加权无论是灰度世界还是完美反射核心问题都在于“哪些像素应该参与白平衡计算”。白点检测算法试图解决这个问题。defwhite_point_detection(img,threshold0.1):# 这里踩过坑阈值设得太低会把浅色物体也纳入白点候选# 阈值设得太高白点数量不够统计结果不稳定# 我一般用动态阈值根据场景亮度自动调整# 转换到YCbCr空间利用色度信息筛选ycbcrcv2.cvtColor(img,cv2.COLOR_RGB2YCrCb)y,cr,cbcv2.split(ycbcr)# 别这样写直接用固定阈值不同光照下CbCr的分布差异很大# 正确做法先做光照归一化再设定阈值white_mask(abs(cr-128)threshold*128)(abs(cb-128)threshold*128)# 还要加亮度约束太暗的区域噪声大太亮的区域可能过曝white_maskwhite_mask(y30)(y230)returnwhite_mask白点检测之后还需要给每个白点分配置信度权重。靠近中性色区域的像素权重高远离的权重低。这个加权策略能有效抑制误检。我在安防监控项目中用过一种方法对每个白点候选区域计算其色度与理想白点的距离然后用高斯函数映射为权重。效果比硬阈值好很多但计算量也上去了。AI自适应校正数据驱动的突破传统方法遇到的最大瓶颈是它们都基于某种假设而现实场景往往不满足这些假设。AI方法则直接从数据中学习映射关系。AI白平衡的核心思路是输入原始图像输出每个像素的色温估计或直接输出校正后的图像。网络结构可以是轻量级的CNN也可以是更复杂的Transformer。defai_awb_inference(model,raw_img):# 这里踩过坑直接输入全图显存不够推理速度也慢# 我的做法先做下采样到224x224推理出色温估计再应用到全图# 别这样写用固定尺寸下采样会丢失局部色温变化信息# 正确做法用自适应池化保留空间分布特征# 预处理归一化到[0,1]注意不同sensor的raw图bit深度不同img_resizedcv2.resize(raw_img,(224,224))img_normalizedimg_resized.astype(np.float32)/255.0# 推理withtorch.no_grad():# 模型输出可以是色温值也可以是增益矩阵outputmodel(img_normalized.unsqueeze(0))# 后处理把模型输出映射为R/G/B增益gain_routput[0,0].item()gain_boutput[0,1].item()# 应用到全图img_balancedraw_img.copy()img_balanced[:,:,0]np.clip(raw_img[:,:,0]*gain_r,0,255)img_balanced[:,:,2]np.clip(raw_img[:,:,2]*gain_b,0,255)returnimg_balancedAI方法的优势在于它能学习到复杂场景下的非线性映射关系比如混合光源、大面积单色物体、高动态范围场景。但AI方法也有自己的坑数据标注是最大的瓶颈。真实场景下的“正确”白平衡是什么不同人有不同偏好。有人喜欢暖色调的“氛围感”有人追求中性色的“准确”。我见过一个项目标注团队和算法团队因为“这张图应该偏暖还是偏冷”吵了三个月。泛化能力问题。在训练集上表现完美的模型换一个sensor或者换一个场景可能直接翻车。我在车载项目中遇到过用城市道路数据训练的模型到了乡村土路上白平衡完全乱掉。实时性要求。手机拍照可以接受几百毫秒的延迟但视频通话要求30fps车载影像要求实时处理。轻量化网络设计是AI白平衡落地的关键。混合策略传统AI的务实方案纯AI方案在学术论文里表现惊艳但在产线上我更倾向于混合策略。具体做法是用传统方法灰度世界完美反射色温估计做快速初调用轻量级AI模型做场景分类和色温修正最后用白点检测做置信度校验defhybrid_awb(img,ai_model):# 第一步传统方法初调gray_resultgray_world_awb(img)perfect_resultperfect_reflector_awb(img)# 第二步AI场景分类决定融合权重# 这里踩过坑直接用softmax输出做权重遇到未见过的场景会乱来# 我的做法加一个“未知场景”类别置信度低时退回到传统方法scene_type,confidenceai_model.predict_scene(img)# 第三步根据场景自适应融合ifconfidence0.8:# 高置信度场景以AI结果为主resultai_awb_inference(ai_model,img)elifconfidence0.5:# 中等置信度融合传统方法和AI结果ai_resultai_awb_inference(ai_model,img)result(gray_result*0.3perfect_result*0.3ai_result*0.4)else:# 低置信度退回到传统方法result(gray_result*0.5perfect_result*0.5)returnresult这个混合策略在多个项目中验证过效果比纯传统方法好30%以上比纯AI方法更稳定。关键是在“未知场景”下的退化行为是可预测的不会出现AI方法那种“要么完美要么崩盘”的情况。实战经验总结写了这么多最后给几个个人经验性的建议标定比算法更重要。我见过太多团队花几个月调算法结果发现是sensor的响应曲线没标定准。白平衡的根基是sensor的光谱响应这个不准算法再牛也白搭。每次换sensor或者换镜头一定要重新做白平衡标定。场景覆盖比模型复杂度更重要。训练AI白平衡模型时与其花时间调网络结构不如多收集各种极端场景的数据纯色场景、混合光源、高动态范围、低照度。模型再简单数据覆盖全了效果也不会差。用户偏好比物理准确更重要。在手机影像领域用户喜欢“好看”而不是“准确”。人脸肤色偏暖一点、天空偏蓝一点用户会觉得“这手机拍照真棒”。车载和安防领域则相反要求物理准确。搞清楚你的目标用户是谁再决定白平衡策略。永远保留一个“安全模式”。无论算法多先进总会有翻车的时候。设计一个回退机制当算法置信度低时退回到一个保守的默认值。这个默认值可以来自实验室标定的灰卡数据也可以来自历史统计。产线上稳定比惊艳更重要。白平衡这个领域从灰度世界到AI自适应走了将近三十年。传统方法简单可靠但上限低AI方法上限高但稳定性差。真正好的系统是知道什么时候该用哪种方法以及如何优雅地处理边界情况。这大概就是架构师的价值所在。