4. 对焦窗口选择
任务目标
在自动对焦系统中,对焦窗口的选择直接影响对焦速度与精度。本案例将画面划分为3×3共9个区域,计算每个区域的对比度值(Tenengrad梯度),并通过加权策略综合评估,选出最佳对焦区域作为后续对焦窗口。实现后可在标准测试图上验证区域选择结果。
核心实现
import numpy as np
import cv2
def compute_tenengrad(gray_img):
"""计算图像的Tenengrad对比度(Sobel梯度平方和)"""
gx = cv2.Sobel(gray_img, cv2.CV_64F, 1, 0, ksize=3)
gy = cv2.Sobel(gray_img, cv2.CV_64F, 0, 1, ksize=3)
return np.sum(gx**2 + gy**2)
def select_focus_region(image, grid=(3, 3), weight_mode='center'):
"""
多区域对焦窗口选择
image: 灰度图或BGR图
grid: (rows, cols) 区域划分
weight_mode: 'center'中心权重 / 'uniform'均匀权重
返回: (best_idx, region_scores, weighted_scores)
"""
if len(image.shape) == 3:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
else:
gray = image.copy()
h, w = gray.shape
rows, cols = grid
cell_h, cell_w = h // rows, w // cols
# 中心加权矩阵(中心区域权重高)
if weight_mode == 'center':
weight_mat = np.array([[0.5, 0.8, 0.5],
[0.8, 1.5, 0.8],
[0.5, 0.8, 0.5]], dtype=float)
# 若grid不是3x3则退化为均匀权重
if (rows, cols) != (3, 3):
weight_mat = np.ones((rows, cols), dtype=float)
else:
weight_mat = np.ones((rows, cols), dtype=float)
region_scores = np.zeros((rows, cols))
for i in range(rows):
for j in range(cols):
y0, y1 = i * cell_h, (i + 1) * cell_h
x0, x1 = j * cell_w, (j + 1) * cell_w
region = gray[y0:y1, x0:x1]
region_scores[i, j] = compute_tenengrad(region)
weighted_scores = region_scores * weight_mat
best_idx = np.unravel_index(np.argmax(weighted_scores), weighted_scores.shape)
return best_idx, region_scores, weighted_scores
def draw_result(image, best_idx, grid=(3, 3)):
"""在图像上绘制网格与最佳区域标记"""
vis = image.copy()
if len(vis.shape) == 2:
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
h, w = vis.shape[:2]
rows, cols = grid
cell_h, cell_w = h // rows, w // cols
# 绘制网格线
for i in range(1, rows):
cv2.line(vis, (0, i * cell_h), (w, i * cell_h), (0, 255, 0), 1)
for j in range(1, cols):
cv2.line(vis, (j * cell_w, 0), (j * cell_w, h), (0, 255, 0), 1)
# 高亮最佳区域
br, bc = best_idx
y0, y1 = br * cell_h, (br + 1) * cell_h
x0, x1 = bc * cell_w, (bc + 1) * cell_w
cv2.rectangle(vis, (x0, y0), (x1, y1), (0, 0, 255), 3)
cv2.putText(vis, f"Best: ({br},{bc})", (x0 + 5, y0 + 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
return vis
if __name__ == "__main__":
# 生成测试图:中心区域纹理丰富,四周平滑
test_img = np.full((300, 300), 128, dtype=np.uint8)
# 中心区域添加随机纹理
center = test_img[100:200, 100:200]
noise = np.random.default_rng(42).integers(0, 50, center.shape).astype(np.uint8)
test_img[100:200, 100:200] = cv2.add(center, noise)
best_idx, scores, weighted = select_focus_region(test_img, grid=(3, 3))
print(f"最佳区域索引(行,列): {best_idx}")
print(f"区域对比度:\n{scores.round(1)}")
print(f"加权后对比度:\n{weighted.round(1)}")
# 保存可视化结果
result = draw_result(test_img, best_idx)
cv2.imwrite("focus_region_result.png", result)
print("可视化结果已保存: focus_region_result.png")
运行与验证
环境依赖:Python 3.8+,NumPy,OpenCV(pip install numpy opencv-python)。
运行方式:
python focus_region_select.py
验证方法:
- 程序输出最佳区域索引应为
(1, 1),即中心区域——因为测试图中心区域包含随机纹理,Tenengrad梯度值显著高于四周平滑区域。 - 加权后中心区域权重最高(1.5),进一步确保中心区域被选中。
- 打开生成的
focus_region_result.png,应看到红色矩形框标记在图像正中央的3×3网格单元内。
预期输出(基于代码逻辑与给定输入可直接推出):
最佳区域索引(行,列): (1, 1)
区域对比度:
[[0. 0. 0.]
[0. 高值 0.]
[0. 0. 0.]]
加权后对比度:
[[0. 0. 0.]
[0. 更高值 0.]
[0. 0. 0.]]
其中“高值”为具体数值,中心区域因纹理存在其Tenengrad值远大于四周的0值。
关键说明
- 权重矩阵采用中心加权策略,模拟相机对焦时优先考虑画面中央区域的实际需求;若需均匀对待各区域,可将
weight_mode设为'uniform'。 - 区域边界处理使用整除划分,当图像尺寸不能被网格整除时,边缘区域会略小,但不影响对比度计算与区域选择逻辑。
- 实际ISP集成时,可将
select_focus_region的输入替换为传感器输出的RAW图转灰度数据,并将返回的best_idx映射为对焦窗口的像素坐标范围。