3. 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 到预览画面的完整控制链路,以及曝光补偿和对焦模式两个参数分别作用在哪个环节、如何影响最终成像。
关键实现:构建带手动参数的 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 与预期不符。