Làm thế nào để đặt hướng camera Android đúng cách?


88

Tôi muốn đặt hướng camera theo hướng thiết bị trong Android nhưng dường như không có gì hoạt động. Tôi đã thử xoay Surface cũng như các thông số camera nhưng bản xem trước camera ở chế độ chân dung luôn bị lộn ngược. Tôi sẽ cần xoay nó 90 độ theo chiều kim đồng hồ để nó chính xác. Đây là mã tôi đang sử dụng hiện chỉ hoạt động ở chế độ ngang.

    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
AFAIK bản xem trước máy ảnh chỉ thực sự hoạt động ở chế độ ngang, ít nhất là cho phiên bản 2.2 trở về trước. Tôi suy đoán rằng đó là lý do tại sao các hoạt động xem trước máy ảnh có xu hướng ẩn thanh thông báo hệ thống và không có tiêu đề ... mặc dù rõ ràng là chân dung, tôi nghĩ chúng là phong cảnh "thực sự".
Reuben Scratton

Câu trả lời:


71

Từ thành viên khác và vấn đề của tôi:

Vấn đề Xoay máy ảnh phụ thuộc vào các Thiết bị khác nhau và Phiên bản nhất định.

Phiên bản 1.6: để khắc phục sự cố xoay và nó tốt cho hầu hết các thiết bị

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

Phiên bản 2.1: tùy thuộc vào loại thiết bị, ví dụ: Không thể khắc phục sự cố với XPeria X10, nhưng nó tốt cho X8 và Mini

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

Phiên bản 2.2: không dành cho tất cả các thiết bị

camera.setDisplayOrientation(90);

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


3
phiên bản ở đây nghĩa là gì?
Md. Sulayman,

31

Từ Javadocs cho setDisplayOrientation(int)(Yêu cầu API cấp 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 Lớp CameraInfođã không được giới thiệu cho đến khi cấp API 9, vì vậy phương pháp tôi đã đăng đòi hỏi mức API 9.
Jason Robinson

2
result = (360 - result) % 360; // compensate the mirrornên được xóa , những hình ảnh từ camera phía trước nếu không thì quay sai
stevo.mit

@ stevo.mit bạn đã xác minh điều này trên nhiều thiết bị chưa? Tôi đã sử dụng mã này để xoay vòng một số lần và không gặp phải việc xoay vòng không chính xác.
Jason Robinson

2
@ Jason Robinson Tôi có một số danh sách mô hình mà mức api trên 9 nhưng phương pháp này vẫn không có tác dụng. Không biết thời tiết vấn đề liên quan đến phần cứng của nó. Rotation_issue_models của danh sách thiết bị = 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 Hãy xem developer.android.com/reference/android/hardware/… , đặc biệt là CAMERA_FACING_BACK và CAMERA_FACING_FRONT.
Jason Robinson

25

Giải pháp này sẽ hoạt động cho tất cả các phiên bản Android. Bạn có thể sử dụng phản chiếu trong Java để làm cho nó hoạt động cho tất cả các thiết bị Android:

Về cơ bản, bạn nên tạo một trình bao bọc phản chiếu để gọi setDisplayOrientation của Android 2.2, thay vì gọi phương thức cụ thể.

Phương pháp:

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

Và thay vì sử dụng camera.setDisplayOrientation (x), hãy sử dụng 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
Phần khác hoạt động trên một số thiết bị 2.1 nhưng không phải TẤT CẢ (xem giải thích của maydenec ở trên).
Eric Chen

1
Tôi nghĩ p thuộc loại chính tả Camera.Parameters. Hãy thử thêm dòng sau:Camera.Parameters p = camera.getParameters();
Sehrish Khan

6

Tôi gặp sự cố khi sử dụng ZBar để quét trong các tab. Vấn đề về hướng máy ảnh. Sử dụng mã dưới đây, tôi có thể giải quyết vấn đề. Đây không phải là toàn bộ đoạn mã, Vui lòng chỉ giúp đỡ về điều này.

 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

Cuối cùng tôi đã sửa lỗi này bằng ứng dụng máy ảnh của Google. Nó nhận định hướng của điện thoại bằng cách sử dụng một cảm biến và sau đó đặt thẻ EXIF ​​một cách thích hợp. JPEG ra khỏi máy ảnh không được định hướng tự động.

Ngoài ra, bản xem trước máy ảnh chỉ hoạt động bình thường ở chế độ ngang. Nếu bạn cần bố cục hoạt động của mình được định hướng theo chiều dọc, bạn sẽ phải thực hiện theo cách thủ công bằng cách sử dụng giá trị từ cảm biến định hướng.


2
này, làm cách nào để lấy hướng camera bằng cảm biến định hướng ?? vui lòng chia sẻ mã của bạn ...
Rishi


4
Cảm ơn sự giúp đỡ của tôi, nhưng vấn đề của tôi là khi tôi chụp ảnh trên điện thoại symsung ở chế độ dọc lúc đó ảnh được hiển thị xoay 90 độ trên màn hình của tôi. Vì vậy, tôi đang cố gắng lấy hướng của máy ảnh, tôi đã xoay ảnh 90 độ cho chế độ chân dung
Rishi

4

Vấn đề này đã được giải quyết cách đây khá lâu nhưng tôi gặp một số khó khăn để ghép tất cả các mảnh lại với nhau vì vậy đây là giải pháp cuối cùng của tôi, tôi hy vọng điều này sẽ giúp những người khác:

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

'Tôi hy vọng điều này sẽ giúp ích cho người khác' Không, nó sẽ không. Đoạn mã của bạn bị kéo ra khỏi ngữ cảnh. Ví dụ, 'isFrontFacingCam' đến từ đâu?
seanpj

4
Tôi nghĩ thực ra đây là một môn học khác, điều này thực sự không là gì so với vấn đề ban đầu. Bạn có thể lấy nó từ android.hardware.Camera.CameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT. Xin lỗi về điều này.
Louis GRIGNON

4

kiểm tra giải pháp này

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

Cảm ơn bạn đã xử lý camera mặt trước. Điều này giải quyết vấn đề của tôi
Louis CAD

bạn được chào đón @LouisCAD rất vui khi thấy rằng giải pháp của tôi giải quyết được vấn đề của bạn.
Mudassir Khan,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.