C语言实现BMP格式转RGB格式YUV格式

Posted 代二毛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言实现BMP格式转RGB格式YUV格式相关的知识,希望对你有一定的参考价值。

前言

此代码的功能是传入BMP格式的数据,传出提取的RGB数据。BMP图像支持8bit、16bit、24bit、32bit的格式,得到的都是24bit的RGB格式图像,如果想得到YUV格式的图像,可以将得到RGB再转为YUV格式。RGB转YUV格式参考博客《C语言实现RGB packet格式转YUV(NV21)格式》

代码

//BMP图片的压缩方式
#define BI_RGB          (0)
#define BI_BITFIELDS         (3)
//RGB555的掩码
#define RGB555_RED_MASK        (31744)
#define RGB555_GREEN_MASK       (992)
#define RGB555_BLUE_MASK       (31)
//RGB565的掩码
#define RGB565_RED_MASK        (63488)
#define RGB565_GREEN_MASK       (2016)
#define RGB565_BLUE_MASK       (31)
//BMP图片的像素位数
#define BMP_8_BIT         (8)
#define BMP_16_BIT         (16)
#define BMP_24_BIT         (24)
#define BMP_32_BIT         (32)
//16位BMP图片从文件头到图像数据的偏移量
#define BMP_16_BIT_BI_BITFIELDS_OFFSET    (66)
#define BMP_16_BIT_BI_RGB_OFFSET     (54)
//8位BMP图片调色板的大小
#define BMP_8_BIT_OFFSET       (1024)
//BMP图片的文件头,固定14字节
#define BMP_FILE_HEADER_LENGTH       (14)

# isNull(ptr)        	(NULL == (ptr))
# isNotNull(ptr)        (NULL != (ptr))

//BMP图片的信息头
typedef struct InfoHeader
{
 Uint32 bisize;//信息头的大小,一般是40
 Int32 biWidth;//位图的宽
 Int32 biHeight;//位图的高
 Uint16 biPlanes;//固定值1
 Uint16 biBitCount;//每个像素的位数
 Uint32 biCompression;//压缩方式,BI_RGB(0)为不压缩, BI_BITFIELDS(3)用于16位、32位位图  
 Uint32 biSizeImage;//位图全部像素占用的字节
 Int32 biXpelsPerMeter;//水平分辨率
 Int32 biYPelsPerMeter;//垂直分辨率
 Uint32 biClrUsed;//位图使用的颜色数。0代表颜色数为2的biBitCount次方
 Uint32 biClrImportant;//重要的颜色数,0代表所有颜色都重要
 
}BmpInfoHeader;

