【问题标题】:How to use image format YUV_420_888 for MLKIT of Google如何为谷歌的 MLKIT 使用图像格式 YUV_420_888
【发布时间】:2018-07-02 23:33:38
【问题描述】:

ImageReader 从相机预览中获取每一帧是格式为YUV_420_888 的图像,我想将其用作 MLKIT 的输入。

在谷歌的文档中,我可以运行检测器,输入为:

  • 位图
  • 媒体.图片
  • 字节缓冲区
  • 字节数组
  • 一个文件

我尝试将 YUV_420_888 转换为上述对象,但失败了

【问题讨论】:

  • 您是否尝试过使用firebase.google.com/docs/reference/android/com/google/firebase/…?它支持 YUV_420_888。
  • 您从 ImageReader 返回的对象类型是什么?是 media.Image 吗?你能详细说明/添加一些代码吗?
  • @PannagSanketi。抱歉,我来晚了,在 ImageReader 中,我使用 reader.acquireNextImage() 来获取图像
  • 我使用了 FirebaseVisionImage.fromMediaImage 并且出现错误:“在 com.google.firebase.ml.vision 的 com.google.android.gms.common.internal.Preconditions.checkArgument(Unknown Source)。 common.FirebaseVisionImageMetadata$Builder.setRotation(Unknown Source) at com.google.firebase.ml.vision.common.FirebaseVisionImage.fromMediaImage(Unknown Source)"

标签: android firebase google-app-engine firebase-mlkit


【解决方案1】:

我使用这个函数将图像帧转换为NV21格式,并在FirebaseVisionImage的元数据中设置图像类型

fun YUV_420_888toNV21(image: ImageProxy): ByteArray {

            val width = image.width
            val height = image.height
            val ySize = width * height
            val uvSize = width * height / 4

            val nv21 = ByteArray(ySize + uvSize * 2)
            val yBuffer = image.planes[0].buffer // Y
            val uBuffer = image.planes[1].buffer // U
            val vBuffer = image.planes[2].buffer // V

            var rowStride = image.planes[0].rowStride
            assert(image.planes[0].pixelStride == 1)

            var pos = 0

            //may need to flip the buffers if you get underflow exception

            if (rowStride == width) { // likely
                yBuffer.get(nv21, 0, ySize)
                pos += ySize

            } else {
                var yBufferPos = (width - rowStride).toLong() // not an actual position
                while (pos < ySize) {
                    yBufferPos = yBufferPos + (rowStride - width).toLong()
                    yBuffer.position(yBufferPos.toInt())
                    yBuffer.get(nv21, pos, width)
                    pos += width
                }
            }

            rowStride = image.planes[2].rowStride
            val pixelStride = image.planes[2].pixelStride

            assert(rowStride == image.planes[1].rowStride)
            assert(pixelStride == image.planes[1].pixelStride)

            if (pixelStride == 2 && rowStride == width && uBuffer.get(0) == vBuffer.get(1)) {
                // maybe V an U planes overlap as per NV21, which means vBuffer[1] is alias of uBuffer[0]
                val savePixel = vBuffer.get(1)
                vBuffer.put(1, 0.toByte())
                if (uBuffer.get(0).toInt() == 0) {
                    vBuffer.put(1, 255.toByte())
                    if (uBuffer.get(0).toInt() == 255) {
                        vBuffer.put(1, savePixel)
                        vBuffer.get(nv21, ySize, uvSize)
                        //Log.d("NV211",DataConverter.jsonify(nv21))
                        return nv21 // shortcut
                    }
                }

                // unfortunately, the check failed. We must save U and V pixel by pixel
                vBuffer.put(1, savePixel)
            }

            // other optimizations could check if (pixelStride == 1) or (pixelStride == 2),
            // but performance gain would be less significant

            for (row in 0 until height / 2) {
                for (col in 0 until width / 2) {
                    val vuPos = col * pixelStride + row * rowStride
                    nv21[pos++] = vBuffer.get(vuPos)
                    nv21[pos++] = uBuffer.get(vuPos)
                }
            }
            //Log.d("NV212",DataConverter.jsonify(nv21))
            return nv21
        }

【讨论】:

    猜你喜欢
    • 2020-10-04
    • 1970-01-01
    • 2021-10-31
    • 2018-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-06
    • 2020-12-07
    • 1970-01-01
    相关资源
    最近更新 更多