ImageVerifierCode 换一换
格式:DOCX , 页数:16 ,大小:104.74KB ,
资源ID:12255941      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/12255941.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(BMP文件结构读写操作.docx)为本站会员(b****4)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

BMP文件结构读写操作.docx

1、BMP文件结构读写操作1.2 BMP文件结构及其存取数字图像在外存储器设备中的存储形式是图像文件,图像必须按照某个已知的、公认的数据存储顺序和结构进行存储,才能使不同的程序对图像文件顺利进行打开或存盘操作,实现数据共享。图像数据在文件中的存储顺序和结构称为图像文件格式。目前广为流传的图像文件格式有许多种,常见的格式包括BMP、GIF、JPEG、TIFF、PSD、DICOM、MPEG等。在各种图像文件格式中,一部分是由某个软硬件厂商提出并被广泛接受和采用的格式,例如BMP、GIF和PSD格式;另一部分是由各种国际标准组织提出的格式,例如JPEG、TIFF和DICOM,其中JPEG是国际静止图像压

2、缩标准组织提出的格式,TIFF是由部分厂商组织提出的格式,DICOM是医学图像国际标准组织提出的医学图像专用格式。BMP文件是Windows操作系统所推荐和支持的图像文件格式,是一种将内存或显示器的图像数据不经过压缩而直接按位存盘的文件格式,所以称为位图(bitmap)文件,因其文件扩展名为BMP,故称为BMP文件格式,简称BMP文件。本书对图像的算法编程都是针对BMP图像文件的,因此在本章中我们详细介绍BMP文件结构及其读写操作,以加深对图像数据的理解。1.2.1 BMP文件结构如图1-7所示,BMP图像文件被分成4个部分:位图文件头(Bitmap File Header)、位图信息头(Bi

3、tmap Info Header)、颜色表(Color Map)和位图数据(即图像数据,Data Bits或Data Body)。第1部分为位图文件头BITMAPFILEHEADER,是一个结构体类型,该结构的长度是固定的,为14个字节。其定义如下: typedef struct tagBITMAPFILEHEADERWORD bfType;DWORD bfSize;WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

4、BITMAPFILEHEADER结构的各个域详细说明如下:bfType:位图文件类型,必须是0x424D,即字符串“BM”,也就是说,所有的“*.bmp”文件的头两个字节都是“BM”。bfSize:位图文件大小,包括这14个字节。bfReserved1, bfReserved2:Windows保留字,暂不用。bfOffBits:从文件头到实际的位图数据的偏移字节数,图1-7中前3个部分的长度之和。图1-7 BMP文件结构示意图第2部分为位图信息头BITMAPINFOHEADER,也是一个结构体类型的数据结构,该结构的长度也是固定的,为40个字节(WORD为无符号16位整数,DWORD为无符号3

5、2位整数,LONG为32位整数)。其定义如下: typedef struct tagBITMAPINFOHEADERDWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCountDWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed;DWORD biClrImportant; BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBI

6、TMAPINFOHEADER;BITMAPINFOHEADER结构的各个域的详细说明如下:biSize:本结构的长度,为40个字节。biWidth:位图的宽度,以像素为单位。biHeight:位图的高度,以像素为单位。biPlanes:目标设备的级别,必须是1。biBitCount:每个像素所占的位数(bit),其值必须为1(黑白图像)、4(16色图)、8(256色)、24(真彩色图),新的BMP格式支持32位色。biCompresssion:位图压缩类型,有效的值为BI_RGB(未经压缩)、BI_RLE8、BI_RLE4、BI_BITFILEDS(均为Windows定义常量)。这里只讨论未经

7、压缩的情况,即biCompression=BI_RGB。biSizeImage:实际的位图数据占用的字节数,该值的大小在第4部分位图数据中有具体解释。biXPelsPerMeter:指定目标设备的水平分辨率,单位是像素/米。biYPelsPerMeter:指定目标设备的垂直分辨率,单位是像素/米。biClrUsed:位图实际用到的颜色数,如果该值为零,则用到的颜色数为2的biBitCount次幂。biClrImportant:位图显示过程中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。第3部分为颜色表。颜色表实际上是一个RGBQUAD结构的数组,数组的长度由biClrUsed指定(如

8、果该值为零,则由biBitCount指定,即2的biBitCount次幂个元素)。RGBQUAD结构是一个结构体类型,占4个字节,其定义如下:typedef struct tagRGBQUADBYTE rgbBlue;BYTE rgbGreen;BYTE rgbRed;BYTE rgbReserved;RGBQUAD;RGBQUAD结构的各个域的详细说明如下:rgbBlue:该颜色的蓝色分量;rgbGreen:该颜色的绿色分量;rgbRed:该颜色的红色分量;rgbReserved:保留字节,暂不用。有些位图需要颜色表;有些位图(如真彩色图)则不需要颜色表,颜色表的长度由BITMAPINFOH

