将Android camera2 api YUV_420_888转换为RGB

我正在编写一个应用程序,需要摄像头的饲料,将其转换为rgb,以便做一些处理。

它在使用NV21 Yuv格式的旧相机实现方面效果很好。 我遇到的问题是新的Yuv格式,YUV_420_888。 在新的Camera2 Api中,图像不再正确转换为RGB,而是发送YUV_420_888 yuv格式而不是NV21(YUV_420_SP)格式。

有人可以告诉我如何将YUV_420_888转换为RGB?

谢谢

Related of "将Android camera2 api YUV_420_888转换为RGB"

在我的方法中,我使用OpenCV Mat和脚本从https://gist.github.com/camdenfullmer/dfd83dfb0973663a7974

首先,您将YUV_420_888图像转换为Mat,并使用上面链接中的代码。

* mImage是我在ImageReader.OnImageAvailableListener中获得的Image对象

Mat mYuvMat = imageToMat(mImage); public static Mat imageToMat(Image image) { ByteBuffer buffer; int rowStride; int pixelStride; int width = image.getWidth(); int height = image.getHeight(); int offset = 0; Image.Plane[] planes = image.getPlanes(); byte[] data = new byte[image.getWidth() * image.getHeight() * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8]; byte[] rowData = new byte[planes[0].getRowStride()]; for (int i = 0; i < planes.length; i++) { buffer = planes[i].getBuffer(); rowStride = planes[i].getRowStride(); pixelStride = planes[i].getPixelStride(); int w = (i == 0) ? width : width / 2; int h = (i == 0) ? height : height / 2; for (int row = 0; row < h; row++) { int bytesPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8; if (pixelStride == bytesPerPixel) { int length = w * bytesPerPixel; buffer.get(data, offset, length); if (h - row != 1) { buffer.position(buffer.position() + rowStride - length); } offset += length; } else { if (h - row == 1) { buffer.get(rowData, 0, width - pixelStride + 1); } else { buffer.get(rowData, 0, rowStride); } for (int col = 0; col < w; col++) { data[offset++] = rowData[col * pixelStride]; } } } } Mat mat = new Mat(height + height / 2, width, CvType.CV_8UC1); mat.put(0, 0, data); return mat; } 

我们有1个频道的YUV垫。 为BGR定义新的Mat(而不是RGB)图像:

 Mat bgrMat = new Mat(mImage.getHeight(), mImage.getWidth(),CvType.CV_8UC4); 

我刚刚开始学习OpenCV,所以可以这么说,这不一定是4通道的垫,而是可以是3通道,但它适用于我。 现在我使用转换颜色的方法来改变我的yuv垫成bgr垫。

 Imgproc.cvtColor(mYuvMat, bgrMat, Imgproc.COLOR_YUV2BGR_I420); 

现在我们可以做所有的image processing,如find轮廓,颜色,圆形等。要在屏幕上打印图像,我们需要将其转换为位图:

 Mat rgbaMatOut = new Mat(); Imgproc.cvtColor(bgrMat, rgbaMatOut, Imgproc.COLOR_BGR2RGBA, 0); final Bitmap bitmap = Bitmap.createBitmap(bgrMat.cols(), bgrMat.rows(), Bitmap.Config.ARGB_8888); Utils.matToBitmap(rgbaMatOut, bitmap); 

我有我的所有image processing在单独的线程,以便设置我的ImageView我需要在UI线程上执行此操作。

 runOnUiThread(new Runnable() { @Override public void run() { if(bitmap != null) { mImageView.setImageBitmap(bitmap); } } }); 

你有没有尝试过使用这个脚本? 这是yydcdut在这个问题上发布的答案

https://github.com/pinguo-yuyidong/Camera2/blob/master/camera2/src/main/rs/yuv2rgb.rs

比上面提到的“imageToMat”快大约10倍 – 上面的函数是这样的代码:

 Image image = reader.acquireLatestImage(); ... Mat yuv = new Mat(image.getHeight() + image.getHeight() / 2, image.getWidth(), CvType.CV_8UC1); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); final byte[] data = new byte[buffer.limit()]; buffer.get(data); yuv.put(0, 0, data); ... image.close();