setDisplayOrientation示例代码是否正确?

时间:2012-10-27 18:42:35

标签: android android-camera screen-orientation

Camera.setDisplayOrientation的documentation page包含以下代码示例,声明使用它将“使摄像机图像以与显示器相同的方向显示”:

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

然而,我在使用它时遇到了问题,有时图像会颠倒过来。经过一些反复试验,我发现正确的代码是(替换方法的最后8行):

    int result = (360 + info.orientation - degrees) % 360;
    camera.setDisplayOrientation(result);

(这意味着后置摄像头的计算对于前置摄像头也是正确的。)“补偿镜子”评论有点奇怪,因为镜像不能通过旋转来解除,该操作仅交换90°和270°旋转这对我来说没有意义。

所以问题是:样本确实是错误的还是我错过了什么? 我在多个设备上尝试过它,包括后置和前置摄像头以及所有支持的方向,所以我知道我的代码工作正常。可能值得一提的一个小细节:我的所有设备都以info.orientation的形式返回90°。

编辑: Here是我的相机相关代码,我在Nexus One和三星Galaxy S Plus上进行了测试。它在my head-tracking 3D app中使用,预览显示在左下角,并且应始终具有正确的方向。

解决方案(有点):看起来代码是正确的,但我的测试手机(三星Galaxy S Plus)为前置摄像头的CameraInfo.orientation返回了不正确的值。关于此预览在此模型上颠倒显示的许多相关讨论(示例herehere)。一种解决方法是包含一个手动旋转图像的选项。

1 个答案:

答案 0 :(得分:13)

您引用的代码段,我在项目中使用并应用,在我的情况下没问题。

对于我用于测试的所有设备(Galaxy Note,Galaxy S III,Galaxy Nexus,Galaxy Ace II,Nexus S),info.Orientation都在前置摄像头上返回270,在后置摄像头上返回90.

在与问题提升者进行了一些讨论之后,我发现我误解了这些问题,因此我将答案分为两部分。

对于相机预览中的错误方向,请参阅此解决方案:

相机预览中错误方向的解决方案:

首先请确保info.Orientation在前置摄像头上返回270,在后置摄像头上返回90。 然后,请尝试将相机预览活动(或处理预览的类似课程)设置为横向。

因此,当您浏览代码时,您会发现:

degree = 90用于屏幕方向,info.Orientation = 270用于前置摄像头。然后你会得到result = (270 - 90 + 360) % 360result = 180,这意味着它将为您的前置摄像头视图以180度方向旋转,以纠正前置摄像头倒置问题。

解决相机照片结果错误方向的问题:

如果此info.Orientation适用于您,则问题可能是:

  1. 对于某些三星(或其他)设备(如Galaxy Note,Galaxy SIII),相机只会写入方向标记,而不是旋转真实像素。
  2. 如果您正在使用前置摄像头并使用上面的代码,它将以正确的方向显示预览,但如果您拍摄,则会显示“倒置”图片。
  3. 解决方案:

    /**
     *
     * Get the orientation from EXIF
     * @param filepath
     * @return orientation
     */
    public int getExifOrientation(String filepath) {
        int degree = 0;
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(filepath);
        } catch (IOException ex) {
            Log.e("EXIF info", "cannot read exif", ex);
        }
        if (exif != null) {
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
            if (orientation != -1) {
                // We only recognize a subset of orientation tag values.
                switch(orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
                }
            }
        } else {
            degree = 1;
        }
        Log.i("EXIF info", "Orientation degrees: " + degree);
        return degree;
    }
    

    然后

    if (isFromCamera) {
    
        if (fromFrontCam) {
            // try change here if the orientation still wrong, -90 means rotate counter-clockwise 90 degrees.
            matrix.preRotate(-90);
         } else {
            matrix.preRotate(90);
         }
    } else {
        // read EXIF data
        getExifOrientation(path)
        // don't forget to handle the situation that some devices won't write exif data
        matrix.preRotate(degree);
    }