摄像头来源(Google Mobile Vision)在某些设备上返回旋转的图像

4

我有Google Mobile Vision - CameraSource的开源代码,这是我调用拍照的方法: cameraSource.takePicture();

在CameraSource.java的开源版本中,确定屏幕方向的方法是股票方法:

private void setRotation(Camera camera, Camera.Parameters parameters, int cameraId) {
        WindowManager windowManager =
                (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        int degrees = 0;
        int rotation = windowManager.getDefaultDisplay().getRotation();
        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;
            default:
                Log.e(TAG, "Bad rotation value: " + rotation);
        }

        CameraInfo cameraInfo = new CameraInfo();
        Camera.getCameraInfo(cameraId, cameraInfo);

        int angle;
        int displayAngle;
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
            angle = (cameraInfo.orientation + degrees) % 360;
            displayAngle = (360 - angle) % 360; // compensate for it being mirrored
        } else {  // back-facing
            angle = (cameraInfo.orientation - degrees + 360) % 360;
            displayAngle = angle;
        }

        // This corresponds to the rotation constants in {@link Frame}.
        mRotation = angle / 90;

        camera.setDisplayOrientation(displayAngle);
        parameters.setRotation(angle);
    }

在三星、联想和云电H8设备中,displayAngle和angle是相同的。但是每个设备返回的backCamera位图旋转角度不同。我必须手动为每个设备旋转位图(三星:90度,联想:0度,云电:180度)。
我的要求是onPictureTaken应该返回一个匹配当前显示方向的位图。我已经长时间研究这个问题,但还没有找到解决方法。下面是我的onPicturetaken()函数(在拍照后调用):
  @Override
        public void onPictureTaken(byte[] bytes) {
            try {
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 2;
                bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, currentCameraId == 0 ? options : null);
            }catch (Exception ex){
                ex.printStackTrace();
                Log.e("PictureTaken",ex.toString());
        }
    };

上次我实现类似功能时,我遵循了这个答案,看起来你的代码也很相似,应该可以正常工作。 - Eselfar
您的建议中的答案已经在CamerSource.java类中实现。它返回的值对于相同配置(横屏/竖屏)中的所有设备始终相同,但图像的旋转不同。 - V.Bhat
1个回答

2

在设备中保存图像后,您应该对其进行旋转。

然后,您可以将其旋转以匹配拍照时的位置。

示例代码(它可能需要一些清理和改进,但它能用...):

计算图像旋转角度的方法:

private static int rotationNeeded(String path) {
    try {
        File file = new File(path);

        if (!file.getName().contains(".jpg")) {
            return 0;
        }

        ExifInterface exif = new ExifInterface(file.getAbsolutePath());
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
            return 270;
        }

        if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
            return 180;
        }

        if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
            return 90;
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return 0;
}

对图像应用所需的旋转:

public static void rotateImage(String filePath) {
    try {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);

        //check image rotation
        int rotate = rotationNeeded(filePath);
        if (rotate != 0) {
            //rotate image if needed
            Matrix matrix = new Matrix();
            matrix.postRotate(rotate);
            Bitmap rotatedImage = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                    bitmap.getHeight(), matrix, true);

            bitmap.recycle();
            bitmap = rotatedImage;

            //save image
            byte[] dataPicture = bao.toByteArray();
            FileOutputStream fos = new FileOutputStream(filePath);
            fos.write(dataPicture);
            fos.flush();
            fos.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

实际上,一些设备会保存错误的EXIF方向。您不需要依赖该信息,您可以改用方向传感器 - Alex Cohn
@AlexCohn 奇怪。我曾经使用过它,做了一些研究。当我处理来自意图的返回字节数组时,我发现EXIF是错误的。但是当我从已保存的imagePath中读取时,我没有遇到任何问题。您能否确认从已保存的图像中读取EXIF的问题?我还在Galaxy S5上进行了成功测试,这是您链接报告问题的设备之一... - Eduardo Herzer
我刚意识到我使用了普通的相机意图来拍照,然后旋转了图像。所以我不确定使用这种方法是否有效...如果你确认它不起作用,我会删除答案。 - Eduardo Herzer
1
你绝对不应该删除你的答案。它展示了如何正确地将旋转应用于捕获的图片。但是EXIF是另一回事。使用Intent,这是您唯一可靠的数据,因为在相机应用程序为您执行Intent时,您的应用程序被挂起。幸运的是,所有合理的设备都有写入正确EXIF的原始相机应用程序。对于自定义相机(即在**onPictureTaken()**中),某些设备可能对EXIF要求不那么严格,因此最好查询方向传感器。 - Alex Cohn
1
@EduardoHerzer 谢谢您的回答。我已经尝试从存储在外部存储器中的位图获取ExifInterface数据。但是,在三星和联想平板电脑上,它给出了方向值为“0”。根据设备仍然需要手动旋转图像。联想平板电脑不需要旋转,而在三星平板电脑上,后置摄像头拍摄的图像需要旋转90度。 - V.Bhat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接