VisualC++数字图像处理之BMP文件

在多种文件格式中,BMP是最基本的文件格式,因为BMP文件格式是没有经过压缩的图像,今天我们就来看看BMP到底是个啥东东。

一、BMP文件

 BMP(Bitmap-File)图形文件,又叫位图文件,是Windows采用的图形文件格式,在Windows环境下运行的所有图象处理软件都支持BMP图象文件格式。Windows系统内部各图像绘制操作都是以BMP为基础的。一个BMP文件由四部分组成:文件信息头、位图信息头、调色板、位图数据。

1、文件信息头(BITMAPFILEHEADER)

位图文件头(bitmap-file header)包含了图像类型、图像大小、图像数据存放地址和两个保留未使用的字段。

打开WINGDI.h文件,搜索"BITMAPFILEHEADER"就可以定位到BMP文件的位图文件头的数据结构定义。

structtagBITMAPFILEHEADER { // bmfh
    WORD    bfType; (说明文件的类型,该值必需是0x4D42,也就是字符'BM',否则表示根本不是BMP)
    DWORD   bfSize;
    WORD    bfReserved1;
    WORD    bfReserved2;
    DWORD   bfOffBits;

各个字段所占字节数及描述如下:

字 段 名

大小(单位:字节)

描 述

bfType

2

说明文件的类型,该值必需是0x4D42,也就是字符'BM',否则表示根本不是BMP

bfSize

4

说明该位图文件的大小,用字节为单位

bfReserved1

2

保留,必须设置为0

bfReserved2

2

保留,必须设置为0

bfOffBits

4

说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据,以字节为单位。

VisualC++数字图像处理之BMP文件_第1张图片

图1 示例图片

使用UtraEdit打开示例图片1,可以看到文件第一、二个字节分别为42和4D,这正是BM的ascii码值。38、04、01、00代表了该文件的大小,这里的换算关系是:

Ox00010438(Byte)=16*16*16*16+4*16*16+16*3+8=66616≈65KB (如图3中所示,此处要留意二进制文件的解析及换算方式)

这里细心的小伙伴会发现图3中有大小和占用空间两个数量,这是由于windows 系统的文件管理方式带来的差别,有兴趣可以看看windows系统中簇的概念。其他变量以此类推,在此不一一介绍。

VisualC++数字图像处理之BMP文件_第2张图片

图2 二进制文件

VisualC++数字图像处理之BMP文件_第3张图片

图3 bmp文件大小

2、位图信息头

位图信息头(bitmap-information header)包含了位图信息头的大小、图像的宽高、图像的色深、压缩说明图像数据的大小和其他一些参数。

打开WINGDI.h文件,搜索"tagBITMAPINFOHEADER"就可以定位到BMP文件的位图信息头的数据结构定义。

typedef struct tagBITMAPINFOHEADER{

        DWORD      biSize;

        LONG       biWidth;

        LONG       biHeight;

        WORD       biPlanes;

        WORD       biBitCount;

        DWORD      biCompression;

        DWORD      biSizeImage;

        LONG       biXPelsPerMeter;

        LONG       biYPelsPerMeter;

        DWORD      biClrUsed;

        DWORD      biClrImportant;

} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

字 段 名

大小

(单位:

字节)

描 述

biSize

4

本结构所占用的字节数大小,

biWidth

4

BMP图像的宽度,单位像素

biHeight

4

BMP图像的高度,单位像素

biPlanes

2

总为1,目标设备的级别

biBitCount

2

BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色

biCompression

4

说明图象数据压缩的类型,其中: 

BI_RGB:没有压缩

BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);

BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成

BI_BITFIELDS:每个象素的比特由指定的掩码决定。

BI_JPEG:JPEG格式

biSizeImage

4

BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足,若BI_RGB格式时即未压缩,可设置为0

biXPelsPerMeter

4

水平分辨率,单位像素/m

biYPelsPerMeter

4

垂直分辨率,单位像素/m

biClrUsed

4

BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256

biClrImportant

4

重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色

在图2中,第一行的e,f对应列的28和00代表biSize的数值,40个字节,其他的以此类推。

在本图片中

biSize=40

biWidth=256

biPlanes=1

biBitCount=8

biCompression=0

biSizeImage=0

biXPelsPerMeter=0x000B12

biYPelsPerMeter=0x000B12

biClrUsed=0

biClrImportant=0

注意:windows规定一个扫描行所占的字节数必须是4的倍数,不足的以0填充,一个扫描行所占字节数计算方法如下

DataSizePerLine=(biWidth*biBitCount+31)/8(这里是+31是非常聪明的一种写法,保证每行必须有四个字节而且能被4整除)。

 

3、调色板

那么究竟调色板是什么东西?有什么用?为什么我们这种图片不带调试板呢?

我们先来说说三元色RGB概念。我们知道,自然界中的所有颜色都可以由红、绿、蓝(R,G,B)组合而成。有的颜色含有红色成分多一些,如深红;有的含有红色成分少一些,如浅红。针对含有红色成分的多少,可以分成0到255共256个等级,0级表示不含红色成分;255级表示含有100%的红色成分。同样,绿色和蓝色也被分成256级。这种分级概念称为量化。

