图像处理学习之路 -- 认识BMP

因为公司的主要业务是图像识别相关的,因此对图像处理、识别是我学习的重点。虽然写程序也不少年了,但是对于图像处理领域,我还是一个新兵。对很多基础的概念也还是存在盲区,所以想在边学边做的过程中,对一些概念的梳理和学习心得进行记录。

BMP文件格式

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

image

  • 位图文件头
  • 位图信息段
  • 调色板
  • 位图数据

                 

                一个BMP文件,可以用代码表示,如下:

                typedef struct tagBITMAP_FILE{

                BITMAPFILEHEADER bitmapheader;
                BITMAPINFOHEADER bitmapinfoheader;
                PALETTEENTRY palette[256];
                UCHAR *buffer; //UCHAR 大小1字节(同BYTE), 在VC6下

                } BITMAP_FILE;

                1、 BMP文件头:BITMAPFILEHEADER

                typedef struct tagBITMAPFILEHEADER { // bmfh 
                WORD bfType;
                DWORD bfSize;
                WORD bfReserved1;
                WORD bfReserved2;
                DWORD bfOffBits;
                } BITMAPFILEHEADER;

                bfType 说明文件的类型,该值必需是0x4D42,也就是字符'BM',否则表示根本不是BMP
                bfSize 说明该位图文件的大小,用字节为单位
                bfReserved1 保留,必须设置为0
                bfReserved2 保留,必须设置为0
                bfOffBits 说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。

                 

                下面用Notepad++打开一个BMP文件:

                image(测试BMP文件)

                image

                这里:

                bfType:0X040d(BM)

                bfSize:0X0004a436 == 304182字节 == 297K字节,说明这个位图文件的大小为297K字节,和我看到的符合:

                image

                跳过4字节的保留字节,

                bfOffBits:0X00000036 == 54字节

                 

                2、位图信息段:BITMAPINFOHEADER

                typedef struct tagBITMAPINFOHEADER{ // bmih 
                DWORD biSize;
                LONG biWidth;
                LONG biHeight;
                WORD biPlanes;
                WORD biBitCount
                DWORD biCompression;
                DWORD biSizeImage;
                LONG biXPelsPerMeter;
                LONG biYPelsPerMeter;
                DWORD biClrUsed;
                DWORD biClrImportant;
                } BITMAPINFOHEADER;

                biSize 说明BITMAPINFOHEADER结构所需要的字节数
                biWidth 说明图象的宽度,以象素为单位
                biHeight 说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,即:数据的第一行其实是图像的最后一行,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。
                biPlanes 表示bmp图片的平面属,显然显示器只有一个平面,所以恒等于1
                biBitCount 说明比特数/象素,其值为1、4、8、16、24、或32。
                biCompression 说明图象数据压缩的类型,其中:

                BI_RGB:没有压缩

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

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

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

                BI_JPEG:JPEG格式

                biSizeImage 说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0。
                biXPelsPerMeter 说明水平分辨率,用象素/米表示。
                biYPelsPerMeter 说明垂直分辨率,用象素/米表示。
                biClrUsed 说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。
                biClrImportant 说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。

                image

                biSize:位图信息段结构BITMAPINFOHEADER的字节数 0x00000028 ==40字节

                biWidth:352像素;

                biHeight:288像素;

                和图片信息相符:

                image

                biPlanes:1

                biBitCount :24位图

                biCompression:没有压缩;

                biSizeImage:0x4a400 == 304128字节 ,当用BI_RGB格式时,可设置为0,为什么这里是304128呢?这里的304128是怎么出来的呢?

                原来biSizeImage = biWidth*biHeight*每个像素的字节数

                那么我们这里应该是:352*288*24/8 = 304128。(我们这里的位数/像素为24,所以每个像素的字节数为3)

                注:这里的biWidth必须是4的倍数,如果不是4的倍数,则需要取4的倍数,比如241,则取244;为什么必须是4的倍数?这里涉及到一个行对齐的问题:

                由于Windows在进行行扫描的时候最小的单位为4个字节,所以当

                图片宽 X 每个像素的字节数 != 4的整数倍

                时要在每行的后面补上缺少的字节,以0填充

                biXPelsPerMeter:0x00000000

                biYPelsPerMeter:0x00000000

                biClrUsed:0x00000000  使用所有调色板项

                biClrImportant:00000000

                 

                3、调色板

                上面这张BMP图片是否有调色板呢?答案是否定的。

                因为从bfOffBits = 54字节可以看出,刚好是sizeof(BITMAPFILEHEADER )+sizeof(BITMAPINFOHEADER);

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

                我们先来说说三元色RGB概念。

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

                1.1 常见颜色的RGB组合值

                image

                当一幅图中每个象素赋予不同的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 struct tagPALETTEENTRY { // pe 
                BYTE peRed;
                BYTE peGreen;
                BYTE peBlue;
                BYTE peFlags;
                } PALETTEENTRY;

                那么为什么我们这张BMP不带调色板呢?

                       是因为我们这张BMP是24位真彩色的BMP,所谓真彩色图(true color),就是它的颜色数高达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 有关,不同类型的位图,其中的设计原理也不同,下面对此作一个对比:

                image

                 

                4、位图数据

                上面基本把调色板及相关取色策略梳理清楚了,接着回到我们上面的例子。24位BMP图,每3个字节表示一个像素,3个字节分别表示R、G、B的分量值

                image

                这里每3个字节表示一个像素的颜色,注意:由于位图信息头中的图像高度是正数,所以位图数据在文件中的排列顺序是从左下角到右上角,以行为主序排列的。

                 

                参考了BMP文件格式详解(BMP file format)的学习思路,对BMP格式进行了梳理和学习。

                参考资源:

                        BMP文件格式详解(BMP file format)

                        百度BMP格式

                posted @ 2012-05-09 09:07  红心李  阅读(6635)  评论(12编辑  收藏  举报