Android setFocusArea and Auto Focus

后端 未结 5 1167
余生分开走
余生分开走 2020-12-02 07:34

I\'ve been battling with this feature for couple of days now...

It seems, that camera is ignoring(?) focus areas that I\'ve defined. Here is snippets of the code:

相关标签:
5条回答
  • 2020-12-02 08:05

    My problem was much simpler :)

    All I had to do is cancel previously called autofocus. Basically the correct order of actions is this:

    protected void focusOnTouch(MotionEvent event) {
        if (camera != null) {
    
            camera.cancelAutoFocus();
            Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f);
            Rect meteringRect = calculateTapArea(event.getX(), event.getY(), 1.5f);
    
            Parameters parameters = camera.getParameters();
            parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
            parameters.setFocusAreas(Lists.newArrayList(new Camera.Area(focusRect, 1000)));
    
            if (meteringAreaSupported) {
                parameters.setMeteringAreas(Lists.newArrayList(new Camera.Area(meteringRect, 1000)));
            }
    
            camera.setParameters(parameters);
            camera.autoFocus(this);
        }
    }
    

    Update

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        ...
        Parameters p = camera.getParameters();
        if (p.getMaxNumMeteringAreas() > 0) {
           this.meteringAreaSupported = true;
        }
        ...
    }
    
    /**
     * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
     */
    private Rect calculateTapArea(float x, float y, float coefficient) {
        int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
    
        int left = clamp((int) x - areaSize / 2, 0, getSurfaceView().getWidth() - areaSize);
        int top = clamp((int) y - areaSize / 2, 0, getSurfaceView().getHeight() - areaSize);
    
        RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
        matrix.mapRect(rectF);
    
        return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
    }
    
    private int clamp(int x, int min, int max) {
        if (x > max) {
            return max;
        }
        if (x < min) {
            return min;
        }
        return x;
    }
    
    0 讨论(0)
  • 2020-12-02 08:13

    use FOCUS_MODE_FIXED

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            mCamera = Camera.open(mCameraId);
        } else {
            mCamera = Camera.open();
        }
    cameraParams = mCamera.getParameters();
    // set the focus mode
    cameraParams.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
    // set Camera parameters
    mCamera.setParameters(cameraParams);
    
    0 讨论(0)
  • 2020-12-02 08:18

    Hi, try below code copy and change for yourself

    public class CameraActivity extends AppCompatActivity implements Camera.AutoFocusCallback {
    
        private Camera camera;
        private FrameLayout fl_camera_preview;
    
        ...
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView( R.layout.camera_activity );
            //this View, is lens camera 
            fl_camera_preview = findViewById( R.id.fl_camera_preview );
            Button someButtonCapturePicture = findViewById(R.id.someButtonCapturePicture);
    
            pictureCall = getPictureCallback();
    
            //check camera access
            if ( getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) ) {
    
                if ( safeCameraOpen(0) ) {
    
                    cameraPreview = new CameraPreview( this, camera );
                    fl_camera_preview.addView( cameraPreview );
    
                    someButtonCapturePicture.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
    
                            camera.takePicture(null, null, pictureCall);
    
                        }
                    });
    
                } else {
                    Log.w(TAG, "getCameraInstance:  Camera is not available (in use or does not exist)." );
                }        
    
            }
    
        }
    
        private boolean safeCameraOpen(int id) {
    
            boolean qOpened = false;
    
            try {
    
                camera = Camera.open( id );
                // set some parameters
                Camera.Parameters par = camera.getParameters();
    
            List<Camera.Size> supportedPreviewSizes = par.getSupportedPreviewSizes();
    
                for ( Camera.Size cs : supportedPreviewSizes ) {
                  if ( cs.height == 720 ) {
                     par.setPictureSize(cs.width, cs.height);
                     par.setPreviewSize(cs.width, cs.height);
                     break;
                  }
                }
    
                camera.setParameters(par);
    
                qOpened = ( camera != null );
    
            } catch (Exception e) {
                Log.e(TAG, "safeCameraOpen: failed to open Camera");
                e.printStackTrace();
            }
    
            return qOpened;
    
        }
    
        public void touchFocusCamera( final Rect touchFocusRect ) {
    
            //Convert touche coordinate, in width and height to -/+ 1000 range
            final Rect targetFocusRect = new Rect(
                    touchFocusRect.left * 2000/fl_camera_preview.getWidth() - 1000,
                    touchFocusRect.top * 2000/fl_camera_preview.getHeight() - 1000,
                    touchFocusRect.right * 2000/fl_camera_preview.getWidth() - 1000,
                    touchFocusRect.bottom * 2000/fl_camera_preview.getHeight() - 1000);
    
            final List<Camera.Area> focusList = new ArrayList<Camera.Area>();
            Camera.Area focusArea = new Camera.Area(targetFocusRect, 1000);
            focusList.add(focusArea);
    
            Camera.Parameters para = camera.getParameters();
            List<String> supportedFocusModes = para.getSupportedFocusModes();
            if ( supportedFocusModes != null &&
                    supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO) ) {
    
                try {
    
                    para.setFocusAreas(focusList);
                    para.setMeteringAreas(focusList);
                    camera.setParameters(para);
    
                    camera.autoFocus( CameraActivity.this );
    
                } catch (Exception e) {
                    Log.e(TAG, "handleFocus: " + e.getMessage() );
                }
    
            }
    
        }
    
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
    
            if ( success ) {
                camera.cancelAutoFocus();
            }
    
            float focusDistances[] = new float[3];
            camera.getParameters().getFocusDistances(focusDistances);
    
        }
    
        /**
         * Get Bitmap from camera
         * @return picture
         */
        private Camera.PictureCallback getPictureCallback() {
    
            Camera.PictureCallback picture = new Camera.PictureCallback() {
                @Override
                public void onPictureTaken(byte[] data, Camera camera) {
    
                    Log.i(TAG, "onPictureTaken: size bytes photo: " + data.length );
    
                }
            };
    
            return picture;
    
        }
    
        ...
    
    }
    
    //And SurfaceView with Callback
    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    
        private static final String TAG = "CameraPreview";
        SurfaceHolder holder;
        Camera camera;
    
        public CameraPreview( Context context, Camera _camera ) {
            super(context);
    
            camera = _camera;
    
            // Install a SurfaceHolder.Callback so we get notified when the
            // underlying surface is created and destroyed.
            holder = getHolder();
            holder.addCallback(this);
    
            // deprecated setting, but required on Android versions prior to 3.0
            holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
    
            // The Surface has been created, now tell the camera where to draw the preview.
            try {
    
                camera.setPreviewDisplay(holder);
                camera.startPreview();
    
            } catch (IOException e) {
                Log.d(TAG, "Error setting camera preview: " + e.getMessage());
            }
    
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            if( event.getAction() == MotionEvent.ACTION_DOWN ) {
    
                // Get the pointer's current position
                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));
    
                ((CameraActivity)getContext())
                            .touchFocusCamera( touchRect );
    
            }
    
            return true;
    
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
            // If your preview can change or rotate, take care of those events here.
            // Make sure to stop the preview before resizing or reformatting it.
    
            if (this.holder.getSurface() == null) {
                // preview surface does not exist
                return;
            }
    
            // stop preview before making changes
            try {
                camera.stopPreview();
            } catch (Exception e) {
                // ignore: tried to stop a non-existent preview
            }
    
            // set preview size and make any resize, rotate or
            // reformatting changes here
    
            // start preview with new settings
            try {
                camera.setPreviewDisplay(this.holder);
                camera.startPreview();
    
            } catch (Exception e) {
                Log.d(TAG, "Error starting camera preview: " + e.getMessage());
            }
    
        }
    
        ...
    
    }
    
    0 讨论(0)
  • 2020-12-02 08:19

    Beside setting:

    parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
    

    you need to set:

    parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
    

    if you want real 'live' auto-focus. Also, it will be good to check available focuses:

    List<String> focusModes = parameters.getSupportedFocusModes();
    LLog.d("focusModes=" + focusModes);
    if (focusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
        parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
    

    On Samsung S6 you must set this with little delay (~ 500 ms) after getting camera preview.

    0 讨论(0)
  • 2020-12-02 08:22

    I had this problem today :/

    And after hours of struggling, I found the solution!

    It's strange, but it appears that setting focus-mode to "macro" right before setting focus-areas solved the problem ;)

    params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
    params.setFocusAreas(focusAreas);
    mCamera.setParameters(params);
    

    I have Galaxy S3 with Android 4.1.2

    I hope this will work for you either :)

    0 讨论(0)
提交回复
热议问题