3. Camera2 手动控制曝光与对焦

Camera2 手动控制曝光与对焦 学习卡片

Camera2 手动曝光与对焦的控制链路

Camera2 与 CameraX 最大的区别在于:CameraX 帮你封装了用例,而 Camera2 需要你自己构建 CaptureRequest,把每一个控制参数显式写进请求里。本节聚焦两个最直观的手动控制项——曝光补偿(AE Compensation)与对焦模式(AF Mode),通过修改 CaptureRequest 参数并观察预览变化,理解 Camera2 的请求-响应模型。

核心对象与参数

  • CameraManager:枚举相机、查询 CameraCharacteristics,确认设备支持哪些控制能力。
  • CameraDevice:打开指定相机,创建 CameraCaptureSession。
  • CaptureRequest.Builder:每次预览/拍照前构建请求,写入控制参数。
  • CONTROL_AE_EXPOSURE_COMPENSATION:曝光补偿,单位为 EV 步进,取值范围由 CONTROL_AE_COMPENSATION_RANGE 决定。
  • CONTROL_AF_MODE:对焦模式,常用 AF_MODE_CONTINUOUS_PICTURE(连续对焦)、AF_MODE_OFF(锁定/手动)、AF_MODE_AUTO(单次触发)。
  • CONTROL_AF_TRIGGER:触发一次对焦,配合 AF_MODE_AUTO 使用。
曝光补偿只在 AE 自动模式下生效;如果 AE 被关闭(CONTROL_AE_MODE_OFF),补偿值不会起作用。对焦模式切换时,建议先发送一次 AF_TRIGGER_CANCEL 再设置新模式,避免状态残留。

参数如何影响预览:一张图看清控制链路

下面的 SVG 展示了从 CameraDevice 到预览画面的完整控制链路,以及曝光补偿和对焦模式两个参数分别作用在哪个环节、如何影响最终成像。

CameraDevice 相机硬件抽象 CaptureRequest .Builder 每次预览/拍照构建 写入控制参数 曝光补偿 CONTROL_AE_EXPOSURE _COMPENSATION 范围:-2 ~ +2 EV 对焦模式 CONTROL_AF_MODE CONTINUOUS_PICTURE AF_MODE_OFF / AUTO CaptureSession setRepeatingRequest 预览画面 SurfaceView / TextureView 观察亮度/清晰度 变化 曝光补偿↑ → 画面变亮 对焦模式切换 → 清晰度变化 修改参数 → 重建 CaptureRequest → setRepeatingRequest → 预览实时更新

关键实现:构建带手动参数的 CaptureRequest

以下代码展示如何在 Camera2 预览会话中动态修改曝光补偿和对焦模式。核心思路是:保存 CaptureRequest.Builder 引用,修改参数后重新调用 setRepeatingRequest。

// 1. 查询设备支持的曝光补偿范围
CameraCharacteristics chars = cameraManager.getCameraCharacteristics(cameraId);
Range<Integer> evRange = chars.get(
    CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
// 典型值:[-2, 2],步进为 1/3 EV 或 1/2 EV
Rational step = chars.get(
    CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);

// 2. 构建预览请求(在 createCaptureSession 的 onConfigured 中)
previewBuilder = cameraDevice.createCaptureRequest(
    CameraDevice.TEMPLATE_PREVIEW);
previewBuilder.addTarget(previewSurface);

// 3. 设置初始参数
previewBuilder.set(CaptureRequest.CONTROL_AF_MODE,
    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
previewBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);

// 4. 提交重复请求,持续输出预览帧
session.setRepeatingRequest(previewBuilder.build(), null, null);

// 5. 用户拖动曝光滑条时调用
public void setExposureCompensation(int ev) {
    // ev 为实际 EV 值,需转换为步进数
    int steps = Math.round(ev / step.floatValue());
    steps = Math.max(evRange.getLower(), Math.min(evRange.getUpper(), steps));
    previewBuilder.set(
        CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, steps);
    session.setRepeatingRequest(previewBuilder.build(), null, null);
}

// 6. 切换对焦模式
public void setFocusMode(int afMode) {
    // 先取消当前对焦触发,避免状态残留
    previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
        CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
    session.capture(previewBuilder.build(), null, null);

    // 设置新模式
    previewBuilder.set(CaptureRequest.CONTROL_AF_MODE, afMode);
    previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
        CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
    session.setRepeatingRequest(previewBuilder.build(), null, null);
}

观察与验证

操作预期现象判断依据
曝光补偿从 0 调到 +2 EV预览画面明显变亮高光区域可能过曝,暗部细节提升
曝光补偿从 0 调到 -2 EV预览画面明显变暗高光细节保留,暗部趋于纯黑
对焦模式设为 CONTINUOUS_PICTURE移动手机时画面持续自动对焦远近物体切换时短暂模糊后恢复清晰
对焦模式设为 AF_MODE_OFF画面锁定在当前焦距,不再自动调整靠近或远离物体时持续模糊
AF_MODE_AUTO + AF_TRIGGER_START触发一次对焦后锁定对焦完成后画面清晰且不再变化
部分设备在 AF_MODE_OFF 下不支持手动对焦距离(LENS_FOCUS_DISTANCE),此时画面会固定在无穷远或最近焦距。切换模式前建议通过 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES 确认设备支持的模式列表。

常见问题排查

  • 曝光补偿无效果:检查 CONTROL_AE_MODE 是否为 ON 或 ON_AUTO_FLASH;若为 OFF,补偿值被忽略。
  • 对焦模式切换后画面卡住:切换前未发送 AF_TRIGGER_CANCEL,导致对焦状态机未复位。
  • setRepeatingRequest 抛异常:Builder 被重复使用前未调用 build() 生成新请求,或 Session 已关闭。
  • 预览亮度跳变不连续:曝光补偿步进值未按 CONTROL_AE_COMPENSATION_STEP 换算,导致实际 EV 与预期不符。