4. AE工程实现
AE(自动曝光)这东西,说简单也简单,说复杂也复杂。简单版本就是调一下曝光时间、增益、光圈,让画面亮度合适。但真正落地到芯片上,你会发现一堆坑等着你踩。
我个人习惯把AE分成四个核心模块来看:状态机、收敛曲线、防闪烁、以及与AWB的交互。今天咱们一个一个聊。
4.1 AE算法状态机设计
AE状态机,说白了就是告诉芯片“你现在该干嘛”。我见过不少团队,上来就写一个巨大的if-else,结果调试的时候改一处崩三处。嗯,这里还是老老实实用状态机。
我常用的AE状态机分四个阶段:
| 状态 | 触发条件 | 行为 |
|---|---|---|
| AE_IDLE | 上电/复位/场景切换 | 等待触发,不调整参数 |
| AE_RUNNING | 帧同步信号到来 | 计算当前亮度,调整曝光参数 |
| AE_CONVERGED | 亮度误差小于阈值 | 停止大幅调整,进入微调模式 |
| AE_LOCKED | 用户锁定/场景稳定 | 冻结参数,只做统计不调整 |
你想想看,为什么要有AE_LOCKED?我在项目中遇到过,用户拍一张照片,结果AE还在那里来回跳,画面忽明忽暗,用户体验极差。所以拍照前必须锁住AE。
关键点:状态切换的时机要精确到帧边界。我建议在VSYNC(帧同步)中断里做状态判断,不要在ISP pipeline中间乱切,否则会出现半帧参数不一致的问题。
4.2 AE收敛曲线平滑
收敛曲线平滑,这活儿看着不起眼,但做不好画面就会“呼吸”。什么叫呼吸?就是画面一亮一暗,像有人在喘气。
我曾经在一个低端平台上调试,AE收敛步长设得太大,结果画面从暗到亮直接“闪”过去,用户投诉说“这摄像头是不是坏了”。后来我加了一个指数平滑滤波器,问题就解决了。
平滑的核心公式其实很简单:
// 指数平滑,alpha 取值 0.1 ~ 0.3
target_luma = get_target_luma(scene_mode);
current_luma = get_current_luma();
error = target_luma - current_luma;
// 平滑后的调整量
smooth_delta = error * alpha;
// 更新曝光参数
exposure_time += smooth_delta * gain_factor;
这里alpha怎么选?我个人的经验是:
- 场景切换时:alpha取0.3~0.5,快速响应
- 正常跟踪时:alpha取0.1~0.2,平滑过渡
- 接近收敛时:alpha取0.05,防止过冲
小技巧:我习惯把alpha做成动态的,根据当前误差大小自动调整。误差大时alpha大,误差小时alpha小。这样既保证了响应速度,又避免了过冲。
4.3 AE防闪烁(Flicker)处理
防闪烁,这是AE落地里最头疼的问题之一。说白了,就是灯光在闪,你的摄像头也在闪,两个频率对不上,画面就出现明暗条纹。
为什么会这样?因为市电是50Hz或60Hz的交流电,灯光亮度会以100Hz或120Hz的频率波动。如果你的曝光时间不是这个周期的整数倍,就会拍到亮暗条纹。
我常用的防闪烁策略分两步:
- 检测闪烁频率:通过统计相邻帧的亮度差异,判断是50Hz还是60Hz环境
- 锁定曝光时间:将曝光时间限制为闪烁周期的整数倍
举个例子,50Hz环境下,闪烁周期是10ms(100Hz的两倍)。那么曝光时间只能取10ms、20ms、30ms……不能取15ms或25ms。
注意:锁定曝光时间后,AE的调节能力会受限。比如你想从10ms调到15ms,但15ms被禁用了,只能跳到20ms。这时候画面亮度会跳变。我建议在防闪烁模式下,用增益来微调亮度,不要只靠曝光时间。
我曾经在一个项目中,防闪烁模式打开后,画面亮度跳变严重。后来我加了一个“增益补偿”逻辑:当曝光时间跳变时,同步调整增益,让亮度变化平滑过渡。效果好了很多。
4.4 AE与AWB交互
AE和AWB(自动白平衡)是ISP里最“暧昧”的两个模块。为什么这么说?因为它们互相影响。
你想想看,AE调整曝光时间,会影响图像的色彩亮度;AWB调整白平衡增益,会影响图像的亮度统计。如果两个模块各调各的,很容易出现“震荡”——AE调亮了,AWB觉得色温变了,又去调增益,结果AE又觉得亮度变了……
我建议的交互策略是:
| 场景 | AE行为 | AWB行为 |
|---|---|---|
| 场景切换 | 快速收敛,允许大调整 | 冻结AWB,等待AE稳定 |
| 正常跟踪 | 平滑调整,步长较小 | 正常调整,但限制增益变化率 |
| 低照度 | 优先保证亮度,允许高增益 | 降低AWB灵敏度,防止偏色 |
| 高色温变化 | 保持曝光稳定 | 快速响应,但限制增益上限 |
我个人习惯的做法是:在AE收敛之前,AWB先“等一等”。等AE稳定了,AWB再开始调整。这样能避免两个模块互相打架。
核心原则:AE和AWB的调整周期要错开。比如AE每帧调整,AWB每两帧调整一次。或者AE调整后,AWB延迟一帧再响应。这个“时间差”能解决大部分震荡问题。
4.5 AE整体流程图
下面这张图是我自己总结的AE整体流程,包含了状态机、收敛、防闪烁和AWB交互。你可以把它当作一个参考框架。
这张图里,我把AE的核心流程串起来了。从帧同步开始,经过状态机判断,然后做亮度统计、防闪烁检测、收敛平滑,最后与AWB协调后输出参数。每一步都有它的作用,缺一不可。
落地建议:如果你刚开始做AE,建议先把状态机和收敛平滑做好。这两个是基础,基础打牢了,防闪烁和AWB交互才能稳定。我见过太多团队一上来就搞防闪烁,结果基础没做好,越调越乱。
好了,AE工程实现的这几个核心模块,今天就聊到这儿。每个模块都有很多细节,但掌握了这些核心思路,你至少不会走偏。下次调试AE的时候,记得先看看状态机对不对,再检查收敛曲线平不平,最后再处理防闪烁和AWB交互。按这个顺序来,能省不少时间。