Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android camera2 api touch to focus example?

Hi I'm using camera2basic example to implement my camera2 application. I can't find any good example to implement touch to focus with camera2 api. Currently the code i'm using for touch to focus is this:

    private void setFocusArea(MotionEvent event) {
    if (mCameraId == null) return;
    CameraManager cm = (CameraManager)getActivity().getSystemService(Context.CAMERA_SERVICE);
    CameraCharacteristics cc = null;
    try {
        cc = cm.getCameraCharacteristics(mCameraId);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }

    int myX = (int)event.getX();
    int myY = (int)event.getY();
    MeteringRectangle focusArea = new MeteringRectangle(myX-100,myY-100,200,200,MeteringRectangle.METERING_WEIGHT_DONT_CARE);
    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
    try {
        mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                mBackgroundHandler);
        // After this, the camera will go back to the normal state of preview.
        mState = STATE_PREVIEW;
    } catch (CameraAccessException e){
        // log
    }

    if (isMeteringAreaAESupported(cc)) {
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS,
                new MeteringRectangle[]{focusArea});
    }
    if (isMeteringAreaAFSupported(cc)) {
        mPreviewRequestBuilder
                .set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusArea});
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                CaptureRequest.CONTROL_AF_MODE_AUTO);
    }
    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
            CameraMetadata.CONTROL_AF_TRIGGER_START);
    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
            CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START);
    try {
        mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback,
                mBackgroundHandler);
        mManualFocusEngaged = true;
    } catch (CameraAccessException e) {
        // error handling
    }
}

But the problem is that it shows strange behavior, with auto-flash on it keeps repeating the auto-focus sequence for unlimited times also it doesnot seem to focus on the touched area. I tried changing

mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);

to:

mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);

this stopped the repeating auto-focus sequence but it still doesn't focus on the touched area and the flash just blinks for less than a second instead of a normal focus sequence. Please help me with this or guide me to a working touch to focus example. Thanks

like image 492
Zaeem Adil Avatar asked Jan 14 '17 11:01

Zaeem Adil


1 Answers

Your problem is setting the AF region's control.

  1. Calculate the region that you want to set Focus
  2. stop current session mPreviewSession.stopRepeating()
  3. Start AF trigger!!!

3.1. Safely start to make the AF region IDLE

3.2. then start AF trigger

        mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
        mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
  1. Capture once to apply your settings

  2. Check if AF and AE regions are supported or not is supported If supported then apply this region

    if ( isMeteringAreaAESupported()) {
        //System.out.println("AE regions are supported");
        mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, new MeteringRectangle[]{focusArea});
    }
    if (  isMeteringAreaAFSupported()) {
        //System.out.println("AF regions are supported");
    
        mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusArea});
        mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
    }
    
  3. Again capture once to set the focus

     mPreviewCaptureSession.capture(mCaptureRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
    
  4. inside mCaptureCallback you should cancel AF trigger, but the documentation says AF trigger can be null in some device so I did like

    mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
    mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
    mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, null);
    
  5. The last things is mPreviewCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(), null, mBackgroundHandler);

EDIT

Here is the working example

private void setFocusArea(int focus_point_x, int focus_point_y) throws CameraAccessException {

if (cameraId == null || mManualFocusEngaged) return;

if (mCameraManager == null){
    mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
}

MeteringRectangle focusArea = null;

if (mCameraManager != null) {
    if (mCameraCharacteristics == null) {
        mCameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraId);
    }

    final Rect sensorArraySize = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);

    int y = focus_point_x;
    int x = focus_point_y;

    if (sensorArraySize != null) {
        y = (int)(((float)focus_point_x / currentWidth)  * (float)sensorArraySize.height());
        x = (int)(((float)focus_point_y / currentHeight) * (float)sensorArraySize.width());
    }

    final int halfTouchLength  = 150;
    focusArea = new MeteringRectangle(Math.max(x - halfTouchLength,  0),
            Math.max(y - halfTouchLength, 0),
            halfTouchLength  * 2,
            halfTouchLength * 2,
            MeteringRectangle.METERING_WEIGHT_MAX - 1);
}

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

    @Override
    public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
        super.onCaptureCompleted(session, request, result);

        mManualFocusEngaged = false;

        if (request.getTag().equals(FOCUS_TAG)) { // previously getTag == "Focus_tag"
            //the focus trigger is complete -
            //resume repeating (preview surface will get frames), clear AF trigger
            mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
            mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
            mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, null);// As documentation says AF_trigger can be null in some device
            try {
                mCurrentCameraCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(), null, mBackgroundHandler);
            } catch (CameraAccessException e) {
                // error handling
            }
        }
    }

    @Override
    public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
        super.onCaptureFailed(session, request, failure);
        mManualFocusEngaged = false;
    }

};

mCurrentCameraCaptureSession.stopRepeating(); // Destroy current session
mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mCurrentCameraCaptureSession.capture(mCaptureRequestBuilder.build(), mCaptureCallback, mBackgroundHandler); //Set all settings for once

if ( isMeteringAreaAESupported()) {
    mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, new MeteringRectangle[]{focusArea});
}
if ( isMeteringAreaAFSupported()) {
    mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusArea});
    mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
}

mCaptureRequestBuilder.setTag(FOCUS_TAG); //it will be checked inside mCaptureCallback
mCurrentCameraCaptureSession.capture(mCaptureRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);

mManualFocusEngaged = true;
}




   private boolean isMeteringAreaAFSupported() { // AF stands for AutoFocus

    Integer afRegion = mCameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
    return afRegion != null && afRegion >= 1;

   }


private boolean isMeteringAreaAESupported() {//AE stands for AutoExposure

    Integer aeState = mCameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
    return aeState!=null && aeState >=1;

}

Hope it helps. Enjoy coding

like image 122
Jasurbek Avatar answered Oct 13 '22 23:10

Jasurbek