Ask an expert. Trust the answer.

Your academic and career questions answered by verified experts

10 bit YUV420 to RGB Conversion

Date: 2022-12-01 11:41:29

I am working with conversion from YUV420 to RGB but the image colours are not producing fine. Originally my own files are 10 bit. Initially, I started with 8 bit files.

I am using the code below to read YUV420 image and convert to RGB. Because I have YUV420.YUV image file but that code is for video therefore, I only read 1 frame. Then I get YUV as Y as the full size but U and V as half size as described at Wikipedia. I then resize the images to the full size of the image and apply YUV to RGB conversion. But the RGB images are not in correct colors. I have attached the files so that you can run and see what is the problem. Here is the YUV file tulips_yuv420_inter_planar_qcif.yuv.

I have two more questions;

Firstly, The size of the "stream" for one frame should be equal to 1.5*the size of the Y but it is very large whether I use uint8 or uint16 to read the file.

Secondly, If I have 10bit YUV420 file how to I to modify this code to show correct RGB. 

 

fname = 'tulips_yuv420_inter_planar_qcif.yuv'; width = 176; height = 144; nFrame=1; fid = fopen(fname,'r'); % Open the video file stream = fread(fid,'uint8'); % uint16 % stream = fread(fid); % uint8 length = 1.5 * width * height; % Length of a single frame y = double(zeros(height, width, nFrame)); u = double(zeros(height/2, width/2, nFrame)); v = double(zeros(height/2, width/2, nFrame)); for iFrame = 1:nFrame frame = stream((iFrame-1)*length+1:iFrame*length); % Y component of the frame yImage = reshape(frame(1:width*height), width, height)'; % U component of the frame uImage = reshape(frame(width*height+1:1.25*width*height), width/2, height/2)'; % V component of the frame vImage = reshape(frame(1.25*width*height+1:1.5*width*height), width/2, height/2)'; y(:,:,iFrame) = double(yImage); u(:,:,iFrame) = double(uImage); v(:,:,iFrame) = double(vImage); end u=imresize(u,size(y),'bicubic'); v=imresize(v,size(y),'bicubic'); yuv=cat(3,y,u,v); T = [1,0,1.28033;1,-0.21482,-0.38059;1,2.12798,0]; RGB(:,:,1) = T(1)*yuv(:,:,1) + T(4)*yuv(:,:,2) + T(7)*yuv(:,:,3) ; RGB(:,:,2) = T(2)*yuv(:,:,1) + T(5)*yuv(:,:,2) + T(8)*yuv(:,:,3) ; RGB(:,:,3) = T(3)*yuv(:,:,1) + T(6)*yuv(:,:,2) + T(9)*yuv(:,:,3) ; figure,imshow(uint8(RGB)) 

Answer: 

The sample file is 8 bit (not 10 bit), and the storage format is tricky.

The tool allows you selecting the format.
The suitable format is as follows:
enter image description here

The frame is divided to two fields - upper filed and lower filed (interlace format).
Resolution of each filed is 176x72.
Because the format is YUV420, the size of U and V fields is 88x36.

The code sample uses the following stages:

  • Read the upper filed of Y, U and V (8 bits per element).
  • Read the lower filed of Y, U and V.
  • Interleave upper and lower filed.
  • Up-sample U and V to the size of Y.
  • Convert YUV to RGB (use existing MATLAB function ycbcr2rgb).

The following code sample reads the first frame and convert to RGB: 

 

fname = 'tulips_yuv420_inter_planar_qcif.yuv'; width = 176; height = 144; fid = fopen(fname, 'r'); % Open the video file Y0 = (fread(fid, [width, height/2], 'uint8'))'; %Read upper field of Y plane U0 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of Y plane V0 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read upper field of U plane Y1 = (fread(fid, [width, height/2], 'uint8'))'; %Read upper field of Y plane U1 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of U plane V1 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of V plane fclose(fid); %Interleave upper and lower fields Y = zeros(height, width); Y(1:2:end, :) = Y0; Y(2:2:end, :) = Y1; U = zeros(height/2, width/2); U(1:2:end, :) = U0; U(2:2:end, :) = U1; V = zeros(height/2, width/2); V(1:2:end, :) = V0; V(2:2:end, :) = V1; U = imresize(U, size(Y), 'bicubic'); V = imresize(V, size(Y), 'bicubic'); YUV = cat(3, Y, U, V); %Convert YUV to RGB (MATLAB function ycbcr2rgb uses BT.601 conversion formula). RGB = ycbcr2rgb(uint8(YUV)); figure,imshow(RGB) 

