原生Camera2的对焦原理和框架,以及代码实现流程

发布时间:2024年01月03日

在Android中,Camera2 API提供了对相机硬件的底层访问,包括对焦功能。以下是Camera2对焦原理和框架的简要概述,以及代码实现流程:

对焦原理和框架:

预览: 在开始对焦之前,通常需要先启动相机的预览。预览不仅允许用户看到实时视频流,还可以提供关于相机状态的信息,如对焦模式和当前的对焦区域。
对焦模式: Android支持多种对焦模式,如连续自动对焦(AF-C)、单次自动对焦(AF-S)和手动对焦。每种模式都有不同的应用场景和行为。
对焦区域: 相机可以设置多个对焦区域,每个区域可以独立地对焦。这允许用户选择特定的焦点或自动选择焦点。
触发对焦: 通过API可以手动触发对焦操作,也可以让系统自动触发。一旦触发对焦,相机会尝试调整镜头焦距以实现对焦。
对焦回调: 当对焦完成或发生变化时,系统会发出回调通知。应用程序可以监听这些回调,以便在需要时更新UI或执行其他任务。

代码实现流程:

打开相机: 使用CameraManager获取相机的列表,并选择一个相机打开。
设置预览: 创建一个Surface,用于接收相机的预览输出。将这个Surface与相机预览会话关联起来。
配置相机参数: 通过CameraCharacteristics获取相机的详细信息,并配置必要的参数,如对焦模式和区域。
触发对焦: 使用Camera2 API的方法来触发对焦操作。这通常涉及调用takePicture或startAutofocus方法。
处理回调: 注册一个回调来监听对焦事件。当对焦完成或失败时,可以在这个回调中处理后续逻辑,例如重新触发对焦或显示对焦结果给用户。
清理资源: 在不再需要相机时,确保释放资源并关闭相机连接。

请注意,Camera2 API是一个相对高级的API,需要对Android系统和相机硬件有深入的了解才能有效地使用。此外,由于Android设备众多,不同设备的Camera2实现可能会有所不同。因此,在开发过程中可能需要进行一些特定设备的适配工作。

在Android中,使用原生Camera2 API实现对焦功能需要遵循一系列步骤。下面是一个简化的代码实现过程:

// 导入必要的Camera2 API类  
import android.hardware.camera2.CameraAccessException;  
import android.hardware.camera2.CameraManager;  
import android.hardware.camera2.CameraCharacteristics;  
import android.hardware.camera2.CameraDevice;  
import android.hardware.camera2.CameraMetadata;  
import android.hardware.camera2.CaptureRequest;  
  
// 获取CameraManager实例  
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);  
  
// 获取相机列表和默认相机ID  
String cameraId = manager.getCameraIdList()[0]; // 假设使用默认相机  
  
// 打开相机并获取CameraCharacteristics  
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);  
  
// 创建CaptureRequest.Builder  
CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);  
  
// 设置对焦模式和区域(根据需要配置)  
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);  
captureBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, regions); // regions是定义的对焦区域  
  
// 开始预览并触发对焦  
try {  
    cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {  
        @Override  
        public void onConfigured(CameraCaptureSession session) {  
            try {  
                session.setRepeatingRequest(captureBuilder.build(), null, null);  
            } catch (CameraAccessException e) {  
                e.printStackTrace();  
            }  
        }  
        @Override  
        public void onConfigureFailed(CameraCaptureSession session) {  
            // 处理配置失败的情况  
        }  
    }, null);  
} catch (CameraAccessException e) {  
    e.printStackTrace();  
}

这段代码提供了一个基本的框架,用于打开相机、设置预览、配置对焦模式和区域,并开始预览和触发对焦。请注意,这是一个简化的示例,实际应用中可能需要处理更多的异常情况、权限请求,以及根据具体需求进行更详细的配置。

现在继续分析原生Camera2对焦代码的实现过程:

