//*************************************************YUV***********************************************//
以将YUV420P数据中的Y、U、V三个分量分离开来并保存成三个文件。函数的代码如下所示
- int 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;
- }
//*************************************************RGB***********************************************//output_420_y.y:纯Y数据,分辨率为256x256。
output_420_u.y:纯U数据,分辨率为128x128。output_420_v.y:纯V数据,分辨率为128x128。
函数可以将RGB24数据中的R、G、B三个分量分离开来并保存成三个文件。函数的代码如下所示。
- int 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;
- }
从代码可以看出,与YUV420P三个分量分开存储不同,RGB24格式的每个像素的三个分量是连续存储的。一帧宽高分别为w、h的RGB24图像一共占用w*h*3 Byte的存储空间。RGB24格式规定首先存储第一个像素的R、G、B,然后存储第二个像素的R、G、B…以此类推。类似于YUV420P的存储方式称为Planar方式,而类似于RGB24的存储方式称为Packed方式。上述调用函数的代码运行后,将会把一张分辨率为500x500的RGB24格式的像素数据文件分离成为三个文件:
output_r.y:R数据,分辨率为256x256。
output_g.y:G数据,分辨率为256x256。
output_b.y:B数据,分辨率为256x256。
//*************************************************RGB2YUV***********************************************//
将RGB24格式的像素数据转换为YUV420P格式的像素数据
- unsigned char clip_value(unsigned char x,unsigned char min_val,unsigned char max_val){
- if(x>max_val){
- return max_val;
- }else if(x<min_val){
- return min_val;
- }else{
- return x;
- }
- }
- //RGB to YUV420
- bool RGB24_TO_YUV420(unsigned char *RgbBuf,int w,int h,unsigned char *yuvBuf)
- {
- unsigned char*ptrY, *ptrU, *ptrV, *ptrRGB;
- memset(yuvBuf,0,w*h*3/2);
- ptrY = yuvBuf;
- ptrU = yuvBuf + w*h;
- ptrV = ptrU + (w*h*1/4);
- unsigned char y, u, v, r, g, b;
- for (int j = 0; j<h;j++){
- ptrRGB = RgbBuf + w*j*3 ;
- for (int i = 0;i<w;i++){
- r = *(ptrRGB++);
- g = *(ptrRGB++);
- b = *(ptrRGB++);
- y = (unsigned char)( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16 ;
- u = (unsigned char)( ( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128 ;
- v = (unsigned char)( ( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128 ;
- *(ptrY++) = clip_value(y,0,255);
- if (j%2==0&&i%2 ==0){
- *(ptrU++) =clip_value(u,0,255);
- }
- else{
- if (i%2==0){
- *(ptrV++) =clip_value(v,0,255);
- }
- }
- }
- }
- return true;
- }
- int rgb24_to_yuv420(char *url_in, int w, int h,int num,char *url_out){
- FILE *fp=fopen(url_in,"rb+");
- FILE *fp1=fopen(url_out,"wb+");
- unsigned char *pic_rgb24=(unsigned char *)malloc(w*h*3);
- unsigned char *pic_yuv420=(unsigned char *)malloc(w*h*3/2);
- for(int i=0;i<num;i++){
- fread(pic_rgb24,1,w*h*3,fp);
- RGB24_TO_YUV420(pic_rgb24,w,h,pic_yuv420);
- fwrite(pic_yuv420,1,w*h*3/2,fp1);
- }
- free(pic_rgb24);
- free(pic_yuv420);
- fclose(fp);
- fclose(fp1);
- return 0;
- }
RGB到YUV的转换公式:
Y= 0.299*R+0.587*G+0.114*B
V= 0.615*R-0.515*G-0.100*B
在转换的过程中有以下几点需要注意:1) RGB24存储方式是Packed,YUV420P存储方式是Packed。
2) U,V在水平和垂直方向的取样数是Y的一半