9、EADER结构中biBitCount分量决定。对于biBitCount值为1的二值图像,每像素占1bit,图像中只有两种(如黑白)颜色,颜色表也就有21=2个表项,整个颜色表的大小为 个字节;对于biBitCount值为8的灰度图像,每像素占8bit,图像中有 颜色,颜色表也就有256个表项,且每个表项的R、G、B分量相等,整个颜色表的大小为 个字节;而对于biBitCount=24的真彩色图像,由于每像素3个字节中分别代表了R、G、B三分量的值,此时不需要颜色表,因此真彩色图的BITMAPINFOHEADER结构后面直接就是位图数据。第4部分是位图数据,即图像数据,其紧跟在位图文件头、位图信

10、息头和颜色表(如果有颜色表的话)之后,记录了图像的每一个像素值。对于有颜色表的位图,位图数据就是该像素颜色在调色板中的索引值;对于真彩色图,位图数据就是实际的R、G、B值(三个分量的存储顺序是B、G、R)。下面分别就2色、16色、256色和真彩色位图的位图数据进行说明:对于2色位图,用1位就可以表示该像素的颜色,所以1个字节能存储8个像素的颜色值。对于16色位图,用4位可以表示一个像素的颜色。所以一个字节可以存储2个像素的颜色值。对于256色位图,1个字节刚好存储1个像素的颜色值。对于真彩色位图,3个字节才能表示1个像素的颜色值。需要注意两点:第一,Windows规定一个扫描行所占的字节数必须

11、是4的倍数,不足4的倍数则要对其进行扩充。假设图像的宽为biWidth个像素、每像素biBitCount个比特,其一个扫描行所占的真实字节数的计算公式如下:DataSizePerLine = (biWidth * biBitCount /8+ 3) / 4*4那么,不压缩情况下位图数据的大小(BITMAPINFOHEADER结构中的biSizeImage成员)计算如下:biSizeImage = DataSizePerLine * biHeight第二,一般来说,BMP文件的数据是从图像的左下角开始逐行扫描图像的,即从下到上、从左到右,将图像的像素值一一记录下来,因此图像坐标零点在图像左下角。

12、1.2.2 BMP图像文件的读写分析了BMP文件结构后,让我们用简单的C程序实现一个给定BMP位图文件的读写操作,来进一步巩固对图像数据的理解,这也是我们后续图像可视化编程的基础。此部分的代码以及后面两节所讲述的代码在工程chap1-1中的bmpReadWrite.cpp文件中,读者可以查阅。1BMP文件的读入BMP文件分为4个组成部分,那么BMP文件的读入也要按照4个组成部分依次进行处理,即先处理BITMAPFILEHEADER结构,然后是BITMAPINFOHEADER结构、颜色表,最后是位图数据。首先,有关BITMAPFILEHEADER、BITMAPINFOHEADER、RGBQUAD

13、等结构的定义包含在头文件“Windows.h”中,应把其包含进来。 #include Windows.h其次,为了后面对图像进行修改及存盘方便,我们定义了几个全局变量,用来存放读入图像的位图数据、宽、高、颜色表及每像素位数等信息。所定义的全局变量如下: unsigned char *pBmpBuf;/读入图像数据的指针int bmpWidth;/图像的宽int bmpHeight;/图像的高RGBQUAD *pColorTable;/颜色表指针int biBitCount;/图像类型,每像素位数 根据BMP文件结构,BMP文件读入操作的基本流程如图1-8所示。图1-8 BMP文件读入操作流程图

