CameraX前置摄像头ImageProxy旋转处理:固定输出竖屏Bitmap
解决CameraX ImageAnalysis固定竖屏Bitmap问题
核心思路
放弃不可靠的OrientationEventListener,直接利用CameraX提供的图像旋转信息,结合相机朝向(前置/后置)计算正确的旋转矩阵,确保Bitmap始终为竖屏。Activity已锁定竖屏,无需监听系统方向变化。
步骤1:修正ImageAnalysis初始化配置
不要固定setTargetRotation为Surface.ROTATION_0,而是绑定Activity窗口的实际旋转角度(竖屏模式下该值固定),让CameraX自动对齐图像与窗口方向:
// 获取当前窗口旋转角度(竖屏模式下固定为Surface.ROTATION_0) int displayRotation = getWindowManager().getDefaultDisplay().getRotation(); imageAnalysis = new ImageAnalysis.Builder() .setTargetRotation(displayRotation) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888) .setTargetResolution(new Size(720, 480)) .build(); imageAnalysis.setAnalyzer(getExecutor(), this);
步骤2:记录相机朝向
在绑定CameraX时记录当前使用的是前置还是后置摄像头,用于后续旋转计算:
// 全局变量存储相机朝向,默认后置 private int lensFacing = CameraSelector.LENS_FACING_BACK; // 绑定相机时设置 CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(lensFacing) .build(); // 后续绑定CameraProvider的代码...
步骤3:在analyze方法中计算旋转矩阵并转换Bitmap
利用imageProxy.getImageInfo().getRotationDegrees()获取图像与窗口方向的偏移角度,结合相机朝向处理旋转和镜像:
@Override public void analyze(@NonNull ImageProxy imageProxy) { Image image = imageProxy.getImage(); if (image == null) { imageProxy.close(); return; } // 1. 将YUV_420_888格式图像转为Bitmap Bitmap rawBitmap = convertYuvToBitmap(image); // 2. 计算旋转矩阵 int imageRotation = imageProxy.getImageInfo().getRotationDegrees(); Matrix transformMatrix = new Matrix(); if (lensFacing == CameraSelector.LENS_FACING_FRONT) { // 前置摄像头:旋转角度取反,同时添加水平镜像(前置图像默认是镜像的) int targetRotation = (360 - imageRotation) % 360; transformMatrix.postRotate(targetRotation); transformMatrix.postScale(-1, 1); // 水平翻转 } else { // 后置摄像头:直接旋转对应角度即可 transformMatrix.postRotate(imageRotation); } // 3. 应用矩阵得到竖屏Bitmap Bitmap portraitBitmap = Bitmap.createBitmap( rawBitmap, 0, 0, rawBitmap.getWidth(), rawBitmap.getHeight(), transformMatrix, true ); // ------------------------------ // 这里添加你的Bitmap后续处理逻辑 // ------------------------------ // 4. 资源回收,避免内存泄漏 imageProxy.close(); if (rawBitmap != portraitBitmap) { rawBitmap.recycle(); } }
步骤4:实现YUV转Bitmap工具方法
将CameraX返回的YUV_420_888格式图像转换为Bitmap:
private Bitmap convertYuvToBitmap(Image image) { Image.Plane[] planes = image.getPlanes(); ByteBuffer yBuffer = planes[0].getBuffer(); ByteBuffer uBuffer = planes[1].getBuffer(); ByteBuffer vBuffer = planes[2].getBuffer(); int ySize = yBuffer.remaining(); int uSize = uBuffer.remaining(); int vSize = vBuffer.remaining(); // 将YUV_420_888转为NV21格式(YuvImage支持的格式) byte[] nv21Bytes = new byte[ySize + uSize + vSize]; yBuffer.get(nv21Bytes, 0, ySize); vBuffer.get(nv21Bytes, ySize, vSize); uBuffer.get(nv21Bytes, ySize + vSize, uSize); YuvImage yuvImage = new YuvImage( nv21Bytes, ImageFormat.NV21, image.getWidth(), image.getHeight(), null ); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()), 100, outputStream); byte[] jpegBytes = outputStream.toByteArray(); return BitmapFactory.decodeByteArray(jpegBytes, 0, jpegBytes.length); }
关键说明
为什么OrientationEventListener失效?
Activity锁定竖屏后,系统不会触发方向变化事件,且物理方向与显示方向分离,该方法无法准确反映图像需要的旋转角度。前置摄像头rotationDegrees固定270是正常的?
前置摄像头的sensor方向与后置相反,当Activity锁定竖屏时,图像需要顺时针旋转270度才能对齐窗口方向,因此该值固定是符合预期的,只需通过矩阵处理旋转和镜像即可。
内容的提问来源于stack exchange,提问作者grendelb
相关产品推荐
相关产品推荐

