20. 相机对焦技术:对比度对焦(CDAF)、相位对焦(PDAF)、激光对焦(TOF)、对焦区域设置

对焦这件事,说白了就是让镜头动起来,找到最清晰的那个位置。你按下快门之前,手机其实在疯狂地做「猜猜看」——到底镜头停在哪个位置,拍出来的照片最清楚?

我刚开始做相机开发时,觉得对焦不就是「动一动马达」嘛,有什么难的?直到我遇到一台弱光下疯狂拉风箱的设备,才意识到这里面的水有多深。今天咱们就把四种主流对焦技术掰开揉碎讲清楚。

对比度对焦(CDAF)

这是最古老、也是最基础的对焦方式。它的原理很简单:找图像中边缘最锐利的位置

你想想看,一张照片如果对焦准确,边缘的明暗变化会非常剧烈。如果对焦不准,边缘就是模糊的一团。CDAF 就是利用这个特性,让镜头从近到远走一遍,每到一个位置就计算当前画面的对比度值,找到那个「峰值」位置。

核心公式(简化版):
对比度值 = Σ(相邻像素亮度差的绝对值)
值越大 → 边缘越锐利 → 对焦越准

我在项目中遇到过一个问题:拍摄纯色墙壁时,CDAF 直接「死机」了。因为整张图根本没有边缘,对比度值几乎为零,镜头就在那里来回晃,就是找不到焦点。这就是 CDAF 的致命伤——对低纹理场景极度不友好

我的经验:CDAF 适合拍风景、文档这类纹理丰富的场景。但如果你要拍白墙、天空、或者光滑的桌面,别指望它。

相位对焦(PDAF)

PDAF 的出现,解决了 CDAF 最大的痛点——速度。它不需要来回扫描,一次就能算出镜头该往哪个方向走、走多远。

原理是什么呢?传感器上有一排特殊的像素,它们被遮掉了一半的光。左边遮一半的像素和右边遮一半的像素,分别看到的是不同的图像。如果两个图像完全重合,说明对焦准确。如果错开了,错开的距离和方向,就是镜头需要移动的距离和方向。

说白了,CDAF 是「猜」,PDAF 是「算」。一个靠试错,一个靠计算。

PDAF 的优势:
  • 速度快:一次计算到位,不需要扫描
  • 适合运动物体:能跟踪移动中的目标
  • 弱光表现优于 CDAF

不过 PDAF 也有坑。我记得有一次调试,发现画面左侧总是对焦不准。查了半天,发现是传感器上的相位像素分布不均匀,导致左侧区域没有足够的相位信息。嗯,这里要注意——不是所有 PDAF 像素都覆盖全画面,边缘区域经常是盲区。

避坑指南:我曾经在某个项目里,PDAF 在强光下表现完美,但一到黄昏就开始抽风。原因是光线太弱,相位像素的信噪比急剧下降,算出来的偏移量全是噪声。这时候需要回退到 CDAF 模式。

激光对焦(TOF)

TOF 全称是 Time of Flight,飞行时间。它发射一束激光,打到物体上反射回来,根据时间差算出距离。然后直接把镜头推到那个距离位置就行了。

这个技术的好处是:完全不受纹理影响。你拍白墙、拍天空、拍黑夜,它都能对焦。因为它根本不看图像,只看距离。

但 TOF 也有局限性。我做过一个测试,在户外阳光下,TOF 的有效距离直接缩水到 1 米以内。因为太阳光里的红外成分太强,把激光信号淹没了。另外,如果拍摄透明物体(比如玻璃杯),激光会直接穿透,测出来的距离是错的。

技术 速度 弱光 低纹理 运动物体
CDAF 极差
PDAF
TOF 极快

对焦区域设置

光有对焦技术还不够,你还得告诉相机「对哪里对焦」。这就是对焦区域设置干的事。

Android 提供了三种模式:

  • 自动对焦(FOCUS_MODE_AUTO):相机自己决定对焦区域,通常是画面中央
  • 连续对焦(FOCUS_MODE_CONTINUOUS_PICTURE/VIDEO):相机持续跟踪画面中的主体,适合拍视频
  • 触摸对焦(手动设置对焦区域):用户点击屏幕,相机在那个区域对焦

实际开发中,我建议你这样做:

// 设置触摸对焦区域
Camera2 中通过 MeteringRectangle 实现
MeteringRectangle focusRect = new MeteringRectangle(
    x - width/2, y - height/2, 
    width, height, 
    MeteringRectangle.METERING_WEIGHT_MAX
);

CaptureRequest.Builder.set(CaptureRequest.CONTROL_AF_REGIONS, 
    new MeteringRectangle[]{focusRect});
CaptureRequest.Builder.set(CaptureRequest.CONTROL_AE_REGIONS, 
    new MeteringRectangle[]{focusRect});

这里有个细节:对焦区域和测光区域通常是绑定的。你点哪里对焦,相机也会根据那个区域的亮度来调整曝光。但如果你想要「对焦在 A 点,测光在 B 点」,也是可以分开设置的。

我的习惯:在实现触摸对焦时,我会把对焦区域设成用户点击位置的一个小方块(比如 100x100 像素),同时把测光区域设成稍大一圈(比如 150x150)。这样对焦精准,测光也不会太极端。

四种技术的协作流程

实际手机里,这三种技术不是互斥的,而是协同工作的。我画了一张图来说明:

多技术协同对焦流程 用户触发对焦 有TOF? TOF 直接测距 纹理丰富? PDAF 快速对焦 CDAF 扫描对焦 对焦完成 开始/结束 判断条件 执行动作

流程是这样的:用户触发对焦后,系统先看有没有 TOF 硬件。如果有,直接用激光测距,一步到位。如果没有,再看画面纹理是否丰富。纹理丰富就用 PDAF 快速计算,纹理少(比如白墙)就回退到 CDAF 慢慢扫描。

我做过一个优化:在 PDAF 和 CDAF 之间加了一个「置信度阈值」。如果 PDAF 算出来的偏移量置信度低于 80%,就自动切换到 CDAF 模式。这样既保证了速度,又避免了 PDAF 在弱光下乱跑。

我曾经踩过的坑:在某个项目里,我把 TOF 和 PDAF 同时开启了。结果两个系统都在控制镜头,互相打架,画面一直在抖动。后来才意识到,同一时刻只能有一个对焦系统在控制镜头,其他系统只能提供参考数据。

最后说一句:对焦这件事,没有银弹。最好的方案是根据场景动态切换。光线好、纹理多 → PDAF。光线差、纹理少 → TOF。两者都没有 → CDAF 兜底。把这些逻辑写进你的相机应用里,用户体验会好很多。


公众号:蓝海资料掘金营,微信deep3321