Android camera2 api touch to focus example?

醉酒当歌 提交于 2021-02-07 02:50:30

问题


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


回答1:


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



来源:https://stackoverflow.com/questions/41649691/android-camera2-api-touch-to-focus-example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!