简体   繁体   English

如何在没有预览的情况下将焦点锁定在服务上的 Camera2API 应用程序上

[英]How to lock focus on Camera2API app on a service without preview

I am building an app which uses Camera2API to take pictures.我正在构建一个使用 Camera2API 拍照的应用程序。 The thing is I need the Camera to take a picture without needing a preview.问题是我需要相机拍照而不需要预览。 So far, I managed to do it by dumping (and adapting) the code from an activity into a service and it works like a charm, except for the fact that it is not focusing.到目前为止,我设法通过将代码从活动转储(并调整)到服务中来做到这一点,它就像一个魅力,除了它没有集中的事实。 On previous versions I had a state machine in charge of that focusing on the preview by means of a separate CaptureRequest.Builder, but I can't make it work without creating a new CaptureRequest.Builder on the service.在以前的版本中,我有一台 state 机器负责通过单独的 CaptureRequest.Builder 进行预览,但如果不在服务上创建新的 CaptureRequest.Builder,我就无法使其工作。

I followed this topic on the following stackoverflow discussion How to lock focus in camera2 api, android?我在以下stackoverflow讨论中关注了这个主题如何在camera2 api,android中锁定焦点? but I did not manage to make it work.但我没能成功。

My code does the following: First I create a camera session once the camera has been opened.我的代码执行以下操作:首先,一旦打开相机,我就会创建一个相机 session。

public void createCameraSession() {
    try {
        // Here, we create a CameraCaptureSession for camera preview.
        cameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()),
                new CameraCaptureSession.StateCallback() {

                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                        // The camera is already closed
                        if (null == cameraDevice) {
                            return;
                        }

                        // When the session is ready, we start displaying the preview.
                        mCaptureSession = cameraCaptureSession;

                        camera2TakePicture();
                    }

                    @Override
                    public void onConfigureFailed(
                            @NonNull CameraCaptureSession cameraCaptureSession) {
                    }
                }, null
        );
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

Then on that camera session I call my method "camera2TakePicture()":然后在那台相机上 session 我将我的方法称为“camera2TakePicture()”:

protected void camera2TakePicture() {
    if (null == cameraDevice) {
        return;
    }
    try {
        Surface readerSurface = imageReader.getSurface();
        List<Surface> outputSurfaces = new ArrayList<Surface>(2);
        outputSurfaces.add(readerSurface);
        final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(readerSurface);
        captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
        captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
        captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
        //MeteringRectangle meteringRectangle = getAFRegion();
        //captureBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[] {meteringRectangle});
        /**** TO BE USED ONCE SAMSUNG TABLETS HAVE BEEN REPLACED ****/
        boolean samsungReplaced = false;
        if(Boolean.parseBoolean(getPreferenceValue(this, "manualCamSettings"))) {
            int exposureCompensation = Integer.parseInt(getPreferenceValue(this, "exposureCompensation"));
            captureBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureCompensation);
            if(samsungReplaced) {
                //Exposure
                captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF);
                Float shutterSpeed = 1 / Float.parseFloat(getPreferenceValue(this, "camSSpeed"));
                Long exposureTimeInNanoSec = new Long(Math.round(shutterSpeed * Math.pow(10, 9)));
                captureBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposureTimeInNanoSec);
                captureBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, 10 * exposureTimeInNanoSec);
                //ISO
                int ISO = Integer.parseInt(getPreferenceValue(this, "camISO"));
                captureBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, ISO);
                //Aperture
                Float aperture = Float.parseFloat(getPreferenceValue(this, "camAperture"));
                captureBuilder.set(CaptureRequest.LENS_APERTURE, aperture);
            }
        }
        // Orientation
        WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        Display display = window.getDefaultDisplay();
        int rotation = display.getRotation();
        captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));

        CameraCaptureSession.CaptureCallback CaptureCallback
                = new CameraCaptureSession.CaptureCallback() {

            @Override
            public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                           @NonNull CaptureRequest request,
                                           @NonNull TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);
                while(result.get(CaptureResult.CONTROL_AF_STATE) != CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED){
                    System.out.println("Not focused");
                }
                System.out.println("Focused");
            }
        };

        mCaptureSession.stopRepeating();
        mCaptureSession.abortCaptures();
        mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
        captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

As you can see, I set the CONTROL_AF_MODE to AUTO then start the AF_TRIGGER and launch the capture.如您所见,我将 CONTROL_AF_MODE 设置为 AUTO,然后启动 AF_TRIGGER 并启动捕获。 I add a check on onCaptureCompleted() but the AF_STATE never seems to be on FOCUSED_LOCKED.我在 onCaptureCompleted() 上添加了一个检查,但 AF_STATE 似乎从来没有在 FOCUSED_LOCKED 上。 It stays on ACTIVE_SCAN.它停留在 ACTIVE_SCAN 上。

What am I doing wrong?我究竟做错了什么?

In your code snippet, you've stopped the repeating request, and issue one capture request for the still image, but just one.在您的代码片段中,您已停止重复请求,并为静止图像发出一个捕获请求,但只有一个。

Do you then go on to restart the repeating request?你然后 go 就重新开始重复请求? If you don't, there are no frames flowing through the camera, and AF cannot make progress.如果不这样做,则没有帧流过相机,并且自动对焦无法取得进展。

So if you want to lock AF before you take a picture, you want to所以如果你想在拍照前锁定AF,你想

  1. Set AF_TRIGGER to START for a single capture only将 AF_TRIGGER 设置为 START 仅用于单次捕获
  2. Run preview until you get AE_STATE out of ACTIVE_SCAN运行预览,直到您从 ACTIVE_SCAN 中获得 AE_STATE
  3. Issue single capture for still image.为静止图像发出单次捕获。

Being in the background or foreground doesn't really change any of this.在后台或前台并没有真正改变这一切。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM