Google Mobile Vision CameraSource部分设备返回旋转图像的适配问题
解决Google Mobile Vision CameraSource拍照Bitmap旋转不一致的问题
我之前也踩过Android多设备相机拍照旋转的坑,不同厂商对相机传感器的方向处理差异确实让人头疼,原生的parameters.setRotation()在部分设备上并不会自动修正拍摄图片的方向,导致解码后的Bitmap和屏幕显示方向不匹配。下面是我整理的可行解决方案:
第一步:修改CameraSource.java保存旋转角度
首先我们需要把setRotation()方法中计算好的angle值留存下来,这个值是根据设备屏幕方向和摄像头朝向算出的正确旋转角度。修改CameraSource的代码如下:
// 在CameraSource类中添加成员变量 private int mCameraRotationAngle; 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); // 保存计算好的旋转角度 mCameraRotationAngle = angle; } // 添加公共方法供外部获取旋转角度 public int getCameraRotationAngle() { return mCameraRotationAngle; }
第二步:在onPictureTaken中手动旋转Bitmap
现在我们可以在拍照回调里,用保存的旋转角度来修正Bitmap方向,同时处理前置摄像头的镜像问题:
@Override public void onPictureTaken(byte[] bytes) { try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, currentCameraId == 0 ? options : null); // 获取CameraSource中计算好的旋转角度 int rotationAngle = cameraSource.getCameraRotationAngle(); if (bitmap != null) { Matrix matrix = new Matrix(); if (currentCameraId == 0) { // 前置摄像头:先水平镜像翻转,再旋转对应角度 matrix.postScale(-1, 1); matrix.postRotate(rotationAngle); } else { // 后置摄像头:直接旋转对应角度 matrix.postRotate(rotationAngle); } // 创建旋转后的Bitmap,注意回收原Bitmap避免内存泄漏 Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); bitmap.recycle(); bitmap = rotatedBitmap; // 这里就可以使用与屏幕显示方向一致的bitmap了 } } catch (Exception ex) { ex.printStackTrace(); Log.e("PictureTaken", ex.toString()); } }
方案原理
原生的parameters.setRotation(angle)只是告知相机传感器要记录图片的旋转信息,但部分设备的相机驱动并没有正确应用这个信息,导致解码后的Bitmap还是原始传感器方向。我们手动使用CameraSource中已经计算好的angle值来旋转Bitmap,这个值是严格根据屏幕方向和摄像头朝向推导出来的,能保证和当前屏幕显示方向一致。
如果个别设备仍有异常,可以考虑添加设备型号的特殊判断,但优先使用这种通用的角度计算方式,避免硬编码设备列表带来的维护麻烦。
内容的提问来源于stack exchange,提问作者V.Bhat
相关产品推荐
相关产品推荐

