首先声明一点,这里的YUV其实不是YUV,严格来说是YCbCr。这里就先这样称呼YUV吧。本文是关于YUV420格式的视频转成图片序列的。

关于YUV格式的图片,存储如下图所示:

举个例子,一个640*480的420的图片,读入matlab中的数据量为460800个数据。

460800/640*480=3/2。相当于每二个像素有3个数据。

 

如果想要把一个YUV文件转成RGB数据,那么必须要知道这个YUV文件是怎么以文件格式存储的。举个例子,假如一张4*4的大小的图片,它的YUV420格式的存储是这样的,如下图:

这只是一个示意图,假如一个图片是100*100像素的,那么它的存储文件中,前100*100=10000个字节是用来存储Y的。接下来2500个字节是用来存储U的,然后的2500个字节是用来存储V的。

当然这种格式也不是唯一的,我发现大多数的图片都是这种格式。当然还有其他的方式来验证一个图片是不是这样的格式。对于一个YUV420格式的图片来说,它一帧画面的数据量是它像素数的1.5倍,当然,我们肯定是知道一帧画面的分辨率的,然后可以读入YUV420视频文件中的1.5*X*Y个数据量,然后查看它对应有图片。如图所示:

红框中的是Y数据,蓝框中的是U数据,黄框中的是V数据。

现在应该可以得到一个YUV帧的YUV分量啦,接下来要做的就是把这三个分量加权求和,生成R,G,B分量啦。加权公式如下:

    R=1.164*(Y-16)+1.596*(VV-128);

    G=1.164*(Y-16)-0.813*(UU-128)-0.392*(VV-128);

    B=1.164*(Y-16)+2.017*(UU-128);


这里要注意一下,这里的YUV最好是double型的,我刚才始生成RGB的时候,YUV都是uint8型的,最后生成的图片颜色总是不对,换成double型的话,就没有问题啦,注意一下,double型的数据还要再归一化或者强制转换成uint8型的数据,才可以用imshow()显示出来。还有RGB三个分量矩阵中,大于255的量要设置成255,小于0的元素要设置为0。

本实验中用的图片恢复出来,如下图所示:

大功告成。

本程序实现代码如下图所示:

 




[plain] ​​view plain​​ ​​copy​

 


  1.   




[plain] view plain copy

 


  1.   


%函数功能:这个函数用于加载一个UYV序列文件

%入口参数:  path是包含要读写YUV序列的地址的字符串

%           x,y是这个图片的高与宽

%           start表示要从第几帧开始读取画面

%           count表示要读出的图片的张数

%出口参数:  picout(x,y,,3,count)表示出口参数

function [picout]=loadYUV(path,x,y,start,count);



% clear;

% clc



% x=288;

% y=352;

% count=10;

% path='e:\test-pic\flower.yuv';

fid=fopen(path,'r');



for ii=1:count

    fseek(fid,1.5*x*y*(ii-1+start-1),-1);

    pic=uint8(fread(fid,[y,1.5*x],'uint8'));

    pic=pic';

    Y=double(pic(1:x,:));

    u=double(pic(x+1:1.25*x,:));

    v=double(pic(1.25*x+1:1.5*x,:));

    for i=1:0.25*x

        U(2*i-1,1:y/2)=u(i,1:y/2);

        U(2*i,1:y/2)=u(i,y/2+1:y);

        V(2*i-1,1:y/2)=v(i,1:y/2);

        V(2*i,1:y/2)=v(i,y/2+1:y);

    end



    UU=imresize(U,2);

    VV=imresize(V,2);



%     R=Y+1.140*(VV-128);

%     G=Y-0.395*(UU-128)-0.581*(VV-128);

%     B=Y+2.032*(UU-128);   

    R=1.164*(Y-16)+1.596*(VV-128);

    G=1.164*(Y-16)-0.813*(UU-128)-0.392*(VV-128);

    B=1.164*(Y-16)+2.017*(UU-128);



    for i=1:x

    for j=1:y

    if R(i,j)<0

    R(i,j)=0;

    end

    if R(i,j)>255

    R(i,j)=255;

    end

    if G(i,j)<0

    G(i,j)=0;

    end

    if G(i,j)>255

    G(i,j)=255;

    end

    if B(i,j)<0

    B(i,j)=0;

    end

    if B(i,j)>255

    B(i,j)=255;

    end

    end

    end

    R=uint8(R);

    G=uint8(G);

    B=uint8(B);

    %R=R/255;G=G/255;B=B/255;

    picout(:,:,:,ii)=cat(3,R,G,B);

end

%imshow(picout(:,:,:,1));

上文只是一个子程序,但是绝对可用。