Come impostare correttamente l'orientamento della fotocamera Android?


89

Voglio impostare l'orientamento della fotocamera in base all'orientamento del dispositivo in Android ma sembra che non funzioni nulla. Ho provato a ruotare la superficie così come i parametri della fotocamera, ma l'anteprima della fotocamera in modalità verticale viene sempre capovolta. Dovrei ruotarlo di 90 gradi in senso orario affinché sia ​​corretto. Ecco il codice che sto usando in questo momento che funziona solo in modalità orizzontale.

    SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        camera.release();
        camera = null;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {          
        initCamera();           
    }

    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.2;
        double targetRatio = (double) w / h;
        if (sizes == null)
            return null;

        Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Size size : sizes) {
            Log.d(TAG, "Checking size " + size.width + "w " + size.height
                    + "h");
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the
        // requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Camera.Parameters parameters = camera.getParameters();

        List<Size> sizes = parameters.getSupportedPreviewSizes();
        Size optimalSize = getOptimalPreviewSize(sizes, width, height);         
        Log.d(TAG, "Surface size is " + width + "w " + height + "h");
        Log.d(TAG, "Optimal size is " + optimalSize.width + "w " + optimalSize.height + "h");           
        parameters.setPreviewSize(optimalSize.width, optimalSize.height);           
        // parameters.setPreviewSize(width, height);            
        camera.setParameters(parameters);
        camera.startPreview();
    }
};  

6
Per quanto ne so, l'anteprima della fotocamera funziona davvero solo in orizzontale, almeno per 2.2 e precedenti. Suppongo che sia per questo che le attività che fanno l'anteprima della fotocamera tendono a nascondere la barra di notifica del sistema e non hanno titoli ... nonostante siano apparentemente verticali, penso che siano "davvero" panoramiche.
Reuben Scratton

Risposte:


71

Dall'altro membro e dal mio problema:

Il problema di rotazione della telecamera dipende da diversi dispositivi e determinate versioni.

Versione 1.6: per risolvere il problema di rotazione, ed è buono per la maggior parte dei dispositivi

if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
        {   
            p.set("orientation", "portrait");
            p.set("rotation",90);
        }
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
        {                               
            p.set("orientation", "landscape");          
            p.set("rotation", 90);
        }

Versione 2.1: dipende dal tipo di dispositivo, ad esempio, non è possibile risolvere il problema con XPeria X10, ma va bene per X8 e Mini

Camera.Parameters parameters = camera.getParameters();
parameters.set("orientation", "portrait");
camera.setParameters(parameters);

Versione 2.2: non per tutti i dispositivi

camera.setDisplayOrientation(90);

http://code.google.com/p/android/issues/detail?id=1193#c42


3
cosa intendi con la versione qui?
Md. Sulayman

31

Da Javadoc per setDisplayOrientation(int)(richiede il livello API 9):

 public static void setCameraDisplayOrientation(Activity activity,
         int cameraId, android.hardware.Camera camera) {
     android.hardware.Camera.CameraInfo info =
             new android.hardware.Camera.CameraInfo();
     android.hardware.Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay()
             .getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);
 }

1
@Derzu La classe CameraInfonon è stata introdotta fino al livello API 9, quindi il metodo che ho pubblicato richiede il livello API 9.
Jason Robinson

2
result = (360 - result) % 360; // compensate the mirrordovrebbe essere cancellato , le immagini dalla fotocamera anteriore sono altrimenti ruotate in modo errato
stevo.mit

@ stevo.mit l'hai verificato su più dispositivi? Ho usato questo codice per la rotazione un certo numero di volte e non ho riscontrato una rotazione errata.
Jason Robinson

2
@ Jason Robinson Ho un elenco di modelli in cui il livello api è superiore a 9, ma questo metodo non ha alcun effetto. Non conosco il tempo relativo al problema relativo all'hardware. Elenco dei dispositivi rotation_issue_models = Arrays.asList ("GT-S5360", "GT-S6802", "GT-S5830C", "GT-S5830I", "DROID2", "GLOBAL", "XT557", "Desire HD", " PC36100 "," GT-I9000 "," ADR6350 "," Mi-One Plus "," SGH-T989 "," GT-I9100 "," GT-I9001 ");
Vikram

