2. 基于相位检测的自动对焦模拟
任务目标
构建一个最小可运行的相位检测自动对焦(PDAF)模拟器:给定一对来自左右像素的“相位图像”信号,通过互相关计算相位差,据此输出镜头移动方向与步长,并验证对焦收敛。
核心原理与实现路径
相位检测对焦的核心是:同一被摄体经过镜头左右两侧的光线,分别投射到一对相距已知距离的像素对上。当合焦时,左右信号完全对齐;离焦时,两者产生与离焦量成正比的水平偏移(相位差)。本案例用一维数组模拟左右像素接收到的光强分布,通过互相关函数寻找最佳对齐偏移量,该偏移量即为相位差,进而换算为镜头步进电机的移动方向和步数。
完整实现代码
import numpy as np
def simulate_defocused_signal(base_signal, shift):
"""模拟离焦时右像素信号相对左像素的偏移(shift为正表示右信号右移)"""
n = len(base_signal)
x = np.arange(n)
# 用sinc插值实现亚像素平移,更接近真实光学行为
right = np.zeros_like(base_signal, dtype=float)
for i in range(n):
for j in range(n):
dx = i - (j + shift)
if dx == 0:
right[i] += base_signal[j]
else:
right[i] += base_signal[j] * np.sinc(dx)
return right
def compute_phase_difference(left, right, max_shift=10):
"""通过互相关计算右信号相对左信号的相位差(像素单位)"""
n = len(left)
best_shift = 0
best_corr = -np.inf
# 在[-max_shift, max_shift]范围内搜索整数像素偏移
for shift in range(-max_shift, max_shift + 1):
if shift >= 0:
# 右信号右移shift位,与左信号对齐比较
r_shifted = right[shift:]
l_trim = left[:n - shift]
else:
# 右信号左移|shift|位
s = -shift
r_shifted = right[:n - s]
l_trim = left[s:]
if len(l_trim) == 0 or len(r_shifted) == 0:
continue
# 归一化互相关
l_norm = (l_trim - l_trim.mean()) / (l_trim.std() + 1e-9)
r_norm = (r_shifted - r_shifted.mean()) / (r_shifted.std() + 1e-9)
corr = np.mean(l_norm * r_norm)
if corr > best_corr:
best_corr = corr
best_shift = shift
return best_shift # 正值表示右信号需要右移才能与左对齐,即左信号超前
def lens_control(phase_diff, step_scale=1.0):
"""根据相位差输出镜头控制指令"""
if abs(phase_diff) < 0.5:
return "合焦", 0
direction = "正向移动" if phase_diff > 0 else "反向移动"
steps = int(round(abs(phase_diff) * step_scale))
return direction, steps
# ---- 模拟主流程 ----
if __name__ == "__main__":
# 1. 构造一个具有明显纹理特征的被摄体光强分布
np.random.seed(42)
n_pixels = 64
base = np.zeros(n_pixels)
# 模拟一个边缘+细节的图案
base[10:20] = 1.0
base[25] = 0.5
base[30:35] = np.linspace(0, 1, 5)
base[40:50] = 0.8
base += 0.1 * np.random.rand(n_pixels) # 少量噪声
# 2. 模拟当前离焦状态:右信号相对左信号偏移+3.2像素(真实离焦量)
true_shift = 3.2
left_signal = base.copy()
right_signal = simulate_defocused_signal(base, true_shift)
# 3. 计算相位差
measured_shift = compute_phase_difference(left_signal, right_signal, max_shift=8)
print(f"真实相位差: {true_shift:.1f} 像素")
print(f"测量相位差: {measured_shift} 像素")
# 4. 输出镜头控制指令
action, steps = lens_control(measured_shift, step_scale=1.0)
print(f"控制指令: {action}, 步数: {steps}")
# 5. 验证:按指令移动后应接近合焦
corrected_shift = true_shift - measured_shift
print(f"校正后残余相位差: {corrected_shift:.2f} 像素")
if abs(corrected_shift) < 0.5:
print("验证通过:对焦收敛")
else:
print("验证失败:未收敛到合焦阈值内")
运行方式与依赖
依赖:Python 3.8+,NumPy(pip install numpy)。
运行:将上述代码保存为 pdaf_sim.py,在终端执行 python pdaf_sim.py。
验证方法与判定标准
- 输出检查:程序打印的“测量相位差”应接近“真实相位差”(本例真实值为3.2像素,测量值应为3或4像素,因搜索步长为整数像素)。
- 控制指令:当测量相位差为正时输出“正向移动”,步数为相位差值取整(本例应为3或4步)。
- 收敛判定:最后一行输出“验证通过:对焦收敛”即表示闭环成功——因为校正后残余相位差 = 3.2 - 3(或4)= 0.2(或-0.8),值小于0.5像素阈值。
若将 true_shift 改为负值(如 -2.5),则控制指令应变为“反向移动”,步数为2或3,同样满足收敛条件。此模拟验证了相位差测量与镜头控制指令生成的正确性。