Ask Your Question

zarokka's profile - activity

2016-08-16 03:11:54 -0600 commented answer Android Camera2 YUV to RGB conversion turns out green?

this will not work if the pixel stride is 2, see http://answers.opencv.org/question/61... (awaiting moderation)

2016-08-16 03:09:10 -0600 answered a question Android Camera2 YUV to RGB conversion turns out green?

The answer http://answers.opencv.org/question/61... did not fully work for me, it seems that the data format can vary between devices.

The mentioned answer probably works if the pixel stride is 1, but all devices I have available produce images with pixel stride 2 (Nexus 5, Sony Xperia Z3). The pixel stride means that the U and V planes are padded. The full buffer has the size of 2 bytes per pixel.

There is no way to directly convert this padded format with OpenCV currently, but it can be converted to YUV NV21 before converting it to a RGB/BGR image. (NV21 because it requires less work to convert to NV21 than to normal YUV420).

I do not know if a different pixel stride than 1 or 2 is possible (i guess not).

@TargetApi(21)
public Mat convertYuv420888ToMat(Image image, boolean isGreyOnly) {
    int width = image.getWidth();
    int height = image.getHeight();

    Image.Plane yPlane = image.getPlanes()[0];
    int ySize = yPlane.getBuffer().remaining();

    if (isGreyOnly) {
        byte[] data = new byte[ySize];
        yPlane.getBuffer().get(data, 0, ySize);

        Mat greyMat = new Mat(height, width, CvType.CV_8UC1);
        greyMat.put(0, 0, data);

        return greyMat;
    }

    Image.Plane uPlane = image.getPlanes()[1];
    Image.Plane vPlane = image.getPlanes()[2];

    // be aware that this size does not include the padding at the end, if there is any
    // (e.g. if pixel stride is 2 the size is ySize / 2 - 1)
    int uSize = uPlane.getBuffer().remaining();
    int vSize = vPlane.getBuffer().remaining();

    byte[] data = new byte[ySize + (ySize/2)];

    yPlane.getBuffer().get(data, 0, ySize);

    ByteBuffer ub = uPlane.getBuffer();
    ByteBuffer vb = vPlane.getBuffer();

    int uvPixelStride = uPlane.getPixelStride(); //stride guaranteed to be the same for u and v planes
    if (uvPixelStride == 1) {
        uPlane.getBuffer().get(data, ySize, uSize);
        vPlane.getBuffer().get(data, ySize + uSize, vSize);

        Mat yuvMat = new Mat(height + (height / 2), width, CvType.CV_8UC1);
        yuvMat.put(0, 0, data);
        Mat rgbMat = new Mat(height, width, CvType.CV_8UC3);
        Imgproc.cvtColor(yuvMat, rgbMat, Imgproc.COLOR_YUV2RGB_I420, 3);
        yuvMat.release();
        return rgbMat;
    }

    // if pixel stride is 2 there is padding between each pixel
    // converting it to NV21 by filling the gaps of the v plane with the u values
    vb.get(data, ySize, vSize);
    for (int i = 0; i < uSize; i += 2) {
        data[ySize + i + 1] = ub.get(i);
    }

    Mat yuvMat = new Mat(height + (height / 2), width, CvType.CV_8UC1);
    yuvMat.put(0, 0, data);
    Mat rgbMat = new Mat(height, width, CvType.CV_8UC3);
    Imgproc.cvtColor(yuvMat, rgbMat, Imgproc.COLOR_YUV2RGB_NV21, 3);
    yuvMat.release();
    return rgbMat;
}
2016-08-15 04:39:20 -0600 received badge  Supporter (source)