3. AE场景适配策略:背光/顺光/夜景/高动态场景的AE策略
AE(自动曝光)这东西,说白了就是帮摄像头找到那个「不亮不暗刚刚好」的曝光值。但现实世界哪有那么多「刚刚好」?背光人脸黑成剪影、夜景噪点满天飞、高动态场景亮部死白暗部死黑……这些都是AE要解决的硬骨头。
我刚开始调AE那会儿,总觉得算法能自动搞定一切。直到有一次在强背光会议室里,领导的脸完全看不见,我才意识到——场景适配策略才是AE的灵魂。
3.1 四大典型场景的AE策略
3.4.1 背光场景:人脸不能丢
背光,就是主体背后有强光源。人脸在画面中占比小、亮度低,全局测光很容易把背景曝得正常,人脸却黑成一团。
我的策略:
- 人脸优先:检测到人脸时,强制把人脸区域作为曝光参考。权重至少占60%以上。
- 局部提亮:AE计算目标亮度时,对人脸区域的目标亮度提高1~2档EV。
- 防过曝裁剪:背景高亮区域不能完全不管。我会加一个「高亮保护」逻辑——如果背景亮度超过某个阈值(比如220/255),就适当降低整体曝光,避免背景死白。
3.4.2 顺光场景:简单但别翻车
顺光是最「友好」的场景。光线均匀,动态范围小。但越简单越容易大意。
我的策略:
- 全局平均测光:直接上全局平均,简单高效。
- 目标亮度适中:一般设在18%灰附近(约120~128/255)。
- 注意高光溢出:顺光下白色物体容易过曝。我会检查直方图最右端,如果像素堆积超过5%,就适当降0.3~0.5EV。
3.4.3 夜景场景:噪点与亮度的博弈
夜景是AE最难啃的骨头。亮度不够,噪点爆炸;亮度太高,画面假亮、运动模糊。
我的策略:
- 曝光时间优先:先拉长曝光时间(上限30ms~60ms,视帧率而定),再提增益。
- 增益上限控制:模拟增益不超过12dB,数字增益不超过6dB。超过这个范围,噪点就压不住了。
- 目标亮度降低:夜景目标亮度设在80~100/255,比白天低一档。这样能保留夜景氛围,同时减少噪点。
- 防闪烁:50Hz/60Hz光源下,曝光时间必须是10ms的整数倍(50Hz)或8.33ms的整数倍(60Hz)。
3.4.4 高动态场景:HDR是救星
高动态场景(HDR)就是亮的地方特别亮、暗的地方特别暗。比如逆光窗户、日落天空、车灯夜景。单帧曝光根本搞不定。
我的策略:
- 多帧合成HDR:拍2~3帧不同曝光的图像(短曝、中曝、长曝),然后合成。
- AE控制曝光帧:AE负责决定每帧的曝光参数。短曝帧保护高光,长曝帧提亮暗部。
- 动态范围目标:合成后的目标动态范围达到100dB以上。
- 运动物体处理:多帧之间如果有运动,会产生鬼影。我会在AE层面控制帧间隔尽量短(< 16ms),同时配合去鬼影算法。
| 场景类型 | 测光模式 | 目标亮度 | 特殊处理 |
|---|---|---|---|
| 背光 | 人脸/中心加权 | 人脸区域140~160 | 高亮保护 |
| 顺光 | 全局平均 | 120~128 | 防高光溢出 |
| 夜景 | 全局平均+降噪 | 80~100 | 曝光时间优先,增益限制 |
| 高动态 | 多帧HDR | 合成后100~120 | 防鬼影,帧间隔控制 |
3.2 AE权重矩阵与区域测光
全局平均测光太「笨」了。它把画面每个像素一视同仁,但实际场景中,不同区域的重要性完全不同。比如人脸区域的重要性远高于背景。
权重矩阵就是给画面不同区域分配不同的「话语权」。权重高的区域,对最终曝光值的影响更大。
3.2.1 权重矩阵的设计
我一般把画面分成15x15或17x17的网格。每个网格有一个权重值。权重值范围0~15。
// 15x15权重矩阵示例(中心区域权重高)
// 数值越大,权重越高
int weight_matrix[15][15] = {
{1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 2, 2, 1, 1, 1},
{1, 1, 2, 2, 3, 4, 4, 4, 4, 4, 3, 2, 2, 1, 1},
{1, 2, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 2, 1},
{2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 5, 4, 3, 2, 2},
{2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2},
{3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 7, 6, 5, 4, 3},
{3, 4, 5, 6, 7, 8, 9, 9, 9, 8, 7, 6, 5, 4, 3},
{3, 4, 5, 6, 7, 8, 9, 10,9, 8, 7, 6, 5, 4, 3},
{3, 4, 5, 6, 7, 8, 9, 9, 9, 8, 7, 6, 5, 4, 3},
{3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 7, 6, 5, 4, 3},
{2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2},
{2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 5, 4, 3, 2, 2},
{1, 2, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 2, 1},
{1, 1, 2, 2, 3, 4, 4, 4, 4, 4, 3, 2, 2, 1, 1},
{1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 2, 2, 1, 1, 1}
};
这个矩阵的中心权重最高(10),边缘最低(1)。这样画面中心的主体对曝光的影响最大。
3.2.2 区域测光的计算
区域测光的最终曝光值计算公式很简单:
// 加权平均亮度计算
float total_weight = 0;
float weighted_sum = 0;
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 15; j++) {
float block_luma = get_block_luma(i, j); // 获取该区域平均亮度
weighted_sum += block_luma * weight_matrix[i][j];
total_weight += weight_matrix[i][j];
}
}
float target_luma = weighted_sum / total_weight;
嗯,这里要注意:权重矩阵不是一成不变的。检测到人脸时,我会动态调整权重——把人脸所在区域的权重提高3~5倍。
3.3 AE Flicker抑制
Flicker(闪烁)是AE最烦人的问题之一。在50Hz或60Hz的交流光源下,如果曝光时间不是光源周期的整数倍,画面就会出现明暗交替的条纹或闪烁。
为什么会这样?
交流光源的亮度以100Hz(50Hz电源)或120Hz(60Hz电源)的频率波动。如果曝光时间不是波动周期的整数倍,每帧捕获的光能量就不一致,导致帧间亮度跳变。
3.3.1 Flicker检测
我一般用两种方法检测Flicker:
- 帧间亮度波动检测:连续采集N帧的亮度值,计算方差。如果方差超过阈值,说明有Flicker。
- 频域分析:对亮度序列做FFT,看100Hz/120Hz分量是否突出。
3.3.2 Flicker抑制策略
策略一:曝光时间锁定
最简单粗暴的方法——把曝光时间锁定为光源周期的整数倍。
// 50Hz光源:周期10ms,曝光时间必须是10ms的整数倍
// 60Hz光源:周期8.33ms,曝光时间必须是8.33ms的整数倍
int flicker_free_exposure(int target_exposure_us, int freq_hz) {
int period_us = (freq_hz == 50) ? 10000 : 8333;
int n = target_exposure_us / period_us;
if (n < 1) n = 1;
return n * period_us;
}
策略二:增益补偿
如果曝光时间不能锁定(比如夜景需要长曝光),可以用增益做动态补偿。检测到亮度波动时,实时调整增益来抵消波动。
策略三:帧率调整
调整帧率,使帧间隔是光源周期的整数倍。比如50Hz光源下,帧率设为25fps或50fps。
| 光源频率 | 周期 | 安全曝光时间(整数倍) | 安全帧率 |
|---|---|---|---|
| 50Hz | 10ms | 10ms, 20ms, 30ms, 40ms... | 25fps, 50fps |
| 60Hz | 8.33ms | 8.33ms, 16.67ms, 25ms, 33.33ms... | 30fps, 60fps |
3.4 知识体系总览
下面这张图总结了本章的核心逻辑:
3.5 本章小结
AE场景适配,说白了就是「看人下菜碟」。背光场景保人脸,顺光场景求稳定,夜景场景压噪点,高动态场景上HDR。权重矩阵让测光更智能,Flicker抑制让画面不闪。
我个人觉得,AE调试最考验的不是算法能力,而是对场景的理解。你想想看,同一个算法在不同场景下表现天差地别。所以我的建议是:多收集真实场景数据,多分析失败案例,慢慢积累自己的「场景库」。