首先,在packages\apps\Camera2\src\com\android\camera\one\v2\common\BasicCameraFactory.java文件中构建BasicCameraFactory时会创建初始化自动对焦:

ManualAutoFocusFactory manualAutoFocusFactory = ManualAutoFocusFactory.create(new
                Lifetime(lifetime), frameServer, cameraCommandExecutor, cropRegion,
                sensorOrientation, mPreviewUpdater, requestTemplate,
                templateType, new Settings3A(), Executors.newScheduledThreadPool(1),
                3 /* afHoldSeconds */, cameraCharacteristics.isAutoExposureSupported(),
                cameraCharacteristics.isAutoFocusSupported());
        mManualAutoFocus = manualAutoFocusFactory.provideManualAutoFocus();
        Supplier<MeteringRectangle[]> aeRegions =
                manualAutoFocusFactory.provideAEMeteringRegion();
        Supplier<MeteringRectangle[]> afRegions =
                manualAutoFocusFactory.provideAFMeteringRegion();

        requestTemplate.setParam(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
        requestTemplate.setParam(CaptureRequest.CONTROL_AF_REGIONS, afRegions);

在看重点,packages\apps\Camera2\src\com\android\camera\one\v2\autofocus\ManualAutoFocusFactory.java

public static ManualAutoFocusFactory create(Lifetime lifetime, FrameServer frameServer,
            CameraCommandExecutor commandExecutor, Supplier<Rect> cropRegion,
            int sensorOrientation,
            Runnable previewRunner, RequestBuilder.Factory rootBuilder,
            int templateType, Settings3A settings3A,
            ScheduledExecutorService threadPool,
            int afHoldSeconds, boolean aeSupport, boolean afSupport) {
        ConcurrentState<MeteringParameters> currentMeteringParameters = new ConcurrentState<>(
                GlobalMeteringParameters.create());
        AEMeteringRegion aeMeteringRegion = new AEMeteringRegion(currentMeteringParameters,
                cropRegion);
        AFMeteringRegion afMeteringRegion = new AFMeteringRegion(currentMeteringParameters,
                cropRegion);

        RequestTemplate afScanRequestBuilder = new RequestTemplate(rootBuilder);
        if (aeSupport) {
            afScanRequestBuilder.setParam(CaptureRequest.CONTROL_AE_REGIONS, aeMeteringRegion);
        }
        if (afSupport) {
            afScanRequestBuilder.setParam(CaptureRequest.CONTROL_AF_REGIONS, afMeteringRegion);
        }

        CameraCommand initialCommand;
        if (afSupport) {
            initialCommand  = new FullAFScanCommand(frameServer, afScanRequestBuilder,
                    templateType);
        } else {
            initialCommand  = new UpdateRequestCommand(frameServer, afScanRequestBuilder,
                    templateType);
        }

        ResettingDelayedExecutor afHoldDelayedExecutor = new ResettingDelayedExecutor(
                threadPool, afHoldSeconds, TimeUnit.SECONDS);
        lifetime.add(afHoldDelayedExecutor);

        CameraCommand afScanHoldResetCommand = new AFScanHoldResetCommand(initialCommand,
                afHoldDelayedExecutor, previewRunner, currentMeteringParameters);

        Runnable afRunner = new ResettingRunnableCameraCommand(commandExecutor,
                afScanHoldResetCommand);

        ManualAutoFocusImpl manualAutoFocus = new ManualAutoFocusImpl(currentMeteringParameters,
                afRunner, sensorOrientation, settings3A);

        return new ManualAutoFocusFactory(manualAutoFocus, aeMeteringRegion, afMeteringRegion);
    }

在这个地方的重点看FullAFScanCommand,packages\apps\Camera2\src\com\android\camera\one\v2\autofocus\FullAFScanCommand.java,这个类里面的run线程里实现对焦的请求。

// Build a request to send a single AF_TRIGGER
            RequestBuilder triggerBuilder = createAFTriggerRequest(afScanResult);
            session.submitRequest(Arrays.asList(triggerBuilder.build()),
                    FrameServer.RequestType.NON_REPEATING);
private RequestBuilder createAFTriggerRequest(AFTriggerResult afScanResult) throws
            CameraAccessException {
        RequestBuilder triggerBuilder = mBuilderFactory.create(mTemplateType);
        triggerBuilder.addResponseListener(forPartialMetadata(afScanResult));
        triggerBuilder.setParam(CaptureRequest.CONTROL_MODE, CaptureRequest
                .CONTROL_MODE_AUTO);
        triggerBuilder.setParam(CaptureRequest.CONTROL_AF_MODE, CaptureRequest
                .CONTROL_AF_MODE_AUTO);
        triggerBuilder.setParam(CaptureRequest.CONTROL_AF_TRIGGER,
                CaptureRequest.CONTROL_AF_TRIGGER_START);
        return triggerBuilder;
    }

这里直接把request下发到cameraservice里实现HAL的调用,实现对焦。

继续看如何实现触摸对焦,在packages\apps\Camera2\src\com\android\camera\CaptureModule.java这里实现触摸对焦的调用:

private void startActiveFocusAt(int viewX, int viewY) {
        if (mCamera == null) {
            // If we receive this after the camera is closed, do nothing.
            return;
        }

        // TODO: make mFocusController final and remove null check.
        if (mFocusController == null) {
            Log.v(TAG, "CaptureModule mFocusController is null!");
            return;
        }
        mFocusController.showActiveFocusAt(viewX, viewY);

        // Normalize coordinates to [0,1] per CameraOne API.
        float points[] = new float[2];
        points[0] = (viewX - mPreviewArea.left) / mPreviewArea.width();
        points[1] = (viewY - mPreviewArea.top) / mPreviewArea.height();

        // Rotate coordinates to portrait orientation per CameraOne API.
        Matrix rotationMatrix = new Matrix();
        rotationMatrix.setRotate(mDisplayRotation, 0.5f, 0.5f);
        rotationMatrix.mapPoints(points);

        // Invert X coordinate on front camera since the display is mirrored.
        if (mCameraCharacteristics.getCameraDirection() == Facing.FRONT) {
            points[0] = 1 - points[0];
        }

        mCamera.triggerFocusAndMeterAtPoint(points[0], points[1]);

        // Log touch (screen coordinates).
        if (mZoomValue == 1f) {
            TouchCoordinate touchCoordinate = new TouchCoordinate(
                    viewX - mPreviewArea.left,
                    viewY - mPreviewArea.top,
                    mPreviewArea.width(),
                    mPreviewArea.height());
            // TODO: Add to logging: duration, rotation.
            UsageStatistics.instance().tapToFocus(touchCoordinate, null);
        }
    }

这个的重点看mCamera.triggerFocusAndMeterAtPoint,最终调用到packages\apps\Camera2\src\com\android\camera\one\v2\autofocus\ManualAutoFocusImpl.java

public void triggerFocusAndMeterAtPoint(float nx, float ny) {
        PointF point = new PointF(nx, ny);
        mMeteringParameters.update(PointMeteringParameters.createForNormalizedCoordinates(
                point /* afPoint */, point /* aePoint */, mSensorOrientation, mSettings3A));
        mAFScanRunnable.run();
    }

这里就可以看到调用到前面讲的自动对焦里去了。

最后,总结一下具体的框图逻辑:

BasicCameraFactory ManualAutoFocusFactory FullAFScanCommand ManualAutoFocusImpl CaptureModule.java ManualAutoFocusFactory.creat new FullAFScanCommand new ManualAutoFocusImpl run() triggerFocusAndMeterAtPoint run BasicCameraFactory ManualAutoFocusFactory FullAFScanCommand ManualAutoFocusImpl CaptureModule.java
文章来源:https://blog.csdn.net/jiangchaobing_2017/article/details/135365659
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。