Int32 BMPExtractBGR(Uint8* pSrcData, Uint8* pDstData)
{
 BmpInfoHeader BmpInfoHeader;
 Uint32 width, height;
 Int32 i, j;
 Int32 offSet;
 Int32 RGB24 = 0;
 Uint16 RGB16 = 0;  
 Int32 count = 0;
 if(isNull(pSrcData) || isNull(pDstData))
 {
  	printf("input parameter invalid\\n");
  	return -1;
 }
 //获取信息头
 memcpy(&BmpInfoHeader, pSrcData + BMP_FILE_HEADER_LENGTH, sizeof(IVS_BmpInfoHeader)); 

 width  = BmpInfoHeader.biWidth;
 height = BmpInfoHeader.biHeight;

 //判断BMP图片像素的位数
 if(BmpInfoHeader.biBitCount == BMP_24_BIT)
 { 
  	offSet = BMP_FILE_HEADER_LENGTH + BmpInfoHeader.bisize;//文件头到BGR数据的偏移量
  	j = 0;
  //读取文件的BRG数据
  for(i = height - 1; i >=0; i-- )
  {
   		memcpy(pDstData + j * width * 3, pSrcData + offSet + i * width * 3, width * 3);
   		j++;
  }
 }
 else if(BmpInfoHeader.biBitCount == BMP_8_BIT)
 { 
  	offSet = BMP_FILE_HEADER_LENGTH + BmpInfoHeader.bisize + BMP_8_BIT_OFFSET;
  	for(i = height - 1; i >= 0; i --)
  	{
   	for(j = 0; j < width; j++)
   	{ 
    	memcpy(pDstData + count * 3, pSrcData + BMP_FILE_HEADER_LENGTH + BmpInfoHeader.bisize + 4 * (int)pSrcData[offSet + i * width + j], 3);
    	count++;
   }
   
  }
 }
  else if(BmpInfoHeader.biBitCount == BMP_16_BIT)
 { 
  	if(BmpInfoHeader.biCompression == BI_BITFIELDS)
  	{ 
   	//根据掩码判断是RGB555
   	if((*((Int32 *)(pSrcData + 54)) == RGB555_RED_MASK) && (*((Int32 *)(pSrcData + 58)) == RGB555_GREEN_MASK) \\
    	&& (*((Int32 *)(pSrcData + 62)) == RGB555_BLUE_MASK))
   	{
    	//提取BGR数据
    	for(i = height - 1; i >= 0; i--)
    	{
     	for(j = 0; j < width; j++)
     	{
      	RGB24 = 0;
      	RGB16 = *((Uint16 *)(pSrcData + BMP_16_BIT_BI_BITFIELDS_OFFSET + 2 * (i * width + j)));
      	RGB24 |= ((RGB16 & RGB555_RED_MASK) << 9) | ((RGB16 & RGB555_GREEN_MASK) << 6) | ((RGB16 & RGB555_BLUE_MASK) << 3);
      	memcpy(pDstData + count * 3, &RGB24, 3);
      	count++;
     	}
    	}
   	}
   //根据掩码判断是RGB565
   else if((*((Int32 *)(pSrcData + 54)) == RGB565_RED_MASK) && (*((Int32 *)(pSrcData + 58)) == RGB565_GREEN_MASK) \\
    && (*((Int32 *)(pSrcData + 62)) == RGB565_BLUE_MASK))
   {
    for(i = height - 1; i >= 0; i--)
    {
     for(j = 0; j < width; j++)
     {
      	RGB24 = 0;
      	RGB16 = *((Uint16 *)(pSrcData + BMP_16_BIT_BI_BITFIELDS_OFFSET + 2 * (i * width + j)));
      	RGB24 |= ((RGB16 & RGB565_RED_MASK) << 8) | ((RGB16 & RGB565_GREEN_MASK) << 5) | ((RGB16 & RGB565_BLUE_MASK) << 3);
      	memcpy(pDstData + count * 3, &RGB24, 3);
      	count++;
     }
    }
   }
  }
  else if(BmpInfoHeader.biCompression == BI_RGB)
  {
   //提取BGR数据
   for(i = height - 1; i >= 0; i--)
   {
    	for(j = 0; j < width; j++)
    	{
     		RGB24 = 0;
     		RGB16 = *((Uint16 *)(pSrcData + BMP_16_BIT_BI_RGB_OFFSET + 2 * (i * width + j)));
     		RGB24 |= ((RGB16 & RGB555_RED_MASK) << 9) | ((RGB16 & RGB555_GREEN_MASK) << 6) | ((RGB16 & RGB555_BLUE_MASK) << 3);
     		memcpy(pDstData + count * 3, &RGB24, 3);
     		count++;
    	}
   	}
  }
 }
  else if(BmpInfoHeader.biBitCount == BMP_32_BIT)
 {
  offSet = BMP_FILE_HEADER_LENGTH + BmpInfoHeader.bisize;//文件头到BGR数据的偏移量
  count = 0;
  for(i = height - 1; i >= 0; i--)
  {
   for(j = 0; j < width; j++)
   {
    memcpy(pDstData + 3 *count, pSrcData + offSet + 4 *(i * width + j), 3);
    count++;
   }
  }
 }
  else
 {
 	printf("not support bmp format\\n");
 	return -1;
 }
 	return 0;
}

以上是关于C语言实现BMP格式转RGB格式YUV格式的主要内容,如果未能解决你的问题,请参考以下文章

C语言实现RGB888转BMP格式图片功能

怎么将图像YUV格式转成RGB格式(C++)

PAL或者NTSC制式 BT.656(YUV 4:2:2) 转化为BMP格式图片(RGB)算法

如何把摄像头采集的rgb图像转成yuv格式,并进行H264硬编码?

如何将rgb 模式转换成 yuv 模式

YUV与RGB格式详解