3. 全局搜索:遍历搜索、斐波那契搜索、黄金分割搜索
全局搜索,说白了就是「地毯式排查」。当镜头离焦点很远,或者场景太复杂时,局部搜索很容易掉进坑里。这时候,你得先做一轮全局扫描,找到大致位置,再交给精细算法。
我刚开始做对焦算法时,总觉得全局搜索太笨——费时间、费算力。后来在户外强光下拍树叶,局部搜索直接卡在局部极值上,画面糊成一团。嗯,从那以后,我再也不敢小看全局搜索了。
3.1 遍历搜索:最笨但最可靠
遍历搜索的思路很简单:把整个对焦范围分成 N 步,每一步拍一张图,算清晰度,然后挑最大值。就像你在停车场找车,一辆一辆看过去,总能找到。
步长 = (对焦范围上限 - 下限) / 步数
清晰度值 = 拉普拉斯方差 / 索贝尔梯度 / Brenner 梯度...
我在项目中遇到过一个问题:步长设太大,容易漏掉焦点;步长设太小,时间又受不了。后来我总结了一个经验——
| 场景类型 | 推荐步数 | 单步耗时(ms) | 总耗时(ms) |
|---|---|---|---|
| 低倍镜(10x) | 20~30 | 30~50 | 600~1500 |
| 中倍镜(40x) | 40~60 | 50~80 | 2000~4800 |
| 高倍镜(100x) | 80~120 | 80~120 | 6400~14400 |
3.2 斐波那契搜索:数学家的优雅解法
斐波那契搜索,本质上是一种「不对称二分法」。它利用斐波那契数列来划分搜索区间,每次只比较两个点,就能缩小范围。你想想看,这比遍历搜索聪明多了——不用拍那么多张图。
为什么用斐波那契数列?因为它的比值趋近黄金分割(0.618),但每一步都是整数步长,适合离散的电机控制。我个人习惯在步数较少(< 50)时用斐波那契,效果比黄金分割更稳定。
// 斐波那契搜索伪代码
function fibonacciSearch(low, high, n):
fib = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
k = findK(fib, n) // 找到大于等于 n 的斐波那契数索引
x1 = low + fib[k-2] * (high - low) / fib[k]
x2 = low + fib[k-1] * (high - low) / fib[k]
while k > 1:
if clarity(x1) > clarity(x2):
high = x2
x2 = x1
x1 = low + fib[k-2] * (high - low) / fib[k]
k = k - 1
else:
low = x1
x1 = x2
x2 = low + fib[k-1] * (high - low) / fib[k]
k = k - 1
return (low + high) / 2
3.3 黄金分割搜索:连续域的王者
黄金分割搜索和斐波那契很像,区别在于它用固定的 0.618 比例。说白了,就是每次在区间内取两个点,位置在 0.382 和 0.618 处,然后比较、缩小区间。
我记得有一次做显微镜自动对焦,电机步进精度是 0.1μm,斐波那契的整数步长反而限制了精度。换成黄金分割后,收敛速度更快,而且能直接输出浮点位置。
| 特性 | 遍历搜索 | 斐波那契搜索 | 黄金分割搜索 |
|---|---|---|---|
| 搜索方式 | 等步长扫描 | 不对称二分 | 固定比例二分 |
| 收敛速度 | O(N) | O(log N) | O(log N) |
| 适用场景 | 初始搜索、多峰 | 离散步进电机 | 连续运动、高精度 |
| 抗噪能力 | 强(可多次采样) | 中 | 中 |
| 实现复杂度 | 低 | 中 | 低 |
- 第一次对焦:用遍历搜索(20~30步),找到大致位置
- 第二次精搜:用黄金分割搜索(10~15次迭代),收敛到亚微米级
- 如果电机是步进式:换成斐波那契搜索,避免浮点舍入误差
3.4 三种搜索策略的对比与选择
你可能会问:到底该用哪个?其实没有银弹。我一般这样选——
- 场景一: 第一次对焦,或者场景变化剧烈 → 遍历搜索(稳)
- 场景二: 已知大致位置,电机步进精度有限 → 斐波那契搜索(准)
- 场景三: 连续运动控制,需要高精度浮点输出 → 黄金分割搜索(快)
为什么会这样?因为遍历搜索不怕多峰,斐波那契适合离散控制,黄金分割在连续域里效率最高。你想想看,如果场景里既有玻璃反光又有运动物体,直接上黄金分割,大概率会卡在局部极值上。
最后说一句:全局搜索不是终点,而是起点。找到大致位置后,我会立刻切换到爬山算法或曲线拟合,把精度推到极限。这三种搜索策略,说白了就是给你一个「靠谱的初始值」——没有它,后面的精细算法全是空中楼阁。