You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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捕获控制。

代码问题分析

  1. AF模式选择错误:原TriggerAutoFocus方法使用ControlAFMode.Auto(单次自动对焦),完成后会锁定对焦状态,不会自动重新触发对焦;
  2. 区域更新与AF模式不匹配:更新测光区域时未确保AF模式处于支持持续对焦的模式,导致区域设置无法生效;
  3. 单次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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 08:06:09