在使用 CameraX 库中的 ImageAnalysis 类时,我在 Android 应用程序中遇到图像旋转问题。在特定设备(华为 Nova 12 SE)上,纵向模式拍摄的图像无法正确旋转。在我测试的其他设备(Pixel 7、三星 Galaxy A55)上运行良好。
相关代码如下:
fun <T, R> analyzeImageAsync(
imageProxy: ImageProxy,
onProcess: (input: InputImage) -> Task<T>,
transform: (result: T) -> R?
): Deferred<R?> = scope.async {
val image = InputImage.fromMediaImage(
imageProxy.image ?: return@async null,
imageProxy.imageInfo.rotationDegrees
)
suspendCoroutine { continuation ->
onProcess(image)
.addOnSuccessListener { result ->
continuation.resume(transform(result))
}.addOnFailureListener { exception ->
continuation.resumeWithException(exception)
}
}
}
当我查看捕获的图像时,我看到图像旋转了 90 度,将旋转度更改为 0 不会改变图像的结果。
我也尝试将图像更改为Bitmap,希望能解决问题,但结果是一样的:
fun <T, R> analyzeImageAsync(
imageProxy: ImageProxy,
onProcess: (input: InputImage) -> Task<T>,
transform: (result: T) -> R?
): Deferred<R?> = scope.async {
val bitmap = imageProxy.toBitmap()
val inputImage = InputImage.fromBitmap(bitmap, imageProxy.imageInfo.rotationDegrees)
// Further processing...
}
有什么帮助吗?
编辑:
第一个图像是我期望的图像,第二个是我得到的图像,它是旋转的。
将 ImageProxy 转换为 Bitmap 并应用手动旋转:将 ImageProxy 转换为 Bitmap 后需要手动应用旋转。这允许您通过旋转度数来解释任何特定于设备的怪癖。
这是代码的固定版本:
fun ImageProxy.toBitmap(): Bitmap {
val yBuffer = planes[0].buffer
val uBuffer = planes[1].buffer
val vBuffer = planes[2].buffer
val ySize = yBuffer.remaining()
val uSize = uBuffer.remaining()
val vSize = vBuffer.remaining()
val nv21 = ByteArray(ySize + uSize + vSize)
yBuffer.get(nv21, 0, ySize)
vBuffer.get(nv21, ySize, vSize)
uBuffer.get(nv21, ySize + vSize, uSize)
val yuvImage = YuvImage(nv21, ImageFormat.NV21, width, height, null)
val out = ByteArrayOutputStream()
yuvImage.compressToJpeg(Rect(0, 0, width, height), 100, out)
val imageBytes = out.toByteArray()
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
}
fun rotateBitmap(bitmap: Bitmap, rotationDegrees: Int): Bitmap {
val matrix = Matrix().apply {
postRotate(rotationDegrees.toFloat())
}
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}
fun <T, R> analyzeImageAsync(
imageProxy: ImageProxy,
onProcess: (input: InputImage) -> Task<T>,
transform: (result: T) -> R?
): Deferred<R?> = scope.async {
val bitmap = imageProxy.toBitmap()
val rotationDegrees = imageProxy.imageInfo.rotationDegrees
val rotatedBitmap = rotateBitmap(bitmap, rotationDegrees)
val inputImage = InputImage.fromBitmap(rotatedBitmap, 0) // Pass 0 since we manually rotate
suspendCoroutine { continuation ->
onProcess(inputImage)
.addOnSuccessListener { result ->
continuation.resume(transform(result))
}
.addOnFailureListener { exception ->
continuation.resumeWithException(exception)
}
}
}
toBitmap() 转换:使用 YuvImage 将 ImageProxy 从 YUV 格式转换为位图,以确保正确处理图像缓冲区。 使用矩阵手动旋转:rotateBitmap() 方法根据 imageProxy.imageInfo.rotationDegrees 旋转位图。这可以处理不同设备上的旋转不一致问题。 InputImage 中的零旋转:由于位图已经旋转,因此将 0 作为旋转参数传递给 InputImage.fromBitmap()。