12、Camera 对焦模式:AF模式详解

对焦这件事,说白了就是让镜头动起来,找到最清晰的那个位置。我刚开始做相机开发时,觉得对焦不就是调调焦距嘛,后来踩了不少坑才明白——这里面的门道,远比想象中复杂。

今天咱们就好好聊聊Android Camera框架里的对焦机制。我会把AF模式、触发方式、状态回调,还有手动对焦的实现,一个一个掰开来讲。

AF模式有哪些?

Android系统定义了多种对焦模式,每种模式对应不同的使用场景。我整理了一张表,方便你对照着看:

AF模式 常量值 适用场景
AUTO FOCUS_MODE_AUTO 单次对焦,拍静止物体
MACRO FOCUS_MODE_MACRO 微距拍摄,近距离物体
EDOF FOCUS_MODE_EDOF 扩展景深,固定焦距
CONTINUOUS_VIDEO FOCUS_MODE_CONTINUOUS_VIDEO 视频录制,持续追焦
CONTINUOUS_PICTURE FOCUS_MODE_CONTINUOUS_PICTURE 拍照预览,持续追焦
FIXED FOCUS_MODE_FIXED 固定焦距,不支持自动对焦

AUTO模式详解

AUTO模式是最基础的对焦模式。你调用autoFocus(),相机就开始对焦,对焦完成后回调告诉你结果。

我个人习惯在拍照场景下用AUTO模式。为什么?因为它省电、稳定。你想想看,用户按下快门前,系统做一次对焦就够了,没必要一直让马达转着。

核心要点:AUTO模式下,必须主动调用autoFocus()才能触发对焦。不调用,镜头就停在当前位置。

代码示例:

// 设置AUTO模式
Camera.Parameters params = mCamera.getParameters();
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(params);

// 触发对焦
mCamera.autoFocus(new Camera.AutoFocusCallback() {
    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        if (success) {
            // 对焦成功,可以拍照了
        } else {
            // 对焦失败,可能需要重新对焦
        }
    }
});

MACRO模式

MACRO模式,说白了就是微距模式。镜头会驱动到最近的对焦距离,让你拍清楚几厘米外的物体。

我在项目中遇到过一个问题:有些低端手机的MACRO模式,对焦范围特别窄,稍微动一下就模糊了。后来我加了个对焦锁定功能,用户半按快门时锁定对焦,效果好了很多。

小技巧:MACRO模式下,建议配合autoFocus()使用。因为微距场景下,相机很难自动判断你要拍什么,手动触发更靠谱。

EDOF模式

EDOF(Extended Depth of Field),扩展景深。这个模式比较特殊,它不靠移动镜头,而是通过算法合成来实现大景深效果。

嗯,这里要注意:EDOF模式其实不支持真正的自动对焦。镜头是固定的,所谓的「对焦」是软件层面的处理。所以你在EDOF模式下调用autoFocus(),回调会直接返回成功,但镜头根本没动。

警告:EDOF模式下,不要依赖autoFocus()的回调来判断对焦是否完成。它永远返回true,但实际画面可能并不清晰。

CONTINUOUS_VIDEO模式

视频录制时,场景一直在变,物体也在动。这时候就需要持续追焦了。

CONTINUOUS_VIDEO模式就是干这个的。相机驱动会持续检测画面中的对比度变化,自动调整镜头位置。你不需要手动调用autoFocus(),系统自己会处理。

我曾经在调试视频对焦时发现一个问题:画面快速移动时,对焦会来回抽动,画面忽清晰忽模糊。后来查了驱动代码,发现是算法参数没调好。把搜索步长调小一点,问题就解决了。

// 设置视频连续对焦
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
mCamera.setParameters(params);

// 注意:连续对焦模式下,不需要调用autoFocus()
// 但如果你想手动干预,可以调用autoFocus()强制对焦一次

AF触发方式

触发对焦的方式,主要有三种:

  1. 主动触发:调用autoFocus(),适合AUTO和MACRO模式。
  2. 自动触发:系统自动检测场景变化,适合CONTINUOUS模式。
  3. 触摸触发:用户点击屏幕指定区域,调用autoFocus(AutoFocusCallback)并配合setFocusAreas()

触摸触发这块,我多说两句。很多App的「点击屏幕对焦」功能,其实就两步:

// 1. 设置对焦区域
Rect focusRect = calculateFocusRect(touchX, touchY);
List<Camera.Area> focusAreas = new ArrayList<>();
focusAreas.add(new Camera.Area(focusRect, 1000));
params.setFocusAreas(focusAreas);
mCamera.setParameters(params);

// 2. 触发对焦
mCamera.autoFocus(callback);

你想想看,如果不设置focusAreas,相机默认对画面中心对焦。用户点了左上角,结果对焦还在中心,那体验就差了。

AF状态回调

对焦状态回调,是开发者必须关注的东西。Android提供了两种回调方式:

回调类型 接口 说明
单次回调 AutoFocusCallback 调用autoFocus()时传入,对焦完成后回调一次
持续回调 AutoFocusMoveCallback 连续对焦模式下,镜头移动时持续回调

单次回调很简单,就是告诉你成功还是失败。但持续回调很多人容易忽略。我记得有一次调试视频录制,画面总是突然模糊一下,后来加了AutoFocusMoveCallback,发现镜头在来回搜索,这才定位到问题。

// 设置持续回调(API 16+)
mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
    @Override
    public void onAutoFocusMoving(boolean moving, Camera camera) {
        if (moving) {
            // 镜头正在移动,画面可能模糊
            // 可以显示一个对焦指示器
        } else {
            // 镜头停止,对焦完成
        }
    }
});

重要:AutoFocusMoveCallback只在CONTINUOUS模式下有效。AUTO模式下调用autoFocus(),不会触发这个回调。

手动对焦实现

手动对焦,就是让用户自己控制镜头位置。Android Camera API提供了setFocusMode(FOCUS_MODE_FIXED)配合setFocusPosition()来实现。

不过要注意,不是所有设备都支持手动对焦。你得先检查一下:

// 检查是否支持手动对焦
if (params.getMaxFocusDistance() > 0) {
    // 支持手动对焦
    params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
    // 设置对焦位置,范围0到getMaxFocusDistance()
    params.setFocusPosition(position);
    mCamera.setParameters(params);
} else {
    // 不支持,只能用自动对焦
}

我做过一个手动对焦的SeekBar,用户滑动时实时调整镜头位置。这里有个坑:setFocusPosition()设置后,要等下一帧才能看到效果。所以滑动过程中,画面会有延迟感。

怎么优化?我当时的做法是:滑动停止后200ms再设置最终位置,滑动过程中只更新UI指示器,不频繁调用setParameters()。这样既流畅又省电。

经验之谈:手动对焦模式下,autoFocus()会失效。如果你需要临时切回自动对焦,记得先改focusMode再调用。

知识体系总览

下面这张图,我把本章的核心内容串起来了。你可以对照着梳理一下思路:

Camera AF 模式知识体系 AF 对焦模式 AF 模式类型 • AUTO:单次对焦,拍静止物体 • MACRO:微距模式,近距离拍摄 • EDOF:扩展景深,固定焦距 • CONTINUOUS_VIDEO:视频追焦 • CONTINUOUS_PICTURE:拍照追焦 • FIXED:固定焦距 AF 触发方式 • 主动触发:autoFocus() • 自动触发:系统检测场景变化 • 触摸触发:setFocusAreas() AF 状态回调 • AutoFocusCallback:单次回调 • AutoFocusMoveCallback:持续回调 手动对焦实现 • setFocusMode(FIXED) • setFocusPosition()

这张图把AF模式、触发方式、状态回调和手动对焦串在了一起。你写代码时,可以对照着这张图,看看自己当前处于哪个环节。

好了,关于Camera对焦模式的内容,我就讲到这里。核心就三点:选对模式、用好回调、注意兼容性。尤其是兼容性,不同厂商的驱动实现差异很大,多测试总没错。

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