Cannot get Camera2 API touch to focus to work

514 Views Asked by At

I'm unable to get the touch to focus to work properly on Camera2 API. On touching I just seem to focus for a second and then it becomes extremely blurred. The phone is a Nexus 5X. Here is my code for touch to focus.

private void refocus(MotionEvent event, View view){

    //Handler for autofocus callback
    CameraCaptureSession.CaptureCallback captureCallbackHandler = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);

            if (request.getTag() == "FOCUS_TAG") {
                //the focus trigger is complete -
                //resume repeating (preview surface will get frames), clear AF trigger
                previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, null);
                try{
                    mSession.setRepeatingRequest(previewRequest.build(), null, null);}
                catch (Exception e){

                }
            }
        }

        @Override
        public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
            super.onCaptureFailed(session, request, failure);
            Log.e(TAG, "Manual AF failure: " + failure); }
    };

    try {
        final Rect sensorArraySize = manager.getCameraCharacteristics(mCameraDevice.getId()).get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);

        //Find area size
        int x = (int)(event.getX()/(float)view.getWidth() * (float)sensorArraySize.width());
        int y = (int)(event.getY()/(float)view.getHeight() * (float)sensorArraySize.height());
        final int halfTouchWidth  = 150; //(int)motionEvent.getTouchMajor(); //TODO: this doesn't represent actual touch size in pixel. Values range in [3, 10]...
        final int halfTouchHeight = 150; //(int)motionEvent.getTouchMinor();
        MeteringRectangle rect = new MeteringRectangle(Math.max(x - halfTouchWidth,  0),
                Math.max(y - halfTouchHeight, 0),
                halfTouchWidth  * 2,
                halfTouchHeight * 2,
                MeteringRectangle.METERING_WEIGHT_MAX - 1);
        mSession.stopRepeating();
        transparentLayer.drawFeedback(rect);

        //Cancel requests
        previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
        previewRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
        mSession.capture(previewRequest.build(), captureCallbackHandler, null);

        //Now add a new AF trigger with focus region
        if (isMeteringAreaAFSupported()) {
            previewRequest.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{rect});
        }
        previewRequest.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
        previewRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
        previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
        previewRequest.setTag("FOCUS_TAG"); //we'll capture this later for resuming the preview

        //then we ask for a single request (not repeating!)
        mSession.capture(previewRequest.build(), captureCallbackHandler, null);

    }catch (Exception e){
        e.printStackTrace();
    }

}

Also have another helper function:

private boolean isMeteringAreaAFSupported() {
    try {
        return manager.getCameraCharacteristics(mCameraDevice.getId()).get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF) >= 1;
    }catch (Exception e){
        return false;
    }
}

What could be the possible reason for the focus working for a brief second, and then restarting, or getting completely blurry? There is no solution that I can find which is helpful.

Thanks all!

1

There are 1 best solutions below

2
On

I would try setting AF_TRIGGER to IDLE in onCaptureCompleted - removing it entirely isn't totally well-specified.

Beyond that, it's not clear to me how you're converting from the screen touch coordinates to the camera active array coordinates for the metering regions. It looks like you're assuming the coordinates are identical, which isn't true. That shouldn't cause blurriness, but will cause you to focus on a different area than you think.

You need to scale the x and y correctly (based on the current crop region which defines the visible field of view when using digital zoom, and the active array rectangle)