What's the correct way to implement Tap To Focus for camera?

前端 未结 5 1491
难免孤独
难免孤独 2021-01-30 10:59

I\'m working on an app which has a custom camera screen, for which I\'m supposed to implement tap to focus, like in the Android(more specifically, the Galaxy S4) camera app.

相关标签:
5条回答
  • 2021-01-30 11:32

    I have the same issue. I've checked this on many devices, and many Android versions.

    It appears that focus-area is not working in CONTINUOUS focus-mode.

    My workaround is to set focus-mode to AUTO or MACRO along with setting focus-area:

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

    Please note that the stock Camera app on Galaxy S3 & S4 works the same way: it's permanently in continuous mode. When you touch the screen it switches to auto & sets focus-area. But after a while it comes back to continuous mode, and focus-area goes back to the center of the screen.

    I hope this helps you somehow.

    0 讨论(0)
  • 2021-01-30 11:41

    this has the solution. I just added the implementation of some missing methods in his code.

    private static  final int FOCUS_AREA_SIZE= 300;
    

    //

    mCameraPreview.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    focusOnTouch(event);
                }
                return true;
            }
        });
    

    //

     private void focusOnTouch(MotionEvent event) {
        if (mCamera != null ) {
    
            Camera.Parameters parameters = mCamera.getParameters();
            if (parameters.getMaxNumMeteringAreas() > 0){
                Log.i(TAG,"fancy !");
                Rect rect = calculateFocusArea(event.getX(), event.getY());
    
                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
                meteringAreas.add(new Camera.Area(rect, 800));
                parameters.setFocusAreas(meteringAreas);
    
                mCamera.setParameters(parameters);
                mCamera.autoFocus(mAutoFocusTakePictureCallback);
            }else {
                mCamera.autoFocus(mAutoFocusTakePictureCallback);
            }
        }
    }
    
    private Rect calculateFocusArea(float x, float y) {
        int left = clamp(Float.valueOf((x / mCameraPreview.getWidth()) * 2000 - 1000).intValue(), FOCUS_AREA_SIZE);
        int top = clamp(Float.valueOf((y / mCameraPreview.getHeight()) * 2000 - 1000).intValue(), FOCUS_AREA_SIZE);
    
        return new Rect(left, top, left + FOCUS_AREA_SIZE, top + FOCUS_AREA_SIZE);
    }
    
    private int clamp(int touchCoordinateInCameraReper, int focusAreaSize) {
        int result;
        if (Math.abs(touchCoordinateInCameraReper)+focusAreaSize/2>1000){
            if (touchCoordinateInCameraReper>0){
                result = 1000 - focusAreaSize/2;
            } else {
                result = -1000 + focusAreaSize/2;
            }
        } else{
             result = touchCoordinateInCameraReper - focusAreaSize/2;
        }
        return result;
    }
    

    // implement this callback to trigger the focus.

    private Camera.AutoFocusCallback mAutoFocusTakePictureCallback = new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                if (success) {
                    // do something...
                    Log.i("tap_to_focus","success!");
                } else {
                    // do something...
                    Log.i("tap_to_focus","fail!");
                }
            }
        };
    
    0 讨论(0)
  • 2021-01-30 11:44

    Bumped into this issue recently. As MatheusJardimB said, this question helps a lot.

    However, in my case, I wanted to start in the ContinuousPicture mode then be able to tap to focus and then continue with the ContinuousPicture mode.

    I managed to get it to work by using the onAutoFocus method of the Camera.AutoFocusCallback(). I'm not sure if it's the best or the prettiest way of doing it, but it seems to work.

    Here's the code:

    setOnTouchListener(new View.OnTouchListener() {         
        @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (mCamera != null) {
                    Camera camera = mCamera.getCamera();
                    camera.cancelAutoFocus();
                    Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f);
    
                    Parameters parameters = camera.getParameters();
                    parameters.setFocusMode(Parameters.FOCUS_MODE_MACRO);
    
                    if (parameters.getMaxNumFocusAreas() > 0) {
                        List<Area> mylist = new ArrayList<Area>();
                        mylist.add(new Camera.Area(focusRect, 1000));
                        parameters.setFocusAreas(mylist);
                    }
    
                    camera.setParameters(parameters);
                    camera.autoFocus(new Camera.AutoFocusCallback() {                   
                        @Override
                        public void onAutoFocus(boolean success, Camera camera) {
                            camera.cancelAutoFocus();
                            Parameters params = camera.getParameters();
                            if (!params.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                                params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                                camera.setParameters(params);
                            }
                        }
                    });
                }
                return true;
            }
            return false;
        });
    

    You could just change the focus area to

    ArrayList<Area> focusAreas = new ArrayList<Camera.Area>(1);
    focusAreas.add(new Area(new Rect(-1000, -1000, 1000, 0), 750));
    

    and it should work.

    UPDATE

    I recently acquired a Samsung S5 and tested this out on it. It didn't work that well, so I added a few modifications and it's working now. This was also successfully tested on the Galaxy S6 and Galaxy Note4.

    Here's the modified code:

    setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (mCamera != null) {
                Camera camera = mCamera.getCamera();
                camera.cancelAutoFocus();
                Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f);
    
                Parameters parameters = camera.getParameters();
                if (parameters.getFocusMode().equals(
                        Camera.Parameters.FOCUS_MODE_AUTO) {
                    parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
                }
    
                if (parameters.getMaxNumFocusAreas() > 0) {
                    List<Area> mylist = new ArrayList<Area>();
                    mylist.add(new Camera.Area(focusRect, 1000));
                    parameters.setFocusAreas(mylist);
                }
    
                try {
                    camera.cancelAutoFocus();
                    camera.setParameters(parameters);
                    camera.startPreview();
                    camera.autoFocus(new Camera.AutoFocusCallback() {
                        @Override
                        public void onAutoFocus(boolean success, Camera camera) {
                            if (!camera.getParameters().getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                                Parameters parameters = camera.getParameters();
                                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                                if (parameters.getMaxNumFocusAreas() > 0) {
                                    parameters.setFocusAreas(null);
                                }
                                camera.setParameters(parameters);
                                camera.startPreview();
                            }
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
    });
    
    0 讨论(0)
  • 2021-01-30 11:45

    One of the other answers causes your camera to discard the focus points previously given and return to continuous focus which I don't think makes sense.

    Also if you take a look at the link in the post the original answer uses parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);

    I've implemented the above with this line of code instead of Continuous focus and it seems to work much better.

    0 讨论(0)
  • 2021-01-30 11:53
     binding.cPreview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCamera.autoFocus(myAutoFocusCallback);
            }
        });
    
    
     Camera.AutoFocusCallback myAutoFocusCallback = new Camera.AutoFocusCallback(){
    
            @Override
            public void onAutoFocus(boolean arg0, Camera arg1) {
                // TODO Auto-generated method stub
            }};
    
    0 讨论(0)
提交回复
热议问题