3. 搜索策略与爬山算法:全局搜索、爬山算法原理、步长自适应策略、安防场景下的搜索陷阱
调AF算法,说白了就是在找一个最优解。你想想看,镜头要对准目标,焦距要清晰,这本质上就是一个搜索问题。我们得在无数个可能的焦距位置里,找到那个让图像最清晰的点。
这一章,我们就来聊聊搜索策略。我会结合自己在安防项目里踩过的坑,把全局搜索、爬山算法、步长自适应这些概念讲透。
3.1 全局搜索:最笨但最可靠的方法
全局搜索,也叫穷举搜索。它的思路很简单:把整个搜索空间遍历一遍,找到最优值。
在AF里,就是把镜头从最近端推到最远端,每走一步算一次清晰度评价函数值,最后挑出最大值对应的位置。
核心特点:
- 优点:一定能找到全局最优解,不会陷入局部极值
- 缺点:速度极慢,不适合实时场景
我记得有一次做固定枪机的调试,场景很简单,背景单一。我直接用全局搜索做对比实验,结果一个完整的对焦周期花了将近3秒。这在安防场景里是完全不能接受的——你想想看,如果有人在画面里走动,3秒后才对上焦,关键信息早丢了。
所以,全局搜索在实际产品里很少单独使用。它更多是作为标定工具或参考基准。比如,我们在实验室里用全局搜索跑一遍,记录下每个位置的清晰度值,然后拿这个数据去验证其他算法的效果。
| 对比项 | 全局搜索 | 爬山算法 |
|---|---|---|
| 搜索速度 | 慢(遍历全部) | 快(定向搜索) |
| 全局最优 | 保证 | 不保证 |
| 适用场景 | 标定、离线分析 | 实时对焦 |
| 计算量 | 大 | 小 |
3.2 爬山算法原理:像爬山一样找峰值
爬山算法,名字很形象。你想象一下,你在一个山谷里,目标是爬到最高的山顶。你只能感知脚下的坡度,然后朝着坡度最陡的方向走一步。走一步,停一下,再判断方向,再走一步。直到你发现无论往哪个方向走,高度都在下降,那你就认为到山顶了。
在AF里,这个「高度」就是清晰度评价函数值,「方向」就是镜头的移动方向。
算法流程很简单:
- 初始化:镜头停在当前位置,计算清晰度值
F0 - 试探:向一个方向移动一步,计算新位置的清晰度值
F1 - 判断:
- 如果
F1 > F0,说明方向正确,继续向该方向移动 - 如果
F1 < F0,说明方向错了,反向移动 - 如果
F1 ≈ F0,可能到了平坦区域,需要特殊处理
- 如果
- 重复步骤2-3,直到满足停止条件
// 伪代码:基础爬山算法
int currentPos = getCurrentLensPosition();
float currentSharpness = calcSharpness(currentPos);
while (true) {
int nextPos = currentPos + stepSize;
float nextSharpness = calcSharpness(nextPos);
if (nextSharpness > currentSharpness) {
// 方向正确,继续前进
currentPos = nextPos;
currentSharpness = nextSharpness;
} else {
// 方向错误,反向搜索
stepSize = -stepSize;
nextPos = currentPos + stepSize;
nextSharpness = calcSharpness(nextPos);
if (nextSharpness > currentSharpness) {
currentPos = nextPos;
currentSharpness = nextSharpness;
} else {
// 两边都下降,到达峰值
break;
}
}
}
嗯,这里要注意。基础爬山算法有个致命问题:它只能找到局部最优。如果清晰度曲线有多个峰值,它很可能停在第一个峰上,而不是最高的那个。
3.3 步长自适应策略:让算法更聪明
固定步长的爬山算法,就像你闭着眼睛走路,每一步都迈一样大。步子小了,走得慢;步子大了,容易跨过山顶。
我个人习惯用步长自适应策略。核心思路是:根据当前「坡度」动态调整步长。
- 坡度陡(清晰度变化大):用大步长,快速接近峰值
- 坡度缓(清晰度变化小):用小步长,精细定位
具体实现方式有很多种,我常用的是比例自适应:
// 步长自适应策略
float adaptiveStep(float currentSharpness, float prevSharpness, float baseStep) {
float delta = abs(currentSharpness - prevSharpness);
float ratio = delta / currentSharpness; // 变化率
if (ratio > 0.1) {
// 变化剧烈,用大步
return baseStep * 2;
} else if (ratio > 0.02) {
// 中等变化,用正常步长
return baseStep;
} else {
// 变化平缓,用小步精细搜索
return baseStep * 0.5;
}
}
我的经验:步长自适应的阈值需要根据镜头特性调整。我一般会在实验室里先跑一遍全行程,记录下清晰度曲线的斜率分布,然后根据统计结果设定阈值。不同镜头的曲线特性差异很大,不能一套参数打天下。
3.4 安防场景下的搜索陷阱
理论讲完了,我们来聊聊实战。安防场景和实验室环境完全是两码事。我踩过的坑,说出来都是泪。
3.4.1 低光照陷阱
低光照下,图像信噪比急剧下降。清晰度评价函数的值会变得非常「毛躁」——相邻位置的清晰度值可能因为噪声而剧烈波动。
这会带来什么问题?
- 爬山算法会误判方向:明明在往正确的方向走,但噪声让清晰度值突然下降,算法以为到顶了
- 或者更糟:算法在平坦区域来回震荡,永远停不下来
我曾经在调试一个夜间监控项目时,发现算法在低光照下频繁误触发。后来分析数据才发现,清晰度曲线的信噪比已经低到无法区分真实变化和噪声了。
避坑指南:低光照下,建议先做图像预处理(如降噪),或者改用对噪声更鲁棒的评价函数(如基于梯度的函数)。另外,可以设置一个「最小变化阈值」——只有当清晰度变化超过这个阈值时,才认为方向有效。
3.4.2 运动模糊陷阱
安防场景里,运动物体是常态。行人走过、车辆驶过,都会在画面里留下运动模糊。
运动模糊对AF的影响很隐蔽。它会让清晰度评价函数出现假峰值。比如,一个运动物体刚好在某个位置停了一下,那个位置的清晰度值会突然升高,算法以为找到了焦点,实际上只是运动模糊的干扰。
我记得有一次做交通卡口的项目,算法总是在车辆经过时误对焦。后来分析发现,车辆在画面中短暂停留时,车身的纹理让清晰度值飙升,算法就被「骗」过去了。
解决方案:
- 引入时域滤波:连续多帧的清晰度值做平均,消除瞬时干扰
- 增加运动检测:检测到画面中有运动物体时,暂停AF或降低权重
- 使用多区域评价:不只看全图,而是分区域计算,避免局部运动干扰全局
3.4.3 局部极值陷阱
安防场景的清晰度曲线往往不是单峰的。比如,画面中有玻璃反光、灯光、或者纹理重复的区域,都可能产生多个峰值。
爬山算法一旦陷入局部极值,就再也出不来了。
我的做法是:多起点搜索。在搜索空间里选几个不同的起始位置,分别跑爬山算法,最后取最优的那个结果。虽然增加了计算量,但能有效避免陷入局部极值。
3.5 知识结构图:搜索策略全景
下面这张图,把本章的核心知识点串起来了。你可以看到全局搜索和爬山算法的关系,以及步长自适应和搜索陷阱在整个体系中的位置。
3.6 本章小结
搜索策略是AF算法的骨架。全局搜索可靠但慢,爬山算法快但容易陷入局部最优。步长自适应是让爬山算法更聪明的关键技巧。
但真正决定算法能不能用的,是你对安防场景的理解。低光照、运动模糊、局部极值——这些陷阱在实验室里很难复现,但在现场一定会遇到。
我个人建议,在开发阶段就引入这些场景的模拟数据,而不是等到现场调试才发现问题。嗯,经验之谈,希望对你有帮助。