表1.1 常见颜色的RGB组合值

 VisualC++数字图像处理之BMP文件_第4张图片

当一幅图中每个象素赋予不同的RGB值时,能呈现出五彩缤纷的颜色了,这样就形成了彩色图。

让我们举例说明什么是调色板?为什么需要调色板?

       有一个长宽各为200个象素,颜色数为16色的彩色图,每一个象素都用R、G、B三个分量表示。因为每个分量有256个级别,要用8位(bit),即一个字节(byte)来表示,所以每个象素需要用3个字节。整个图象要用200×200×3,约120k字节,可不是一个小数目呀!如果我们用下面的方法,就能省的多。

因为是一个16色图,也就是说这幅图中最多只有16种颜色,我们可以用一个表:表中的每一行记录一种颜色的R、G、B值。这样当我们表示一个象素的颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值。举个例子,如果表的第0行为255,0,0(红色),那么当某个象素为红色时,只需要标明0即可。

让我们再来计算一下:16种状态可以用4位(bit)表示,所以一个象素要用半个字节。整个图象要用200×200×0.5,约20k字节,再加上表占用的字节为3×16=48字节.整个占用的字节数约为前面的1/6,省很多吧?

这张R、G、B的表,就是我们常说的调色板(Palette),另一种叫法是颜色查找表LUT(Look Up Table),似乎更确切一些。调色板在windows里的结构定义如下:

typedef structtagPALETTEENTRY { // pe
    BYTE peRed;
    BYTE peGreen;
    BYTE peBlue;
    BYTE peFlags;
} PALETTEENTRY;

表1.2 tagRGBTRIPLE结构

字 段 名

大小(单位:字节)

描 述

rgbBlue

1

蓝色值

rgbGreen

1

绿色值

rgbRed

1

红色值

rgbReserved

1

保留,总为0

 

调色板中RGBQUAD结构的个数由bitBitCount来确定,当等于1.4.8时候,分别有2,16,256个表项;当bitBit=24,没有颜色表项。

这是因为当BMP是24位真彩色的BMP,它的颜色数高达256×256×256种,也就是说包含我们上述提到的R、G、B颜色表示方法中所有的颜色。真彩色图并不是说一幅图包含了所有的颜色,而是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。表示真彩色图时,每个象素直接用R、G、B三个分量字节表示,而不采用调色板技术。原因很明显:如果用调色板,表示一个象素也要用24位,这是因为每种颜色的索引要用24位(因为总共有256×256×256种颜色,即调色板256×256×256行),和直接用R,G,B三个分量表示用的字节数一样,不但没有任何便宜,还要加上一个256×256×256×3个字节的大调色板。所以真彩色图直接用R、G、B三个分量表示,它又叫做24位色图。

这么看来BMP文件不能一概而论了,其是否用调色板或者是RGB掩码,位图数据中的数据的真正含义直接与biBitCount 有关,不同类型的位图,其中的设计原理也不同,下面对此作一个对比:

VisualC++数字图像处理之BMP文件_第5张图片

通过计算得出bfOffBits为0x000436=1078,而sizeof(BITMAPFILEHEADER )+sizeof(BITMAPINFOHEADER)=14+40=54(bite)

剩下的就是1078-54=1024,说明该结构是有调色版的,调色版的字节数为1024。根据以上分析我们可以得到biBitCount代表有256种颜色,而每个tagRGBTRIPLE结构是4个字节,则256*4=1024,这样就对应了起来。

4、位图数据
      如果图像是1、4和8位色,则紧跟着调色板的是位图数据,位图数据是指向调色板的索引序号。

如果位图是16位、24位和32位色,则图像文件中不保留调色板,即不存在调色板,图像的颜色直接在位图数据中给出。

16位图像使用2字节保存颜色值,常见有两种格式:5位红5位绿5位蓝和5位红6位绿5位蓝,即555格式和565格式。555格式只使用了15 位,最后一位保留,设为0。

24位图像使用3字节保存颜色值,每一个字节代表一种颜色,按红、绿、蓝排列。

32位图像使用4字节保存颜色值,每一个字节代表一种颜色,除了原来的红、绿、蓝,还有Alpha通道,即透明色。

如果图像带有调色板,则位图数据可以根据需要选择压缩与不压缩,如果选择压缩,则根据BMP图像是16色或256色,采用RLE4或RLE8压缩算法压缩。

二、编程实现


参考链接

1、http://blog.csdn.net/lanbing510/article/details/8176231

2、http://www.cnblogs.com/tiandsp/archive/2012/10/22/2734552.html

3、http://www.cnblogs.com/lzlsky/archive/2012/08/16/2641698.html

4、http://blog.csdn.net/lanbing510/article/details/8176231

5、VisualC++ 数字图像处理典型案例详解 机械工业出版社        沈晶、刘海波等著

你可能感兴趣的:(机器视觉)