1
@AbdulMohsin Guarda developer.android.com/reference/android/hardware/… , in particolare CAMERA_FACING_BACK e CAMERA_FACING_FRONT.
Jason Robinson

25

Questa soluzione funzionerà per tutte le versioni di Android. Puoi utilizzare la riflessione in Java per farlo funzionare su tutti i dispositivi Android:

Fondamentalmente dovresti creare un wrapper di riflessione per chiamare setDisplayOrientation di Android 2.2, invece di chiamare il metodo specifico.

Il metodo:

    protected void setDisplayOrientation(Camera camera, int angle){
    Method downPolymorphic;
    try
    {
        downPolymorphic = camera.getClass().getMethod("setDisplayOrientation", new Class[] { int.class });
        if (downPolymorphic != null)
            downPolymorphic.invoke(camera, new Object[] { angle });
    }
    catch (Exception e1)
    {
    }
}

E invece di usare camera.setDisplayOrientation (x) usa setDisplayOrientation (camera, x) :

    if (Integer.parseInt(Build.VERSION.SDK) >= 8)
        setDisplayOrientation(mCamera, 90);
    else
    {
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
        {
            p.set("orientation", "portrait");
            p.set("rotation", 90);
        }
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
        {
            p.set("orientation", "landscape");
            p.set("rotation", 90);
        }
    }   

1
La parte else funziona su alcuni dispositivi 2.1 ma non su TUTTI (vedere la spiegazione di maydenec sopra).
Eric Chen

1
Penso che p sia di tipo Camera.Parameters. Prova ad aggiungere la seguente riga:Camera.Parameters p = camera.getParameters();
Sehrish Khan

6

Ho affrontato il problema quando stavo usando ZBar per la scansione nelle schede. Problema di orientamento della fotocamera. Utilizzando il codice seguente sono stato in grado di risolvere il problema. Questo non è l'intero snippet di codice, per favore prendi solo aiuto da questo.

 public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {
     if (isPreviewRunning) {
            mCamera.stopPreview();
        }

 setCameraDisplayOrientation(mCamera);

        previewCamera();

    }



 public void previewCamera() {

        try {
            // Hard code camera surface rotation 90 degs to match Activity view
            // in portrait
            mCamera.setPreviewDisplay(mHolder);
            mCamera.setPreviewCallback(previewCallback);
            mCamera.startPreview();
            mCamera.autoFocus(autoFocusCallback);
            isPreviewRunning = true;
        } catch (Exception e) {
            Log.d("DBG", "Error starting camera preview: " + e.getMessage());
        }


    }


