• 图像处理学习之路 认识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格式

                • 相关阅读:
                  2013 蓝桥杯B组C++
                  Kruskal 算法 && Kruskal 重构树
                  并查集与其优化(启发式合并、压缩路径)
                  【2021 首祭】一周晴天
                  Docker以过时,看Containerd怎样一统天下
                  史上最全的Nginx配置文档
                  Windows环境Android studio运行RN项目,Node突然闪退
                  solr docker 配置
                  腾讯2017暑期实习生编程题详解
                  华为2016研发工程师编程题详解
                • 原文地址:https://www.cnblogs.com/xiekeli/p/2491191.html
                Copyright © 2020-2023  润新知