3、自动对焦(AF)基础:对焦评价函数与搜索策略
自动对焦,说白了就是让镜头自己找到最清晰的那个位置。你想想看,手机拍照时从模糊变清晰的那一瞬间,背后就是 AF 算法在干活。我做了这么多年 ISP,发现很多工程师把 AF 想得太简单——不就是找最大值吗?其实坑多得很。
3.1 对焦评价函数:怎么判断“清晰”?
相机自己又没长眼睛,它怎么知道画面清不清晰?靠的是评价函数。目前主流的有两种:对比度检测和相位差检测。我习惯把它们比作“瞎子摸象”和“一眼看穿”。
3.1.1 对比度检测(Contrast Detection AF)
原理很简单:图像越清晰,相邻像素的亮度差异越大。说白了就是算梯度。常用的算子有 Sobel、Laplacian,还有基于频域的 FFT 方法。
核心公式(Tenengrad 梯度函数):
F(I) = Σ_x Σ_y [ G_x(x,y)² + G_y(x,y)² ]
其中 G_x、G_y 是 Sobel 算子在水平和垂直方向的梯度值。
我在项目中遇到过一个问题:用 Tenengrad 函数对焦时,画面里有大面积纯色区域(比如白墙),梯度值几乎为零,算法直接“死机”。后来我加了一个区域权重策略——只对画面中心 60% 区域做梯度计算,效果好了很多。
| 评价函数 | 计算量 | 抗噪性 | 适用场景 |
|---|---|---|---|
| Tenengrad(Sobel) | 中 | 中 | 通用场景,纹理丰富 |
| Laplacian | 低 | 差 | 快速对焦,噪声低 |
| FFT 高频能量 | 高 | 好 | 静态场景,精度要求高 |
| Brenner 梯度 | 极低 | 中 | 嵌入式实时系统 |
避坑指南:我曾经在低光照场景下用 Laplacian 算子,结果噪声被当成“清晰度”放大,对焦直接偏到噪声上。后来我加了高斯预滤波,才把这个问题压下去。记住:评价函数对噪声非常敏感,预处理不能省。
3.1.2 相位差检测(Phase Detection AF)
相位差检测就聪明多了。它不需要来回移动镜头找最大值,而是通过传感器上的专用像素(PD 像素)直接算出离焦方向和距离。我刚开始接触 PDAF 时觉得这东西很神奇——它怎么知道该往哪边转?
原理是这样的:PD 像素成对出现,一个遮左半瞳,一个遮右半瞳。合焦时两个信号完全对齐;离焦时信号会错位。错位的方向和大小,直接对应镜头的移动方向和步数。
个人经验:PDAF 在光线充足时又快又准,但一到暗光环境,PD 像素的信噪比急剧下降,相位差计算会飘。我建议在低照度场景下回退到 CDAF,或者做混合加权。
3.2 AF 的搜索策略:怎么找到最优点?
有了评价函数,下一步就是怎么找最大值。搜索策略直接决定对焦速度和稳定性。我见过不少方案,总结下来就三种:全局搜索、爬山搜索、混合搜索。
3.2.1 全局搜索(Global Search)
最简单粗暴的方法:从最近端扫到最远端,记录每个位置的评价值,最后取最大值对应的位置。优点是保证找到全局最优,缺点是慢——扫一遍可能要几百毫秒。
- 优点:不会陷入局部极值,适合静态场景
- 缺点:速度慢,功耗高,不适合视频
- 适用:拍照场景的首次对焦,或者校准阶段
我记得有一次做安防摄像头项目,客户要求开机后 1 秒内完成对焦。全局搜索根本来不及,后来我改成了粗扫+精扫的两段式,才勉强达标。
3.2.2 爬山搜索(Hill Climbing Search)
这是最常用的方法。算法先朝一个方向移动镜头,如果评价值上升就继续,下降就反向。直到评价值开始下降,就认为找到了峰值。
爬山搜索伪代码:
step = initial_step
direction = +1
while step > min_step:
move_lens(direction * step)
new_val = evaluate_sharpness()
if new_val > last_val:
last_val = new_val
step = step * 1.2 // 加速
else:
direction = -direction
step = step * 0.5 // 减速
// 直到步长小于阈值
爬山搜索的问题很明显——容易陷入局部极值。比如画面里有前景清晰、背景模糊的情况,算法可能停在第一个小峰上。我建议在爬山前先做一次粗扫,确定大致范围,再爬山精搜。
我曾经踩过的坑:爬山搜索的步长设置很关键。步长太大容易跳过峰值,步长太小又太慢。我一般用自适应步长:初始步长设大(比如 20 步),接近峰值时自动缩小到 1-2 步。另外,一定要加一个“回退机制”——如果发现评价值突然暴跌,说明可能跳过了峰值,要退回去重新搜。
3.2.3 混合搜索(Hybrid Search)
混合搜索就是把全局搜索和爬山搜索结合起来。先用大步长全局粗扫,找到评价值最高的几个候选区间,再在这些区间内做爬山精搜。这是目前手机 ISP 的主流方案。
| 搜索策略 | 速度 | 精度 | 抗局部极值 | 典型场景 |
|---|---|---|---|---|
| 全局搜索 | 慢 | 高 | 强 | 首次对焦、校准 |
| 爬山搜索 | 快 | 中 | 弱 | 追焦、视频 |
| 混合搜索 | 中 | 高 | 强 | 通用场景 |
3.3 AF 的典型场景与挑战
理论说完了,咱们聊聊实战。AF 在实际场景中会遇到各种麻烦,我挑几个典型的说说。
3.3.1 低光照场景
光线暗了,图像信噪比下降,评价函数的值会被噪声淹没。我建议的做法是:先做多帧叠加降噪,再算梯度;或者切换到 PDAF 模式(如果传感器支持)。
3.3.2 低对比度场景
比如拍白墙、蓝天、雾景。梯度值几乎为零,评价函数失效。这时候 PDAF 也救不了——因为 PD 像素也需要纹理。我的经验是:检测到对比度过低时,直接切到预设的“无穷远”对焦位置,或者用激光/ToF 辅助测距。
3.3.3 运动场景
拍跑步的小孩、飞行的鸟。AF 还没对上焦,目标已经跑了。这时候需要预测性对焦——根据目标运动轨迹提前计算镜头位置。我做过一个方案:结合陀螺仪数据和光流法,预测下一帧的合焦位置,效果还不错。
3.3.4 微距与无穷远切换
从拍近处的花切换到远处的山,镜头行程很长。如果直接用爬山搜索,可能花好几秒。我建议用“双峰检测”——如果评价值曲线出现两个明显的峰,说明有前景和背景,优先对焦到用户点击的区域。
我的一个实用技巧:在 ISP 里加一个“场景分类器”,提前判断当前是低光、运动还是微距场景,然后动态切换 AF 策略。这个分类器不需要很复杂,用几个简单的统计特征(平均亮度、运动向量幅值、对比度方差)就能做到 90% 以上的准确率。
3.4 AF 评价与搜索策略知识图谱
下面这张图把 AF 的核心模块和流程串起来了。你可以看到评价函数和搜索策略是怎么配合的,以及不同场景下该怎么选。
3.5 小结
自动对焦这件事,说难不难,说简单也不简单。评价函数是基础,搜索策略是手段,场景适配是灵魂。我个人觉得,做 AF 最重要的不是把某个算法做到极致,而是学会在不同场景下灵活切换。你想想看,一个算法打天下,在 ISP 这行是行不通的。
嗯,这一章就到这里。记住我提到的那些坑——低光照的噪声、爬山搜索的局部极值、运动场景的预测——这些在后面的章节里还会反复出现。