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

来源:互联网 发布:视频监控客户端软件 编辑:程序博客网 时间:2024/04/29 23:04

视频原始数据叫做:视频像素数据


本文分别介绍如下几个RGB/YUV视频像素数据处理函数:
分离YUV420P像素数据中的Y、U、V分量
分离YUV444P像素数据中的Y、U、V分量
将YUV420P像素数据去掉颜色(变成灰度图)
将YUV420P像素数据的亮度减半
将YUV420P像素数据的周围加上边框
生成YUV420P格式的灰阶测试图
计算两个YUV420P像素数据的PSNR
分离RGB24像素数据中的R、G、B分量
将RGB24格式像素数据封装为BMP图像
将RGB24格式像素数据转换为YUV420P格式像素数据
生成RGB24格式的彩条测试图

本文中的RGB/YUV文件需要使用RGB/YUV播放器才能查看。YUV播放器种类比较多,例如YUV Player Deluxe

(1) 分离YUV420P像素数据中的Y、U、V分量

本程序中的函数可以将YUV420P数据中的Y、U、V三个分量分离开来并保存成三个文件。函数的代码如下所示。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Split Y, U, V planes in YUV420P file. 
  3.  * @param url  Location of Input YUV file. 
  4.  * @param w    Width of Input YUV file. 
  5.  * @param h    Height of Input YUV file. 
  6.  * @param num  Number of frames to process. 
  7.  * 
  8.  */  
  9. int simplest_yuv420_split(char *url, int w, int h,int num){  
  10.     FILE *fp=fopen(url,"rb+");  
  11.     FILE *fp1=fopen("output_420_y.y","wb+");  
  12.     FILE *fp2=fopen("output_420_u.y","wb+");  
  13.     FILE *fp3=fopen("output_420_v.y","wb+");  
  14.   
  15.     unsigned char *pic=(unsigned char *)malloc(w*h*3/2);  
  16.   
  17.     for(int i=0;i<num;i++){  
  18.   
  19.         fread(pic,1,w*h*3/2,fp);  
  20.         //Y  
  21.         fwrite(pic,1,w*h,fp1);  
  22.         //U  
  23.         fwrite(pic+w*h,1,w*h/4,fp2);  
  24.         //V  
  25.         fwrite(pic+w*h*5/4,1,w*h/4,fp3);  
  26.     }  
  27.   
  28.     free(pic);  
  29.     fclose(fp);  
  30.     fclose(fp1);  
  31.     fclose(fp2);  
  32.     fclose(fp3);  
  33.   
  34.     return 0;  
  35. }  

调用上面函数的方法如下所示。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. simplest_yuv420_split("lena_256x256_yuv420p.yuv",256,256,1);  

从代码可以看出,如果视频帧的宽和高分别为w和h,那么一帧YUV420P像素数据一共占用w*h*3/2 Byte的数据。其中前w*h Byte存储Y,接着的w*h*1/4 Byte存储U,最后w*h*1/4 Byte存储V。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv420p.yuv的YUV420P格式的像素数据文件分离成为三个文件:

output_420_y.y:纯Y数据,分辨率为256x256。

output_420_u.y:纯U数据,分辨率为128x128。

output_420_v.y:纯V数据,分辨率为128x128。

注:本文中像素的采样位数一律为8bit。由于1Byte=8bit,所以一个像素的一个分量的采样值占用1Byte。


程序输入的原图如下所示。

lena_256x256_yuv420p.yuv

程序输出的三个文件的截图如下图所示。在这里需要注意输出的U、V分量在YUV播放器中也是当做Y分量进行播放的。

 

output_420_y.y

           

output_420_u.y和output_420_v.y



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

本程序中的函数可以将YUV444P数据中的Y、U、V三个分量分离开来并保存成三个文件。函数的代码如下所示。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Split Y, U, V planes in YUV444P file. 
  3.  * @param url  Location of YUV file. 
  4.  * @param w    Width of Input YUV file. 
  5.  * @param h    Height of Input YUV file. 
  6.  * @param num  Number of frames to process. 
  7.  * 
  8.  */  
  9. int simplest_yuv444_split(char *url, int w, int h,int num){  
  10.     FILE *fp=fopen(url,"rb+");  
  11.     FILE *fp1=fopen("output_444_y.y","wb+");  
  12.     FILE *fp2=fopen("output_444_u.y","wb+");  
  13.     FILE *fp3=fopen("output_444_v.y","wb+");  
  14.     unsigned char *pic=(unsigned char *)malloc(w*h*3);  
  15.   
  16.     for(int i=0;i<num;i++){  
  17.         fread(pic,1,w*h*3,fp);  
  18.         //Y  
  19.         fwrite(pic,1,w*h,fp1);  
  20.         //U  
  21.         fwrite(pic+w*h,1,w*h,fp2);  
  22.         //V  
  23.         fwrite(pic+w*h*2,1,w*h,fp3);  
  24.     }  
  25.   
  26.     free(pic);  
  27.     fclose(fp);  
  28.     fclose(fp1);  
  29.     fclose(fp2);  
  30.     fclose(fp3);  
  31.   
  32.     return 0;  
  33. }  

