图像处理学习笔记——BMP图片详解

2023年5月9日12:09:49

一、位图和调色板的概念

1.位图(Bitmap):

例如我们常说的屏幕分辨率为 640*480,刷新频率为70Hz,意思是说每行要扫描 640 个象素,一共有 480 行,每秒重复扫描屏幕 70 次。我们称这种显示器为位映象设备。所谓位映象,就是指一个二维的象素矩阵,而位图就是采用位映象方法显示和存储的图象。

2.彩色图:

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

颜色 R G B
255 0 0
0 0 255
绿 0 255 0
255 255 255
0 0 0
128 128 128

3.调色板(颜色查找表):

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

如果我们用下面的方法, 就能省的多。
因为是一个 16 色图,也就是说这幅图中最多只有 16 种颜色,我们可以用一个表:表中的每一行记录一种颜色的 R,G,B 值。这样当我们 表示一个象素的颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值。举个例子,如果表的第 0 行为 255,0,0(红色) ,那么当某个象素为 色时,只需要标明 0 即可。 让我们再来计算一下:16 种状态可以用 4 位(bit)表示,所以一个象素要用半个字节。整个图象要用 2002000.5,约 20k 字节,再加上表占用的字节为 3*16=48 字节.整个占用的字节数约为前面的1/6。

这张 RGB 的表,即是我们常说的调色板(Palette) 。不光是 Windows 位图,许多图象文件格式如 pcx,tif,gif 等都用到了调色板。

4.真彩色图

有一种图,它的颜色数高达 256 * 256 * 256 种,也就是说包含 R,G,B 颜色表示方法中所有的颜色,这种图叫做真彩色图( TrueColor)。真彩色图并不是说一幅图包含了所有的颜色,而是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。

表示真彩色图时,每个象素直接用 R,G,B 三个分量字节表示,而不采用调色板技术,原因很明显:如果用调色板,表示一个象素也要用 24 位,这是因为每种颜色的索引要用 24 位(因为总共有 2 的 24 次方种颜色,即调色板有 2 的 24 次方行),和直接用 R, G,B 三个分量表示用的字节数一样,不但没有任何便宜,还要加上一个 256* 256* 256 *3 个字节的大调色板。所以真彩色图直接用 R,G,B 三个分量表示,它又叫做 24 位色图。

二、Bmp 文件格式

Windows 的位图文件(.bmp 文件)的格式大体上分成四个部分,如图 3 所示。
图像处理学习笔记——BMP图片详解

1.位图文件头

第一部分为位图文件头BITMAPFILEHEADER,是一个结构,其定义如下:

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

这个结构的长度是固定的,为14个字节(WORD为无符号16位整数,DWORD为无符号32位整数),各个域的说明如下:

bfType 指定文件类型,必须是0x424D,即字符串"BM",也就是说所有.bmp文件的头两个字节都是"BM"
bfSize 指定文件大小,包括这14个字节
bfReserved1,bfReserved2 为保留字,不用考虑
bfOffBits 为从文件头到实际的位图数据的偏移字节数,即图3中前三个部分的长度之和。

2.位图信息头

第二部分为位图信息头BITMAPINFOHEADER,也是一个结构,其定义如下

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; 

这个结构的长度是固定的,为40个字节(WORD为无符号16位整数,DWORD无符号32位整数,LONG为32位整数),各个域的说明如下:

biSize:          指定这个结构的长度,为40
biWidth:         指定图象的宽度,单位是象素
biHeight:        指定图象的高度,单位是象素;这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是说,高度值是一个正数。
biPlanes:        必须是1,不用考虑
biBitCount:      指定表示颜色时要用到的位数,常用的值为1(黑白二色图),4(16色图),8(256色图),24(真彩色图),新的.bmp格式支持32位图
biCompression:   指定位图是否压缩,有效的值为BI_RGB(不压缩),BI_RLE8,BI_RLE4,BI_BITFIELDS(每个象素的比特由指定的掩码决定)。要说明的是,Windows位图可以采用RLE4,和RLE8的压缩格式,但用的不多。我们今后所讨论的只有第一种不压缩的情况,即BI_RGB。
biSizeImage:     指定实际的位图数据占用的字节数,如果biCompression为BI_RGB,则该项为零,其实也可以从以下的公式中计算出来:biSizeImage=biWidth'*biHeight。举个例子,如果biWidth=240,则biWidth'=240;如果biWidth=241,biWidth'=244)
biXPelsPerMeter: 指定目标设备的水平分辨率,用象素/米表示,关于分辨率的概念,我们将在打印部分详细介绍。
biYPelsPerMeter: 指定目标设备的垂直分辨率,用象素/米表示。
biClrUsed:       指定本图像实际用到的颜色数,如果该值为0,则用到的颜色数为2的biBitCount次方
biClrImportant:  指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。

3.调色板(颜色表)

