论YUV422(YUYV)与YUV420相互转换
https://www.cnblogs.com/liangxiaofeng/p/6943594.html
Example 2.13. V4L2_PIX_FMT_YUYV 4 × 4 pixelimage
start + 0: | Y'00 | Cb00 | Y'01 | Cr00 | Y'02 | Cb01 | Y'03 | Cr01 |
start + 8: | Y'10 | Cb10 | Y'11 | Cr10 | Y'12 | Cb11 | Y'13 | Cr11 |
start + 16: | Y'20 | Cb20 | Y'21 | Cr20 | Y'22 | Cb21 | Y'23 | Cr21 |
start + 24: | Y'30 | Cb30 | Y'31 | Cr30 | Y'32 | Cb31 | Y'33 | Cr31 |
YUV422码流存放位置
(转自http://www.chineselinuxuniversity.net/kerneldocs/media/V4L2-PIX-FMT-YUYV.html)
Example 2.18. V4L2_PIX_FMT_YUV420 4 × 4 pixelimage
start + 0: | Y'00 | Y'01 | Y'02 | Y'03 |
start + 4: | Y'10 | Y'11 | Y'12 | Y'13 |
start + 8: | Y'20 | Y'21 | Y'22 | Y'23 |
start + 12: | Y'30 | Y'31 | Y'32 | Y'33 |
start + 16: | Cb00 | Cb01 |
|
|
start + 18: | Cb10 | Cb11 |
|
|
start + 20: | Cr00 | Cr01 |
|
|
start + 22: | Cr10 | Cr11 |
| |
|
|
|
|
|
YUV420码流存放位置
(转自http://www.chineselinuxuniversity.net/kerneldocs/media/re18.html该处是YVU420)
这里要顺带提一下YUV444,既无损YUV色彩空间.一个Y带一个Cb一个Cr,即YCbCr.
YUV422采样即从YUV444基础上,从第一个Y开始只保留Cb,剔去Cr,第二个Y只保留Cr剔去Cb…...这样交替采样,长度大小为width*height*2,Y:U:V=4:2:2,一个色彩分量占一个字节.
而YUV420即从YUV422基础上进行隔行采样,例如第一行只保留Cb,第二行只保留Cr……这样交替进行,Y:U:V=4:2:0并不是没有V分量,也可以是Y:U:V=4:0:2.相信这样大家容易理解.最后在这个基础上,把Y,U,V三种分量打包排列,即如上图,长度大小为width*height*3/2.
说了这么多,是时候贴上具体代码.
#include <stdio.h>
#include <string.h>
#define READ_WRITE_FILE_SIZE 176*144*2 //YUV422 图像分辨率为177x144
unsigned char filebuf[38017] = {0};
int YUV422To420(unsigned char yuv422[], unsigned char yuv420[], int width, int height)
{
int ynum=width*height;
int i,j,k=0;
//得到Y分量
for(i=0;i<ynum;i++){
yuv420[i]=yuv422[i*2];
}
//得到U分量
for(i=0;i<height;i++){
if((i%2)!=0)continue;
for(j=0;j<(width/2);j++){
if((4*j+1)>(2*width))break;
yuv420[ynum+k*2*width/4+j]=yuv422[i*2*width+4*j+1];
}
k++;
}
k=0;
//得到V分量
for(i=0;i<height;i++){
if((i%2)==0)continue;
for(j=0;j<(width/2);j++){
if((4*j+3)>(2*width))break;
yuv420[ynum+ynum/4+k*2*width/4+j]=yuv422[i*2*width+4*j+3];
}
k++;
}
return 1;
}
int main(void)
{
int len = 0;
FILE *fpr, *fpw;
unsigned char buf[READ_WRITE_FILE_SIZE];
fpr = fopen( "WEBCAM-00012.YUV", "rb" );
fpw = fopen( "yuyv_2_yy_u_v.yuv", "wb" );
if( fpr == NULL || fpw == NULL )
{
printf("can not read or write file\n");
fcloseall();
return 1;
}
fread( buf, READ_WRITE_FILE_SIZE, 1, fpr );
if(YUV422To420(buf,filebuf,176,144))printf("ok\n");
printf("size:%d",sizeof(filebuf));
fwrite( &filebuf, sizeof(filebuf), 1, fpw );
fcloseall();
return 0;
}
#include <stdio.h>
#include <string.h>
#define READ_WRITE_FILE_SIZE 176*144*2 //YUV422 图像分辨率为177x144
unsigned char filebuf[38017] = {0};
int YUV422To420(unsigned char yuv422[], unsigned char yuv420[], int width, int height)
{
int ynum=width*height;
int i,j,k=0;
//得到Y分量
for(i=0;i<ynum;i++){
yuv420[i]=yuv422[i*2];
}
//得到U分量
for(i=0;i<height;i++){
if((i%2)!=0)continue;
for(j=0;j<(width/2);j++){
if((4*j+1)>(2*width))break;
yuv420[ynum+k*2*width/4+j]=yuv422[i*2*width+4*j+1];
}
k++;
}
k=0;
//得到V分量
for(i=0;i<height;i++){
if((i%2)==0)continue;
for(j=0;j<(width/2);j++){
if((4*j+3)>(2*width))break;
yuv420[ynum+ynum/4+k*2*width/4+j]=yuv422[i*2*width+4*j+3];
}
k++;
}
return 1;
}
int main(void)
{
int len = 0;
FILE *fpr, *fpw;
unsigned char buf[READ_WRITE_FILE_SIZE];
fpr = fopen( "WEBCAM-00012.YUV", "rb" );
fpw = fopen( "yuyv_2_yy_u_v.yuv", "wb" );
if( fpr == NULL || fpw == NULL )
{
printf("can not read or write file\n");
fcloseall();
return 1;
}
fread( buf, READ_WRITE_FILE_SIZE, 1, fpr );
if(YUV422To420(buf,filebuf,176,144))printf("ok\n");
printf("size:%d",sizeof(filebuf));
fwrite( &filebuf, sizeof(filebuf), 1, fpw );
fcloseall();
return 0;
}
« 上一篇:图文详解YUV420数据格式
» 下一篇:用DirectX实现多视图渲染