【数据与封装格式】BMP图像(位图)

梳理了点阵、位图、RGB图像、矢量图这几个之间的区别关系与联系,重点描述了RGB怎么转位图,以及位图的格式

一、概念

1、矢量图

  • 使用直线和曲线来描述图形,这些图形的元素是一些点、线、矩形、多边形、圆和弧线等等,它们都是通过数学公式计算获得的。
  • 位图和矢量图最简单的区别就是:矢量图可以无限放大,而且不会失真;而位图则不能。
  • 像Photoshop(PS)这样主要用于处理位图的软件,我们称之为图像处理软件;专门处理矢量图的软件,我们称之为图形设计软件

2、位图

  • 图像又称点阵图或光栅图,它使用我们称为像素(象素,Pixel)的一格一格的小点来描述图像。计算机屏幕其实就是一张包含大量像素点的网格。当我们把位图放大时,每一个像素小点看上去就像是一个个马赛克色块。
  • 位图的像素都分配有特定的位置和颜色值。每个像素的颜色信息由RGB组合或者灰度值表示。根据位深度,可将位图分为1、4、8、16、24及32位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量越大
  • BMP图像内部实际上存储的就是RGB数据

3、点阵

  • 位深度为 1 的像素位图只有两个可能的值(黑色和白色),所以又称为二值位图
  • 点阵即为位深为1的像素位图

二、BMP位图文件结构

BMP文件由4部分组成:

  1. 位图文件头(bitmap-file header)

  2. 位图信息头(bitmap-informationheader)

  3. 颜色表(color table)

  4. 颜色点阵数据(bits data)

24位真彩色位图没有颜色表,所以只有1、2、4这三部分,看图像属性,位深度,如果是24,就说明图片是24位真彩色,实际就是对RGB数据的

1、位图文件头

  • 位图信息头占用14bytes
  • 位图文件头分4部分,共14字节:

名称

占用空间

内容

实际数据

bfType

2字节

标识,就是“BM”二字

BM

bfSize

4字节

整个BMP文件的大小

0x000C0036(786486)【与右键查看图片属性里面的大小值一样】

bfReserved1/2

4字节

保留字,没用

0

bfOffBits

4字节

偏移数,即 位图文件头+位图信息头+调色板 的大小

0x36(54)

在这里插入图片描述

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

2、位图信息头

  • 位图信息头共40字节:

名称

占用空间

内容

实际数据

biSize

4字节

位图信息头的大小,为40

0x28(40)

biWidth

4字节

位图的宽度,单位是像素

0x200(512)

biHeight

4字节

位图的高度,单位是像素

0x200(512)

biPlanes

2字节

固定值1

1

biBitCount

2字节

每个像素的位数

1-黑白图,4-16色,8-256色,24-真彩色

0x18(24)

biCompression

4字节

压缩方式,BI_RGB(0)为不压缩

0

biSizeImage

4字节

位图全部像素占用的字节数,BI_RGB时可设为0

0x0C

biXPelsPerMeter

4字节

水平分辨率(像素/米)

0

biYPelsPerMeter

4字节

垂直分辨率(像素/米)

0

biClrUsed

4字节

位图使用的颜色数

如果为0,则颜色数为2的biBitCount次方

0

biClrImportant

4字节

重要的颜色数,0代表所有颜色都重要

0

作为真彩色位图,我们主要关心的是biWidth和biHeight这两个数值,两个数值告诉我们图像的尺寸。biSize,biPlanes,biBitCount这几个数值是固定的。想偷懒的话,其它的数值可以一律用0来填充。

在这里插入图片描述

  • 结构体的定义
typedef  struct  tagBITMAPINFOHEADER 
{ 
int biSize;                        //该结构大小,字节为单位
int  biWidth;                     //图形宽度以象素为单位
int  biHeight;                     //图形高度以象素为单位
short int  biPlanes;               //目标设备的级别,必须为1 
short int  biBitcount;             //颜色深度,每个象素所需要的位数
short int  biCompression;        //位图的压缩类型
int  biSizeImage;              //位图的大小,以字节为单位
int  biXPelsPermeter;       //位图水平分辨率,每米像素数
int  biYPelsPermeter;       //位图垂直分辨率,每米像素数
int  biClrUsed;            //位图实际使用的颜色表中的颜色数
int  biClrImportant;       //位图显示过程中重要的颜色数
}BITMAPINFOHEADER;

3、颜色表

24位真彩色位图没有颜色表。为了简化,只讨论24位真彩色位图。

4、颜色点阵数据

位图全部的像素,是按照自下向上,自左向右的顺序排列的。
RGB数据也是倒着念的,原始数据是按B、G、R的顺序排列的

三、RGB数据封装成BMP图像

BMP图像内部实际上存储的就是RGB数据。本程序实现了对RGB像素数据的封装处理。通过本程序中的函数,可以将RGB数据封装成为一张BMP图像。


int simplest_rgb24_to_bmp(const char *rgb24path,int width,int height,const char *bmppath){
	typedef struct 
	{  
		long imageSize;
		long blank;
		long startPosition;
	}BmpHead;
 
	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;
	}InfoHead;
 
	int i=0,j=0;
	BmpHead m_BMPHeader={0};
	InfoHead  m_BMPInfoHeader={0};
	char bfType[2]={'B','M'};
	int header_size=sizeof(bfType)+sizeof(BmpHead)+sizeof(InfoHead);
	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);
	fread(rgb24_buffer,1,width*height*3,fp_rgb24);
 
	m_BMPHeader.imageSize=3*width*height+header_size;
	m_BMPHeader.startPosition=header_size;
 
	m_BMPInfoHeader.Length=sizeof(InfoHead); 
	m_BMPInfoHeader.width=width;
	//BMP storage pixel data in opposite direction of Y-axis (from bottom to top).
	m_BMPInfoHeader.height=-height;
	m_BMPInfoHeader.colorPlane=1;
	m_BMPInfoHeader.bitColor=24;
	m_BMPInfoHeader.realSize=3*width*height;
 
	fwrite(bfType,1,sizeof(bfType),fp_bmp);
	fwrite(&m_BMPHeader,1,sizeof(m_BMPHeader),fp_bmp);
	fwrite(&m_BMPInfoHeader,1,sizeof(m_BMPInfoHeader),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");

代码主要做了两个工作:

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

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

四、参考

位图(bmp)文件格式分析
视音频数据处理入门:RGB、YUV像素数据处理

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值