AF算法核心:对焦窗口选择与爬山策略
这一章,我们聊聊AF算法里最核心的两个东西——对焦窗口(ROI)怎么选,以及爬山算法到底怎么爬。这两个点,说白了就是AF的“眼睛”和“腿”。眼睛看不准,腿再快也没用;腿不会走,眼睛再亮也白搭。
我在高通的几个项目里,见过太多因为ROI选错导致对焦失败的案例。嗯,咱们一个一个来拆。
一、对焦窗口(ROI)选择策略
ROI,Region of Interest,就是告诉ISP:“你只算这一块区域的清晰度,别的地方别管。” 为什么要有ROI?你想想看,如果整帧图像都参与计算,背景的纹理、天空的渐变都会干扰对焦。尤其是拍人像时,背景虚化,背景的对比度反而可能比人脸高,算法就会往背景跑——这就是典型的“拉风箱”。
1.1 固定中心ROI
最简单粗暴的方式。取画面中心一块矩形区域,比如宽高各占画面的30%。
- 优点:实现简单,计算量小。
- 缺点:主体不在中心时,直接翻车。
我记得早期功能机时代,基本都是固定中心ROI。用户得先把主体挪到中间,半按快门锁定,再构图。现在谁还这么干?
1.2 多区域加权ROI
把画面分成3x3或5x5的网格,每个格子给一个权重。中心区域权重高,边缘权重低。这样即使主体稍微偏离中心,也能被覆盖到。
| 网格位置 | 权重系数 | 说明 |
|---|---|---|
| 中心1格 | 0.4 | 主体最可能的位置 |
| 中间环8格 | 0.4 | 次重要区域 |
| 边缘16格 | 0.2 | 背景干扰,权重压低 |
这种策略在预览场景下够用,但遇到人脸在边缘、或者主体很小的情况,还是不够。
1.3 人脸/物体检测ROI
这才是现代AF的主流做法。通过Face Detection或Object Detection拿到主体坐标,然后动态生成ROI。
具体做法:
- 从3A统计模块获取人脸坐标 (x, y, w, h)。
- 计算ROI中心:center_x = x + w/2, center_y = y + h/2。
- 计算ROI尺寸:roi_w = w * 0.7, roi_h = h * 0.7。
- 将ROI坐标写入ISP的统计寄存器。
// 伪代码:人脸ROI生成
void generateFaceROI(FaceRect face, ROI *roi) {
roi->center_x = face.x + face.width / 2;
roi->center_y = face.y + face.height / 2;
roi->width = face.width * 0.7; // 缩窄20%
roi->height = face.height * 0.7; // 缩窄20%
// 限制ROI不超出画面边界
clampROI(roi, sensor_width, sensor_height);
}
1.4 触控对焦ROI
用户点哪里,ROI就放哪里。这个逻辑简单,但有个坑——用户点的位置可能刚好是纯色区域(比如白墙),对比度为零。这时候算法必须做fallback。
二、爬山算法(Hill Climbing)详解
爬山算法,名字很形象。你想象自己站在一个山谷里,蒙着眼,想走到最高点。你只能靠脚底的感觉——哪边地势高,就往哪边迈一步。AF的爬山算法就是这个逻辑:通过移动镜头,找到对比度最大的位置。
2.1 基本原理
AF的“地势”就是对比度值(Focus Value, FV)。镜头在不同位置,FV不同。理想情况下,FV曲线是一个单峰函数,峰值对应最清晰的位置。
算法步骤:
- 初始化:镜头从当前位置开始,设定步长。
- 采样:移动镜头,采集当前FV。
- 比较:如果FV上升,继续同方向移动;如果FV下降,反转方向并减小步长。
- 终止:当步长小于阈值,或者FV变化小于阈值,认为到达峰值。
2.2 步长策略
步长太大,容易越过峰值(overshoot);步长太小,对焦太慢。我一般用自适应步长:
- 粗搜索阶段:大步长(比如每次移动镜头行程的10%),快速找到峰值附近区域。
- 精搜索阶段:小步长(比如每次移动1%-2%),精确锁定峰值。
高通平台里,步长通常映射到DAC Code或者镜头位置。举个例子:
// 自适应步长示例
if (fv_delta > threshold_high) {
step_size = coarse_step; // 大步前进
} else if (fv_delta > threshold_low) {
step_size = fine_step; // 小步逼近
} else {
// 到达峰值,停止
stop_search();
}
2.3 全局搜索 vs 局部搜索
这是面试常问的问题,也是实际项目中必须做的选择。
| 对比项 | 全局搜索 | 局部搜索 |
|---|---|---|
| 搜索范围 | 整个镜头行程(macro到infinity) | 当前焦点附近的小范围 |
| 耗时 | 长,通常200-500ms | 短,通常50-100ms |
| 适用场景 | 开机首次对焦、场景突变 | 连续AF、追踪AF |
| 风险 | 可能被局部峰值欺骗 | 可能丢失主体(跑出范围) |
我个人的习惯是:开机或场景切换时,做一次全局搜索,找到全局峰值。之后进入局部搜索模式,只在峰值附近小范围跟踪。如果连续几次局部搜索都找不到峰值(FV持续下降),就触发一次全局搜索重新定位。
三、SVG:AF对焦策略与搜索流程
下面这张图,我把ROI选择、全局搜索、局部搜索、爬山算法的关系画了出来。你看一眼就能明白整个AF的决策链路。
四、实战中的坑与对策
讲完理论,说几个我在项目中踩过的坑。
4.1 局部峰值陷阱
爬山算法最大的敌人就是局部峰值。比如你拍一个隔着纱窗的物体,纱窗的纹理可能形成一个局部峰值,算法停在那里,真正的主体反而虚了。
对策:我习惯在爬山过程中记录“历史最高FV”和对应的镜头位置。如果最终停下的位置FV低于历史最高值的90%,就强制跳转到历史最高位置重新确认。
4.2 低对比度场景
晚上拍纯色墙壁,FV曲线几乎是平的。爬山算法会随机游走,找不到峰值。
对策:检测FV的峰均比(Peak-to-Average Ratio)。如果比值小于1.2,说明场景对比度太低,直接切换到固定焦距(比如hyperfocal distance),或者启用激光/ToF辅助对焦。
4.3 运动主体
如果主体在动,爬山算法还没爬到峰值,主体已经跑了。
对策:结合运动检测(Motion Detection)。检测到运动时,增大步长,减少采样次数,用“粗定位+预测”代替精确爬山。高通平台里有专门的Motion Vector统计模块,可以拿来用。
五、小结
ROI选择和爬山算法,是AF的两条腿。ROI选对了,爬山才有意义;爬山算法稳健了,ROI才能发挥价值。实际项目中,没有一套策略能打天下。你需要根据场景、硬件、用户行为动态调整。
嗯,这一章的内容就到这里。记住:多测、多调、多踩坑,AF的功力就是这么练出来的。