2. 对比度检测自动对焦模块搭建

任务目标

搭建一个基于图像对比度最大化的自动对焦模块:通过移动镜头位置采集图像序列,计算各位置图像的对比度评价值,搜索峰值对应的镜头位置即为最佳对焦点。本案例聚焦于对比度检测的核心算法与最小可运行闭环,不涉及电机驱动硬件控制。

实现方案

采用Tenengrad梯度算子计算图像清晰度(对比度评价值),使用爬山搜索策略寻找峰值位置。系统输入为一系列离散镜头位置及其对应的灰度图像,输出为最佳对焦位置索引。算法流程:

  1. 对每个位置的图像计算Tenengrad评价值(Sobel梯度平方和);
  2. 从起始位置开始,沿评价值上升方向移动,直到评价值下降则回溯到峰值位置;
  3. 若序列为单峰分布,爬山法可正确收敛;若存在噪声,可选用全局搜索(遍历所有位置取最大值)作为对照。

完整代码

import numpy as np
from scipy import ndimage

def tenengrad_score(image):
    """计算单张灰度图的Tenengrad对比度评价值"""
    if image.ndim == 3:
        image = np.mean(image, axis=2)  # 转灰度
    image = image.astype(np.float32)
    # Sobel梯度
    gx = ndimage.sobel(image, axis=1)
    gy = ndimage.sobel(image, axis=0)
    return np.sum(gx**2 + gy**2)

def hill_climb_search(scores, start=0, step=1):
    """
    爬山法搜索峰值位置
    scores: 各镜头位置的评价值列表
    返回: 最佳位置索引
    """
    n = len(scores)
    pos = start
    # 向右探索
    while pos + step < n and scores[pos + step] > scores[pos]:
        pos += step
    # 向左探索(处理起始点不在左侧斜坡的情况)
    while pos - step >= 0 and scores[pos - step] > scores[pos]:
        pos -= step
    return pos

def global_search(scores):
    """全局搜索:遍历所有位置取最大值(对照/验证用)"""
    return int(np.argmax(scores))

def autofocus_module(images, search_method='hill_climb'):
    """
    对比度检测自动对焦主函数
    images: list[np.ndarray],按镜头位置顺序排列的灰度图
    search_method: 'hill_climb' 或 'global'
    返回: (最佳位置索引, 各位置评价值列表)
    """
    scores = [tenengrad_score(img) for img in images]
    if search_method == 'hill_climb':
        best_pos = hill_climb_search(scores)
    else:
        best_pos = global_search(scores)
    return best_pos, scores

# ========== 最小验证闭环 ==========
if __name__ == '__main__':
    # 构造模拟图像序列:位置5最清晰,两侧逐渐模糊(高斯模糊模拟失焦)
    from scipy.ndimage import gaussian_filter
    np.random.seed(42)
    base = np.random.randint(0, 255, (64, 64)).astype(np.float32)
    image_seq = []
    for i in range(11):
        sigma = abs(i - 5) * 0.8 + 0.3  # 离位置5越远越模糊
        blurred = gaussian_filter(base, sigma=sigma)
        image_seq.append(blurred)

    # 运行自动对焦
    best, scores = autofocus_module(image_seq, search_method='hill_climb')
    best_global, _ = autofocus_module(image_seq, search_method='global')

    print(f"爬山法最佳位置: {best}")
    print(f"全局搜索最佳位置: {best_global}")
    print(f"评价值序列: {[int(s) for s in scores]}")
    # 预期输出(确定性结果):
    # 爬山法最佳位置: 5
    # 全局搜索最佳位置: 5
    # 评价值序列: 位置5处最大,两侧递减

运行与验证

依赖安装:

pip install numpy scipy

运行方式:直接执行上述脚本(已包含模拟数据与验证入口)。

通过条件:

  • 控制台输出中,爬山法最佳位置与全局搜索最佳位置均为5;
  • 打印的评价值序列在索引5处取得最大值,且两侧单调递减——这验证了Tenengrad评分函数对清晰度的区分能力以及搜索算法的正确性。

集成说明

在实际系统中,将images替换为相机在步进电机不同位置采集的真实帧,调用autofocus_module即可获得对焦位置。若镜头移动存在噪声导致评价值非严格单峰,建议改用global_search或先对评价值做中值滤波再搜索。

对比度检测自动对焦原理 镜头位置 对比度评价值 最佳对焦位置 ← 向评价值上升方向移动 评价值下降 → 回溯 各位置评价值 峰值(对焦点)