数字图像处理与机器视觉:Visual C++与Matlab实现(第2版)
上QQ阅读APP看书,第一时间看更新

2.1 位图文件及其C++操作

Windows操作系统中使用最多的图形文件格式就是位图格式,最常见的位图文件的扩展名为BMP。BMP是英文Bitmap(位图)的简写,这种格式的特点是包含的图像信息较丰富,几乎不进行压缩,因此它占用的磁盘空间较大。下面主要介绍使用Visual C++对BMP文件的操作。

2.1.1 设备无关位图

Windows 3.0以后的BMP位图文件格式与显示设备无关,因此把这种BMP位图文件称为设备无关位图(Device Independent Bitmap, DIB)。DIB自带颜色信息,因此调色板管理非常简单。现在,任何Windows操作系统的计算机都能够显示和处理DIB,它通常以BMP文件的形式被保存在磁盘中。

2.1.2 BMP图像文件数据结构

典型的BMP图像文件由以下4部分组成,如图2.1所示。

图2.1 BMP文件的组成

(1)位图文件头(BITMAPFILEHEADER)数据结构,包含BMP图像文件的类型、显示内容等信息。

(2)位图信息头(BITMAPINFOHEADER)数据结构,包含有BMP图像的宽、高、压缩方法以及定义颜色等信息。

(3)调色板,即颜色索引表。

(4)实际的位图数据。

下面分别介绍BMP图像文件的这4个部分。

1.位图文件头(BITMAPFILEHEADER)结构

位图文件头(BITMAPFILEHEADER)的定义可以在微软公司提供的类库(Microsoft Foundation Classes, MFC)Library中找到,这部分文件头包含了位图文件的类型、大小和包含设备无关位图的图像文件布局。

BITMAPFILEHEADER结构体具有固定的长度14字节,其定义和描述如下。

      typedef struct     tagBITMAPFILEHEADER {
        WORD bfType;                // 指定文件类型,必须是“BM”(0x4D42)
        DWORD    bfSize;           // 指定位图文件的大小,以字节表示
        WORD bfReserved1;           // 保留字,必须为0
        WORD bfReserved2;           // 保留字,必须为0
        DWORD    bfOffBits;        // 指定从实际图像数据到文件头起始的偏移量,以字节为单位
      } BITMAPFILEHEADER, *PBITMAPFILEHEADER;

2.位图信息头(BITMAPINFOHEADER)结构

BITMAPINFOHEADER结构体中包含了设备无关位图关于颜色维度和色彩格式的信息,其定义和描述如下。

      typedef struct tagBITMAPINFOHEADER{
        DWORD    biSize;           // 本结构体占用的大小,单位为字节
        LONG biWidth;               // 位图图像的宽度,单位为像素
        LONG biHeight;              // 位图图像的高度,单位为像素
        WORD biPlanes;              // 设备上颜色平面数目,必须为1
        WORD biBitCount;            // 存储每个像素所使用的二进制位数
        DWORD    biCompression;    // 是否压缩存储图像数据
        DWORD    biSizeImage;      // 指定图像的大小(以字节为单位)
        LONG biXPelsPerMeter;       // 图像的水平分辨率,单位是像素每米
        LONG biYPelsPerMeter;       // 图像的垂直分辨率,单位是像素每米
        DWORD    biClrUsed;        // 图像中实际使用了颜色索引表中的多少种颜色
        DWORD    biClrImportant;   // 图象中重要的颜色数,如果该值为0,则认为所有的颜色都是重要的
      } BITMAPINFOHEADER, *PBITMAPINFOHEADER;

重要成员参数解释如下。

• biBitCount指定存储每个像素使用的二进制数据位数,间接确定图像中可能存在的最大颜色数目。可取:1、4、8、16、24、32,其含义见下文讲解。

• biSizeImage指定图像大小(以字节为单位)。biSizeImage=biWidth' × biHeight。其中biWidth’是图像每行占用的字节数,与实际宽度biWidth不同,biWidth’必须是4的整数倍,即大于或等于biWidth的,最接近4的整倍数。例如,biWidth=400,则biWidth'=400,如果biWidth=401,则biWidth'=404。如果biCompression为BI_RGB,该项可能为零。

• biClrUsed成员指定了在位图图像中实际使用到的颜色数目。如果biClrUsed成员被设置为零,那么图像中实际使用的颜色数目是和biBitCount成员中规定的值相同的最大数目。

