Wie stelle ich die Ausrichtung der Android-Kamera richtig ein?

88

Ich möchte die Kameraausrichtung entsprechend der Geräteausrichtung in Android einstellen, aber nichts scheint zu funktionieren. Ich habe versucht, die Oberfläche sowie die Kameraparameter zu drehen, aber die Kameravorschau im Hochformat steht immer auf dem Kopf. Ich müsste es um 90 Grad im Uhrzeigersinn drehen, damit es korrekt ist. Hier ist der Code, den ich gerade verwende und der nur im Querformat funktioniert.

    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();
    }
};  
Abhinav
quelle
6
AFAIK die Kameravorschau funktioniert wirklich nur im Querformat, zumindest für 2.2 und früher. Ich spekuliere, dass deshalb Aktivitäten, die eine Vorschau der Kamera durchführen, dazu neigen, die Systembenachrichtigungsleiste auszublenden und keine Titel zu haben ... obwohl sie anscheinend im Hochformat sind, denke ich, dass sie "wirklich" Landschaft sind.
Reuben Scratton

Antworten:

71

Von einem anderen Mitglied und meinem Problem:

Das Problem mit der Kameradrehung hängt von verschiedenen Geräten und bestimmten Versionen ab.

Version 1.6: Behebung des Rotationsproblems, das für die meisten Geräte geeignet ist

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

Version 2.1: Abhängig von der Art der Geräte, z. B. Cannt behebt das Problem mit XPeria X10, aber es ist gut für X8 und Mini

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

Version 2.2: nicht für alle Geräte

camera.setDisplayOrientation(90);

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

LTEHUB
quelle
3
Was meinst du mit der Version hier?
Md. Sulayman
31

Aus den Javadocs für setDisplayOrientation(int)(erfordert API-Level 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);
 }
Jason Robinson
quelle
1
@Derzu Die Klasse CameraInfowurde erst auf API-Ebene 9 eingeführt, daher erfordert die von mir veröffentlichte Methode API-Ebene 9.
Jason Robinson
2
result = (360 - result) % 360; // compensate the mirrorsollte gelöscht werden , werden die Bilder von der Frontkamera sonst falsch gedreht
stevo.mit
@ stevo.mit hast du das auf mehreren geräten überprüft? Ich habe diesen Code mehrmals für die Rotation verwendet und bin auf keine falsche Rotation gestoßen.
Jason Robinson
2
@ Jason Robinson Ich habe eine Modellliste, bei der die API-Stufe über 9 liegt, aber diese Methode hat immer noch keine Auswirkung. Ich weiß nicht, ob es sich um ein Hardwareproblem handelt. Geräteliste 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 Schauen Sie sich developer.android.com/reference/android/hardware/… an , insbesondere CAMERA_FACING_BACK und CAMERA_FACING_FRONT.
Jason Robinson
25

Diese Lösung funktioniert für alle Versionen von Android. Sie können Reflection in Java verwenden, damit es für alle Android-Geräte funktioniert:

Grundsätzlich sollten Sie einen Reflection-Wrapper erstellen, um Android 2.2 setDisplayOrientation aufzurufen, anstatt die spezifische Methode aufzurufen.

Die Methode:

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

Und anstatt camera.setDisplayOrientation (x) zu verwenden, verwenden Sie 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);
        }
    }   
hnviet
quelle
1
Der else-Teil funktioniert auf einigen 2.1-Geräten, jedoch nicht auf ALL (siehe die Erklärung von maydenec oben).
Eric Chen
1
Ich denke, p ist typistisch Camera.Parameters. Versuchen Sie, die folgende Zeile hinzuzufügen:Camera.Parameters p = camera.getParameters();
Sehrish Khan
6

Ich hatte das Problem, als ich ZBar zum Scannen in Registerkarten verwendete. Problem mit der Kameraausrichtung. Mit dem folgenden Code konnte ich das Problem beheben. Dies ist nicht das gesamte Code-Snippet. Bitte nehmen Sie nur Hilfe davon.

 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;
    }
DeepakPanwar
quelle
5

Ich habe dies schließlich mit der Kamera-App von Google behoben. Mithilfe eines Sensors wird die Ausrichtung des Telefons ermittelt und das EXIF-Tag entsprechend festgelegt. Das JPEG, das aus der Kamera kommt, wird nicht automatisch ausgerichtet.

Außerdem funktioniert die Kameravorschau nur im Querformat ordnungsgemäß. Wenn Sie möchten, dass Ihr Aktivitätslayout im Hochformat ausgerichtet ist, müssen Sie dies manuell anhand des Werts des Orientierungssensors tun.

Abhinav
quelle
2
Hey, wie bekomme ich die Kameraausrichtung mit dem Orientierungssensor? Bitte teilen Sie Ihren Code ...
Rishi
@ Rishi siehe diesen Link stackoverflow.com/questions/9055460/…
PiyushMishra
4
Vielen Dank für die Hilfe, aber mein Problem ist, wenn ich Fotos auf Symsung-Handys im Hochformat mache. Das Foto wird zu diesem Zeitpunkt um 90 Grad gedreht auf meinem Bildschirm angezeigt. Also, ich versuche, die Ausrichtung der Kamera so zu bekommen, im gedrehtes Foto um 90 Grad für den Porträtmodus
Rishi
4

Dieses Problem wurde vor langer Zeit gelöst, aber ich hatte einige Schwierigkeiten, alle Teile zusammenzusetzen. Hier ist meine endgültige Lösung. Ich hoffe, dies wird anderen helfen:

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());
        }
    }
Louis GRIGNON
quelle
"Ich hoffe, das wird anderen helfen." Nein, das wird es nicht. Ihr Code wird aus dem Kontext gezogen. Woher kommt zum Beispiel die 'isFrontFacingCam'?
Seanpj
4
Ich denke, das ist eigentlich ein anderes Thema, das ist wirklich nichts im Vergleich zum ursprünglichen Problem. Sie können es von android.hardware.Camera.CameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT erhalten. Tut mir leid.
Louis GRIGNON
4

Schauen Sie sich diese Lösung an

 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);
    }
Mudassir Khan
quelle
Vielen Dank für die Handhabung der nach vorne gerichteten Kamera. Dies löste mein Problem
Louis CAD
Sie sind herzlich willkommen @LouisCAD freut sich zu sehen, dass meine Lösung Ihr Problem löst.
Mudassir Khan