Bagaimana cara mengatur orientasi kamera Android dengan benar?

90

Saya ingin mengatur orientasi kamera sesuai dengan orientasi perangkat di Android tetapi sepertinya tidak ada yang berfungsi. Saya mencoba memutar Permukaan serta parameter kamera tetapi pratinjau kamera dalam mode potret selalu terbalik. Saya perlu memutarnya 90 derajat searah jarum jam agar benar. Berikut adalah kode yang saya gunakan sekarang yang hanya berfungsi dalam mode lanskap.

    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
sumber
6
AFAIK pratinjau kamera hanya benar-benar berfungsi dalam lanskap, setidaknya untuk versi 2.2 dan sebelumnya. Saya berspekulasi bahwa itulah mengapa aktivitas yang melakukan pratinjau kamera cenderung menyembunyikan bilah notifikasi sistem dan tidak memiliki judul ... meskipun tampaknya potret, saya pikir mereka "benar-benar" lanskap.
Ruben Scratton

Jawaban:

71

Dari anggota lain dan masalah saya:

Masalah Rotasi Kamera bergantung pada Perangkat yang berbeda dan Versi tertentu.

Versi 1.6: untuk memperbaiki Masalah Rotasi, dan ini bagus untuk sebagian besar perangkat

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

Versi 2.1: bergantung pada jenis perangkat, misalnya, Tidak dapat memperbaiki masalah dengan XPeria X10, tetapi bagus untuk X8, dan Mini

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

Versi 2.2: tidak untuk semua perangkat

camera.setDisplayOrientation(90);

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

LTEHUB
sumber
3
Apa yang Anda maksud dengan versi di sini?
Md. Sulayman
31

Dari Javadocs untuk setDisplayOrientation(int)(Memerlukan 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
sumber
1
@Derzu Kelas CameraInfotidak diperkenalkan sampai API level 9, jadi metode yang saya posting membutuhkan API level 9.
Jason Robinson
2
result = (360 - result) % 360; // compensate the mirrorharus dihapus , gambar dari kamera depan diputar secara tidak benar
stevo.mit
@ stevo.mit sudahkah Anda memverifikasi ini di beberapa perangkat? Saya telah menggunakan kode ini untuk rotasi beberapa kali dan tidak menemukan rotasi yang salah.
Jason Robinson
2
@ Jason Robinson Saya memiliki beberapa daftar model dengan tingkat api di atas 9 tetapi tetap saja metode ini tidak berpengaruh. Tidak tahu cuaca masalah terkait perangkat kerasnya. Daftar perangkat 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 Lihat developer.android.com/reference/android/hardware/… , khususnya CAMERA_FACING_BACK dan CAMERA_FACING_FRONT.
Jason Robinson
25

Solusi ini akan berfungsi untuk semua versi Android. Anda dapat menggunakan refleksi di Java agar berfungsi di semua perangkat Android:

Pada dasarnya Anda harus membuat pembungkus refleksi untuk memanggil Android 2.2 setDisplayOrientation, daripada memanggil metode tertentu.

Metode:

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

Dan alih-alih menggunakan camera.setDisplayOrientation (x) gunakan 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.dll
sumber
1
Bagian lain berfungsi pada beberapa perangkat 2.1 tetapi tidak SEMUA (lihat penjelasan maydenec di atas).
Eric Chen
1
Saya pikir p adalah typre Camera.Parameters. Coba tambahkan baris berikut:Camera.Parameters p = camera.getParameters();
Sehrish Khan
6

Saya menghadapi masalah ketika saya menggunakan ZBar untuk memindai di tab. Masalah orientasi kamera. Menggunakan kode di bawah ini saya dapat menyelesaikan masalah. Ini bukan keseluruhan cuplikan kode, Mohon bantuannya saja dari sini.

 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
sumber
5

Saya akhirnya memperbaikinya menggunakan aplikasi kamera Google. Itu mendapat orientasi telepon dengan menggunakan sensor dan kemudian mengatur tag EXIF ​​dengan tepat. JPEG yang keluar dari kamera tidak diorientasikan secara otomatis.

Selain itu, pratinjau kamera berfungsi dengan baik hanya dalam mode lanskap. Jika Anda membutuhkan layout aktivitas Anda untuk diorientasikan dalam potret, Anda harus melakukannya secara manual menggunakan nilai dari sensor orientasi.

Abhinav
sumber
2
hai, bagaimana cara mendapatkan orientasi kamera menggunakan sensor orientasi ?? tolong bagikan kode Anda ...
Rishi
@Rishi lihat tautan ini stackoverflow.com/questions/9055460/…
PiyushMishra
4
Terima kasih atas Bantuan, tetapi masalah saya adalah ketika saya mengambil foto pada ponsel symsung dalam mode potret pada saat itu foto ditampilkan diputar 90 derajat di layar saya. Jadi, saya mencoba untuk mendapatkan orientasi kamera jadi, saya memutar foto 90 derajat untuk mode potret
Rishi
5

lihat solusi ini

 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
sumber
Terima kasih telah menangani kamera depan. Ini memecahkan masalah saya
Louis CAD
sama-sama @LouisCAD senang melihat bahwa solusi saya memecahkan masalah Anda.
Mudassir Khan
4

Masalah ini telah diselesaikan sejak lama tetapi saya mengalami beberapa kesulitan untuk menyatukan semua bagian jadi inilah solusi terakhir saya, saya harap ini akan membantu orang lain:

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
sumber
'Saya harap ini akan membantu orang lain' Tidak, tidak akan. Sepotong kode Anda ditarik keluar dari konteks. Misalnya, dari mana 'isFrontFacingCam' berasal?
seanpj
4
Saya pikir ini adalah subjek lain sebenarnya, ini benar-benar tidak seberapa dibandingkan dengan masalah awal. Anda bisa mendapatkannya dari android.hardware.Camera.CameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT. Maaf soal ini.
Louis GRIGNON