小技巧:biBitCount成员

BITMAPINFOHEADER结构的biBitCount成员可用于确定位图图像中每个像素所占用的数据长度(单位是位)和图像中所包含的最多颜色数目。这个成员的取值可以有6种,分别对应BMP图像允许的6种颜色模式。

BMP文件的色深也就是存储每个像素使用的位数有1(单色)、4(16色)、8(256色)、16(64×1024色,高彩色)、24(16×10242色,真彩色)、32(4096×10242色,增强型真彩色)6种。它们与biBitCount之间的对应关系如下。

(1)biBitCount=1,位图图像是单色的,并且成员bmiColor索引表包含两个条目。位图图像数组中的每一个数据位代表一个像素。如果这个数据位是0,那么此像素在显示时使用bmiColors索引表中的第一种颜色;如果这个数据位是1,那么此像素在显示时使用bmiColors索引表中的第二种颜色。

(2)biBitCount=4,位图图像包含最多16种颜色,并且成员bmiColors索引表中包含至多16个条目。此时位图图像数据区中的每一个像素条目长度是4位(0.5字节)。例如,如果位图图像数据区的第一个字节数值是0x1F,这一字节表示2个像素的颜色,第一个像素是在索引表中的第二种颜色,第二个像素是在索引表中的第16种颜色。

(3)biBitCount=8,位图图像包含最多256种颜色,并且成员bmiColors索引表中包含至多256种颜色。在这种情况下,位图图像数据区中的每个字节代表一个像素的图像数据。

(4)biBitCount=16,位图图像包含最多216种颜色,并且BITMAPINFOHEADER的biCompression成员取值必须为BI_BITFIELDS。此时bmiColors成员包含3个DWORD类型的颜色掩码分别用以指定每个像素的红、绿、蓝的颜色成分。

(5)biBitCount=24,位图图像包含最多224种颜色,并且成员bmiColors索引表为空(NULL)。在位图图像数据区中的每个三比特组中的数据表示某个像素中的红、绿、蓝颜色成分的相对强度。

(6)biBitCount=32,位图图像包含最多232种颜色,BITMAPINFOHEADER的biCompression成员必须是BI_BITFIELDS, bmiColors成员包含三个DWORD类型的颜色掩码用以指定每个像素颜色中的红色、绿色和蓝色成分。

3.调色板结构

有些位图(如索引图像)需要调色板(Palette),有些(像真彩色图)则不需要,它们的BITMAPINFOHEADER后面直接是位图数据。

调色板实际上是一个RGBQUAD型的数组,该数组总共有biClrUsed个元素(如果biClrUsed等于0,则有2的biBitCount次幂个元素)。RGBQUAD是一个用于存储RGB颜色数据的4个字节的结构体,其定义如下。

        typedef struct tagRGBQUAD {
          BYTE    rgbBlue;           //该颜色的蓝色分量
          BYTE    rgbGreen;          //该颜色的绿色分量
          BYTE    rgbRed;            //该颜色的红色分量
          BYTE    rgbReserved;       //保留值
        } RGBQUAD;

注意

除位图调色板外,还有逻辑调色板和系统调色板的概念。有时,在更新了位图调色板后需要更新逻辑调色板和系统调色板,才能将颜色的变换正确地反映出来。但仅当系统处于256色显示模式时才需要用到系统调色板,而目前的系统已经很少使用256色的显示模式了,因此一般不会涉及相关的操作,本书也对此不加讨论,仅在DIPDemo程序中实现了该逻辑。

4.实际位图数据

实际位图数据是一片连续的存储区域,其中保存着图像中每个像素的灰度(颜色)信息。对于256色灰度图像,图像数据就是该像素的实际灰度,1个像素需要1字节来表示;对于索引图像,图像数据就是该像素颜色在调色板中的索引值;而对于真彩色图,图像数据就是实际的RGB值,1个像素需要3字节来表示。

注意

一般来说,BMP文件的实际位图数据是从下到上、从左到右的。即从文件中最先读到的是图像最后一行左边第1个像素,然后是左边第2个像素,…,接下来是倒数第2行的最左边第1个,左边第2个,…,最后是第1行的左侧第1个像素,第2个像素,…,第1行最右侧的像素。

位图数据每一行占用的字节数必须是4的整数倍,如果不是,则需要补齐。