调用上面函数的方法如下所示。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. simplest_yuv444_split("lena_256x256_yuv444p.yuv",256,256,1);  
从代码可以看出,如果视频帧的宽和高分别为w和h,那么一帧YUV444P像素数据一共占用w*h*3 Byte的数据。其中前w*h Byte存储Y,接着的w*h Byte存储U,最后w*h Byte存储V。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv444p.yuv的YUV444P格式的像素数据文件分离成为三个文件:
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像素数据去掉颜色(变成灰度图)

本程序中的函数可以将YUV420P格式像素数据的彩色去掉,变成纯粹的灰度图。函数的代码如下。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Convert YUV420P file to gray picture 
  3.  * @param url     Location of Input YUV file. 
  4.  * @param w       Width of Input YUV file. 
  5.  * @param h       Height of Input YUV file. 
  6.  * @param num     Number of frames to process. 
  7.  */  
  8. int simplest_yuv420_gray(char *url, int w, int h,int num){  
  9.     FILE *fp=fopen(url,"rb+");  
  10.     FILE *fp1=fopen("output_gray.yuv","wb+");  
  11.     unsigned char *pic=(unsigned char *)malloc(w*h*3/2);  
  12.   
  13.     for(int i=0;i<num;i++){  
  14.         fread(pic,1,w*h*3/2,fp);  
  15.         //Gray  
  16.         memset(pic+w*h,128,w*h/2);  
  17.         fwrite(pic,1,w*h*3/2,fp1);  
  18.     }  
  19.   
  20.     free(pic);  
  21.     fclose(fp);  
  22.     fclose(fp1);  
  23.     return 0;  
  24. }  


调用上面函数的方法如下所示。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. simplest_yuv420_gray("lena_256x256_yuv420p.yuv",256,256,1);  

从代码可以看出,如果想把YUV格式像素数据变成灰度图像,只需要将U、V分量设置成128即可。这是因为U、V是图像中的经过偏置处理的色度分量。色度分量在偏置处理前的取值范围是-128至127,这时候的无色对应的是“0”值。经过偏置后色度分量取值变成了0至255,因而此时的无色对应的就是128了。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv420p.yuv的YUV420P格式的像素数据文件处理成名称为output_gray.yuv的YUV420P格式的像素数据文件。输入的原图如下所示。
 
处理后的图像如下所示。
 

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

本程序中的函数可以通过将YUV数据中的亮度分量Y的数值减半的方法,降低图像的亮度。函数代码如下所示。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Halve Y value of YUV420P file 
  3.  * @param url     Location of Input YUV file. 
  4.  * @param w       Width of Input YUV file. 
  5.  * @param h       Height of Input YUV file. 
  6.  * @param num     Number of frames to process. 
  7.  */  
  8. int simplest_yuv420_halfy(char *url, int w, int h,int num){  
  9.     FILE *fp=fopen(url,"rb+");  
  10.     FILE *fp1=fopen("output_half.yuv","wb+");  
  11.   
  12.     unsigned char *pic=(unsigned char *)malloc(w*h*3/2);  
  13.   
  14.     for(int i=0;i<num;i++){  
  15.         fread(pic,1,w*h*3/2,fp);  
  16.         //Half  
  17.         for(int j=0;j<w*h;j++){  
  18.             unsigned char temp=pic[j]/2;  
  19.             //printf("%d,\n",temp);  
  20.             pic[j]=temp;  
  21.         }  
  22.         fwrite(pic,1,w*h*3/2,fp1);  
  23.     }  
  24.   
  25.     free(pic);  
  26.     fclose(fp);  
  27.     fclose(fp1);  
  28.   
  29.     return 0;  
  30. }  

调用上面函数的方法如下所示。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. simplest_yuv420_halfy("lena_256x256_yuv420p.yuv",256,256,1);  

从代码可以看出,如果打算将图像的亮度减半,只要将图像的每个像素的Y值取出来分别进行除以2的工作就可以了。图像的每个Y值占用1 Byte,取值范围是0至255,对应C语言中的unsigned char数据类型。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv420p.yuv的YUV420P格式的像素数据文件处理成名称为output_half.yuv的YUV420P格式的像素数据文件。输入的原图如下所示。


处理后的图像如下所示。
 




0 0
原创粉丝点击