3. AE与AWB的耦合关系:为什么曝光变化会导致白平衡漂移?

做ISP调试的人,迟早都会撞上这个问题:明明AWB单独调好了,AE一动,画面颜色就跑了。这不是算法bug,而是传感器和ISP的物理特性决定的。说白了,曝光和白平衡是绑在一根绳上的蚂蚱。

3.1 耦合的根源:传感器响应非线性

理想情况下,传感器每个像素的响应应该是线性的——光强翻倍,输出值翻倍。但现实世界没这么完美。我遇到过不少项目,低照度下AWB飘得离谱,高亮场景反而稳如泰山。原因就在传感器的响应曲线上。

传感器在不同曝光量下,R/G/B通道的增益并不是等比例变化的。举个例子:

  • 低照度(暗电流主导):暗电流噪声会抬升暗部,尤其对B通道影响大,导致偏蓝。
  • 高照度(饱和区):R通道先饱和,G/B还在爬升,导致偏绿或偏品。
  • 中间区(线性区):相对稳定,但也不是完全线性。

核心结论:曝光量改变 → 各通道增益比例改变 → 传感器输出的R/G/B比值改变 → AWB统计值漂移。

3.2 亮度与色温的相互影响机制

你想想看,AWB算法本质上是在估计场景的色温。它依赖的是图像中“灰色区域”的R/G和B/G比值。但问题来了——这些比值会随着亮度变化而改变。

我画了一张图,帮你理清这个循环:

AE与AWB耦合循环图 场景亮度变化 AE调整曝光参数 传感器输出R/G/B变化 各通道增益非线性 R/G、B/G比值漂移 AWB色温估计偏差 AE介入 传感器响应 曝光参数变化 输出值变化 增益比例偏移 比值漂移 反馈影响AE决策 这是一个正反馈循环:亮度变化 → AE调整 → 传感器输出变化 → 比值漂移 → AWB偏差 → 影响AE决策

3.3 具体场景分析:为什么低照度下AWB容易飘?

我调试过一款手机摄像头,暗光下拍白墙总是偏蓝。查了半天,发现是B通道的暗电流噪声在作祟。

低照度时,AE会拉高增益(ISO)或延长曝光时间。这时候:

  • B通道暗电流最大:B通道的暗电流噪声通常比R/G高,导致B输出值虚高。
  • AWB统计误判:B/G比值变大,算法以为场景色温偏高(偏蓝),于是拼命压低B增益。
  • 结果:画面反而偏黄了。这就是典型的“过补偿”。

我的调试习惯:在低照度场景下,我会先锁定AWB增益,单独调AE。等AE稳定后,再放开AWB。这样可以避免两者互相拉扯。

3.4 高亮场景的另一个坑:通道饱和

高亮场景下,问题反过来。R通道通常最先饱和,因为传感器的R量子效率往往最高。一旦R饱和:

  • R输出值不再随光强增加
  • R/G比值下降
  • AWB误判为色温偏低(偏红),于是拉高R增益
  • 结果:画面偏红,甚至出现“红脸”现象

我曾经在户外强光下调试人脸,AE一收,人脸就红得像关公。后来发现是R通道饱和导致的AWB误判。

3.5 解耦策略:联合调试的三种方法

既然耦合不可避免,那就得想办法解耦。我总结了三套方案,按效果从低到高排列:

方法 原理 优点 缺点 适用场景
1. 分段锁定法 按亮度区间锁定AWB增益 实现简单,计算量小 过渡区不平滑,可能跳变 低端平台、快速交付
2. 亮度补偿法 建立亮度-增益补偿表 过渡平滑,效果较好 需要大量标定数据 中端平台、量产项目
3. 联合优化法 AE和AWB共用统计信息 效果最优,自适应强 算法复杂,调试周期长 高端平台、旗舰机型

避坑指南:我曾经在分段锁定法上吃过亏。分段边界处(比如从室内到室外),AWB增益突然跳变,画面颜色会“闪”一下。后来加了平滑过渡才解决。如果你用方法1,务必在分段边界做插值。

3.6 实战:瑞芯微平台上的解耦配置

在瑞芯微平台上,我通常这样处理AE与AWB的耦合:

// 示例:RKISP 联合调试配置片段
// 1. 建立亮度-增益补偿表
struct luma_compensation {
    uint16_t luma_level;      // 亮度等级 0-255
    float r_gain_offset;      // R增益偏移
    float b_gain_offset;      // B增益偏移
};

// 2. 典型补偿表(需根据传感器标定)
luma_compensation comp_table[] = {
    {  0, +0.15, -0.10},  // 极暗:补偿B通道暗电流
    { 50, +0.08, -0.05},  // 暗光
    {100, +0.00, +0.00},  // 正常光
    {150, -0.05, +0.08},  // 亮光
    {200, -0.12, +0.15},  // 高亮:补偿R通道饱和
    {255, -0.20, +0.20},  // 极亮
};

// 3. 在AWB统计前应用补偿
void awb_apply_luma_comp(uint16_t luma, float* r_gain, float* b_gain) {
    // 线性插值
    // ... 实际代码略
}

嗯,这里要注意:补偿表不是通用的。每个传感器、每个镜头模组都需要单独标定。我建议你在暗室中,用标准光源(D65、A光源、TL84等)配合灰卡,在不同亮度下采集数据,建立自己的补偿表。

3.7 小结:记住这三句话

  • 耦合是物理规律:传感器非线性决定了AE和AWB必然互相影响。
  • 低照度看暗电流:B通道暗电流是低照度AWB漂移的主因。
  • 高照度看饱和:R通道饱和是高亮场景AWB漂移的主因。