【问题标题】:How to correctly pass YUV_420_888 Image Buffer from Java through JNI to OpenCV, accounting for stride/padding如何通过 JNI 将 Java 中的 YUV_420_888 图像缓冲区正确传递到 OpenCV,并考虑步幅/填充
【发布时间】:2020-04-04 03:29:11
【问题描述】:

我正在尝试将来自 Android 设备的图像数据从 YUV_420_888 转换为 C++ 端的 RGB 矩阵。在某些设备上,这可以完美运行。在 Note 10 上,图像看起来像这样:

我的猜测是步幅导致了这个问题。如何删除这些额外数据,然后通过 JNI 传递正确的缓冲区?

这是Java代码:

IntBuffer rgb = image.getPlanes()[0].getBuffer().asIntBuffer();
NativeLib.passImageBuffer(rgb);

这里是 C++ 代码:

cv::Mat outputRGB;
cv::cvtColor(cv::Mat(height+height/2, width, CV_8UC1, inputRGB), outputRGB, CV_YUV2BGR_NV21);

我在 C++ 端尝试了一些不同的图像格式,但它们都在屏幕一侧返回相同的波段。

我已经实现了this answer,以移除额外的填充,但是传递的图像最终变成了完全绿色。是否需要对 C++ 代码进行一些相应的编辑?我尝试过使用 3 通道格式,但在运行时会崩溃。我在想,由于传递缓冲区适用于每像素 8 位的手机上的 1 通道矩阵,所以应该可以使用 note 10 来做到这一点?

            Image.Plane Y = image.getPlanes()[0];
            Image.Plane U = image.getPlanes()[1];
            Image.Plane V = image.getPlanes()[2];

            int[] rgbBytes = new int[image.getHeight()*image.getWidth()*4];
            int idx = 0;
            ByteBuffer yBuffer = Y.getBuffer();
            int yPixelStride = Y.getPixelStride();
            int yRowStride = Y.getRowStride();
            ByteBuffer uBuffer = U.getBuffer();
            int uPixelStride = U.getPixelStride();
            int uRowStride = U.getRowStride();
            ByteBuffer vBuffer = V.getBuffer();
            int vPixelStride = V.getPixelStride();
            int vRowStride = V.getRowStride();

            ByteBuffer rgbBuffer = ByteBuffer.allocateDirect(rgb.limit());
            for (int row = 0; row < image.getHeight(); row++) {
              for (int col = 0; col < image.getWidth(); col++) {
                int y = yBuffer.get(col*yPixelStride + row*yRowStride) & 0xff;
                int u = uBuffer.get(col/2*uPixelStride + row/2*uRowStride) & 0xff;
                int v = vBuffer.get(col/2*vPixelStride + row/2*vRowStride) & 0xff;

                int y1 = ((19077 << 8) * y) >> 16;
                int r = (y1 + (((26149 << 8) * v) >> 16) - 14234) >> 6;
                int g = (y1 - (((6419 << 8) * u) >> 16) - (((13320 << 8) * v) >> 16) +  8708) >> 6;
                int b = (y1 + (((33050 << 8) * u) >> 16) - 17685) >> 6;

                if (r < 0) r = 0;
                if (g < 0) g = 0;
                if (b < 0) b = 0;
                if (r > 255) r = 255;
                if (g > 255) g = 255;
                if (b > 255) b = 255;
                byte pixel = (byte)(0xff000000 + b + 256 * (g + 256 * r));
                rgbBuffer.put(pixel);
              }
            }

【问题讨论】:

    标签: android c++ android-ndk java-native-interface android-camera


    【解决方案1】:

    看看这个回购 https://github.com/quickbirdstudios/yuvToMat/

    它支持不同的格式(YUV420、NV12)以及各种像素和行跨度。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    • 1970-01-01
    • 2014-10-26
    相关资源
    最近更新 更多