Camera2如何实现测光区域失焦时自动触发对焦?
问题:Android相机基于动态检测区域的自动对焦失效
开发了一款基于相机实时预览的场景检测应用,目标是根据检测结果设置图像的曝光与对焦兴趣点。iOS端通过FocusPointOfInterest和ExposurePointOfInterest实现该功能,运行正常;但在Android端使用MeteringRectangle为重复捕获请求设置ControlAfRegions和ControlAeRegions后,曝光可随动态变化的区域正常响应,对焦却无法在测光区域失焦时自动触发,即使初始化时设置单一固定区域也是如此。
已尝试的方案:
- 每次检测区域变化时调用
SetUpCaptureRequestMeteringAreas和TriggerAutoFocus,但区域动态变化频繁导致对焦触发陷入无限循环; - 在捕获回调中监听AF状态,首次触发后AF状态从
inactive→active scan→focus locked,但后续无论测光区域是否失焦均保持锁定状态; - 设置连续拍照对焦模式并保留测光区域,对焦偶尔触发但似乎基于整个场景,忽略了设置的测光区域;
- 尝试使用
CONTROL_AF_SCENE_CHANGE_DETECTED相关属性,但手头设备均不支持该属性及对应的CONTROL_AF_SCENE_CHANGE捕获控制。
代码问题分析
- AF模式选择错误:原
TriggerAutoFocus方法使用ControlAFMode.Auto(单次自动对焦),完成后会锁定对焦状态,不会自动重新触发对焦; - 区域更新与AF模式不匹配:更新测光区域时未确保AF模式处于支持持续对焦的模式,导致区域设置无法生效;
- 单次AF触发后未恢复持续逻辑:单次对焦完成后未切换回连续模式,无法实现后续的自动重新对焦。
修正方案
1. 选择正确的连续对焦模式
使用ControlAFMode.ContinuousPicture,该模式专为拍照场景设计,会持续监测指定对焦区域,当区域内失焦时自动触发重新对焦,同时完全支持ControlAfRegions指定兴趣区域。
2. 调整初始化与区域更新逻辑
修改初始化代码
// 初始化预览请求时直接设置连续对焦模式 SetUpCaptureRequestBuilder(mPreviewRequestBuilder); mPreviewRequestBuilder.Set(CaptureRequest.ControlAfMode, new Java.Lang.Integer((int)ControlAFMode.ContinuousPicture)); mPreviewRequest = mPreviewRequestBuilder.Build(); mPreviewSession.SetRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler); // 设置初始测光区域 SetUpCaptureRequestMeteringAreas(new PointF(0.1f, 0.5f), new PointF(0.9f, 0.5f));
优化SetUpCaptureRequestMeteringAreas方法
确保更新区域时保持连续对焦模式,并增加设备兼容性检查:
public void SetUpCaptureRequestMeteringAreas(PointF focusPt, PointF exposurePt) { Rect sensorSize = (Rect)mCharacteristics.Get(CameraCharacteristics.SensorInfoActiveArraySize); // 创建对焦区域(调整区域大小为传感器的5%,避免过小无法识别) int areaSizeW = (int)(sensorSize.Width() * 0.05); int areaSizeH = (int)(sensorSize.Height() * 0.05); MeteringRectangle focusAreaTouch = new MeteringRectangle( (int)(focusPt.X * sensorSize.Width()) - areaSizeW/2, (int)(focusPt.Y * sensorSize.Height()) - areaSizeH/2, areaSizeW, areaSizeH, MeteringRectangle.MeteringWeightMax); MeteringRectangle[] focusRegions = new MeteringRectangle[] { focusAreaTouch }; // 创建曝光区域 MeteringRectangle exposureAreaTouch = new MeteringRectangle( (int)(exposurePt.X * sensorSize.Width()) - areaSizeW/2, (int)(exposurePt.Y * sensorSize.Height()) - areaSizeH/2, areaSizeW, areaSizeH, MeteringRectangle.MeteringWeightMax); MeteringRectangle[] exposureRegions = new MeteringRectangle[] { exposureAreaTouch }; // 先检查设备是否支持区域设置 if (mCharacteristics.Get(CameraCharacteristics.ControlAfRegionsSupported)) { mPreviewRequestBuilder.Set(CaptureRequest.ControlAfRegions, focusRegions); } if (mCharacteristics.Get(CameraCharacteristics.ControlAeRegionsSupported)) { mPreviewRequestBuilder.Set(CaptureRequest.ControlAeRegions, exposureRegions); mPreviewRequestBuilder.Set(CaptureRequest.ControlAwbRegions, exposureRegions); } // 强制保持连续对焦模式 mPreviewRequestBuilder.Set(CaptureRequest.ControlAfMode, new Java.Lang.Integer((int)ControlAFMode.ContinuousPicture)); mPreviewRequest = mPreviewRequestBuilder.Build(); try { mPreviewSession.SetRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler); } catch (CameraAccessException ex) { ex.PrintStackTrace(); } }
优化单次对焦触发逻辑(可选)
仅在首次设置区域或需要快速锁定时调用,完成后自动恢复连续模式:
public void TriggerAutoFocus(CameraCaptureListener captureCallback) { // 临时切换为单次AF模式并触发对焦 mPreviewRequestBuilder.Set(CaptureRequest.ControlAfMode, new Java.Lang.Integer((int)ControlAFMode.Auto)); mPreviewRequestBuilder.Set(CaptureRequest.ControlAfTrigger, new Java.Lang.Integer((int)ControlAFTrigger.Start)); var tempRequest = mPreviewRequestBuilder.Build(); try { mPreviewSession.Capture(tempRequest, new CameraCaptureListener { OnCaptureCompleted = (session, request, result) => { // 对焦完成后恢复连续对焦模式 mPreviewRequestBuilder.Set(CaptureRequest.ControlAfMode, new Java.Lang.Integer((int)ControlAFMode.ContinuousPicture)); mPreviewRequestBuilder.Set(CaptureRequest.ControlAfTrigger, null); // 清除触发指令 mPreviewRequest = mPreviewRequestBuilder.Build(); mPreviewSession.SetRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler); // 执行传入的回调逻辑 captureCallback?.OnCaptureCompleted(session, request, result); } }, mBackgroundHandler); } catch (CameraAccessException ex) { ex.PrintStackTrace(); } }
3. 监控AF状态(可选)
在捕获回调中监听AF状态,确保连续模式正常工作:
public override void OnCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { var afState = (ControlAFState)result.Get(CaptureResult.ControlAfState); switch (afState) { case ControlAFState.PassiveScan: // 连续模式下的被动扫描状态,正常监测对焦区域 break; case ControlAFState.FocusedLocked: // 对焦锁定,区域内清晰 break; case ControlAFState.NotFocusedLocked: // 未锁定,连续模式下会自动重新扫描 break; } }
关键注意事项
- 区域大小调整:对焦区域过小可能被相机忽略,建议设置为传感器尺寸的5%-10%;
- 防抖处理:对检测区域做防抖过滤(如设置位置变化阈值、限制更新频率),避免频繁更新干扰对焦逻辑;
- 设备兼容性:部分低端设备可能不支持
ControlAfRegions,需通过CameraCharacteristics.ControlAfRegionsSupported提前检查。
内容的提问来源于stack exchange,提问作者Antonio Lopes
相关产品推荐
相关产品推荐

