参考:
前言:
图像都以像素为单位,但是不同数据格式图像(不是指图像文件格式)在存储数据(字节)时数据结构是不一样的。
注:下面内容中,每一个长方形的格子代表一个字节的数据,不是代表一个像素。
RGB:
内存模型(1):
数据是连续存储的,每个像素都由3个字节组成,因此对于 w*h 像素的 rgb 图像,则需要 3*w*h 个字节来表示
内存模型(2):
注:模型1和模型2都能表示图像,模型2更贴近图像的表示方式,模型1更贴近实际内存分布。二者是一样的。
代码表示:
/**
* Split R, G, B planes in RGB24 file.
* @param url Location of Input RGB file.
* @param w Width of Input RGB file.
* @param h Height of Input RGB file.
* @param num Number of frames to process.
*
*/
int simplest_rgb24_split(char *url, int w, int h,int num){
FILE *fp=fopen(url,"rb+");
FILE *fp1=fopen("output_r.y","wb+");
FILE *fp2=fopen("output_g.y","wb+");
FILE *fp3=fopen("output_b.y","wb+");
unsigned char *pic=(unsigned char *)malloc(w*h*3);
for(int i=0;i<num;i++){
fread(pic,1,w*h*3,fp);
for(int j=0;j<w*h*3;j=j+3){
//R
fwrite(pic+j,1,1,fp1);
//G
fwrite(pic+j+1,1,1,fp2);
//B
fwrite(pic+j+2,1,1,fp3);
}
}
free(pic);
fclose(fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}
YUV420:
内存模型:
w*h个像素的yuv图像占用的内存空间为 1.5*w*h 。
Y 数据量 = w*h 个字节
U 数据量 = 0.25 * w*h 个字节
V 数据量 = 0.25 * w*h 个字节
YUV420的存放是先存放所有 Y 数据,接着是 U 数据,最后是 V数据,我们在解析的时候可以以此为标准进行数据拆分。
代码表示:
/**
* Split Y, U, V planes in YUV420P file.
* @param url Location of Input YUV file.
* @param w Width of Input YUV file.
* @param h Height of Input YUV file.
* @param num Number of frames to process.
*
*/
int simplest_yuv420_split(char *url, int w, int h,int num){
FILE *fp=fopen(url,"rb+");
FILE *fp1=fopen("output_420_y.y","wb+");
FILE *fp2=fopen("output_420_u.y","wb+");
FILE *fp3=fopen("output_420_v.y","wb+");
unsigned char *pic=(unsigned char *)malloc(w*h*3/2);
for(int i=0;i<num;i++){
fread(pic,1,w*h*3/2,fp);
//Y
fwrite(pic,1,w*h,fp1);
//U
fwrite(pic+w*h,1,w*h/4,fp2);
//V
fwrite(pic+w*h*5/4,1,w*h/4,fp3);
}
free(pic);
fclose(fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}
YUV444:
内存模型:
w*h个像素的yuv图像占用的内存空间为 3*w*h 。
Y 数据量 = w*h 个字节
U 数据量 = w*h 个字节
V 数据量 = w*h 个字节
和YUV420的区别在于U和V的字节数不同。YUV444和RGB占用同样的内存空间。
代码表示:
/**
* Split Y, U, V planes in YUV444P file.
* @param url Location of YUV file.
* @param w Width of Input YUV file.
* @param h Height of Input YUV file.
* @param num Number of frames to process.
*
*/
int simplest_yuv444_split(char *url, int w, int h,int num){
FILE *fp=fopen(url,"rb+");
FILE *fp1=fopen("output_444_y.y","wb+");
FILE *fp2=fopen("output_444_u.y","wb+");
FILE *fp3=fopen("output_444_v.y","wb+");
unsigned char *pic=(unsigned char *)malloc(w*h*3);
for(int i=0;i<num;i++){
fread(pic,1,w*h*3,fp);
//Y
fwrite(pic,1,w*h,fp1);
//U
fwrite(pic+w*h,1,w*h,fp2);
//V
fwrite(pic+w*h*2,1,w*h,fp3);
}
free(pic);
fclose(fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}
理解采样:
下图中每个方块代表当前像素的Y分量,每个圆代表U和V分量。
YUV444:每一个像素都采集 Y U V三个分量
YUV422:所有行策略一致,每两个像素中采集一个U和一个V,每个像素都采集Y
YUV420:每四个像素采集一个U和一个V,没个像素都采集Y,这里需要注意这里示意图的表示方法中对于 U和V 的采集并没有落到实际的像素上,这只是一种表示方法,实际采样的时候会落到具体的像素点上,或者考虑使用4个点U和V的平均值作为采样值。