内容简介:手机 Camera 的图像数据都是来自于摄像头硬件的图像传感器(Image Sensor),这个 Sensor 被固定到手机之后是有一个默认的取景方向的,这个方向如下图所示,坐标原点位于手机横放时的左上角:拍照得到的图片方向是与图像 Sensor 的方向一致的。
Camera 预览方向
手机 Camera 的图像数据都是来自于摄像头硬件的图像传感器(Image Sensor),这个 Sensor 被固定到手机之后是有一个默认的取景方向的,这个方向如下图所示,坐标原点位于手机横放时的左上角:
由于手机屏幕可以 360 度旋转,为了保证用户无论怎么旋转手机都能看到“正确”的预览画面。Android 系统底层根据当前手机屏幕的方向对图像 Sensor 采集到的数据进行了旋转处理后才传输给显示系统。因此,你在打开 Camera 应用后,无论怎么旋转手机都能看到“正确”的画面。
Android 系统提供一个 API 来手动设置 Camera 的预览方向,叫 setDisplayOrientation
。默认情况下这个值是0,与图像 Sensor 方向一致,所以对于横屏应用来说就不需要更改这个 Camera 预览方向。
但是,如果你的应用是竖屏应用,就必须通过这个 API 将 Camera 的预览方向旋转 90 度,让摄像头预览方向与手机屏幕方向保持一致,这样才会得到正确的预览画面。
当然要处理 Camera 方向不可能通过一个简单的 setDisplayOrientation(90) 就能搞定所有问题。比如前置摄像头的话预览要水平翻转才行,同样的情况下你可能要 setDisplayOrientation(270) 。具体的可参考官方文档的建议进行处理:
/** * If you want to make the camera image show in the same orientation as the display, you can use the following code. */ 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); }复制代码
真实的图像方向
当你点击拍照按钮,得到的图片方向不一定与画面中的预览方向一致,这是因为拍摄的照片是将图像 Sensor 采集到的数据直接存储到 SDCard上的,因此 Camera 的拍照方向与图像 Sensor 方向一致。
拍照得到的图片方向是与图像 Sensor 的方向一致的。 setDisplayOrientation
这个 API 修改的仅仅是 Camera 的预览方向而已,并不会影响到 PreviewCallback 回调、生成的 JPEG 图片和录像文件的方向,这些数据的方向依然会跟图像 Sensor 的方向一致。
在Camera类的的PreviewCallback回调中,这个接口回调的是相机的真实图像,而不是预览图像,并且它是YUV格式的,所以,如果需要将PreviewCallback回调的图像转换成一个bitmap需要使用YuvImage。
@Override public void onPreviewFrame(final byte[] data, Camera camera) { camera.setPreviewCallback(null); if (mCamera == null) return; Camera.Parameters parameters = camera.getParameters(); int width = parameters.getPreviewSize().width; int height = parameters.getPreviewSize().height; YuvImage yuv = new YuvImage(data, parameters.getPreviewFormat(), width, height, null); ByteArrayOutputStream out = new ByteArrayOutputStream(); yuv.compressToJpeg(new Rect(0, 0, width, height), 50, out); byte[] bytes = out.toByteArray(); final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); this.mCamera.setPreviewCallback(this); } 复制代码
上面说过,PreviewCallback回调图片方向跟 Sensor 的方向一致,所以需要进行旋转。
private byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) { byte [] yuv = new byte[imageWidth*imageHeight*3/2]; // Rotate the Y luma int i = 0; for(int x = 0;x < imageWidth;x++) { for(int y = imageHeight-1;y >= 0;y--) { yuv[i] = data[y*imageWidth+x]; i++; } } // Rotate the U and V color components i = imageWidth*imageHeight*3/2-1; for(int x = imageWidth-1;x > 0;x=x-2) { for(int y = 0;y < imageHeight/2;y++) { yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+x]; i--; yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)]; i--; } } return yuv; } 复制代码
参考文章:
https://www.jianshu.com/p/7d88ec1347b6
https://blog.csdn.net/illidantao/article/details/51366047
https://www.51dev.com/android/8993
https://stackoverflow.com/questions/14167976/rotate-an-yuv-byte-array-on-android
https://www.cnblogs.com/cq-jiang/p/7823462.html
https://blog.csdn.net/xx326664162/article/details/78534241
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Android音视频开发笔记(二)--ffmpeg命令行的使用&相机预览
- [译] 同时使用多个相机流 — Android 相机介绍
- 一块玻璃也可以是相机,新型无镜头相机助力计算机视觉
- 再谈相机标定
- iOS 上的相机捕捉
- 使用Android相机进行颜色检测
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。