Android相机的动态对焦区域

时间:2017-07-19 18:31:36

标签: android camera autofocus

我正在构建一个Android相机应用程序(不使用camera2 api)来拍摄室外条件下某些物体的近距离照片。图片需要以连拍模式拍摄,即一旦激活,相机将连续拍摄5张照片,并且所有照片都需要很好地聚焦。用户可能在拍摄照片时移动相机,并且用户将无法手动选择焦点。物体颜色较深,有时相机视野中的明亮物体会过度曝光相机 我知道如何将焦点区域设置为摄像机参数,但必须自动更改焦点区域的位置,以便始终将焦点集中在摄像机视图中的暗区域。在摄像机视图中,暗物体的位置不固定,因此应用程序必须在设置对焦区域之前在每个帧中查找暗像素。
我正在考虑检查onPreviewFrame()回调中的暗区域,但我不确定这是否是正确的方法。有谁做过这个,谁可以指出我正确的方向?例如,是否有一个项目将使Android摄像头始终使用面部检测器专注于脸部?我试图在互联网上查找,但找不到任何相关项目。

1 个答案:

答案 0 :(得分:0)

你必须实现触摸焦点。像这样的东西:

 @Override
 public boolean onTouchEvent(MotionEvent event) {

  if(event.getAction() == MotionEvent.ACTION_DOWN){
   float x = event.getX();
      float y = event.getY();
      float touchMajor = event.getTouchMajor();
      float touchMinor = event.getTouchMinor();

      Rect touchRect = new Rect(
        (int)(x - touchMajor/2), 
        (int)(y - touchMinor/2), 
        (int)(x + touchMajor/2), 
        (int)(y + touchMinor/2));
      if (mTouchEventListener != null)
          mTouchEventListener.touchFocus(touchRect, false);
  }

其中touchFocus看起来像这样:

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public void touchFocus(Rect tfocusRect, boolean useInMid) {

        if (mCamera == null) return;

        try{
        mCamera.cancelAutoFocus(); 

         //Convert from View's width and height to +/- 1000
      Rect targetFocusRect = (useInMid || sfv == null) ? new Rect() :
          new Rect(tfocusRect.left * 2000/sfv.getWidth() - 1000,
                tfocusRect.top * 2000/sfv.getHeight() - 1000,
                tfocusRect.right * 2000/sfv.getWidth() - 1000,
                tfocusRect.bottom * 2000/sfv.getHeight() - 1000);

      final List<Camera.Area> focusList = new ArrayList<Camera.Area>();
      Camera.Area focusArea = new Camera.Area(targetFocusRect, 1000);
      focusList.add(focusArea);
      Parameters para = mCamera.getParameters();
      O.Log.d(TAG,para.getMaxNumFocusAreas() + ";" +  para.getMaxNumMeteringAreas() + " >> " + tfocusRect.toString()); 
      para.setFocusAreas(focusList);
      para.setMeteringAreas(focusList);
          try{
          mCamera.setParameters(para);
          }catch(RuntimeException e){
              O.Log.e(TAG, "setParameters failed", e);
          }
     mCamera.autoFocus(myAutoFocusCallback);
//   _.setCameraTorch(1);
        }catch (Exception e){
            O.Log.e(TAG, "Touch Focus Camera Error", e);
        }
    }
     private static AutoFocusCallback myAutoFocusCallback = new AutoFocusCallback() {

            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                // TODO Auto-generated method stub

            }
        };

for new API阅读了这篇文章http://www.morethantechnical.com/2017/02/28/android-camera2-touch-to-focus/

 //Override in your touch-enabled view (this can be differen than the view you use for displaying the cam preview)
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        final int actionMasked = motionEvent.getActionMasked();
        if (actionMasked != MotionEvent.ACTION_DOWN) {
            return false;
        }
        if (mManualFocusEngaged) {
            Log.d(TAG, "Manual focus already engaged");
            return true;
        }

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

        //TODO: here I just flip x,y, but this needs to correspond with the sensor orientation (via SENSOR_ORIENTATION)
        final int y = (int)((motionEvent.getX() / (float)view.getWidth())  * (float)sensorArraySize.height());
        final int x = (int)((motionEvent.getY() / (float)view.getHeight()) * (float)sensorArraySize.width());
        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 focusAreaTouch = new MeteringRectangle(Math.max(x - halfTouchWidth,  0),
                                                                 Math.max(y - halfTouchHeight, 0),
                                                                 halfTouchWidth  * 2,
                                                                 halfTouchHeight * 2,
                                                                 MeteringRectangle.METERING_WEIGHT_MAX - 1);

        CameraCaptureSession.CaptureCallback captureCallbackHandler = new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);
                mManualFocusEngaged = false;

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

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

        //first stop the existing repeating request
        mCameraOps.stopRepeating();

        //cancel any existing AF trigger (repeated touches, etc.)
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
        mCameraOps.capture(mPreviewRequestBuilder.build(), captureCallbackHandler, mBackgroundHandler);

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

        //then we ask for a single request (not repeating!)
        mCameraOps.capture(mPreviewRequestBuilder.build(), captureCallbackHandler, mBackgroundHandler);
        mManualFocusEngaged = true;

        return true;
    }

    private boolean isMeteringAreaAFSupported() {
        return mCameraInfo.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF) >= 1;
    }