2. 自动对焦(AF)基础原理:反差对焦(CDAF)与相位对焦(PDAF)的工作机制

自动对焦这事儿,说白了就是让镜头找到那个最清晰的位置。我入行那会儿,手机摄像头还都是定焦的,后来才慢慢有了AF。今天咱们就聊聊两种最主流的对焦方式——反差对焦和相位对焦。

你想想看,相机怎么知道画面清不清晰?它又不知道你拍的是猫还是花。它只能靠一些数学指标来判断。嗯,这就是CDAF和PDAF的出发点不同了。

2.1 反差对焦(CDAF)——"爬山"找最锐

CDAF的原理特别直观。它就像在爬山——镜头从近到远移动,每到一个位置就计算当前画面的对比度值。对比度最高的地方,就是焦点所在。

核心逻辑:对比度值越高 → 画面越清晰 → 焦点越准。

我在项目中遇到过一个问题:客户反馈某些场景下对焦来回"拉风箱"。其实就是CDAF在对比度变化平缓的区域找不到明显的峰值,镜头在那反复试探。

2.1.1 对比度怎么算?

常用的算法是计算相邻像素的亮度差。比如Sobel算子、Laplacian算子。说白了就是看边缘锐不锐。

// 简化的对比度计算示例
int calc_contrast(uint8_t *frame, int width, int height) {
    int sum = 0;
    for (int y = 1; y < height - 1; y++) {
        for (int x = 1; x < width - 1; x++) {
            int dx = frame[y * width + x + 1] - frame[y * width + x - 1];
            int dy = frame[(y + 1) * width + x] - frame[(y - 1) * width + x];
            sum += abs(dx) + abs(dy);
        }
    }
    return sum;
}

这段代码虽然简单,但实际ISP里用的差不多就是这个思路。值越大,说明边缘越锐利。

2.1.2 CDAF的"爬山算法"

镜头移动过程中,对比度值会形成一个曲线。算法要做的就是找到这个曲线的顶点。

  1. 粗搜阶段:大步长移动,快速定位峰值大致区域。
  2. 细搜阶段:小步长来回,精确找到峰值位置。
  3. 确认阶段:在峰值附近再采样几次,防止误判。

我曾经踩过的坑:在低光照环境下,CDAF的对比度曲线会变得非常平坦。算法容易把噪声当成峰值。后来我加了一个"最小对比度阈值"判断,低于阈值的场景直接切换到PDAF或者用更大的步长搜索。

2.2 相位对焦(PDAF)——"一眼看穿"距离

PDAF就聪明多了。它不需要来回移动镜头去"试"。它通过相位检测像素,一次就能判断出焦点偏前还是偏后,以及偏了多少。

我记得第一次接触PDAF是在某款旗舰传感器的datasheet上。当时觉得这玩意儿简直是黑科技——它怎么知道镜头该往哪边转?

2.2.1 相位检测像素的结构

普通的像素只有一个光电二极管。PDAF像素则被一分为二——左边和右边各有一个光电二极管,或者用微透镜遮挡一半。

类型 结构 特点
2x1 OCL 两个像素共享一个微透镜 灵敏度高,但分辨率损失
Dual Pixel 每个像素内部分成两个PD 全像素相位检测,无分辨率损失
Masked PD 遮挡一半像素 成本低,但暗光性能差

2.2.2 相位差的计算

左右两个"半像素"分别成像。如果焦点准确,两个图像完全重合。如果焦点偏前或偏后,两个图像就会错位——这个错位量就是相位差。

个人习惯:我调试PDAF时,会先看"相位差-镜头位置"曲线。这条曲线应该是线性的。如果出现非线性或者跳变,基本可以断定是校准参数出了问题。

// 相位差计算示意
int calc_phase_diff(uint8_t *left_line, uint8_t *right_line, int len) {
    int min_diff = INT_MAX;
    int best_shift = 0;
    for (int shift = -MAX_SHIFT; shift <= MAX_SHIFT; shift++) {
        int diff = 0;
        for (int i = 0; i < len; i++) {
            int l = left_line[i];
            int r = (i + shift >= 0 && i + shift < len) ? 
                    right_line[i + shift] : 0;
            diff += abs(l - r);
        }
        if (diff < min_diff) {
            min_diff = diff;
            best_shift = shift;
        }
    }
    return best_shift;  // 返回相位差
}

2.3 CDAF vs PDAF:谁更厉害?

其实没有谁厉害。两者各有各的脾气。

维度 CDAF PDAF
对焦速度 慢(需要来回搜索) 快(一次判断方向)
低光性能 差(对比度低) 中等(相位像素灵敏度低)
精度 高(直接基于图像) 中等(依赖校准)
硬件成本 低(纯算法) 高(需要特殊像素)
适用场景 静态场景、高对比度 运动场景、低对比度

2.4 混合对焦——取长补短

现在的手机摄像头基本都是混合对焦了。PDAF快速拉到大致位置,CDAF做最后的精确微调。

我建议的混合策略是这样的:

  1. 启动阶段:PDAF先跑一次,给出镜头目标位置。
  2. 粗调阶段:镜头快速移动到目标位置附近。
  3. 精调阶段:CDAF在小范围内搜索峰值。
  4. 锁定阶段:确认峰值稳定后,锁定对焦。

关键点:PDAF给出的位置不能直接作为最终焦点。因为相位像素的校准会随温度、光照变化而漂移。必须用CDAF做最终确认。

2.5 知识结构图

下面这张图把CDAF和PDAF的核心流程串起来了。你可以看到两者如何协同工作。

自动对焦工作机制 自动对焦工作机制总览 传感器原始数据 CDAF:计算对比度值 爬山算法搜索峰值 输出精确焦点位置 PDAF:提取相位像素 计算左右图像相位差 输出粗略焦点方向/距离 混合对焦:PDAF引导 + CDAF精调 最终对焦完成 注意 PDAF校准会随温度漂移 最终必须用CDAF确认

2.6 调试中的常见问题

最后分享几个我在调试AF时遇到的典型问题,希望能帮你少走弯路。

问题1:PDAF方向判断错误

我曾经遇到一个案子,PDAF总是往反方向跑。查了两天才发现是相位像素的左右标记反了。校准文件里把left和right搞混了。

问题2:CDAF在低对比度场景下"拉风箱"

我的解决办法是:当对比度值低于某个阈值时,强制使用PDAF的结果,不再做CDAF精调。虽然精度会差一点,但至少不会来回抖动。

问题3:混合对焦切换时的"顿挫感"

从PDAF切换到CDAF时,如果镜头位置跳变太大,用户会感觉到画面突然模糊一下。我建议做平滑过渡——用插值的方式让镜头慢慢移动到目标位置。