图像基础:BMP、RGB、JPG、PNG等格式详解(一)

什么是BMP

BMP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持。随着Windows操作系统的流行与丰富的Windows应用程序的开发,BMP位图格式理所当然地被广泛应用。这种格式的特点是包含的图像信息较丰富,几乎不进行压缩,但由此导致了它与生俱生来的缺点–占用磁盘空间过大。所以,目前BMP在单机上比较流行。

BMP文件结构

BMP文件由4部分组成:
1.位图文件头(bitmap-file header)(大小为14Byte)
2.位图信息头(bitmap-informationheader)(大小为40Byte)
3.颜色表(color table)
4.颜色点阵数据(bits data)
(24位真彩色位图没有颜色表,所以只有1、2、4这三部分。)

示例如下图:
图像基础:BMP、RGB、JPG、PNG等格式详解(一)_第1张图片

BMP常见参数

色彩深度又叫色彩位数,即位图中要用多少个二进制位来表示每个点的颜色,是分辨率的一个重要指标。常用有1位(单色)2位(4色,CGA)4位(16色,VGA)8位(256色)16位(增强色)24位和32位(真彩色)等
BMP文件记录一行图像是以字节为单位的。因此,就不存在一个字节中的数据位信息表示的点在不同的两行中。也就是说,设显示模式位16色,在每个字节分配两个点信息时,如果图像的宽度位奇数,那么最后一个像素点的信息将独占一个字节,这个字节的后4位将没有意义。接下来的一个字节将开始记录下一行的信息。 
为了显示的方便,除了真彩色外,其他的每种颜色模式的行字节数要用数据“00”补齐为4的整数倍。如果显示模式为16色(2个字节),当图像宽为19时,存储时每行则要补充4-(19/2+1)%4=2个字节。如果显示模式为256色,当图像宽为19时,每行也要补充4-19%4=1个字节。

位图行四字节对齐算法:
第一种表示方法:
LineByte = [(biWidth * biBitCount + 7) / 8 +3 ])/ 4 * 4
第二种表示方法:
LineByte = (biWidth * biBitCount + 31) /32 *4

LineByte :每行所占的字节
biWidth : 图片像素宽度
biBitCount :像素深度,1bit,4bit,8bit…
biWidth * biBitCount :未填充时一行数据所占的位数
(biWidth * biBitCount+7) / 8 :未对齐时一行数据所占的字节数
[(biWidth * biBitCount + 7) / 8 +3 ])/ 4 :对齐时一行数据所占的字节单元(4Byte)数
(biWidth * biBitCount + 31) /32 :对齐时一行数据所占的字节单元(4Byte)数

BMP文件大小计算

1色黑白:
文件头(14字节) + 信息头(40字节) + 2个调色板(共8字节) + Height(图像高度) * (Width + 8 - Width % 8) / 8

16色:
文件头(14字节) + 信息头(40字节) + 16个调色板(共64字节) + Height(图像高度) * (Width + 4 - Width % 4) / 2

256色:
文件头(14字节) + 信息头(40字节) + 256个调色板(共1024字节) + Height(图像高度) * (Width + 4 - Width % 4)

16位色:
文件头(14字节) + 信息头(40字节) + Height(图像高度) * (Width + 4 - Width % 4) * 2 (由于每个像素由两个字节表示)

24位色:
文件头(14字节) + 信息头(40字节) + Height(图像高度) * (Width + 4 - Width % 4) * 3 (由于每个像素由三个字节表示)

BMP颜色点阵数据

1、RGB数据也是倒着念的,原始数据是按B、G、R的顺序排列的。
2、位图全部的像素,是按照自下向上,自左向右的顺序排列的。
即:BMP内存第0行,是真实图像下面的最后一行。
举例,假如图像为2*2大小,像素三颜色按照RGB的顺序, 我们看到的图像为:
1 2 3, 11 22 33
4 5 6, 44 55 66

内存表示如下:
6 5 4, 66 55 44 (0 0) – 第0行
3 2 1, 33 22 11 (0 0) – 第1行
注意,通常内存是需要内存对齐的,所以每行后面可能会有对齐所产生的0.

图像基础:BMP、RGB、JPG、PNG等格式详解(一)_第2张图片

BMP相关代码

读取BMP头文件信息

#include  
#include 

typedef  struct  tagBITMAPFILEHEADER
{ 
	unsigned short int  bfType;       //位图文件的类型,必须为BM 
	unsigned long       bfSize;       //文件大小,以字节为单位
	unsigned short int  bfReserverd1; //位图文件保留字,必须为0 
	unsigned short int  bfReserverd2; //位图文件保留字,必须为0 
	unsigned long       bfbfOffBits;  //位图文件头到数据的偏移量,以字节为单位
}BITMAPFILEHEADER; 

typedef  struct  tagBITMAPINFOHEADER 
{ 
	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;       //位图显示过程中重要的颜色数
}BITMAPINFOHEADER; 

typedef  struct 
{ 
	BITMAPFILEHEADER  file; //文件信息区
	BITMAPINFOHEADER  info; //图象信息区
}bmp;

bmp  readbmpfile(void); //函数声明

int  main(void){ 
  bmp m;          //定义一个结构变量
  m=readbmpfile(); //读取一个位图
  getchar();
  return 0;
}

 

