摘 要:本文简单介绍了位图文件的两种存储格式,并且在VC++6.0下实现了读取位图文件中的数据,用SetPixel()函数在窗口中重现图像,最后在程序中实现了一种存储格式到另一种存储格式的转换。
关键字:BMP、灰度位图、24位真彩色位图、存储格式
一、前言
BMP(Bitmap的缩写)图像是指文件名后缀为BMP的位图图像。位图图像在计算机中使用很广泛,例如在windows中,记事本、写字板中的文字就是用位图图像表示出来的。许多以其它格式存储的图像,就是在位图图像的基础上,进行优化处理后得到的,例如JPEG图像等。
在数字图像处理中,许多算法就是针对24位真彩色位图或灰度位图设计的。因此,很有必要介绍一下位图文件的这两种存储格式。
二、24位真彩色图像存储格式
把下图的24位真彩色图像格式在16位编辑器(例如VC编辑器)中打开,可以看到图像的二进制数据。
24位真彩色的二进制数据为:
这是24位真彩色位图文件数据一部分。这一部分数据包括位图文件头、位图信息头和位图阵列三部分。
(一)位图文件头
位图文件头用来记录标志文件大小的一些信息,在文件中占14个字节,存储的内容如下:
字节 |
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
9 |
10 |
11 |
12 |
13 |
14 |
000000 |
|
42 |
4D |
CC |
B4 |
02 |
00 |
00 |
00 |
|
00 |
00 |
36 |
00 |
00 |
00 |
其中:
42 4D 为位图的标志,即ASCII码为BM
CC B4 02 表示位图文件的总字节数,换算成十进制为(02B4CC)H=(177356)10,即这副图像的大小为177356字节。
00 00 00 00 00 为保留字节,用来存储文件大小的数据。
36 00 00 00 00 表示位图阵列的起始位置,(36)H=(54)10即54字节开始为位图阵列。
(二) 位图信息头
位图信息头记录和位图相关的一些信息,在文件中占40个字节,存储的内容如下:
字节 |
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
000000 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
00 |
000016 |
|
00 |
00 |
2C |
01 |
00 |
00 |
C5 |
00 |
|
00 |
00 |
01 |
00 |
18 |
00 |
00 |
00 |
000032 |
|
00 |
00 |
00 |
00 |
00 |
00 |
12 |
0B |
|
00 |
00 |
12 |
0B |
00 |
00 |
00 |
00 |
000048 |
|
00 |
00 |
00 |
00 |
00 |
00 |
|
|
|
|
|
|
|
|
|
|
|
其中:
28 00 00 00 表示信息头的长度,(28)H=(40)10,即位图信息头占40个字节。
2C 01 00 00 表示位图宽度,单位为像素。(012C)H=(300)10,即位图的宽度为300个像素。
C5 00 00 00 表示位图高度,单位为像素。(C5)H=(197)10,即位图的宽度为197个像素。
01 00 表示位图设备级别
18 00 位图级别,(0018)H=(24)10,即24位真彩色。
00 00 00 00 表示压缩类型,为零表示不压缩。
00 00 00 00 保留字节。
12 0B 00 00 表示水平分辨率
12 0B 00 00 表示垂直分辨率
00 00 00 00 表示位图实际使用的颜色表中的颜色变址数。
00 00 00 00 表示位图显示过程中被认为重要颜色变址数。
(三)位图像素阵列
剩下的部分为位图像素阵列,即像素表示部分,每个象素点由3个字节的数据组成,按照从左到右的顺序,分别表示蓝色、绿色、红色。
在VC++中的wingdi.h中对于位图的编码和格式有更加详细的定义,下面给出24位真彩色位图格式在VC++中的定义。
typedef struct tagBITMAPFILEHEADER {//位图文件头
WORD bfType; //位图标志“BM”
DWORD bfSize; //位图文件总字节数
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{ //位图信息头格式定义
DWORD biSize; //位图信息头占用字节数
LONG biWidth; //位图图像宽度(以像素为单位)
LONG biHeight; //位图图像高度(以像素为单位)
WORD biPlanes; //位图设备级别
WORD biBitCount //位图级别设定,每个像素所需的位数,必须是1(双色), // 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; //压缩类型
DWORD biSizeImage; //位图阵列表字节数
LONG biXPelsPerMeter; //水平分辨率
LONG biYPelsPerMeter; //垂直分辨率
DWORD biClrUsed; //位图实际使用的颜色表中的颜色变址数
DWORD biClrImportant; //位图显示过程中被认为重要颜色变址数
} BITMAPINFOHEADER;
typedef struct tagRGBTRIPLE { //位图阵列格式定义
BYTE rgbtBlue; //定义蓝色
BYTE rgbtGreen; //定义绿色
BYTE rgbtRed; //定义红色
} RGBTRIPLE;//构成一个3字节的RGBTRIPLE。
按照这个这个结构可以从BMP文件中读取数据,然后在屏幕上用SetPixel()函数描绘出来。主要代码如下:
if (!cf.Open(TransValue,CFile::modeRead, &e))//找到文件后,打开文件
{
MessageBox("Can not open the file!","Open File");
return;
}
cf.SeekToBegin();
cf.Read(&bmfh,sizeof(bmfh));//读取文件头
cf.Read(&bmih,sizeof(bmih));//读取文件信息头
rgb = new RGBTRIPLE[bmih.biWidth*bmih.biHeight];
cf.SeekToBegin();
cf.Seek(54,CFile::begin);
//读取文件数据
if (cf.GetLength()>64*1024)
{
cf.ReadHuge(rgb,bmih.biWidth*bmih.biHeight*3);//
}
else
{
cf.Read(rgb,bmih.biWidth*bmih.biHeight);
}
//在屏幕上打点显示图像
for (int i=0; i<bmih.biHeight;i++)
{
for (int j=0; j<bmih.biWidth; j++)
{
pDC->SetPixel(j,bmih.biHeight-i,RGB(rgb[i*bmih.biWidth+j].rgbtRed,rgb[i*bmih.biWidth+j].rgbtGreen,rgb[i*bmih.biWidth+j].rgbtBlue));
}
}
cf.Close();//关闭文件
delete rgb;//释放内存
三、灰度位图存储格式
同样,把下面的灰度位图在VC编辑器中以Binary方式打开,可以看到如下的数据(部分):
灰度位图数据:
从上述数据中可以看出,灰度位图的存储格式与24位真彩色位图的存储格式基本相同。唯一的差别是,灰度位图比24位真彩色位图增加了一部分:颜色索引表。因此,灰度位图的像素阵列的起始位置不是第(36)H=(54)10个字节,而是第(436)H=(1078)10个字节,同时灰度位图用一个字节来表示一个像素。这样,灰度位图的像素阵列小了三分之二。
颜色索引表定义为: typedef struct rgbn { BYTE red; BYTE green; BYTE blue; BYTE null; } RGBn;
在实际的编程中,读取数据的方式发生了变化,除了要读取文件头,文件信息头外,还要设置变量读取颜色索引表。除此以外,灰度图像的编程读取显示方式与24位真彩色位图的方式完全相同,在此就不再描述。 从上述灰度位图和24位真彩色位图的存储结构中可以看出,把24位真彩色位图的颜色信息去掉,就可以得到灰度位图。根据不同的需要,不同的理论,有不同的去掉颜色的方法。在本文中,仅仅在红、绿、蓝三种基本色前加权三分之一,然后在屏幕上打点显示出来,得到灰度位图图像。如果需要存储,只需要在文件头、文件信息头后加上颜色索引表,然后再以一个字节的空间存储位图像素信息,把上述信息按顺序写到一个文件中,就得到一个灰度位图图像文件。
|