BMP为window系统中广泛使用的图像文件格式,是window的标准图像格式,可以不做任何改变图像像素的数据,可以获取到最原始的图像数据,因此是我们分析图像数据的最重要的来源
BMP图像格式
BMP图像格式主要是在图像元素数据的基础上加了一些文件头,其头部主要包含以下四个部分
- BMP文件头(bmp file header):提供文件的格式,大小等信息
- 位图信息头(bitmap information):提供图像数据的尺寸,位平面数,压缩方式,颜色索引等信息。
- 调色板(color palete):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
- 位图数据(bitmap data):图像元素图像数据
数据块 | 是否必须 |
BMP文件头(bmp file header) | 必须 |
位图信息头(bitmap information) | 必须 |
调色板(color palete) | 非必须 |
位图数据(bitmap data) | 必须 |
下面将根据代码介绍BMP头文件各个信息
BMP文件头(bmp file header)
bmp file header定义如下:
typedef struct
{
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
}BitMapFileHeader;
各个字段定义如下:
字段 | 大小 | 作用 |
bfType | 2 bytes | 表明为文件类型 * BM --- window 3.1x,96, NT,... * BA --- OS/2 Bitmap Array * CI ---- OS/2 Color ICon * CP ----- OS/2 Color Pointer * IC ------ OS/2 Icon * PI ------ OS/2 Pointer |
bfSize | 4 bytes | 文件大小,包括文件头和数据部分 |
bfReserved1 | 2 bytes | 保留位,必须设置0 |
bfReserved2 | 2 bytes | 保留为,必须设0 |
bOffBits | 4 bytes | 位图数据文件,在整个文件中的偏移(跳过BMP头,位图头,调色板(如果有)) |
位图信息头(bitmap information)
位图信息头文定义如下:
typedef struct
{
unsigned int biSize;
int biWidth;
int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} BitMapInfoHeader;
各字段定义如下:
字段 | 大小 | 作用 |
biSi4ze | 4 bytes | 信息头大小, sizeof(BitMapInfoHeader)=40 |
biWidth | 4 bytes | 图像宽度 |
biHeight | 4 bytes | 图像高度(如果是正数那么是倒向的位图,也就是2D屏幕坐标系翻转类似物体坐标系(y轴由下到上,位图数据也由左下角一行行的存放),如果是负数,那么图像是正向的,也就是2D屏幕坐标系(y轴由上到下,位图数据也由左上角一行行存放). |
biPlanes | 2 bytes | 颜色平面数,总是为1 |
biBitCount | 2 bytes | 每个像素的比特数,一般为8,16,24,32. 灰度图一般为8,RGB图为24 |
biCommpression | 4 bytes | 0:BI_RGB 不压缩 1:BI_RLE8 8比特游程编码(RLE),只用于8位位图 2:BI_RLE4 4比特游程编码(RLE),只用于4位位图 3 BI_BITFILELDS 比特域 |
biSizeImage | 4 bytes | 图像数据字节大小 |
biXPelsPerMeter | 4 bytes | 水平分辨率,像素/米表示 |
biYPelsPerMeter | 4 bytes | 垂直分辨率,像素/米表示 |
biClrUsed | 4 bytes | 实际使用的彩色表中的颜色索引数 如果是8位一像素那么这里是256;为0采用所用调色板中的索引或者没有调色板。 |
biClrImportant | 4 bytes | 对图像显示有重要影响的颜色索引的数目 如果是0,表示都重要 |
调色板
位于信息头后面,是可选项,实际上是一个palette[N][4]模型的数据结构,行是N例如256;包含四列是一个unsigned
int类型的整型ARGB,ARGB在内存中的存储序列为:BGRA,每列代表了一个颜色分量,alpha没有则是0。位图数据就是用一个Byte标记调色板中的0~N-1的索引。BMP文件头14字节,位图信息头40字节,如果有调色板256的那么是1024字节,没有调色板那么是54个字节偏移为位图数据了,有调色板那么是1078个字节才是位图信息数据。
位图数据(bitmap data)
8位BMP,每个位图存放的是调色板中的索引,如果像素高度是正数那么是物体坐标系,位图数据由左下角一行行往上存放。
如果是非调色板真彩色像素,那么存放的就是颜色值,而不是索引,像素高度是正数那么是物体坐标系由左下角开始,像素高度是负数那么是屏幕物体坐标系由左上角开始。
24位RGB按照BGR的顺序来存储每个像素的各颜色通道的值,一个像素的所有颜色分量值都存完后才存下一个下一个像素,不进行交织存储。
32位数据按照BGRA的顺序存储,其余与24位位图的方式一样。当高度为正数确实是物体坐标系形式,无论是内存中还是二进制文件中,像素由图像的左下角一行行往上存放;
当高度为负数那么是屏幕坐标系,像素是由图像左上角一行行往下存放;如果一行不足4字节的倍数,那么填充00使得满足4字节的倍数。
用例
void ConvertRGBToBMP(unsigned char *RGBBuffer, unsigned char *BMPBuffer, unsigned int ImageWidth, unsigned int ImageHeight)
{
BitMapFileHeader* BmpFileHeader = (BitMapFileHeader*)BMPBuffer;//填充BMP文件头信息
BmpFileHeader->bfType = 0x4D42;//'BM‘
BmpFileHeader->bfSize = sizeof(BitMapFileHeader) + sizeof(BitMapInfoHeader) + ImageWidth*ImageHeight * 3;
BmpFileHeader->bfOffBits = sizeof(BitMapFileHeader) + sizeof(BitMapInfoHeader);
BmpFileHeader->bfReserved1 = 0;
BmpFileHeader->bfReserved2 = 0;
BitMapInfoHeader* BmpInfoHeader = (BitMapInfoHeader*)((unsigned char*)BMPBuffer + sizeof(BitMapFileHeader));
BmpInfoHeader->biSize = 40;
BmpInfoHeader->biWidth = ImageWidth;
BmpInfoHeader->biHeight = -ImageHeight;
BmpInfoHeader->biPlanes = 1;
BmpInfoHeader->biBitCount = 24;//RGB图像
BmpInfoHeader->biCompression = 0;
BmpInfoHeader->biSizeImage = ImageWidth*ImageHeight * 3;
BmpInfoHeader->biXPelsPerMeter = 0;
BmpInfoHeader->biYPelsPerMeter = 0;
BmpInfoHeader->biClrUsed = 0;
BmpInfoHeader->biClrImportant = 0;
unsigned * ImageBufferHeader = (unsigned char*)((unsigned char*)BmpInfoHeader + sizeof(BitMapInfoHeader));
memcpy(ImageBufferHeader, RGBBuffer, ImageWidth*ImageHeight * 3);
return ;
}