Advertisement

YUV图像格式转换: YUYV 转 NV12 (YUV420SP)

阅读量:

首先需明确YUYV与NV12的具体采样格式差异。其中YUYV对应于4:2:2型采样模式而NV12则采用4:2:0型采样结构。具体分布如图所示:

采样方式

实心圆圈标记了每个Y分量的位置,并用空心圆圈表示了一对U和V的值。此外,在YUV图像中每一个单独的Y分量都对应一个特定的像素点位置。
可以看出,在使用YUV 422采样格式时,两个相邻的像素会共享同一对U和V值;而在采用YUV 420采样格式时,则是四个相邻像素才会共享同一对U和V值。有了这一基本概念的理解后学习相关内容会更加容易。

两者在存储方式上的表现如下图所示:

存储方式对比

就文件大小而言,在以下三种情况下进行比较:对于YUYV格式来说,
filesize = \text{width} \times \text{height} + (\text{width} \times \text{height})/2 + (\text{width} \times \text{height})/2
而对于NV12格式来说,
filesize = \text{width} \times \text{height} + (\text{width} \times \text{height})/4 + (\text{width} \times \text{height})/4
因此,在相同条件下,
NV12格式的尺寸是YUYV格式的75%。

也许你会感到有些不耐烦,"但是还没有讲解转化的问题呢?" 不用着急,"其实转换原理也就是几句话就能说明白." 上面的内容只是打个基础. 转换原理:"当将YUV4_2_2转化为YUV4_2_0时,'Y值保持不变',而'U和V信号值在行(垂直方向)上进行一次隔行抽样.' 具体来说,在'YUYV'格式或'NV12'格式中,则只需关注存储格式的不同即可.

uv 分量隔行抽样

废话不多说了,直接上代码,可以转换多帧YUV图像格式:

复制代码
     void yuyv_to_nv12(char * image_in, char* image_out, int width, int height, unsigned long int filesize)
      {
       /* 计算循环次数,YUYV 一个像素点占2个字节*/
    	   int pixNUM = width * height;
    	   unsigned int cycleNum = filesize /pixNUM/2;
    	   printf("cycleNUM = %d\n",cycleNum);
    	   
    	  /*单帧图像中 NV12格式的输出图像 Y分量 和 UV 分量的起始地址,并初始化*/
    	  char *y = image_out;
    	  char *uv = image_out + pixNUM ;
    	 
    	  char *start = image_in;
          unsigned int i =0; 
    	  int j =0,k =0;
    	  
    	  /*处理Y分量*/
    	  for(i= 0; i<cycleNum ;i++)
    	  {
    		int index =0;
    		for(j =0; j< pixNUM*2; j=j+2) //YUYV单行中每两个字节一个Y分量
    		{
    			*(y+index) = *(start + j);
    			index ++;
    		}
    		start = image_in + pixNUM*2*i;
    		y= y + pixNUM*3/2;
    	  }
      
      /**处理UV分量**/
    	  start = image_in;
    	  for(i= 0; i<cycleNum ;i++)
    	  {
    	    int uv_index = 0;
    		for(j=0; j< height; j =j+2)  // 隔行, 我选择保留偶数行
    		{
    			for(k = j*width*2+1; k< width*2*(j+1); k=k+4) //YUYV单行中每四个字节含有一对UV分量
    			{
    				*(uv+ uv_index) = *(start + k);
    				*(uv +uv_index+1) = *(start +k +2);
    				uv_index += 2;
    			}
    		}
    	    start = image_in + pixNUM*2*i;
    	    uv =uv + pixNUM*3/2;
    	  }	
     }

全部评论 (0)

还没有任何评论哟~