Какой правильный способ реализовать Tap To Focus для камеры?

Я работаю над приложением, у которого есть пользовательский экран камеры, для которого я должен реализовать крайнюю фокусировку, например, в приложении для камеры Android (точнее, Galaxy S4).

Я пробовал использовать шаги, описанные здесь, но, похоже, не вызывает заметной фокусировки. Режим фокусировки установлен на Непрерывное изображение (мы поддерживаем только конкретное устройство).

Когда пользователь нажимает на предварительный просмотр камеры, мне нужно сосредоточиться на верхней половине изображения. Для этого я использую фрагмент кода

Parameters parameters = mCamera.getParameters();

if (parameters.getMaxNumFocusAreas() > 0) {

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

    parameters.setFocusAreas(focusAreas);
    mCamera.setParameters(parameters);
}

Я НЕ хочу, чтобы AutoFocus занимал слишком много времени, чтобы сфокусироваться на изображении. Меня интересует только верхняя половина изображения. Кто-нибудь успешно применил Tap to Focus вместе с режимом непрерывной съемки?

Ответы

Ответ 1

Недавно столкнулся с этим вопросом. Как сказал MatheusJardimB, этот вопрос очень помогает.

Тем не менее, в моем случае, я хотел начать в режиме ContinuousPicture затем нажать, чтобы сфокусироваться, а затем продолжить режим ContinuousPicture.

Мне удалось заставить его работать, используя метод onAutoFocus для Camera.AutoFocusCallback(). Я не уверен, что это лучший или самый красивый способ сделать это, но, похоже, он работает.

Здесь код:

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;
    });

Вы можете просто изменить область фокусировки на

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

и он должен работать.

ОБНОВИТЬ

Недавно я приобрел Samsung S5 и протестировал его на нем. Это не сработало, поэтому я добавил несколько изменений, и теперь он работает. Это было также успешно протестировано на Galaxy S6 и Galaxy Note4.

Здесь измененный код:

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;
    }
});

Ответ 2

this имеет решение. Я просто добавил реализацию некоторых недостающих методов в свой код.

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;
}

//реализуем этот обратный вызов для запуска фокуса.

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!");
            }
        }
    };

Ответ 3

Один из других ответов заставляет камеру отбрасывать ранее заданные фокусные точки и возвращаться к непрерывной фокусировке, что, по моему мнению, не имеет смысла.

Также, если вы посмотрите на ссылку в сообщении, исходный ответ использует параметры .setFocusMode(Parameters.FOCUS_MODE_AUTO);

Я реализовал выше с этой строкой кода вместо непрерывного фокуса и, похоже, работает намного лучше.

Ответ 4

 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
        }};

Ответ 5

У меня такая же проблема. Я проверил это на многих устройствах и на многих версиях Android.

Похоже, что область фокусировки не работает в режиме непрерывного фокуса.

Мое обходное решение - установить режим фокусировки на AUTO или MACRO вместе с настройкой области фокусировки:

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

Обратите внимание, что приложение Camera Camera на Galaxy S3 и S4 работает одинаково: оно постоянно в непрерывном режиме. Когда вы касаетесь экрана, он переключается на авто и устанавливает область фокусировки. Но через некоторое время он возвращается в непрерывный режим, а область фокусировки возвращается в центр экрана.

Надеюсь, вам это поможет.