简体   繁体   English

如何从 Android MediaImage 以 OUTPUT_IMAGE_FORMAT_RGBA_8888 格式创建 Bitmap?

[英]How to create Bitmap from Android MediaImage in OUTPUT_IMAGE_FORMAT_RGBA_8888 format?

I am trying to use this new feature of CameraX Image Analysis (version 1.1.0-alpha08): using setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888), images sent to the analyzer will have RGBA format.我正在尝试使用 CameraX 图像分析(版本 1.1.0-alpha08)的这个新功能:使用 setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888),发送到分析器的图像将具有 RGBA 格式。

See this for reference: https://developer.android.com/reference/androidx/camera/core/ImageAnalysis#OUTPUT_IMAGE_FORMAT_RGBA_8888请参阅此以供参考: https://developer.android.com/reference/androidx/camera/core/ImageAnalysis#OUTPUT_IMAGE_FORMAT_RGBA_8888

I need to turn the image sent to the analyzer into a Bitmap so that I can input it to a TensorFlow classifier.我需要将发送到分析器的图像转换为 Bitmap,以便我可以将其输入到 TensorFlow 分类器。 Without this new feature I would receive the image in the standard YUV_420_888 format then I would have to use one of the several solutions that can be googled in order to turn YUV_420_888 to RGBA then to Bitmap. Like this: https://blog.minhazav.dev/how-to-convert-yuv-420-sp-android.media.Image-to-Bitmap-or-jpeg/ .如果没有这个新功能,我将收到标准 YUV_420_888 格式的图像,然后我将不得不使用可以用谷歌搜索的几种解决方案之一,以便将 YUV_420_888 转换为 RGBA,然后转换为 Bitmap。像这样: https://blog.minhazav .dev/how-to-convert-yuv-420-sp-android.media.Image-to-Bitmap-or-jpeg/ I assume getting the Media Image directly in RGBA format should help me avoid implementing those painfull solutions (that I have actually tried and do not seem to work very well for me so far).我假设直接以 RGBA 格式获取媒体图像应该可以帮助我避免实施那些痛苦的解决方案(我实际上已经尝试过,但到目前为止似乎对我来说效果不是很好)。

Problem is I don't know how to turn this RGBA Media Image into a Bitmap. I have noticed that calling mediaImage.getFormat() returns 1 which is not an ImageFormat value but a PixelFormat one, the one logically corresponding to RGBA_8888 format, which is in line with the documentation: "All ImageProxy sent to ImageAnalysis.Analyzer.analyze(ImageProxy) will have format PixelFormat.RGBA_8888".问题是我不知道如何将此 RGBA 媒体图像转换为 Bitmap。我注意到调用 mediaImage.getFormat() 返回 1,它不是 ImageFormat 值而是 PixelFormat 值,逻辑上对应于 RGBA_8888 格式,它与文档一致:“发送到 ImageAnalysis.Analyzer.analyze(ImageProxy) 的所有 ImageProxy 都将具有 PixelFormat.RGBA_8888 格式”。

I have tried this:我试过这个:

private Bitmap toBitmapRGBA(Image image) {
    Image.Plane[] planes = image.getPlanes();
    ByteBuffer buffer = planes[0].getBuffer();
    buffer.rewind();
    int size = buffer.remaining();
    byte[] bytes = new byte[size];
    buffer.get(bytes);
    Bitmap bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
    return bitmapImage;
}

This returns null indicating the decodeByteArray does not work.这将返回 null,指示 decodeByteArray 不起作用。 (I notice the image has got only one plane). (我注意到图像只有一架飞机)。

private Bitmap toBitmapRGBA2(Image image) {
    Image.Plane[] planes = image.getPlanes();
    ByteBuffer buffer = planes[0].getBuffer();
    Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
    buffer.rewind();
    bitmap.copyPixelsFromBuffer(buffer);
    return bitmap;
}

This returns a Bitmap that looks noting but noise.这将返回一个 Bitmap,它看起来很明显但很杂乱。

Please help!请帮忙! Kind regards Mickael亲切的问候迈克尔

I actually found a solution myself, so I post it here if anyone is interested:我实际上自己找到了解决方案,所以如果有人感兴趣,我会在这里发布:

private Bitmap toBitmap(Image image) {
    Image.Plane[] planes = image.getPlanes();
    ByteBuffer buffer = planes[0].getBuffer();
    int pixelStride = planes[0].getPixelStride();
    int rowStride = planes[0].getRowStride();
    int rowPadding = rowStride - pixelStride * image.getWidth();
    Bitmap bitmap = Bitmap.createBitmap(image.getWidth()+rowPadding/pixelStride, 
    image.getHeight(), Bitmap.Config.ARGB_8888);
    bitmap.copyPixelsFromBuffer(buffer);
    return bitmap;
    }

if you want to process the pixel array further on without creating a bitmap object you can do something like this:如果你想进一步处理像素阵列而不创建 bitmap object 你可以这样做:

            val data = imageProxy.planes[0].buffer.toByteArray()
            val pixels = IntArray(data.size / imageProxy.planes[0].pixelStride) {
                var index = it * imageProxy.planes[0].pixelStride
                (data[index++].toInt() and 0xff.shl(16)) or
                    (data[index++].toInt() and 0xff).shl(8) or
                    (data[index++].toInt() and 0xff).shl(0) or
                    (data[index].toInt() and 0xff).shl(24)
            }

And then you can create bitmap this way:然后你可以这样创建 bitmap:

        Bitmap.createBitmap(
            pixels,
            0,
            imageProxy.planes[0].rowStride / imageProxy.planes[0].pixelStride,
            imageProxy.width,
            imageProxy.height,
            Bitmap.Config.ARGB_8888
        )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM