# 视音频数据处理入门：RGB、YUV像素数据处理

81 篇文章 144 订阅

=====================================================

=====================================================

## 函数列表

### (1) 分离YUV420P像素数据中的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++){

//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;
}


simplest_yuv420_split("lena_256x256_yuv420p.yuv",256,256,1);

output_420_y.y：纯Y数据，分辨率为256x256。

output_420_u.y：纯U数据，分辨率为128x128。

output_420_v.y：纯V数据，分辨率为128x128。

lena_256x256_yuv420p.yuv

output_420_y.y

output_420_u.y和output_420_v.y

### (2)分离YUV444P像素数据中的Y、U、V分量

/**
* 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++){
//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;
}


simplest_yuv444_split("lena_256x256_yuv444p.yuv",256,256,1);

output_444_y.y：纯Y数据，分辨率为256x256。
output_444_u.y：纯U数据，分辨率为256x256。
output_444_v.y：纯V数据，分辨率为256x256。

output_444_y.y

output_444_u.y

output_444_v.y

### (3) 将YUV420P像素数据去掉颜色（变成灰度图）

/**
* Convert YUV420P file to gray picture
* @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_gray(char *url, int w, int h,int num){
FILE *fp=fopen(url,"rb+");
FILE *fp1=fopen("output_gray.yuv","wb+");
unsigned char *pic=(unsigned char *)malloc(w*h*3/2);

for(int i=0;i<num;i++){
//Gray
memset(pic+w*h,128,w*h/2);
fwrite(pic,1,w*h*3/2,fp1);
}

free(pic);
fclose(fp);
fclose(fp1);
return 0;
}

simplest_yuv420_gray("lena_256x256_yuv420p.yuv",256,256,1);

### (4)将YUV420P像素数据的亮度减半

/**
* Halve Y value of 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_halfy(char *url, int w, int h,int num){
FILE *fp=fopen(url,"rb+");
FILE *fp1=fopen("output_half.yuv","wb+");

unsigned char *pic=(unsigned char *)malloc(w*h*3/2);

for(int i=0;i<num;i++){
//Half
for(int j=0;j<w*h;j++){
unsigned char temp=pic[j]/2;
//printf("%d,\n",temp);
pic[j]=temp;
}
fwrite(pic,1,w*h*3/2,fp1);
}

free(pic);
fclose(fp);
fclose(fp1);

return 0;
}


simplest_yuv420_halfy("lena_256x256_yuv420p.yuv",256,256,1);

### (5)将YUV420P像素数据的周围加上边框

/**
* Add border for YUV420P file
* @param url     Location of Input YUV file.
* @param w       Width of Input YUV file.
* @param h       Height of Input YUV file.
* @param border  Width of Border.
* @param num     Number of frames to process.
*/
int simplest_yuv420_border(char *url, int w, int h,int border,int num){
FILE *fp=fopen(url,"rb+");
FILE *fp1=fopen("output_border.yuv","wb+");

unsigned char *pic=(unsigned char *)malloc(w*h*3/2);

for(int i=0;i<num;i++){
//Y
for(int j=0;j<h;j++){
for(int k=0;k<w;k++){
if(k<border||k>(w-border)||j<border||j>(h-border)){
pic[j*w+k]=255;
//pic[j*w+k]=0;
}
}
}
fwrite(pic,1,w*h*3/2,fp1);
}

free(pic);
fclose(fp);
fclose(fp1);

return 0;
}


simplest_yuv420_border("lena_256x256_yuv420p.yuv",256,256,20,1);

### (6) 生成YUV420P格式的灰阶测试图

/**
* Generate YUV420P gray scale bar.
* @param width    Width of Output YUV file.
* @param height   Height of Output YUV file.
* @param ymin     Max value of Y
* @param ymax     Min value of Y
* @param barnum   Number of bars
* @param url_out  Location of Output YUV file.
*/
int simplest_yuv420_graybar(int width, int height,int ymin,int ymax,int barnum,char *url_out){
int barwidth;
float lum_inc;
unsigned char lum_temp;
int uv_width,uv_height;
FILE *fp=NULL;
unsigned char *data_y=NULL;
unsigned char *data_u=NULL;
unsigned char *data_v=NULL;
int t=0,i=0,j=0;

barwidth=width/barnum;
lum_inc=((float)(ymax-ymin))/((float)(barnum-1));
uv_width=width/2;
uv_height=height/2;

data_y=(unsigned char *)malloc(width*height);
data_u=(unsigned char *)malloc(uv_width*uv_height);
data_v=(unsigned char *)malloc(uv_width*uv_height);

if((fp=fopen(url_out,"wb+"))==NULL){
printf("Error: Cannot create file!");
return -1;
}

//Output Info
printf("Y, U, V value from picture's left to right:\n");
for(t=0;t<(width/barwidth);t++){
lum_temp=ymin+(char)(t*lum_inc);
printf("%3d, 128, 128\n",lum_temp);
}
//Gen Data
for(j=0;j<height;j++){
for(i=0;i<width;i++){
t=i/barwidth;
lum_temp=ymin+(char)(t*lum_inc);
data_y[j*width+i]=lum_temp;
}
}
for(j=0;j<uv_height;j++){
for(i=0;i<uv_width;i++){
data_u[j*uv_width+i]=128;
}
}
for(j=0;j<uv_height;j++){
for(i=0;i<uv_width;i++){
data_v[j*uv_width+i]=128;
}
}
fwrite(data_y,width*height,1,fp);
fwrite(data_u,uv_width*uv_height,1,fp);
fwrite(data_v,uv_width*uv_height,1,fp);
fclose(fp);
free(data_y);
free(data_u);
free(data_v);
return 0;
}


simplest_yuv420_graybar(640, 360,0,255,10,"graybar_640x360.yuv");

 Y U V 0 128 128 28 128 128 56 128 128 85 128 128 113 128 128 141 128 128 170 128 128 198 128 128 226 128 128 255 128 128

### (7)计算两个YUV420P像素数据的PSNR

