1. 自动对焦基础

自动对焦基础:对比度检测 学习卡片

任务目标

实现一个基于对比度检测的自动对焦算法:输入一组在不同镜头位置采集的图像序列,算法通过计算每帧图像的梯度幅值(Tenengrad算子)作为清晰度评价指标,搜索最大值对应的镜头位置,即为最佳对焦位置。

核心实现

import numpy as np
from scipy import ndimage

def tenengrad_focus_measure(image_gray):
    """计算单帧灰度图像的Tenengrad清晰度评价值(梯度幅值平方和)"""
    # Sobel梯度算子
    sobel_x = np.array([[-1, 0, 1],
                        [-2, 0, 2],
                        [-1, 0, 1]], dtype=np.float32)
    sobel_y = sobel_x.T
    
    gx = ndimage.convolve(image_gray.astype(np.float32), sobel_x)
    gy = ndimage.convolve(image_gray.astype(np.float32), sobel_y)
    
    # 梯度幅值平方和作为清晰度分数
    magnitude_sq = gx**2 + gy**2
    return float(magnitude_sq.sum())

def auto_focus_by_contrast(image_sequence):
    """
    基于对比度检测的自动对焦主函数
    
    参数:
        image_sequence: list[np.ndarray] 或 np.ndarray
            形状为 (N, H, W) 的灰度图像序列,N为镜头位置采样数,
            索引顺序对应镜头从近到远(或从远到近)的移动方向
    
    返回:
        best_index: int  最佳对焦位置索引(0-based)
        scores: np.ndarray  每个位置的清晰度评分
    """
    if isinstance(image_sequence, list):
        image_sequence = np.stack(image_sequence)
    
    n_frames = image_sequence.shape[0]
    scores = np.zeros(n_frames, dtype=np.float64)
    
    for i in range(n_frames):
        scores[i] = tenengrad_focus_measure(image_sequence[i])
    
    # 搜索评分最大值对应的镜头位置
    best_index = int(np.argmax(scores))
    return best_index, scores

# ===== 最小可运行示例 =====
if __name__ == "__main__":
    # 构造模拟图像序列:用高斯模糊模拟不同离焦程度
    # 中心位置(索引5)最清晰,两侧逐渐模糊
    rng = np.random.default_rng(42)
    sharp_img = rng.integers(0, 255, (64, 64)).astype(np.uint8)
    
    # 生成不同模糊程度的图像序列(模拟镜头移动)
    sigma_values = [3.0, 2.2, 1.5, 0.8, 0.3, 0.0, 0.3, 0.8, 1.5, 2.2, 3.0]
    sequence = []
    for sigma in sigma_values:
        if sigma == 0.0:
            sequence.append(sharp_img.copy())
        else:
            sequence.append(ndimage.gaussian_filter(sharp_img, sigma=sigma).astype(np.uint8))
    
    best_idx, scores = auto_focus_by_contrast(sequence)
    
    print(f"模拟序列长度: {len(sequence)}")
    print(f"各位置清晰度评分: {scores}")
    print(f"算法选出的最佳对焦位置索引: {best_idx}")
    print(f"预期最佳位置索引: 5(最清晰处)")
    print(f"判定结果: {'通过' if best_idx == 5 else '失败'}")

运行与验证

依赖安装:

pip install numpy scipy

运行方式:直接执行脚本即可:

python auto_focus_contrast.py

验证方法:程序构造了一个已知最佳对焦位置为索引5的模拟图像序列(中心位置无模糊,两侧高斯模糊程度递增)。运行后观察输出:

  • 清晰度评分曲线应在索引5处出现明显峰值;
  • 程序输出“判定结果: 通过”表示算法正确找到了最佳对焦位置。

若使用真实相机图像序列,只需将灰度帧按镜头移动顺序放入列表传入auto_focus_by_contrast(),返回的best_index即为最佳镜头位置。

关键说明

  • Tenengrad算子使用Sobel核计算水平和垂直梯度,梯度幅值平方和越大表示图像边缘越锐利,即对焦越准确;
  • 本实现采用全局搜索策略,遍历所有采样位置取最大值,适用于离焦搜索范围已知的场景;
  • 实际镜头控制中,可将best_index映射为步进电机位置指令,驱动镜头移动到该位置完成对焦。