【问题标题】:Camera Source (Google Mobile Vision) returns rotated image on some devicesCamera Source (Google Mobile Vision) 在某些设备上返回旋转图像
【发布时间】:2018-01-29 13:09:45
【问题描述】:

我有 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和角度都是一样的。但是为 backCamera 返回的位图在每个设备中的旋转方式不同。我必须手动旋转每个设备的位图(三星:90,联想:0 和 Yuntab: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());
        }
    };

【问题讨论】:

  • 上次我必须实现类似的东西时,我关注了this answer,它似乎工作正常。但是它看起来与您当前的代码相似
  • 您的建议中的答案已经在 CamerSource.java 类中实现。对于相同配置(横向/纵向)的所有设备,它返回的值始终相同,但图像的旋转方式不同。

标签: android android-camera camera-calibration google-vision


【解决方案1】:

当图像已经保存在设备中时,您应该旋转它。

然后您可以旋转它以匹配拍摄照片时的位置。

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

计算图像旋转的方法:

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方向错误。你不需要依赖这些信息,你可以use orientation sensor instead
  • @AlexCohn 很奇怪。我在使用它时做了一些研究。在处理意图返回的字节数组时,我发现了错误的 EXIF。但是当我从已经保存的 imagePath 中读取时,我没有任何问题。您能否确认有关从已保存图像中读取 EXIF 的问题?我还在 Galaxy S5 上成功测试,这是您的链接报告问题的一种设备...
  • 我刚刚意识到我使用普通相机意图拍照然后旋转图像。所以我不确定它是否会使用这种方法......如果你确认它不起作用,我会删除答案
  • 你绝对不应该删除你的答案。它显示了如何正确地将旋转应用于捕获的图片。但 EXIF 是另一回事。使用 Intent,它是您拥有的唯一可靠数据,因为当相机应用程序为您执行 Intent 时,您的应用程序会暂停。幸运的是,所有合理的设备都有存储正确 EXIF 的相机应用程序。对于自定义相机(即在 onPictureTaken() 中),某些设备可能对 EXIF 不那么严格,因此查询方向传感器是谨慎的。
  • @EduardoHerzer 感谢您的回答。我已经尝试从存储在外部存储中的位图中获取 ExifInterface 数据。但它给了我三星和联想标签上的方向值“0”。图像仍需根据设备手动旋转。 Lenovo Tab 不需要旋转,而三星 Tab 则需要在后置摄像头上将图像旋转 90 度。
猜你喜欢
  • 2018-02-13
  • 1970-01-01
  • 1970-01-01
  • 2018-05-13
  • 2019-12-27
  • 1970-01-01
  • 1970-01-01
  • 2020-12-22
  • 1970-01-01
相关资源
最近更新 更多