From 00861b668a548c4546e56fa3becd0c0a00fcd0de Mon Sep 17 00:00:00 2001 From: vdgussem Date: Tue, 16 Apr 2019 01:38:59 +0200 Subject: [PATCH] Changed the way Images are converted into rgba Mats so that JavaCamera2View also shows correct colors when the Image contains I420 or YV12 data --- .../org/opencv/android/JavaCamera2View.java | 107 +++++++++++------- 1 file changed, 67 insertions(+), 40 deletions(-) diff --git a/modules/java/generator/android-21/java/org/opencv/android/JavaCamera2View.java b/modules/java/generator/android-21/java/org/opencv/android/JavaCamera2View.java index 045917edab..cdb03a7108 100644 --- a/modules/java/generator/android-21/java/org/opencv/android/JavaCamera2View.java +++ b/modules/java/generator/android-21/java/org/opencv/android/JavaCamera2View.java @@ -181,17 +181,7 @@ public class JavaCamera2View extends CameraBridgeViewBase { assert (planes.length == 3); assert (image.getFormat() == mPreviewFormat); - // see also https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888 - // Y plane (0) non-interleaved => stride == 1; U/V plane interleaved => stride == 2 - assert (planes[0].getPixelStride() == 1); - assert (planes[1].getPixelStride() == 2); - assert (planes[2].getPixelStride() == 2); - - ByteBuffer y_plane = planes[0].getBuffer(); - ByteBuffer uv_plane = planes[1].getBuffer(); - Mat y_mat = new Mat(h, w, CvType.CV_8UC1, y_plane); - Mat uv_mat = new Mat(h / 2, w / 2, CvType.CV_8UC2, uv_plane); - JavaCamera2Frame tempFrame = new JavaCamera2Frame(y_mat, uv_mat, w, h); + JavaCamera2Frame tempFrame = new JavaCamera2Frame(image); deliverAndDrawFrame(tempFrame); tempFrame.release(); image.close(); @@ -334,50 +324,87 @@ public class JavaCamera2View extends CameraBridgeViewBase { private class JavaCamera2Frame implements CvCameraViewFrame { @Override public Mat gray() { - return mYuvFrameData.submat(0, mHeight, 0, mWidth); + Image.Plane[] planes = mImage.getPlanes(); + int w = mImage.getWidth(); + int h = mImage.getHeight(); + ByteBuffer y_plane = planes[0].getBuffer(); + mGray = new Mat(h, w, CvType.CV_8UC1, y_plane); + return mGray; } @Override public Mat rgba() { - if (mPreviewFormat == ImageFormat.NV21) - Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4); - else if (mPreviewFormat == ImageFormat.YV12) - Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGB_I420, 4); // COLOR_YUV2RGBA_YV12 produces inverted colors - else if (mPreviewFormat == ImageFormat.YUV_420_888) { - assert (mUVFrameData != null); - Imgproc.cvtColorTwoPlane(mYuvFrameData, mUVFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21); - } else - throw new IllegalArgumentException("Preview Format can be NV21 or YV12"); - - return mRgba; - } + Image.Plane[] planes = mImage.getPlanes(); + int w = mImage.getWidth(); + int h = mImage.getHeight(); + int chromaPixelStride = planes[1].getPixelStride(); + + + if (chromaPixelStride == 2) { // Chroma channels are interleaved + ByteBuffer y_plane = planes[0].getBuffer(); + ByteBuffer uv_plane = planes[1].getBuffer(); + Mat y_mat = new Mat(h, w, CvType.CV_8UC1, y_plane); + Mat uv_mat = new Mat(h / 2, w / 2, CvType.CV_8UC2, uv_plane); + Imgproc.cvtColorTwoPlane(y_mat, uv_mat, mRgba, Imgproc.COLOR_YUV2RGBA_NV21); + return mRgba; + } else { // Chroma channels are not interleaved + byte[] yuv_bytes = new byte[w*(h+h/2)]; + ByteBuffer y_plane = planes[0].getBuffer(); + ByteBuffer u_plane = planes[1].getBuffer(); + ByteBuffer v_plane = planes[2].getBuffer(); + + y_plane.get(yuv_bytes, 0, w*h); + + int chromaRowStride = planes[1].getRowStride(); + int chromaRowPadding = chromaRowStride - w/2; + + int offset = w*h; + if (chromaRowPadding == 0){ + // When the row stride of the chroma channels equals their width, we can copy + // the entire channels in one go + u_plane.get(yuv_bytes, offset, w*h/4); + offset += w*h/4; + v_plane.get(yuv_bytes, offset, w*h/4); + } else { + // When not equal, we need to copy the channels row by row + for (int i = 0; i < h/2; i++){ + u_plane.get(yuv_bytes, offset, w/2); + offset += w/2; + if (i < h/2-1){ + u_plane.position(u_plane.position() + chromaRowPadding); + } + } + for (int i = 0; i < h/2; i++){ + v_plane.get(yuv_bytes, offset, w/2); + offset += w/2; + if (i < h/2-1){ + v_plane.position(v_plane.position() + chromaRowPadding); + } + } + } - public JavaCamera2Frame(Mat Yuv420sp, int width, int height) { - super(); - mWidth = width; - mHeight = height; - mYuvFrameData = Yuv420sp; - mUVFrameData = null; - mRgba = new Mat(); + Mat yuv_mat = new Mat(h+h/2, w, CvType.CV_8UC1); + yuv_mat.put(0, 0, yuv_bytes); + Imgproc.cvtColor(yuv_mat, mRgba, Imgproc.COLOR_YUV2RGBA_I420, 4); + return mRgba; + } } - public JavaCamera2Frame(Mat Y, Mat UV, int width, int height) { + + public JavaCamera2Frame(Image image) { super(); - mWidth = width; - mHeight = height; - mYuvFrameData = Y; - mUVFrameData = UV; + mImage = image; mRgba = new Mat(); + mGray = new Mat(); } public void release() { mRgba.release(); + mGray.release(); } - private Mat mYuvFrameData; - private Mat mUVFrameData; + private Image mImage; private Mat mRgba; - private int mWidth; - private int mHeight; + private Mat mGray; }; }