PPP
PPP

Reputation: 1850

Which YUV format is this? Really YUV420SP?

Below is te RGB output of a supposed YUV420SP buffer. No conversion, I' m just displaying the YUV420SP as if it were RGB, just to see some patterns.

The image is in a single unsigned char* buffer of size width*height*3. So if this is indeed YUV420SP, then I should have the Y as a black and white image, and then UV interleaved. I think I should see the Y as a black and white image, but why it repeats 3 times in my image? And should I see anything in the UV part?

Of course I tried to convert this buffer to RGB. I used https://github.com/andrechen/yuv2rgb/blob/master/yuv2rgb.h#L70 but I only get a completely black image.

enter image description here

Upvotes: 0

Views: 4505

Answers (2)

Rotem
Rotem

Reputation: 32104

The format looks like I420 format (also called YV12).

I420 is YUV 4:2:0 format with fully planar ordered format.
In YUV420, the Y color channel is the Luma (brightness) of each pixel.
U and V are the Chroma (color) channels.
The resolution of U and V is half of Y in both axes (downsampled by a factor of 0.5 in each axis).

I420 illustration:

Assume unsigned char* src is a pointer to the frame buffer, and the resolution is 640x480:

src ->               YYYYYY  
                     YYYYYY  
                     YYYYYY  
                     YYYYYY  
src + 640*480     -> UUU  
                     UUU  
src + (320*240)*5 -> VVV  
                     VVV  

I used MATLAB code for restoring the RGB image from the image you have posted.

Here is the result:
enter image description here


MATLAB code (just for reference):

I = imread('Test.png');
R = I(:,:,1);G = I(:,:,2);B = I(:,:,3);

T = zeros(size(R,1), size(R,2)*3, 'uint8');
T(:, 1:3:end) = R;T(:, 2:3:end) = G;T(:, 3:3:end) = B;
T = T';T = T(:);

Y = T(1:640*480);
U = T(640*480+1:640*480+640*480/4);
V = T(640*480+640*480/4+1:640*480+(640*480/4)*2);

Y = (reshape(Y, [640, 480]))';
U = (reshape(U, [320, 240]))';
V = (reshape(V, [320, 240]))';

U = imresize(U, 2);
V = imresize(V, 2);
YUV = cat(3, Y, U, V);
RGB = ycbcr2rgb(YUV);

Upvotes: 2

selbie
selbie

Reputation: 104559

I've done a few YUV renderers before.

A YUV 420 buffer should contain width*height bytes for Y, followed by (width*height)/4) bytes for U. And another (width*height)/4) bytes for V. Hence, if your YUV byte buffer should contain (width*height*3)/2 bytes in size.

Just to see the grey scale pattern as you describe it, you'd need to convert the "Y" bytes into 24-bit RGB like the following:

Something like this:

unsigned char* YUV_BYTES = < some buffer of size (width*height*3)/2 with bytes copied in>
unsigned char* RGB_BYTES = < some buffer of size width*height*3 >

const unsigned char* dst = RGB_BYTES;
for (unsigned int r = 0; r < height; r++)
{
    unsigned int row_offset = r*width;
    for (unsigned int c = 0; c < width; c++)
    {
        *dst[0] = YUV[row_offset + c];  // R
        *dst[1] = YUV[row_offset + c];  // G
        *dst[2] = YUV[row_offset + c];  // B
        dst += 3;
    }
}

I think there's also an implicit assumption about the width and height of YUV images always being divisible by 4. Your renderer might draw this image upside down depending on your graphics library and platform.

Upvotes: 1

Related Questions