14、readBmp()函数实现了BMP文件的读取操作,下面的代码是对readBmp()函数的说明和实现。 /* 函数名称:* readBmp()*函数参数:* char *bmpName -文件名字及路径*返回值:* 0为失败,1为成功*说明:给定一个图像文件名及其路径,读图像的位图数据、宽、高、颜色表及每像素* 位数等数据进内存,存放在相应的全局变量中*/bool readBmp(char *bmpName)/二进制读方式打开指定的图像文件FILE *fp=fopen(bmpName,rb);if(fp=0) return 0;/跳过位图文件头结构BITMAPFILEHEADERfseek(fp

15、, sizeof(BITMAPFILEHEADER),0);/定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中BITMAPINFOHEADER head; fread(&head, sizeof(BITMAPINFOHEADER), 1,fp); /获取图像宽、高、每像素所占位数等信息bmpWidth = head.biWidth;bmpHeight = head.biHeight;biBitCount = head.biBitCount;/定义变量,计算图像每行像素所占的字节数(必须是4的倍数)int lineByte=(bmpWidth * biBitCount/8+3)

16、/4*4;/灰度图像有颜色表,且颜色表表项为256if(biBitCount=8)/申请颜色表所需要的空间,读颜色表进内存pColorTable=new RGBQUAD256;fread(pColorTable,sizeof(RGBQUAD),256,fp);/申请位图数据所需要的空间,读位图数据进内存pBmpBuf=new unsigned charlineByte * bmpHeight;fread(pBmpBuf,1,lineByte * bmpHeight,fp);/关闭文件fclose(fp);return 1;2BMP文件的存盘给定图像路径名以及图像的数据,对图像的写操作也是按照B

17、MP文件4个组成部分进行分别处理的。其基本流程如图1-9所示。图1-9 BMP文件写操作流程图saveBmp()函数实现了BMP文件的写操作,该函数的说明及代码实现如下。 /* 函数名称:* saveBmp()*函数参数:* char *bmpName-文件名字及路径* unsigned char *imgBuf-待存盘的位图数据* int width-以像素为单位待存盘位图的宽* int height-以像素为单位待存盘位图高* int biBitCount-每像素所占位数* RGBQUAD *pColorTable-颜色表指针*返回值:* 0为失败,1为成功*说明:给定一个图像位图数据、宽

18、、高、颜色表指针及每像素所占的位数等信息,* 将其写到指定文件中*/bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable)/如果位图数据指针为0,则没有数据传入,函数返回if(!imgBuf)return 0;/颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0int colorTablesize=0;if(biBitCount=8)colorTablesize=1024;/待存储图像数据每行字节数为

19、4的倍数int lineByte=(width * biBitCount/8+3)/4*4;/以二进制写的方式打开文件FILE *fp=fopen(bmpName,wb);if(fp=0) return 0;/申请位图文件头结构变量,填写文件头信息BITMAPFILEHEADER fileHead;fileHead.bfType = 0x4D42;/bmp类型/bfSize是图像文件4个组成部分之和fileHead.bfSize= sizeof(BITMAPFILEHEADER)+ sizeof(BITMAPINFOHEADER)+ colorTablesize + lineByte*heig

20、ht;fileHead.bfReserved1 = 0;fileHead.bfReserved2 = 0;/bfOffBits是图像文件前3个部分所需空间之和fileHead.bfOffBits=54+colorTablesize;/写文件头进文件fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);/申请位图信息头结构变量,填写信息头信息BITMAPINFOHEADER head; head.biBitCount=biBitCount;head.biClrImportant=0;head.biClrUsed=0;head.biCompressio

21、n=0;head.biHeight=height;head.biPlanes=1;head.biSize=40;head.biSizeImage=lineByte*height;head.biWidth=width;head.biXPelsPerMeter=0;head.biYPelsPerMeter=0;/写位图信息头进内存fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);/如果灰度图像,有颜色表,写入文件 if(biBitCount=8)fwrite(pColorTable, sizeof(RGBQUAD),256, fp);/写位图数据进文件fw

22、rite(imgBuf, height*lineByte, 1, fp);/关闭文件fclose(fp);return 1;对于readBmp()和saveBmp()函数的简单调用如下: void main()/读入指定BMP文件进内存char readPath=dog.BMP;readBmp(readPath);/输出图像的信息printf(width=%d,height=%d, biBitCount=%dn,bmpWidth,bmpHeight, biBitCount);/将图像数据存盘char writePath=dogcpy.BMP;saveBmp(writePath, pBmpBuf

23、, bmpWidth, bmpHeight, biBitCount, pColorTable);/清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间delete pBmpBuf;if(biBitCount=8)delete pColorTable;该main()函数将指定BMP文件读入内存,将图像信息打印输出,最后又原样存入指定文件中。读者可以打开程序当前目录下的“dog.bmp”和“dogcpy.bmp”两个文件进行对比。 以上对于BMP文件的读写函数仅针对灰度图像(biBitCount=8)和彩色图像(biBitCount=24)两种格式,对于其他如biB