第三部分为调色板(Palette),当然,这里是对那些需要调色板的位图文件而言的。有些位图,如真彩色图,前面已经讲过,是不需要调色板的,BITMAPINFOHEADER后直接是位图数据。

调色板实际上是一个数组,共有biClrUsed个元素(如果该值为零,则有2的biBitCount次方个元素:当 biBitCount=1、4、8 时,分
别有 2、16、256 个表项;当 biBitCount 大于 8 时,没有调色板项。)。数组中每个元素的类型是一个RGBQUAD结构,占4个字节,其定义如下:

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

4.位图数据

第四部分就是实际的图象数据了。对于用到调色板的位图,图象数据就是该像素颜在调色板中的索引值,当 biBitCount 大于 8 时,没有调色板项。对于真彩色图,图象数据就是实际的R,G,B值。

下面分别介绍:

  • 当 biBitCount=1bit - 2色位图:用1位就可以表示该像素的颜色(一般0表示黑,1表示白),所以1个字节可以表示8个像素。
  • 当 biBitCount=4bit -16色位图:用4位可以表示一个像素的颜色,所以1个字节可以表示2个像素。
  • 当 biBitCount=8bit -256色位图:1个字节刚好可以表示1个像素。
  • 当 biBitCount=16bit - 高彩色位图,2个字节表示1个像素。
  • 当 biBitCount=24bit - 真彩色图:3个字节才能表示1个像素。
  • 当 biBitCount=32bit - 增强型真彩色位图,4个字节表示1个像素。

biBitCount=1 表示位图最多有两种颜色,缺省情况下是黑色和白色,你也可以自己定义这两种颜色。图像信息头装调色板中将有两个调色板项,称为索引 0 和索引 1。图象数据阵列中的每一位表示一个像素。如果一个位是 0,显示时就使用索引 0 的 RGB 值,如果位是 1,则使用索引 1 的 RGB 值。

biBitCount=16 表示位图最多有 65536 种颜色。每个像素用 16 位(2 个字节)表示。这种格式叫作高彩色,或叫增强型 16 位色,或 64K 色。它的情况比较复杂,当 biCompression 成员的值是 BI_RGB 时,它没有调色板。16 位中,最低的 5 位表示蓝色分量,中间的 5 位表示绿色分量,高的 5 位表示红色分量,一共占用了 15 位,最高的一位保留,设为 0。这种格式也被称作 555 16 位位图。如果biCompression 成员的值是 BI_BITFIELDS,那么情况就复杂了,首先是原来调色板的位置被三个 DWORD 变量占据,称为红、绿、蓝掩码。分别用于描述红、绿、蓝分量在 16 位中所占的位置。在 Windows 95(或 98)中,系统可接受两种格式的位域:555和 565,在 555 格式下,红、绿、蓝的掩码分别是:0x7C00、0x03E0、0x001F,而在 565 格式下,它们则分别为:0xF800、0x07E0、0x001F。你在读取一个像素之后,可以分别用掩码“与”上像素值,从而提取出想要的颜色分量(当然还要再经过适当的左右移操作)。在 NT 系统中,则没有格式限制,只不过要求掩码之间不能有重叠。(注:这种格式的图像使用起来是比较麻烦
的,不过因为它的显示效果接近于真彩,而图像数据又比真彩图像小的多,所以,它更多的被用于游戏软件)。

biBitCount=32 表示位图最多有 4294967296(2 的 32 次方)种颜色。这种位图的结构与 16 位位图结构非常类似,当 biCompression 成员的值是 BI_RGB 时,它也没有调色板,32 位中有 24位用于存放 RGB 值,顺序是:最高位—保留,红 8 位、绿 8 位、蓝 8 位。这种格式也被成为888 32 位图。如果 biCompression 成员的值是BI_BITFIELDS 时,原来调色板的位置将被三个DWORD 变量占据,成为红、绿、蓝掩码,分别用于描述红、绿、蓝分量在 32 位中所占的位置。在 Windows 95(or 98)中,系统只接受 888 格式,也就是说三个掩码的值将只能是:0xFF0000、0xFF00、0xFF。而在 NT 系统中,你只要注意使掩码之间不产生重叠就行。(注:这种图像格
式比较规整,因为它是 DWORD 对齐的,所以在内存中进行图像处理时可进行汇编级的代码优化(简单))。

要注意两点:

  1. 每一行的字节数必须是4的整倍数,如果不是,则需要补齐。这在前面介绍biSizeImage时已经提到了。
  2. 一般来说,.BMP文件的数据从下到上,从左到右的。也就是说,从文件中最先读到的是图象最下面一行的左边第一个像素,然后是左边第二个像素…接下来是倒数第二行左边第一个像素,左边第二个像素…依次类推,最后得到的是最上面一行的最右一个像素。
    ——参考正点原子
  • 作者:Y_Wan_Y
  • 原文链接:https://blog.csdn.net/Y_Wan_Y/article/details/115277300
    更新时间:2023年5月9日12:09:49 ,共 4676 字。