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

BMP文件格式

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

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

一个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文件:

(测试BMP文件)

这里:

bfType:0X040d(BM)

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

跳过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,表示都重要。

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

biWidth:352像素;

biHeight:288像素;

和图片信息相符:

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组合值

当一幅图中每个象素赋予不同的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 有关,不同类型的位图,其中的设计原理也不同,下面对此作一个对比:

4、位图数据

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

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

 
 

BMP图片格式模型(2)的更多相关文章

  1. BMP图片格式模型

    BMP BMP(全称Bitmap)是Window操作系统中的标准图像文件格式 可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广. 它采用位映射存储格式,除了图像深度可选以外,不 ...

  2. BMP图片格式

    BMP图片 BMP采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大.BMP文件的图像深度可选lbit.4bit.8bit及24bit和32bit.BMP文 ...

  3. c语言数字图像处理(一):bmp图片格式及灰度图片转换

    本篇文章首先介绍了bmp图片格式,主要参考wiki上的内容,包括bmp文件的存储方式,对于一些常见的bmp文件格式都给了例子,并且对8位 16位RGB555 16位RGB565格式的bmp文件进行了简 ...

  4. bmp图片格式及读取

    C++读取bmp图片的例子 #include <windows.h> #include <stdio.h> #include <stdlib.h> #include ...

  5. BMP 图片格式

     BMP根据颜色深度,可以分为2(1位).16(4位).256(8位).65536(16位)和1670万(24位)以及32位含有alpha通道.8位图像可以是 索引彩色图像外,也可以是灰阶图像,而索引 ...

  6. linu下C语言之BMP图片操作编程(上)

    BMP文件格式,也被称为位图图像文件或与设备无关的位图文件格式(DIB)或者只是一个位图,是 一个光栅图形 图像文件格式使用 来存储位图,数字,图片,独立的显示设备. 微软已经定义了一个特定的表示颜色 ...

  7. VC++使用CImage在内存中Jpeg转换Bmp图片

    VC++中Jpeg与Bmp图片格式互转应该是会经常遇到,Jpeg相比Bmp在图片大小上有很大优势. 本文重点介绍使用现有的CImage类在内存中进行转换,不需要保存为文件,也不需要引入第三方库. Li ...

  8. BMP图片解析

    本博客参考:https://www.cnblogs.com/l2rf/p/5643352.html 一.简介 BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Window ...

  9. PNG,JPEG,BMP,JIF图片格式详解及其对比

    原文地址:http://blog.csdn.net/u012611878/article/details/52215985 图片格式详解 不知道大家有没有注意过网页里,手机里,平板里的图片,事实上,图 ...

随机推荐

  1. Number,parseInt,parseFloat函数

    Number,parseInt,parseFloat函数 console.group('Number'); console.log(Number( console.log(Number( consol ...

  2. Unable to resolve target 'android-XX'解决办法

    在搭建好安卓编译环境后,我用Eclipse导入冲git上下载的安卓源码编译时,会提示 Unable to resolve target 'android-17' 等 “Unable to resolv ...

  3. javascript 简单工厂

    function detail() { this.imgArr = []; this.codeArr = []; } detail.prototype.addimg = function(img) { ...

  4. JSP中使用Taglib

    http://blog.163.com/jany_1016/blog/static/4604400620091112114127341/ http://blog.csdn.net/yuebinghao ...

  5. Bootstrap入门(二十二)组件16:列表组

    Bootstrap入门(二十二)组件16:列表组 列表组是灵活又强大的组件,不仅能用于显示一组简单的元素,还能用于复杂的定制的内容. 1.默认样式列表组 2.加入徽章 3.链接 4.禁用的列表组 5. ...

  6. 如何在项目中引入MetaQ消息收发机制

    当需要异步发送和接收大量消息时,需要在Crystal项目中引入MetaQ消息收发机制. 关于MetaQ使用的官方例子可参考:https://github.com/killme2008/Metamorp ...

  7. SysLog简介和java操作实例

    什么是SysLog syslog协议属于一种主从式协议:syslog发送端会传送出一个小的文字讯息(小于1024字节)到syslog接收端.接收端通常名为“syslogd”.“syslog daemo ...

  8. IOS网络请求之NSURLSession使用

    前言: 无论是Android还是ios都离不开与服务器交互,这就必须用到网络请求,记得在2013年做iOS的时候那时候用的ASIHTTPRequest框架,现在重新捡起iOS的时候ASIHTTPReq ...

  9. 地图学与GIS制图的基础理论(一)

    说到地图制作,很多人第一时间就会跟地图学进行挂钩.是的,地图学的很多理论和知道思想都非常适合基于GIS制图.可以说,利用GIS进行电子地图制作,其实也属于地图学的一小部分. 地图学是研究地图的理论.地 ...

  10. css3 3D效果

    css3 3D变形 transfrom初学 这个礼拜学了css3 3d,感觉到css无穷的魅力,可以通过几个特定的代码符号创建出3D效果的页面. ___ 透视 一个元素需要一个透视点才能激活3D空间, ...