24、itCount=1的图像类型,读者可以根据需要,自己对程序作简单的修改即可实现。本书中后续的代码实现也都是围绕灰度和彩色两种格式进行的,希望读者予以注意。1.2.3 BMP图像位图数据的访问上面main()函数将图像文件读入内存,又写到文件里去,那么在读入图像数据后、写入文件前的一段时间里,图像的数据是在内存中存在的,这也是我们可以修改(访问)图像数据的时机所在。假设内存中位图数据的指针为pBmpBuf,一行像素所占的字节数为lineByte(4的倍数)那么,对于灰度图像,第i行第j列的像素指针(所在的存储空间位置)为pBmpBuf+i*lineByte+j,*(pBmpBuf+i*lineB

25、yte+j)是该像素的灰度值,如果想让该像素变成指定颜色,只需要给*(pBmpBuf+i*lineByte+j)赋指定的值即可;对于彩色图像,每像素占3个字节,那么pBmpBuf+i*lineByte+j*3+0、pBmpBuf+i*lineByte+j*3+1、pBmpBuf+i*lineByte+j*3+2分别代表了第i行第j列像素B、G、R三个分量的指针,若想给该点指定一种颜色,则需要给三个分量分别赋值。下面的main()函数中,将读入的图像数据左下角1/4部分置成黑色并存盘,图1-10所示是程序运行前后图像的变化情况。 void main()/读入指定BMP文件进内存char read

26、Path=dog.BMP;readBmp(readPath);/输出图像的信息printf(width=%d,height=%d,biBitCount=%dn,bmpWidth,bmpHeight,biBitCount);/循环变量,图像的坐标int i,j;/每行字节数int lineByte=(bmpWidth*biBitCount/8+3)/4*4;/循环变量,针对彩色图像,遍历每像素的三个分量int k;/将图像左下角1/4部分置成黑色if(biBitCount=8)/对于灰度图像for(i=0;ibmpHeight/2;i+)for(j=0;jbmpWidth/2;j+)*(pBmp

27、Buf+i*lineByte+j)=0;else if(biBitCount=24)/彩色图像for(i=0;ibmpHeight/2;i+)for(j=0;jbmpWidth/2;j+) for(k=0;k3;k+)/每像素RGB三个分量分别置0才变成黑色*(pBmpBuf+i*lineByte+j*3+k)=0; /将图像数据存盘char writePath=dogcpy.BMP;saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);/清除缓冲区,pBmpBuf和pColorTable是全局变量,

28、在文件读入时申请的空间delete pBmpBuf;if(biBitCount=8)delete pColorTable;(点击查看大图)图1-10 数据修改后图像对比1.2.4 灰度图像的颜色表如表1-2所示,灰度图像的颜色表是一个256个表项的RGBQUAD结构体数组(具体参看BMP文件结构中对颜色表的描述),而每个RGBQUAD中的R、G、B分量的值是相等的。随着颜色表数组下标从0到255变化,颜色表数组元素中R、G、B分量也从0到255依次变化。灰度图像的位图数据每像素一个字节,其值为0到255之间的一个,当显示一幅灰度图像时,系统根据像素值,到颜色表数组下标与之对应的表项(数组元素)

29、中查看颜色,根据该表项中的颜色显示像素。由于灰度图像颜色表每个表项中R、G、B分量相等,因此只有图像亮度信息,没有颜色信息,因而显示出的灰度图像也就没有颜色了。表1-2 灰度图像的颜色表BGR保 留 位000不确定111不确定222不确定333不确定254254254不确定255255255不确定从以上的解释中我们知道,图像颜色表决定了图像的颜色,如果对灰度图像的颜色表数据进行改变,图像颜色自然也就被改变了。下面的main()函数,把灰度图像颜色表的蓝色分量进行了改变。 void main()/读入指定BMP文件进内存char readPath=dog.BMP;readBmp(readPath);/输出图像的信息printf(width=%d,height=%d,biBitCount=%dn

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1