PSNR是最基本的视频质量评价方法。本程序中的函数可以对比两张YUV图片中亮度分量Y的PSNR。函数的代码如下所示。
/**
* Calculate PSNR between 2 YUV420P file
* @param url1     Location of first Input YUV file.
* @param url2     Location of another 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_psnr(char *url1,char *url2,int w,int h,int num){
FILE *fp1=fopen(url1,"rb+");
FILE *fp2=fopen(url2,"rb+");
unsigned char *pic1=(unsigned char *)malloc(w*h);
unsigned char *pic2=(unsigned char *)malloc(w*h);

for(int i=0;i<num;i++){

double mse_sum=0,mse=0,psnr=0;
for(int j=0;j<w*h;j++){
mse_sum+=pow((double)(pic1[j]-pic2[j]),2);
}
mse=mse_sum/(w*h);
psnr=10*log10(255.0*255.0/mse);
printf("%5.3f\n",psnr);

fseek(fp1,w*h/2,SEEK_CUR);
fseek(fp2,w*h/2,SEEK_CUR);

}

free(pic1);
free(pic2);
fclose(fp1);
fclose(fp2);
return 0;
}


simplest_yuv420_psnr("lena_256x256_yuv420p.yuv","lena_distort_256x256_yuv420p.yuv",256,256,1);

### (8) 分离RGB24像素数据中的R、G、B分量

/**
* 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++){

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;
}


simplest_rgb24_split("cie1931_500x500.rgb", 500, 500,1);

output_r.y：R数据，分辨率为256x256。
output_g.y：G数据，分辨率为256x256。

output_b.y：B数据，分辨率为256x256。

R数据图像如下所示。

G数据图像如下所示。

B数据图像如下所示。

### (9)将RGB24格式像素数据封装为BMP图像

BMP图像内部实际上存储的就是RGB数据。本程序实现了对RGB像素数据的封装处理。通过本程序中的函数，可以将RGB数据封装成为一张BMP图像。
/**
* Convert RGB24 file to BMP file
* @param rgb24path    Location of input RGB file.
* @param width        Width of input RGB file.
* @param height       Height of input RGB file.
* @param url_out      Location of Output BMP file.
*/
int simplest_rgb24_to_bmp(const char *rgb24path,int width,int height,const char *bmppath){
typedef struct
{
long imageSize;
long blank;
long startPosition;

typedef struct
{
long  Length;
long  width;
long  height;
unsigned short  colorPlane;
unsigned short  bitColor;
long  zipFormat;
long  realSize;
long  xPels;
long  yPels;
long  colorUse;
long  colorImportant;

int i=0,j=0;
char bfType[2]={'B','M'};
unsigned char *rgb24_buffer=NULL;
FILE *fp_rgb24=NULL,*fp_bmp=NULL;

if((fp_rgb24=fopen(rgb24path,"rb"))==NULL){
printf("Error: Cannot open input RGB24 file.\n");
return -1;
}
if((fp_bmp=fopen(bmppath,"wb"))==NULL){
printf("Error: Cannot open output BMP file.\n");
return -1;
}

rgb24_buffer=(unsigned char *)malloc(width*height*3);

//BMP storage pixel data in opposite direction of Y-axis (from bottom to top).

fwrite(bfType,1,sizeof(bfType),fp_bmp);

//BMP save R1|G1|B1,R2|G2|B2 as B1|G1|R1,B2|G2|R2
//It saves pixel data in Little Endian
//So we change 'R' and 'B'
for(j =0;j<height;j++){
for(i=0;i<width;i++){
char temp=rgb24_buffer[(j*width+i)*3+2];
rgb24_buffer[(j*width+i)*3+2]=rgb24_buffer[(j*width+i)*3+0];
rgb24_buffer[(j*width+i)*3+0]=temp;
}
}
fwrite(rgb24_buffer,3*width*height,1,fp_bmp);
fclose(fp_rgb24);
fclose(fp_bmp);
free(rgb24_buffer);
printf("Finish generate %s!\n",bmppath);
return 0;
return 0;
}


simplest_rgb24_to_bmp("lena_256x256_rgb24.rgb",256,256,"output_lena.bmp");

1)将RGB数据前面加上文件头。
2)将RGB数据中每个像素的“B”和“R”的位置互换。

typedef  struct  tagBITMAPFILEHEADER
{
unsigned short int  bfType;       //位图文件的类型，必须为BM
unsigned long       bfSize;       //文件大小，以字节为单位
unsigned short int  bfReserverd1; //位图文件保留字，必须为0
unsigned short int  bfReserverd2; //位图文件保留字，必须为0
unsigned long       bfbfOffBits;  //位图文件头到数据的偏移量，以字节为单位
{
long biSize;                        //该结构大小，字节为单位
long  biWidth;                     //图形宽度以象素为单位
long  biHeight;                     //图形高度以象素为单位
short int  biPlanes;               //目标设备的级别，必须为1
short int  biBitcount;             //颜色深度，每个象素所需要的位数
short int  biCompression;        //位图的压缩类型
long  biSizeImage;              //位图的大小，以字节为单位
long  biXPelsPermeter;       //位图水平分辨率，每米像素数
long  biYPelsPermeter;       //位图垂直分辨率，每米像素数
long  biClrUsed;            //位图实际使用的颜色表中的颜色数
long  biClrImportant;       //位图显示过程中重要的颜色数


BMP采用的是小端（Little Endian）存储方式。这种存储方式中“RGB24”格式的像素的分量存储的先后顺序为B、G、R。由于RGB24格式存储的顺序是R、G、B，所以需要将“R”和“B”顺序作一个调换再进行存储。

### (10)将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;
}

/**
* Convert RGB24 file to YUV420P file
* @param url_in  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.
* @param url_out Location of Output YUV file.
*/
int simplest_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++){
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;
}


