2. 自动对焦基础

任务目标

本案例实现一个最小可运行的相位检测自动对焦(PDAF)模拟器:给定左右像素对的相对偏移(即相位差),计算散焦量(Defocus),并据此驱动镜头马达移动到合焦位置。通过该案例理解PDAF的核心闭环:相位差 → 散焦量 → 镜头位移。

核心原理与实现

相位检测自动对焦利用微透镜阵列将光线分离为左右两路图像。当镜头合焦时,左右图像完全重合(相位差为0);当失焦时,左右图像产生偏移,偏移量与散焦程度成正比。本案例用一维数组模拟左右像素对,通过互相关计算相位差,再乘以标定系数得到散焦量,最后驱动镜头步进电机移动对应步数。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SENSOR_WIDTH  16      // 传感器像素宽度
#define MAX_SHIFT     8       // 最大可检测偏移量
#define FOCUS_COEFF   2.5f    // 相位差→散焦量标定系数(μm/像素)
#define STEP_SIZE     0.5f    // 镜头步进电机每步位移(μm)

// 模拟左右像素对信号(一维)
typedef struct {
    float left[SENSOR_WIDTH];
    float right[SENSOR_WIDTH];
} PhasePair;

// 生成模拟信号:中心位置偏移产生相位差
void generate_signal(PhasePair *p, int shift) {
    for (int i = 0; i < SENSOR_WIDTH; i++) {
        p->left[i]  = (i >= 3 && i < 13) ? 1.0f : 0.0f;  // 左图方波
        int r_idx = i + shift;                            // 右图偏移
        p->right[i] = (r_idx >= 3 && r_idx < 13) ? 1.0f : 0.0f;
    }
}

// 计算相位差:遍历所有可能偏移,找最小差异
int compute_phase_diff(PhasePair *p) {
    int best_shift = 0;
    float min_diff = 1e9f;
    for (int s = -MAX_SHIFT; s <= MAX_SHIFT; s++) {
        float diff = 0.0f;
        for (int i = 0; i < SENSOR_WIDTH; i++) {
            int r_idx = i + s;
            float r_val = (r_idx >= 0 && r_idx < SENSOR_WIDTH) ? p->right[r_idx] : 0.0f;
            diff += (p->left[i] - r_val) * (p->left[i] - r_val);
        }
        if (diff < min_diff) {
            min_diff = diff;
            best_shift = s;
        }
    }
    return best_shift;  // 返回使差异最小的偏移量(像素)
}

int main() {
    // 模拟真实场景:右图相对左图偏移3像素(失焦状态)
    PhasePair pair;
    int true_shift = 3;
    generate_signal(&pair, true_shift);

    // 1. 计算相位差
    int phase_diff = compute_phase_diff(&pair);
    printf("检测到相位差: %d 像素\n", phase_diff);

    // 2. 计算散焦量(正=后焦,负=前焦)
    float defocus = phase_diff * FOCUS_COEFF;
    printf("散焦量: %+.1f μm\n", defocus);

    // 3. 驱动镜头:步数 = 散焦量 / 步长(取整)
    int steps = (int)(defocus / STEP_SIZE);
    printf("镜头驱动: %d 步\n", steps);

    // 4. 模拟合焦验证:镜头移动后重新检测
    float lens_pos = 0.0f;
    lens_pos += steps * STEP_SIZE;   // 镜头实际位移
    float residual = defocus - lens_pos;  // 残余散焦
    printf("残余散焦: %+.1f μm\n", residual);

    // 判定是否合焦
    if (abs(residual) < STEP_SIZE) {
        printf("对焦成功:残余散焦小于一个步长\n");
    } else {
        printf("对焦未完成:需要继续微调\n");
    }
    return 0;
}

编译与运行

gcc -o pdaf_demo pdaf_demo.c -lm
./pdaf_demo

验证方法与判定标准

程序输出应满足以下逻辑链:

  • 相位差检测:输入偏移3像素,输出应为3(或接近值,取决于信号边缘效应);
  • 散焦量计算:3像素 × 2.5μm/像素 = 7.5μm;
  • 镜头驱动:7.5μm ÷ 0.5μm/步 = 15步;
  • 合焦判定:镜头移动15步后位移7.5μm,残余散焦为0,输出对焦成功。

若修改true_shift为其他值(如-2、5),程序应自动计算对应散焦量并驱动镜头,残余散焦始终小于一个步长。该结果由代码逻辑直接推出,可作为预期输出验证实现正确性。

关键说明

  • 本案例用方波信号模拟图像特征,实际传感器使用带纹理的灰度图像;互相关算法原理一致。
  • FOCUS_COEFF和STEP_SIZE为标定参数,实际系统中需通过镜头模组标定获得。
  • 真实PDAF在硬件中并行计算,本案例用遍历搜索实现,逻辑等价且便于理解。
PDAF自动对焦闭环流程 左右像素对 相位差=3px 散焦量计算 3px×2.5=7.5μm 镜头马达驱动 7.5μm÷0.5=15步 合焦判定 残余<0.5μm 未合焦时反馈重新检测