• BMP图片格式模型(2)


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

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

     
     
  • 相关阅读:
    web测试学习大纲
    Python语言编程基础
    python文件IO
    Python 正则表达式
    python官网导航翻译
    python常用库
    python连接数据库
    sublime与python交互
    selenium连接浏览器方式
    sublime中运行python时编码格式问题
  • 原文地址:https://www.cnblogs.com/alexhg/p/6543675.html
Copyright © 2020-2023  润新知