public void setCameraDisplayOrientation(android.hardware.Camera camera) {
        Camera.Parameters parameters = camera.getParameters();

        android.hardware.Camera.CameraInfo camInfo =
                new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(getBackFacingCameraId(), camInfo);


        Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        int rotation = display.getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }

        int result;
        if (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (camInfo.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (camInfo.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(result);
    }




    private int getBackFacingCameraId() {
        int cameraId = -1;
        // Search for the front facing camera
        int numberOfCameras = Camera.getNumberOfCameras();
        for (int i = 0; i < numberOfCameras; i++) {
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(i, info);
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {

                cameraId = i;
                break;
            }
        }
        return cameraId;
    }

5

Alla fine ho risolto il problema utilizzando l'app della fotocamera di Google. Ottiene l'orientamento del telefono utilizzando un sensore e quindi imposta il tag EXIF ​​in modo appropriato. Il JPEG che esce dalla fotocamera non è orientato automaticamente.

Inoltre, l'anteprima della fotocamera funziona correttamente solo in modalità orizzontale. Se hai bisogno che il layout della tua attività sia orientato in verticale, dovrai farlo manualmente utilizzando il valore del sensore di orientamento.


2
ehi, come ottenere l'orientamento della fotocamera utilizzando il sensore di orientamento ?? per favore condividi il tuo codice ...
Rishi


4
Grazie per l'aiuto, ma il mio problema è quando scatto foto su telefoni Symsung in modalità verticale in quel momento la foto viene visualizzata ruotata di 90 gradi sul mio schermo. Quindi, sto cercando di ottenere l'orientamento della fotocamera, quindi ho ruotato la foto di 90 gradi per la modalità
verticale

4

Questo problema è stato risolto molto tempo fa ma ho incontrato alcune difficoltà a mettere insieme tutti i pezzi, quindi ecco la mia soluzione finale, spero che questo possa aiutare gli altri:

public void startPreview() {
        try {
            Log.i(TAG, "starting preview: " + started);

            // ....
            Camera.CameraInfo camInfo = new Camera.CameraInfo();
            Camera.getCameraInfo(cameraIndex, camInfo);
            int cameraRotationOffset = camInfo.orientation;
            // ...

            Camera.Parameters parameters = camera.getParameters();
            List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
            Camera.Size previewSize = null;
            float closestRatio = Float.MAX_VALUE;

            int targetPreviewWidth = isLandscape() ? getWidth() : getHeight();
            int targetPreviewHeight = isLandscape() ? getHeight() : getWidth();
            float targetRatio = targetPreviewWidth / (float) targetPreviewHeight;

            Log.v(TAG, "target size: " + targetPreviewWidth + " / " + targetPreviewHeight + " ratio:" + targetRatio);
            for (Camera.Size candidateSize : previewSizes) {
                float whRatio = candidateSize.width / (float) candidateSize.height;
                if (previewSize == null || Math.abs(targetRatio - whRatio) < Math.abs(targetRatio - closestRatio)) {
                    closestRatio = whRatio;
                    previewSize = candidateSize;
                }
            }

            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            int degrees = 0;
            switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break; // Natural orientation
            case Surface.ROTATION_90:
                degrees = 90;
                break; // Landscape left
            case Surface.ROTATION_180:
                degrees = 180;
                break;// Upside down
            case Surface.ROTATION_270:
                degrees = 270;
                break;// Landscape right
            }
            int displayRotation;
            if (isFrontFacingCam) {
                displayRotation = (cameraRotationOffset + degrees) % 360;
                displayRotation = (360 - displayRotation) % 360; // compensate
                                                                    // the
                                                                    // mirror
            } else { // back-facing
                displayRotation = (cameraRotationOffset - degrees + 360) % 360;
            }

            Log.v(TAG, "rotation cam / phone = displayRotation: " + cameraRotationOffset + " / " + degrees + " = "
                    + displayRotation);

            this.camera.setDisplayOrientation(displayRotation);

            int rotate;
            if (isFrontFacingCam) {
                rotate = (360 + cameraRotationOffset + degrees) % 360;
            } else {
                rotate = (360 + cameraRotationOffset - degrees) % 360;
            }

            Log.v(TAG, "screenshot rotation: " + cameraRotationOffset + " / " + degrees + " = " + rotate);

            Log.v(TAG, "preview size: " + previewSize.width + " / " + previewSize.height);
            parameters.setPreviewSize(previewSize.width, previewSize.height);
            parameters.setRotation(rotate);
            camera.setParameters(parameters);
            camera.setPreviewDisplay(mHolder);
            camera.startPreview();

            Log.d(TAG, "preview started");

            started = true;
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

"Spero che questo aiuterà gli altri" No, non lo farà. La tua parte di codice è stata estratta dal contesto. Ad esempio, da dove proviene "isFrontFacingCam"?
seanpj

4
Penso che questo sia un altro argomento in realtà, questo è davvero niente rispetto al problema iniziale. Puoi ottenerlo da android.hardware.Camera.CameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT. Scusa per questo.
Louis GRIGNON

4

controlla questa soluzione

 public static void setCameraDisplayOrientation(Activity activity,
                                                   int cameraId, android.hardware.Camera camera) {
        android.hardware.Camera.CameraInfo info =
                new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay()
                .getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0: degrees = 0; break;
            case Surface.ROTATION_90: degrees = 90; break;
            case Surface.ROTATION_180: degrees = 180; break;
            case Surface.ROTATION_270: degrees = 270; break;
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(result);
    }

Grazie per aver maneggiato la fotocamera frontale. Questo ha risolto il mio problema
Louis CAD

sei il benvenuto @LouisCAD felice di vedere che la mia soluzione risolve il tuo problema.
Mudassir Khan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.