Android 카메라 방향을 올바르게 설정하는 방법은 무엇입니까?


90

Android에서 기기 방향에 따라 카메라 방향을 설정하고 싶지만 아무것도 작동하지 않는 것 같습니다. Surface와 카메라 매개 변수를 회전하려고했지만 세로 모드의 카메라 미리보기가 항상 거꾸로 표시됩니다. 정확하려면 시계 방향으로 90도 회전해야합니다. 다음은 가로 모드에서만 작동하는 지금 사용중인 코드입니다.

    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 카메라 미리보기는 최소한 2.2 이전 버전에서는 가로 모드에서만 작동합니다. 그래서 카메라 미리보기를 수행하는 활동이 시스템 알림 표시 줄을 숨기고 제목이없는 경향이 있다고 추측합니다. 분명히 세로 임에도 불구하고 "정말"풍경이라고 생각합니다.
Reuben Scratton

답변:


71

다른 회원과 내 문제에서 :

카메라 회전 문제는 다른 장치와 특정 버전에 따라 다릅니다.

버전 1.6 : 회전 문제 수정, 대부분의 장치에 적합

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

버전 2.1 : 장치의 종류에 따라 다릅니다. 예를 들어 Cannt는 XPeria X10에서 문제를 해결하지만 X8 및 Mini에 적합합니다.

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

버전 2.2 : 모든 기기에 적용되는 것은 아닙니다.

camera.setDisplayOrientation(90);

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


3
여기 버전이란 무엇을 의미합니까?
. 메릴랜드 Sulayman

31

Javadocs에서 setDisplayOrientation(int)(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이 클래스는 CameraInfo내가 게시 방법은 API 레벨 9를 필요로하므로, API 레벨 9까지 도입되지 않았다
제이슨 로빈슨에게

2
result = (360 - result) % 360; // compensate the mirror삭제 해야합니다. 그렇지 않으면 전면 카메라의 사진이 잘못 회전됩니다
stevo.mit

@ stevo.mit 여러 장치에서 이것을 확인 했습니까? 이 코드를 회전에 여러 번 사용했으며 잘못된 회전이 발생하지 않았습니다.
Jason Robinson

2
@ Jason Robinson API 수준이 9 이상인 모델 목록이 있지만이 방법은 효과가 없습니다. 하드웨어 관련 문제의 날씨를 모릅니다. 장치 목록 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 2014

1
@AbdulMohsin developer.android.com/reference/android/hardware/… , 특히 CAMERA_FACING_BACK 및 CAMERA_FACING_FRONT를보십시오.
Jason Robinson

25

이 솔루션은 모든 버전의 Android에서 작동합니다 . Java에서 리플렉션을 사용하여 모든 Android 장치에서 작동하도록 할 수 있습니다.

기본적으로 특정 메서드를 호출하는 대신 Android 2.2 setDisplayOrientation을 호출하는 리플렉션 래퍼를 만들어야합니다.

방법:

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

그리고 camera.setDisplayOrientation (x)을 사용 하는 대신 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
else 부분은 일부 2.1 장치에서 작동하지만 전부는 아닙니다 (위의 maydenec 설명 참조).
Eric Chen

1
나는 p가 typre라고 생각 Camera.Parameters합니다. 다음 줄을 추가해보십시오.Camera.Parameters p = camera.getParameters();
Sehrish Khan 2012-08-09

6

탭에서 스캔하기 위해 ZBar를 사용할 때 문제에 직면했습니다. 카메라 방향 문제. 아래 코드를 사용하여 문제를 해결할 수있었습니다. 이것은 전체 코드 스 니펫이 아닙니다. 이것으로부터 도움을 받으십시오.

 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

마침내 Google의 카메라 앱을 사용하여이 문제를 해결했습니다. 센서를 사용하여 휴대 전화의 방향을 파악한 다음 EXIF ​​태그를 적절하게 설정합니다. 카메라에서 나오는 JPEG는 자동으로 방향이 지정되지 않습니다.

또한 카메라 미리보기는 가로 모드에서만 제대로 작동합니다. 활동 레이아웃을 세로 방향으로 지정해야하는 경우 방향 센서의 값을 사용하여 수동으로 수행해야합니다.


2
헤이, 방향 센서를 사용하여 카메라 방향을 얻는 방법 ?? 코드를 공유해주세요 ...
Rishi

@Rishi는이 링크를 참조하십시오 stackoverflow.com/questions/9055460/…
PiyushMishra

4
도와 주셔서 감사합니다.하지만 심성 휴대폰에서 세로 모드로 사진을 찍을 때 사진이 화면에 90도 회전되어 표시됩니다. 그래서, 그래서 카메라의 방향을 얻기 위해 노력하고있어, 메신저 세로 모드로 사진을 90도 회전
리시

5

이 솔루션을 확인하십시오

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

전면 카메라를 다루어 주셔서 감사합니다. 이것은 내 문제 해결
루이 CAD

내 솔루션이 문제를 해결하는 것을 보게되어 기쁩니다 @LouisCAD를 환영합니다.
Mudassir 칸

4

이 문제는 오래 전에 해결되었지만 모든 조각을 모으는 데 어려움이 있었으므로 여기에 최종 해결책이 있습니다. 이것이 다른 사람들에게 도움이되기를 바랍니다.

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

'다른 사람들에게 도움이되기를 바랍니다.'아니요, 그렇지 않습니다. 코드 조각이 컨텍스트에서 벗어났습니다. 예를 들어 'isFrontFacingCam'은 어디에서 왔습니까?
seanpj 2014

4
나는 이것이 실제로 또 다른 주제라고 생각합니다. 이것은 초기 문제에 비하면 정말 아무것도 아닙니다. android.hardware.Camera.CameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT에서 가져올 수 있습니다. 이렇게되어 미안합니다.
Louis GRIGNON
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.