1. 自动对焦基础:对焦原理、评价函数、搜索策略概述

大家好,我是老张。做图像处理这些年,我调试过最多的模块就是自动对焦。说实话,很多人觉得对焦不就是「把图像变清楚」嘛,但真正深入进去,你会发现这里面的门道比想象中多得多。

这一章,我们先打好地基。把对焦原理、评价函数、搜索策略这三个核心概念讲透。嗯,都是干货,咱们一个一个来。

1.1 对焦原理:镜头到底在干什么?

自动对焦的本质,说白了就是调整镜头位置,让被摄物体在传感器上清晰成像。你想想看,镜头其实就是一个可以前后移动的透镜组。当物体正好落在焦平面上时,图像最清晰;偏离了,图像就模糊。

为什么会这样?因为光线通过透镜后,会汇聚到一个点。如果传感器刚好在这个点上,每个像素接收到的光就是「点对点」的,画面自然锐利。如果传感器偏前或偏后,一个点就会扩散成一个圆斑——我们管它叫弥散圆。弥散圆越大,图像越糊。

核心结论:对焦过程 = 寻找镜头位置,使得弥散圆直径最小。

我在项目中遇到过一种情况:镜头模组有公差,同一个对焦指令在不同设备上实际移动距离不一样。所以,光知道理论位置没用,必须靠图像反馈来闭环校准。

1.2 评价函数:怎么判断图像清不清晰?

机器不像人眼,看一眼就知道「嗯,这张清楚了」。它需要一个数学指标——对焦评价函数,来量化图像的清晰度。

常用的评价函数,我按原理分成三类:

类别 代表算法 核心思想 我的评价
梯度类 Tenengrad、Laplacian、Brenner 清晰图像边缘锐利,梯度值大 最常用,响应快,适合大多数场景
频域类 FFT高频能量、DCT系数 清晰图像高频分量多 精度高,但计算量大,实时性差
统计类 方差、熵、自相关 清晰图像像素分布更分散 鲁棒性好,但对纹理敏感度一般

我个人习惯首选梯度类。为什么?因为它在计算效率和灵敏度之间取得了很好的平衡。给你看一段我常用的 Tenengrad 实现:

// 简化版 Tenengrad 评价函数
float computeTenengrad(uint8_t* img, int w, int h) {
    float sum = 0.0f;
    // Sobel 水平梯度
    int8_t sobelX[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
    // Sobel 垂直梯度
    int8_t sobelY[9] = {-1, -2, -1, 0, 0, 0, 1, 2, 1};
    
    for (int y = 1; y < h-1; y++) {
        for (int x = 1; x < w-1; x++) {
            int gx = 0, gy = 0;
            for (int ky = -1; ky <= 1; ky++) {
                for (int kx = -1; kx <= 1; kx++) {
                    int idx = (y+ky)*w + (x+kx);
                    gx += img[idx] * sobelX[(ky+1)*3 + (kx+1)];
                    gy += img[idx] * sobelY[(ky+1)*3 + (kx+1)];
                }
            }
            sum += sqrtf(gx*gx + gy*gy);
        }
    }
    return sum / (w * h);
}

经验之谈:评价函数不是越复杂越好。我曾经在一个低功耗项目里试过频域法,精度确实高,但每帧计算耗时从 2ms 飙到了 35ms,直接导致对焦卡顿。后来换回梯度类,配合下采样,效果反而更好。

1.3 搜索策略:怎么找到最佳位置?

有了评价函数,我们就能给每个镜头位置打一个「清晰度分」。接下来要做的,就是找到分数最高的那个位置。这个过程,就是搜索策略。

常见的搜索策略,我画了张图帮你理解:

自动对焦搜索策略分类 搜索策略 全局搜索 局部搜索 全扫描 粗扫+精扫 爬山法 斐波那契 策略选择要点: • 全局搜索:保证找到全局最优,但速度慢。适合静态场景或启动对焦。 • 局部搜索:速度快,但可能陷入局部最优。适合连续对焦或运动场景。 • 实际工程中,常用「粗扫定位区间 + 爬山法精调」的混合策略。

每种策略都有自己的脾气。我简单说说:

  • 全扫描:从最近端扫到最远端,每步都算评价函数。简单粗暴,但慢。适合开机初始化。
  • 爬山法:往评价函数增大的方向走,走到山顶就停。速度快,但容易撞上「假峰」——比如在有纹理的玻璃窗前。
  • 斐波那契法:用斐波那契数列确定搜索步长,收敛快。我记得在某个安防项目里,用它把对焦时间从 1.2 秒压到了 0.6 秒。
  • 粗扫+精扫:先大步粗扫找到峰值区间,再小步精扫定位。这是工程中最常用的方案,兼顾速度和精度。

避坑指南:我曾经在一个户外监控项目里直接用爬山法,结果风一吹树叶晃动,评价函数剧烈抖动,镜头跟着来回乱跑,画面一直在「呼吸」。后来加了时域滤波和死区判断,才稳住。记住:搜索策略必须配合场景做鲁棒性设计。

1.4 三个要素的关系

对焦原理、评价函数、搜索策略,这三者不是孤立的。我习惯这么理解:

  • 对焦原理告诉你「为什么能对焦」——物理基础
  • 评价函数告诉你「怎么算清晰」——数学工具
  • 搜索策略告诉你「怎么找到最清晰的位置」——算法引擎

三者缺一不可。评价函数不准,搜索再快也是白搭;搜索策略太慢,评价函数再准也卡顿;不理解对焦原理,出了问题都不知道从哪排查。

一句话总结:自动对焦 = 用评价函数做「眼睛」,用搜索策略做「腿」,在对焦原理的「地图」上找到最佳位置。

好了,这一章的基础就讲到这里。后面我们会深入每种评价函数的实现细节,以及各种搜索策略的代码实战。嗯,路要一步一步走,地基打牢了,后面才盖得起高楼。