我必须使用 Java 将 com.google.mlkit.vision.common.InputImage 转换为 Android 中的等效位图图像。现在我正在使用以下代码。
// iImage is an object of InputImage
Bitmap bmap = Bitmap.createBitmap(iImage.getWidth(), iImage.getHeight(), Bitmap.Config.RGB_565);
bmap.copyPixelsFromBuffer(iImage.getByteBuffer());
上面的代码没有将InputImage转换为Bitmap。谁能建议我将 InputImage 转换为 Bitmap 的有效方法。
您可以从 byteBuffer 创建位图,可以通过调用 getByteBuffer() 方法接收位图。在 ML Kit Vision 的官方快速入门示例中,您可以找到如何实现这一点的方法。下面是一段可以解决您的问题的代码: getBitmap() 方法将 NV21 格式字节缓冲区转换为位图:
@Nullable
public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {
data.rewind();
byte[] imageInBuffer = new byte[data.limit()];
data.get(imageInBuffer, 0, imageInBuffer.length);
try {
YuvImage image =
new YuvImage(
imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 80, stream);
Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
return rotateBitmap(bmp, metadata.getRotation(), false, false);
} catch (Exception e) {
Log.e("VisionProcessorBase", "Error: " + e.getMessage());
}
return null;
}
rotateBitmap()方法:
private static Bitmap rotateBitmap(
Bitmap bitmap, int rotationDegrees, boolean flipX, boolean flipY) {
Matrix matrix = new Matrix();
// Rotate the image back to straight.
matrix.postRotate(rotationDegrees);
// Mirror the image along the X or Y axis.
matrix.postScale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
Bitmap rotatedBitmap =
Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
// Recycle the old bitmap if it has changed.
if (rotatedBitmap != bitmap) {
bitmap.recycle();
}
return rotatedBitmap;
}
InputImage
具有三种可能的支持数据结构:
使用的支持数据结构由构造函数确定:
Bitmap
InputImage.fromFilePath()
InputImage.fromBitmap()
InputImage.fromMediaImage()
ByteBuffer
InputImage.fromByteArray()
InputImage.fromByteBuffer()
Image
InputImage.fromMediaImage()
每个
InputImage
对象仅使用一个后备数据结构,这意味着其他后备数据获取器将返回 null。
如果支持位图可用,这个问题就已经有了答案。但是,如果找不到怎么办?
有一个方法
InputImage.getFormat()
可以返回代表不同图像格式的4个不同的常量整数值。 IMAGE_FORMAT_NV21
、IMAGE_FORMAT_YV12
、IMAGE_FORMAT_BITMAP
或 IMAGE_FORMAT_YUV_420_888
。
仅当支持数据是 IMAGE_FORMAT_BITMAP
时才使用
Bitmap
。所以剩下的是三种 YUV 图像格式和两种可能的支持数据结构。
ByteBuffer
将使用 IMAGE_FORMAT_NV21
或 IMAGE_FORMAT_YV12
。Image
总是使用 IMAGE_FORMAT_YUV_420_888
这三种YUV格式直接对应于
android.graphics.ImageFormat
,可以在这里阅读:我会简单地请求每个支持数据元素,直到获得非空值。从那时起,如果它是位图,那么您的工作就完成了。对于其他人...
我在 Stack Overflow 上发现的一个不太理想的解决方案是转换为
android.graphics.YuvImage
,使用它的 compressToJPEG()
方法获取 JPEG 压缩字节的输出并将这些字节通过管道传输到 BitmapFactory.decodeByteArray()
创建一个 Bitmap
,如此处所示。
虽然这样效率很低,但直接转换无疑是可能的。
使用上述信息进行研究应该足以帮助您实现目标。但为了帮助您顺利完成旅程,这里还有一些资源。
Jim Bar 的“关于 YUV 格式”,用于学习 YUV 格式的一般概念以及各种 YUV 格式之间的差异
Christopher Wright的“YUV Colorspace”,用于了解从 YUV 到 RGB 转换的实际算法,其中最重要的公式如下所示:
R = Y + 1.4075 * (V - 128)
G = Y - 0.3455 * (U - 128) - (0.7169 * (V - 128))
B = Y + 1.7790 * (U - 128)
我可能会在将来编辑完整的实现,因为我自己将来可能会担心这个问题。但是,我很可能会使用上面提供的信息。