2. 对比度检测自动对焦模块搭建
任务目标
搭建一个基于图像对比度最大化的自动对焦模块:通过移动镜头位置采集图像序列,计算各位置图像的对比度评价值,搜索峰值对应的镜头位置即为最佳对焦点。本案例聚焦于对比度检测的核心算法与最小可运行闭环,不涉及电机驱动硬件控制。
实现方案
采用Tenengrad梯度算子计算图像清晰度(对比度评价值),使用爬山搜索策略寻找峰值位置。系统输入为一系列离散镜头位置及其对应的灰度图像,输出为最佳对焦位置索引。算法流程:
- 对每个位置的图像计算Tenengrad评价值(Sobel梯度平方和);
- 从起始位置开始,沿评价值上升方向移动,直到评价值下降则回溯到峰值位置;
- 若序列为单峰分布,爬山法可正确收敛;若存在噪声,可选用全局搜索(遍历所有位置取最大值)作为对照。
完整代码
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或先对评价值做中值滤波再搜索。