Result:
enter image description here


Reading 10 bit YUV420:

Assumptions:

  • Each 10 bits component is stored in 2 bytes (no "bits packing").
  • Data is stored in lower part of each byte (each uint16 element holds a value in range [0, 1023]).
  • Storage format is the same non-standard interlace format as the uint8 sample.

Build 10 bits YUV420 sample file from the 8 bits sample (singe frame for testing):
The following code build a 10 bits sample out of the 8 bits sample (expands the range from 8 bits stored in uint8 to 10 bits stored in uint16). 

 

fname = 'tulips_yuv420_inter_planar_qcif.yuv'; width = 176; height = 144; fid = fopen(fname, 'r'); % Open the video file Y0 = (fread(fid, [width, height/2], 'uint8'))'; %Read upper field of Y plane U0 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of Y plane V0 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read upper field of U plane Y1 = (fread(fid, [width, height/2], 'uint8'))'; %Read upper field of Y plane U1 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of U plane V1 = (fread(fid, [width/2, height/4], 'uint8'))'; %Read lower field of V plane fclose(fid); fid = fopen('10bits__tulips_yuv420_inter_planar_qcif.yuv', 'w'); % Open for writing fwrite(fid, uint16(Y0'*(1023/255)), 'uint16'); %1023 = 2^10-1, and 255 = 2^8-1 fwrite(fid, uint16(U0'*(1023/255)), 'uint16'); fwrite(fid, uint16(V0'*(1023/255)), 'uint16'); fwrite(fid, uint16(Y1'*(1023/255)), 'uint16'); fwrite(fid, uint16(U1'*(1023/255)), 'uint16'); fwrite(fid, uint16(V1'*(1023/255)), 'uint16'); fclose(fid);

Reading 10 bit YUV420
The following code reads single frame of 10 bit YUV420 (matching list of assumptions): 

 

fname = '10bits__tulips_yuv420_inter_planar_qcif.yuv'; width = 176; height = 144; fid = fopen(fname, 'r'); % Open the video file Y0 = (fread(fid, [width, height/2], 'uint16'))'; %Read upper field of Y plane U0 = (fread(fid, [width/2, height/4], 'uint16'))'; %Read lower field of Y plane V0 = (fread(fid, [width/2, height/4], 'uint16'))'; %Read upper field of U plane Y1 = (fread(fid, [width, height/2], 'uint16'))'; %Read upper field of Y plane U1 = (fread(fid, [width/2, height/4], 'uint16'))'; %Read lower field of U plane V1 = (fread(fid, [width/2, height/4], 'uint16'))'; %Read lower field of V plane fclose(fid); %Interleave upper and lower fields Y = zeros(height, width); Y(1:2:end, :) = Y0; Y(2:2:end, :) = Y1; U = zeros(height/2, width/2); U(1:2:end, :) = U0; U(2:2:end, :) = U1; V = zeros(height/2, width/2); V(1:2:end, :) = V0; V(2:2:end, :) = V1; U = imresize(U, size(Y), 'bicubic'); V = imresize(V, size(Y), 'bicubic'); YUV = cat(3, Y, U, V); %Convert elements range from [0, 1023] to range [0, 1] (MATLAB function ycbcr2rgb supports doubles in range [0, 1]). YUV = YUV/1023; %1023 applies 10 bits range. 2^10-1 = 1023 %Convet YUV to RGB (MATLAB function ycbcr2rgb uses BT.601 conversion formula). RGB = ycbcr2rgb(YUV); %Convert from double to uint8 (from range [0, 1] to range [0, 255]). RGB = im2uint8(RGB); figure,imshow(RGB)

Note:
The code YUV = YUV/1023 converts the "10 bits" format to [0, 1] double format.
Conversion is used because ycbcr2rgb is not supporting 10 bits input.


Computing the size of the file:
You are correct: "The size of one frame equals 1.5*the size of Y".
Assuming 10 bits component is stored in 2 bytes, size of Y is width*height*2, and size of one frame is width*height*3.


Why Matlabhelpers ?

Our Matlab assignment helpers for online MATLAB assignment help service take utmost care of your assignments by keeping the codes simple yet of high-quality. We offer the most reliable MATLAB solutions to students pursuing their Computer Science course from the Monash University, the University of Sydney, the University of New South Wales, the University of Melbourne; to name a few. Approach us today for best Matlab solutions online!

whatsApp order on matlabhelpers.com

telegram order on matlabsolutions.com