How to get Y, U, V from image

I use OpenCV 3.0 in Python3.4. I have BGR image converted to YUV420:

out_image = cv2.cvtColor(in_image, cv2.COLOR_BGR2YUV_I420)


How to get Y, U, V values from out_image?

edit retag close merge delete

do you really need BGR2YUV_I420, or would BGR2YUV do ? (mucho easier case !!)

( 2016-08-12 10:14:13 -0500 )edit
1

I need YUV420, not YUV. so BGR2YUV_I420, not BGR2YUV

( 2016-08-12 10:15:57 -0500 )edit

thanks for the clarification, but count me out then, - no idea how it's packed (or even padded) into bytes.

( 2016-08-12 10:19:50 -0500 )edit
1

btw i don't sure that convertion works properly because saved on disc out_image looks strange

( 2016-08-12 10:20:56 -0500 )edit
1

not sure, if that format is even meant to be used as an image. (it's probably more something like : compress it to go over some wire, decompress back on the other side)

( 2016-08-12 10:26:32 -0500 )edit

Sort by ยป oldest newest most voted

The final image is a single channel image of CV_8U. The size is rows = input.rows*3/2 cols = input.cols.

The first input.rows is the Y. This has full fidelity, the same as if you extracted the first channel from the BGR2YUV.

The next input.rows/4 is the V. This is downsampled by 2 in both the vertical and horizontal. So the first half of output.row(input.rows) is the first row of V, the second half is the second row of V.

Then is the U, which is packed the same way as the V, just in the last input.rows/4 rows of the output.

Make sense? Here's an image that should help. Those are the even rows and the odd rows.

A not particularly efficient but easy to understand way of converting back is to do this. (assuming the original image size is divisible by four)

Mat YUV(mesh.rows * 2 / 3, mesh.cols, CV_8UC3);
insertChannel(mesh(Rect(0, 0, YUV.cols, YUV.rows)), YUV, 0);

Mat U = mesh(Rect(0, YUV.rows, YUV.cols, YUV.rows / 4));
imshow("U1", U);
U = U.reshape(1, YUV.rows / 2);
imshow("U2", U);
resize(U, U, Size(YUV.cols, YUV.rows));
insertChannel(U, YUV, 2);

Mat V = mesh(Rect(0, YUV.rows + YUV.rows/4, YUV.cols, YUV.rows / 4));
V = V.reshape(1, YUV.rows / 2);
resize(V, V, Size(YUV.cols, YUV.rows));
insertChannel(V, YUV, 1);

cvtColor(YUV, YUV, COLOR_YUV2BGR);
imshow("Restored", YUV);


It's a good thing I tested this. I originally had the U and V backwards. Except my reference is saying that U is first, then V. Hell, just try it. If it doesn't work _YV12 is the other way around.

more