bmp  readbmpfile(void) { 
	 bmp  m;        //定义一个位图结构
	 FILE *fp; 
	 if((fp=fopen( "d:\\1.bmp", "r"))==NULL) 
	 { printf( "can't open the bmp imgae.\n "); 
	   	exit(0); 
	 }
	else 
	{ 
		fread(&m.file.bfType,sizeof(char),1,fp); 
		printf("类型为%c",m.file.bfType); 
		fread(&m.file.bfType,sizeof(char),1,fp); 
		printf("%c\n",m.file.bfType);        
		fread(&m.file.bfSize,sizeof(long),1,fp); 
		printf("文件长度为%d\n",m.file.bfSize);  
		fread(&m.file.bfReserverd1,sizeof(short int),1,fp); 
		printf("保留字1为%d\n",m.file.bfReserverd1); 
		fread(&m.file.bfReserverd2,sizeof(short int),1,fp); 
		printf("保留字2为%d\n",m.file.bfReserverd2); 
		fread(&m.file.bfbfOffBits,sizeof(long),1,fp); 
		printf("偏移量为%d\n",m.file.bfbfOffBits);
		fread(&m.info.biSize,sizeof(long),1,fp); 
		printf("此结构大小为%d\n",m.info.biSize); 
		fread(&m.info.biWidth,sizeof(long),1,fp); 
		printf("位图的宽度为%d\n",m.info.biWidth);
		fread(&m.info.biHeight,sizeof(long),1,fp); 
		printf("位图的高度为%d\n",m.info.biHeight);
		fread(&m.info.biPlanes,sizeof(short),1,fp); 
		printf("目标设备位图数%d\n",m.info.biPlanes);
		fread(&m.info.biBitcount,sizeof(short),1,fp); 
		printf("颜色深度为%d\n",m.info.biBitcount);
		fread(&m.info.biCompression,sizeof(long),1,fp); 
		printf("位图压缩类型%d\n",m.info.biCompression); 
		fread(&m.info.biSizeImage,sizeof(long),1,fp); 
		printf("位图大小%d\n",m.info.biSizeImage); 
		fread(&m.info.biXPelsPermeter,sizeof(long),1,fp); 
		printf("位图水平分辨率为%d\n",m.info.biXPelsPermeter); 
		fread(&m.info.biYPelsPermeter,sizeof(long),1,fp); 
		printf("位图垂直分辨率为%d\n",m.info.biYPelsPermeter); 
		fread(&m.info.biClrUsed,sizeof(long),1,fp); 
		printf("位图实际使用颜色数%d\n",m.info.biClrUsed);
		fread(&m.info.biClrImportant,sizeof(long),1,fp); 
		printf("位图显示中比较重要颜色数%d\n",m.info.biClrImportant); 
	} 
	return m; 
}

BMP 32位色深转换24位色深

// transform 32-bit bitmap format to 24-bit bitmap format
void Bmp32ToBmp24(char Filename[])
{
 	char Filename2[] = "output.bmp";

 	//注意:如果没有LR_CREATEDIBSECTION,位图颜色将被映射到屏幕DC颜色
 	//也就是说,如果屏幕是16位颜色,则所有的图像都将映射到16位颜色
 	HBITMAP hbmp32 = (HBITMAP) LoadImage(NULL, Filename,
  	IMAGE_BITMAP, 0, 0,
  	LR_LOADFROMFILE |
 	LR_CREATEDIBSECTION);

	BITMAP bmp;//获取位图信息
 	GetObject(hbmp32, sizeof(BITMAP), &bmp);

 	printf("Image Bit Depth : %dnWidth : %d , Height : %d n",
  	bmp.bmBitsPixel, bmp.bmWidth, bmp.bmHeight);//显示位图颜色模式和图像宽高

 	//计算24位图像每行的字节数
 	int BytesPerLine = 3 * bmp.bmWidth;
 	while(BytesPerLine % 4 != 0)
  	BytesPerLine ++;

 	BITMAPINFOHEADER bih = {0};//位图信息头
 	bih.biBitCount = 24;//每个像素字节大小
 	bih.biCompression = BI_RGB;
 	bih.biHeight = bmp.bmHeight;//高度
 	bih.biPlanes = 1;
 	bih.biSize = sizeof(BITMAPINFOHEADER);
 	bih.biSizeImage = BytesPerLine * bmp.bmHeight;//图像数据大小
 	bih.biWidth = bmp.bmWidth;//宽度
 
 	BITMAPFILEHEADER bfh = {0};//位图文件头
 	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);//到位图数据的偏移量
 	bfh.bfSize = bfh.bfOffBits + bih.biSizeImage;//文件总的大小
 	bfh.bfType = (WORD)0x4d42;
 
 	FILE *fp = fopen(Filename2, "w+b");
 
 	fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);//写入位图文件头
 
 	fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);//写入位图信息头
 
 	byte * p = new byte[bih.biSizeImage];
 
 	//获取当前32位图像数据
 	GetDIBits(GetDC(NULL), hbmp32, 0, bmp.bmHeight, p, (LPBITMAPINFO)&bih, DIB_RGB_COLORS);

 	//只取rgb值,存入文件
 	byte b = 0;//用于填充
 	for(int i = 0 ; i < bmp.bmWidth * bmp.bmHeight ; i ++)
 	{
	  //32位位图图像的格式为:Blue, Green, Red, Alpha
	  fwrite(&(p[i * 3]), 1, 3, fp);
	  if(i % bmp.bmWidth == bmp.bmWidth - 1)//填充字节
	  {
		   for(int k = 0 ; k < (BytesPerLine - bmp.bmWidth * 3) ; k ++)
		   fwrite(&b, sizeof(byte), 1, fp);
	  }
 	}
 
 	delete [] p;
 
 	fclose(fp);

 	DeleteObject(hbmp32);
}

你可能感兴趣的:(视频编码,bmp,c++)