第四章:反差对焦原理——图像清晰度评价函数与爬山算法详解

各位同学,欢迎来到自动对焦的核心章节。

前面我们聊了基础光学和传感器,今天要讲的是反差对焦——说白了,就是让相机自己判断“哪张照片最清楚”。

我刚开始做嵌入式相机时,总觉得对焦是个玄学。后来踩了无数坑才明白,核心就两件事:怎么算清晰,以及怎么找到最清晰的位置

4.1 图像清晰度评价函数

先问个问题:一张模糊的照片和一张清晰的照片,在数学上有什么区别?

答案是边缘的锐利程度。清晰图像的边缘变化剧烈,模糊图像的边缘平缓。评价函数就是量化这个“剧烈程度”的。

4.1.1 Tenengrad 函数

Tenengrad 是我个人最常用的评价函数之一。它基于 Sobel 算子,计算图像在水平和垂直方向的梯度。

公式其实不复杂:

Tenengrad = Σ ( Gx² + Gy² )

其中 Gx 和 Gy 分别是 Sobel 算子在 x 和 y 方向的卷积结果。

核心思想:梯度平方和越大,图像越清晰。

我在项目中遇到过一个问题:用 Tenengrad 评价夜景照片时,噪声会被放大,导致误判。后来我加了一个高斯预滤波,效果好了很多。

4.1.2 Laplacian 函数

Laplacian 用的是二阶导数。它比 Tenengrad 更敏感,但也更容易受噪声影响。

Laplacian = Σ | L(x, y) |

其中 L(x, y) 是 Laplacian 算子卷积结果。

我的经验:Laplacian 适合纹理丰富的场景。如果画面很平滑(比如拍白墙),它的表现就不如 Tenengrad。

4.1.3 Brenner 函数

Brenner 是最简单的评价函数之一。它只计算相邻像素的灰度差。

Brenner = Σ | I(x+2, y) - I(x, y) |

你没看错,就这么简单。它只考虑相隔两个像素的差值。

为什么是相隔两个像素?我当年也纳闷。后来想明白了:相隔一个像素对噪声太敏感,相隔三个又太迟钝。两个像素是个折中。

评价函数 计算量 抗噪性 适用场景
Tenengrad 通用场景
Laplacian 纹理丰富
Brenner 极低 嵌入式实时

注意:不要迷信某个函数。我建议你在项目中至少测试两种,看哪个更稳定。

4.2 爬山算法详解

有了评价函数,下一步就是找到峰值。爬山算法是最直观的方法。

4.2.1 基本原理

想象你站在一座山上,蒙着眼,只能通过脚底的坡度判断方向。你会怎么走?

没错,往坡上走。爬山算法就是这个逻辑:

  1. 朝一个方向移动镜头
  2. 计算当前清晰度值
  3. 如果值变大,继续同方向移动
  4. 如果值变小,反方向移动
  5. 重复直到找到峰值

4.2.2 步长策略

步长是个关键参数。步长太大,容易跳过峰值;步长太小,对焦太慢。

我常用的策略是粗调+细调

  • 先用大步长快速接近峰值区域
  • 再用小步长精确找到峰值
// 伪代码示例
step_size = LARGE_STEP
while (step_size > MIN_STEP) {
    move_lens(step_size)
    current_value = evaluate_sharpness()
    if (current_value > previous_value) {
        continue
    } else {
        move_lens(-step_size * 2)  // 回头
        step_size = step_size / 2  // 步长减半
    }
}

避坑指南:我曾经在步长减半时没处理好边界条件,导致镜头在峰值附近来回震荡。后来加了死区判断,问题才解决。

4.2.3 局部峰值问题

爬山算法有个致命弱点:容易陷入局部峰值。

比如你拍一个物体,背景是虚化的。评价函数可能会出现多个小峰值。爬山算法可能停在第一个小峰上,而不是真正的对焦位置。

怎么解决?我一般用两种方法:

  • 多起点爬山:从不同位置开始爬,取最高值
  • 全局扫描+局部爬山:先大步扫描整个范围,找到几个候选区域,再精细爬山

4.3 知识体系总览

下面这张图是我自己整理的,把本章的核心逻辑串起来了:

反差对焦核心流程 图像输入 清晰度评价函数 Tenengrad | Laplacian | Brenner 计算梯度/二阶导数/像素差 爬山算法 步长策略 | 方向判断 | 峰值检测 粗调→细调 | 多起点 | 全局+局部

从图像输入开始,经过评价函数计算清晰度,再用爬山算法找到峰值位置。每一步都有坑,但掌握了这些,你就掌握了反差对焦的核心。

总结一下:

  • Tenengrad 用 Sobel 梯度,通用性好
  • Laplacian 用二阶导数,敏感但怕噪声
  • Brenner 最简单,适合嵌入式实时系统
  • 爬山算法要配合步长策略,注意局部峰值

嗯,这一章就到这里。内容不少,但都是实战中反复验证过的。你回去可以写个小程序,用摄像头采集几帧图像,试试不同评价函数的效果。亲手跑一遍,比看十遍书都管用。