simplest_rgb24_to_yuv420("lena_256x256_rgb24.rgb",256,256,1,"output_lena.yuv");

Y= 0.299*R+0.587*G+0.114*B

U=-0.147*R-0.289*G+0.463*B

V= 0.615*R-0.515*G-0.100*B

1) RGB24存储方式是Packed，YUV420P存储方式是Packed。
2) U，V在水平和垂直方向的取样数是Y的一半

### (11)生成RGB24格式的彩条测试图

/**
* Generate RGB24 colorbar.
* @param width    Width of Output RGB file.
* @param height   Height of Output RGB file.
* @param url_out  Location of Output RGB file.
*/
int simplest_rgb24_colorbar(int width, int height,char *url_out){

unsigned char *data=NULL;
int barwidth;
char filename[100]={0};
FILE *fp=NULL;
int i=0,j=0;

data=(unsigned char *)malloc(width*height*3);
barwidth=width/8;

if((fp=fopen(url_out,"wb+"))==NULL){
printf("Error: Cannot create file!");
return -1;
}

for(j=0;j<height;j++){
for(i=0;i<width;i++){
int barnum=i/barwidth;
switch(barnum){
case 0:{
data[(j*width+i)*3+0]=255;
data[(j*width+i)*3+1]=255;
data[(j*width+i)*3+2]=255;
break;
}
case 1:{
data[(j*width+i)*3+0]=255;
data[(j*width+i)*3+1]=255;
data[(j*width+i)*3+2]=0;
break;
}
case 2:{
data[(j*width+i)*3+0]=0;
data[(j*width+i)*3+1]=255;
data[(j*width+i)*3+2]=255;
break;
}
case 3:{
data[(j*width+i)*3+0]=0;
data[(j*width+i)*3+1]=255;
data[(j*width+i)*3+2]=0;
break;
}
case 4:{
data[(j*width+i)*3+0]=255;
data[(j*width+i)*3+1]=0;
data[(j*width+i)*3+2]=255;
break;
}
case 5:{
data[(j*width+i)*3+0]=255;
data[(j*width+i)*3+1]=0;
data[(j*width+i)*3+2]=0;
break;
}
case 6:{
data[(j*width+i)*3+0]=0;
data[(j*width+i)*3+1]=0;
data[(j*width+i)*3+2]=255;

break;
}
case 7:{
data[(j*width+i)*3+0]=0;
data[(j*width+i)*3+1]=0;
data[(j*width+i)*3+2]=0;
break;
}
}

}
}
fwrite(data,width*height*3,1,fp);
fclose(fp);
free(data);

return 0;
}


simplest_rgb24_colorbar(640, 360,"colorbar_640x360.rgb");

 颜色 (R, G, B) 白 (255, 255, 255) 黄 (255, 255,   0) 青 (  0, 255, 255) 绿 (  0, 255,   0) 品 (255,   0, 255) 红 (255,   0,   0) 蓝 (  0,   0, 255) 黑 (  0,   0,   0)

## 下载

(1)像素数据处理程序。包含RGB和YUV像素格式处理的函数。
(2)音频采样数据处理程序。包含PCM音频采样格式处理的函数。
(3)H.264码流分析程序。可以分离并解析NALU。
(5)FLV封装格式分析程序。可以将FLV中的MP3音频码流分离出来。

(6)UDP-RTP协议分析程序。可以将分析UDP/RTP/MPEG-TS数据包。

leixiaohua1020@126.com
http://blog.csdn.net/leixiaohua1020

01-06
10-06 8147
10-12 167
11-28 5896
08-29 1万+
10-19 1万+
08-13 8万+
08-04 1万+
03-09 1031
11-15 602
07-20 924
05-30 352

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。