我正在尝试将图像数据从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通道矩阵一起使用,因此应该可以通过注释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);
}
}
看看这个仓库https://github.com/quickbirdstudios/yuvToMat/
它支持不同的格式(YUV420,NV12)以及各种像素和行跨距。