20. 相机对焦技术:对比度对焦(CDAF)、相位对焦(PDAF)、激光对焦(TOF)、对焦区域设置
对焦这件事,说白了就是让镜头动起来,找到最清晰的那个位置。你按下快门之前,手机其实在疯狂地做「猜猜看」——到底镜头停在哪个位置,拍出来的照片最清楚?
我刚开始做相机开发时,觉得对焦不就是「动一动马达」嘛,有什么难的?直到我遇到一台弱光下疯狂拉风箱的设备,才意识到这里面的水有多深。今天咱们就把四种主流对焦技术掰开揉碎讲清楚。
对比度对焦(CDAF)
这是最古老、也是最基础的对焦方式。它的原理很简单:找图像中边缘最锐利的位置。
你想想看,一张照片如果对焦准确,边缘的明暗变化会非常剧烈。如果对焦不准,边缘就是模糊的一团。CDAF 就是利用这个特性,让镜头从近到远走一遍,每到一个位置就计算当前画面的对比度值,找到那个「峰值」位置。
对比度值 = Σ(相邻像素亮度差的绝对值)
值越大 → 边缘越锐利 → 对焦越准
我在项目中遇到过一个问题:拍摄纯色墙壁时,CDAF 直接「死机」了。因为整张图根本没有边缘,对比度值几乎为零,镜头就在那里来回晃,就是找不到焦点。这就是 CDAF 的致命伤——对低纹理场景极度不友好。
相位对焦(PDAF)
PDAF 的出现,解决了 CDAF 最大的痛点——速度。它不需要来回扫描,一次就能算出镜头该往哪个方向走、走多远。
原理是什么呢?传感器上有一排特殊的像素,它们被遮掉了一半的光。左边遮一半的像素和右边遮一半的像素,分别看到的是不同的图像。如果两个图像完全重合,说明对焦准确。如果错开了,错开的距离和方向,就是镜头需要移动的距离和方向。
说白了,CDAF 是「猜」,PDAF 是「算」。一个靠试错,一个靠计算。
- 速度快:一次计算到位,不需要扫描
- 适合运动物体:能跟踪移动中的目标
- 弱光表现优于 CDAF
不过 PDAF 也有坑。我记得有一次调试,发现画面左侧总是对焦不准。查了半天,发现是传感器上的相位像素分布不均匀,导致左侧区域没有足够的相位信息。嗯,这里要注意——不是所有 PDAF 像素都覆盖全画面,边缘区域经常是盲区。
激光对焦(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 点」,也是可以分开设置的。
四种技术的协作流程
实际手机里,这三种技术不是互斥的,而是协同工作的。我画了一张图来说明:
流程是这样的:用户触发对焦后,系统先看有没有 TOF 硬件。如果有,直接用激光测距,一步到位。如果没有,再看画面纹理是否丰富。纹理丰富就用 PDAF 快速计算,纹理少(比如白墙)就回退到 CDAF 慢慢扫描。
我做过一个优化:在 PDAF 和 CDAF 之间加了一个「置信度阈值」。如果 PDAF 算出来的偏移量置信度低于 80%,就自动切换到 CDAF 模式。这样既保证了速度,又避免了 PDAF 在弱光下乱跑。
最后说一句:对焦这件事,没有银弹。最好的方案是根据场景动态切换。光线好、纹理多 → PDAF。光线差、纹理少 → TOF。两者都没有 → CDAF 兜底。把这些逻辑写进你的相机应用里,用户体验会好很多。
公众号:蓝海资料掘金营,微信deep3321