web-dev-qa-db-fra.com

Quelle est la bonne façon d'implémenter Tap To Focus pour la caméra?

Je travaille sur une application dotée d'un écran de caméra personnalisé, pour lequel je suis supposé implémenter une fonctionnalité de mise au point, comme dans l'application de caméra Android (plus précisément, le Galaxy S4).

J'ai essayé d'utiliser les étapes décrites ici , mais cela ne semble pas causer de focalisation notable. Le mode de mise au point est défini sur Image continue (nous ne prenons en charge qu'un périphérique spécifique).

Lorsque l'utilisateur appuie sur l'aperçu de la caméra, je dois me concentrer sur la moitié supérieure de l'image. Pour cela, j'utilise l'extrait de code

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

Je ne veux pas l'autofocus car il faut trop de temps pour se concentrer sur l'image. Je ne m'intéresse qu'à la moitié supérieure de l'image. Quelqu'un a-t-il implémenté avec succès la fonction Tap to Focus avec le mode Continuous Picture?

24
Vinay S Shenoy

Bumped dans cette question récemment. Comme MatheusJardimB l'a dit, cette question aide beaucoup.

Cependant, dans mon cas, je voulais commencer dans le mode ContinuousPicture puis pouvoir appuyer sur pour faire la mise au point, puis continuer avec le mode ContinuousPicture.

J'ai réussi à le faire fonctionner en utilisant la méthode onAutoFocus de la Camera.AutoFocusCallback(). Je ne sais pas si c'est la meilleure ou la plus jolie des façons de le faire, mais cela semble fonctionner.

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

Vous pouvez simplement changer la zone de mise au point en

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

et ça devrait marcher.

METTRE &AGRAVE; JOUR

J'ai récemment acquis un Samsung S5 et l'ai testé. Cela ne fonctionnait pas très bien, alors j’ai ajouté quelques modifications et cela fonctionne maintenant. Cela a également été testé avec succès sur le Galaxy S6 et le Galaxy Note4.

Voici le code modifié:

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

this a la solution. Je viens d'ajouter l'implémentation de certaines méthodes manquantes dans son 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;
}

// implémente ce rappel pour déclencher le 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!");
            }
        }
    };
16
ahmed_khan_89

Une des autres réponses fait en sorte que votre appareil photo supprime les points de mise au point précédemment indiqués et revienne en mise au point continue, ce qui n'a aucun sens.

De plus, si vous regardez le lien dans l'article, la réponse originale utilise parameters.setFocusMode (Parameters.FOCUS_MODE_AUTO);

J'ai implémenté ce qui précède avec cette ligne de code au lieu de la mise au point continue et cela semble fonctionner beaucoup mieux.

2
Arjun
 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
Mohsinali