Как правильно передать буфер изображения YUV_420_888 из Java через JNI в OpenCV с учетом шага / заполнения - PullRequest
0 голосов
/ 02 апреля 2020

Я пытаюсь преобразовать данные изображения с устройства Android из YUV_420_888 в матрицу RGB на стороне C ++. На некоторых устройствах это работает без нареканий. На ноте 10 изображение выглядит следующим образом:

enter image description here

Я предполагаю, что эта проблема возникает из-за шага. Как удалить эти дополнительные данные и затем передать правильный буфер через 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 ++, но все они возвращаются с одной полосой на боковой стороне экрана.

Я реализовал этот ответ , чтобы удалить дополнительный отступ, но переданное изображение становится полностью зеленым. Нужно ли внести соответствующие изменения в код C ++? Я пытался использовать 3-канальный формат, но он вылетает во время выполнения. Я думаю, что, поскольку передача буфера работает с 1-канальной матрицей на телефонах с 8 битами на пиксель, это должно быть возможно сделать с примечанием 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);
              }
            }

1 Ответ

1 голос
/ 03 апреля 2020

Посмотрите на этот репо https://github.com/quickbirdstudios/yuvToMat/

Он поддерживает различные форматы (YUV420, NV12) и различные шаги по пикселям и строкам.

...