对BMP格式图像文件的剖析及编程实现
- 格式:pdf
- 大小:87.75 KB
- 文档页数:2


C语⾔实现BMP图像的读写功能C语⾔实现BMP图像的读写对于刚接触数字图像的同学,应该都有⼀个疑问,如何把⼀个BMP格式的图像⽤纯C语⾔读⼊呢,我相信这也是数字图像处理的第⼀步,如果有幸看到这篇⽂档,我就有幸的成为你数字图像处理路上的第⼀盏明灯!了解BMP的构成这就是BMP图像的理论知识,有个⼤概的了解就⾏,最主要的是从理论到实践废话不多说,直接上⼲货。
代码定义头⽂件为“bmp.h”,定义read_bmp函数为读函数,write_bmp函数为写函数读bmp图#include <stdlib.h>#include <math.h>#include <Windows.h>#include "bmp.h"/*存储原图的像素宽度⾼度和位图深度*/FILE* fpbmp;FILE* fpout;unsigned char* fpBmpHeader; //位图头unsigned char* fpFileHeader; //位图信息RGBQUAD* pColorTable; //BMP 调⾊板int read_bmp(const char* path, unsigned char *pBmpBuf,int *Width,int *Height,int * bitCount){fpbmp = fopen(path, "rb");//path为图像路径unsigned short s;fread(&s, 1, 2, fpbmp);//判断读⼊的图像是否为BMP图字符串"BM"=19778if (s == 19778){printf("Open bmp success\n");}else{printf("Open bmp fail\n");return -1;}fseek(fpbmp, 0, SEEK_SET);BITMAPFILEHEADER fileHead;fread(&fileHead, sizeof(BITMAPFILEHEADER), 1, fpbmp);BITMAPINFOHEADER infoHead;fread(&infoHead, sizeof(BITMAPINFOHEADER), 1, fpbmp);*Width = infoHead.biWidth;//图像的宽*Height = infoHead.biHeight;//图像的⾼*bitCount = infoHead.biBitCount;int lineByte = (*Width * *bitCount / 8 + 3) / 4 * 4;fseek(fpbmp, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) ,SEEK_SET);fread(pBmpBuf, lineByte * *Height, 1, fpbmp);//pBmpBuf为图像的RGB数据,也是我们将要处理的数据return 0;}写BMP图int write_bmp(unsigned char* img, int* Width, int* Height, int* bitCount){fpout = fopen("out.bmp", "wb+");if (fpbmp == NULL){printf("read bmp failed\n");return -1;}int lineByte = (*Width * *bitCount / 8 + 3) / 4 * 4;if (lineByte == 0){printf("err");return -1;}fpFileHeader = new unsigned char[(sizeof(BITMAPFILEHEADER))];fseek(fpbmp, 0, SEEK_SET); //定位原图偏移位置fseek(fpout, 0, SEEK_SET); //定位新图偏移位置fread(fpFileHeader, 1, sizeof(BITMAPFILEHEADER), fpbmp);fwrite(fpFileHeader, 1, sizeof(BITMAPFILEHEADER), fpout);/*复制原图中位图信息到新图像*/fpBmpHeader = new unsigned char[(sizeof(BITMAPINFOHEADER))];fseek(fpbmp, sizeof(BITMAPFILEHEADER), SEEK_SET);fseek(fpout, sizeof(BITMAPFILEHEADER), SEEK_SET);fread(fpBmpHeader, 1, sizeof(BITMAPINFOHEADER), fpbmp);fwrite(fpBmpHeader, 1, sizeof(BITMAPINFOHEADER), fpout);fseek(fpout, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) , SEEK_SET);fwrite(img, lineByte * *Height, sizeof(char), fpout);fclose(fpout);fclose(fpbmp);return 0;}main函数调⽤#include <stdio.h>#include <stdlib.h>#include <math.h>#include <Windows.h>#include "bmp.h"int main(){int width, height, bitCount = 0;unsigned char* pBmpBuf = (unsigned char*)malloc(1000 * 1000 * 3);//申请空间const char* path = "D:\\test\\read_bmp_image\\1-B.bmp";//图的路径read_bmp(path, pBmpBuf, &width, &height, &bitCount);write_bmp(pBmpBuf, &width, &height, &bitCount);}总结,将read_bmp函数返回的pBmpBuf参数,赋值给write_bmp函数的img参数,就实现了BMP图从读到写的全部过程,有兴趣的同学动⼿实践下,会有意向不到的收获。
#include <stdio.h>#include "Windows.h"BOOL readBmp(char *bmpName);BOOL saveBmp(char *bmpName, char *imgBuf, int width, int heigh, int biBitCount, RGBQUAD *pColorTable);char *pBmpBuf; //位图数据int bmpWidth; // 图像宽度int bmpHeight; //图像高度int biBiCount; //图像类型,每像素位数RGBQUAD *pColorTable; //位图颜色表指针int main(){char readName[] = "read.BMP";readBmp(readName);char writeName[] = "write.BMP";saveBmp(writeName, pBmpBuf, bmpWidth, bmpHeight, biBiCount, pColorTable);int lineByte = (bmpWidth*bmpHeight/8+3)/4*4;if (biBiCount == 8){for (int i = 0; i < bmpWidth/2; i++){for (int j = 0; j < bmpHeight/2; j++){*(pBmpBuf+i*lineByte+j) = 0;}}}else if (biBiCount == 24){/////对于24位真彩图,每个像素占三个字节分别存储R、G、B三个颜色分量的颜色值for (int i = 0; i < bmpWidth/2; i++){for (int j = 0; j < bmpHeight/2; j++){for (int k = 0; k < 3; k++)*(pBmpBuf+i*lineByte+j*3+k) = 0; //将rgb三个颜色分量设置成黑色}}}char Name[] = "copy.BMP";saveBmp(Name, pBmpBuf, bmpWidth, bmpHeight, biBiCount, pColorTable);delete []pBmpBuf;if (biBiCount == 8){delete []pColorTable;}return 0;}BOOL readBmp(char *bmpName ){FILE *pf = fopen(bmpName, "rb");if (pf == NULL) return FALSE;printf("read %s succeeded!\n", bmpName);fseek(pf, sizeof(BITMAPFILEHEADER), SEEK_SET);BITMAPINFOHEADER infoHeader;fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, pf);bmpWidth = infoHeader.biWidth;bmpHeight = infoHeader.biHeight;biBiCount = infoHeader.biBitCount;//图像每行的字节数,一定要是4的倍数int lineByte = (bmpWidth*bmpHeight/8+3)/4*4;pBmpBuf = new char[lineByte*bmpHeight];//灰度图像有颜色表if (biBiCount == 8){pColorTable = new RGBQUAD[256];fread(pColorTable, sizeof(RGBQUAD), 1, pf);}fread(pBmpBuf, lineByte*bmpHeight, 1, pf);fclose(pf); //关闭文件return TRUE;}BOOL saveBmp(char *bmpName, char *imgBuf, int width, int heigh, int biBitCount, RGBQUAD *pColorTable ){FILE *pf = fopen(bmpName, "wb");if (pf == NULL) return FALSE;printf("write %s succeeded!\n", bmpName);//写头文件int colorTableSize = 0;if (biBitCount == 8){colorTableSize = 1024;}int lineByte = (width*heigh/8+3)/4*4;BITMAPFILEHEADER filehead;filehead.bfOffBits = 54+colorTableSize;filehead.bfType = 0x4D42;filehead.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+colorTableSize+lineByte*heig h;filehead.bfReserved1 = 0;filehead.bfReserved2 = 0;fwrite(&filehead, sizeof(BITMAPFILEHEADER), 1, pf);BITMAPINFOHEADER infoHead;infoHead.biBitCount = biBitCount;infoHead.biWidth = width;infoHead.biHeight = heigh;infoHead.biSize = 40;infoHead.biClrImportant = 0;infoHead.biSizeImage = lineByte*heigh;infoHead.biClrUsed = 0;infoHead.biPlanes = 1;infoHead.biXPelsPerMeter = 0;infoHead.biYPelsPerMeter = 0;fwrite(&infoHead,sizeof(BITMAPINFOHEADER), 1, pf);if (biBitCount == 8){fwrite(pColorTable, sizeof(RGBQUAD), 256, pf);}fwrite(pBmpBuf, lineByte*heigh, 1, pf);fclose(pf);return TRUE;}。
上一讲我们主要介绍了图像的格式,其中重点说明了BMP文件的存储格式,同时对JEPG和GIF等常用格式作了简单的介绍。
本节主要讲述如何操作BMP文件,如对其读、写和显示等。
在实现数字图象处理的过程中,主要是通过对图像中的每一个像素点运用各种图像处理算法来达到预期的效果,所以进行图像处理的第一步,也是我们最关心的问题,是如何得到图像中每一个像素点的亮度值;为了观察和验证处理的图像效果,另一个需要解决的问题是如何将处理前后的图像正确的显示出来。
我们这章内容就是解决这些问题。
随着科技的发展,图像处理技术已经渗透到人类生活的各个领域并得到越来越多的应用,但是突出的一个矛盾是图像的格式也是越来越多,目前图像处理所涉及的主要的图像格式就有很多种,如TIF、JEMP、BMP等等,一般情况下,为了处理简单方便,进行数字图像处理所采用的都是BMP格式的图像文件(有时也称为DIB格式的图像文件),并且这种格式的文件是没有压缩的。
我们通过操作这种格式的文件,可以获取正确显示图像所需的调色板信息,图像的尺寸信息,图像中各个像素点的亮度信息等等,有了这些数据,开发人员就可以对图像施加各种处理算法,进行相应的处理。
如果特殊情况下需要处理其它某种格式的图像,如GIF、JEMP等格式的图象文件,可以首先将该格式转换为BMP格式,然后再进行相应的处理。
这一点需要读者清楚。
BMP格式的图像文件又可以分为许多种类,如真彩色位图、256色位图,采用RLE(游程编码)压缩格式的BMP位图等等。
由于在实际的工程应用和图像算法效果验证中经常要处理的是256级并且是没有压缩的BMP灰度图像,例如通过黑白采集卡采集得到的图像就是这种格式,所以我们在整个讲座中范例所处理的文件格式都是BMP灰度图像。
如果读者对这种格式的位图能够作到熟练的操作,那么对于其余形式的BMP位图的操作也不会很困难。
BMP灰度图像作为Windows环境下主要的图像格式之一,以其格式简单,适应性强而倍受欢迎。
读取和修改BMP图像代码参考#include#include#includeint main(){BITMAPFILEHEADER bitHead;//定义两个结构体实例bitHead 和bitInfoHeadBITMAPINFOHEADER bitInfoHead;memset(&bitHead, 0x00, sizeof(BITMAPFILEHEADER));//使用memset将两个结构体实例初始化为0memset(&bitInfoHead, 0x00, sizeof(BITMAPINFOHEADER));FILE* pfile = NULL;//定义源文件指针pfile并初始化为空FILE* dst_pfile = NULL;//定义目标文件指针dst_pfile并初始化为空BYTE* pData = NULL;//定义一个BYTE类型的指针pData并初始化为空,用于存储像素信息char strFile[50] = "\\0";//定义一个char类型的数组strFile用于存储源文件名char dstFile[50] = "\\0";//定义一个char类型的数组dstFile用于存储目标文件名printf("please input the source .bmp file name:\");scanf("%s",strFile);//读文件pfile = fopen(strFile,"rb");//使用fopen以rb的方式打开一个24位BMP图像if(NULL == pfile)//判断文件打开是否成功并给出提示{printf("file %s open fail!\", strFile);}printf("\文件 %s 打开成功.\", strFile);WORD fileType;//定义一个WORD类型的变量fileType用于存储前2个字节fread(&fileType,1,sizeof(WORD),pfile);//使用fread读出前2个字节的内容存入fileType//判断文件类型if(fileType != 0x4d42)//判断fileType里的内容是否为0x4d42,如果不是,给出提示{printf("file is not .bmp file!");return 0;}fseek(pfile,0,SEEK_SET); //将指针移到文件头fread(&bitHead,1,sizeof(BITMAPFILEHEADER),pfile); //使用fread读取文件头的内容存入bitHead中fread(&bitInfoHead,1,sizeof(BITMAPINFOHEADER),pfile);//使用fread读取信息头的内容存入bitInfoHead中printf("文件大小:%d\",bitHead.bfSize);printf("实际位图数据的偏移字节数:%d\",bitHead.bfOffBits);printf("结构体的长度:%d\",bitInfoHead.biSize);printf("位图宽:%d\",bitInfoHead.biWidth);printf("位图高:%d\",bitInfoHead.biHeight);printf("采用颜色位数:%d\",bitInfoHead.biBitCount);printf("实际位图数据占用的字节数(包括补位的0):%d\",bitInfoHead.biSizeImage);long nData = bitInfoHead.biSizeImage;//给pData分配内存空间(空间大小为信息头的biSizeImage的值)并初始化,准备存储像素数据pData = (BYTE *)malloc(nData);memset(pData, 0x00, nData);fread(pData,1,nData,pfile);//使用fread读取像素数据存入pDataint width = 0;int i = 0;int num = 0;int add_zero = 0;//补位的0的字节数width = bitInfoHead.biSizeImage/bitInfoHead.biHeight; //计算每一行的实际字节数if((bitInfoHead.biWidth * 3) % 4 == 0)//计算每一行补位的0的字节数add_zero = 0;elseadd_zero = 4 - (bitInfoHead.biWidth * 3) % 4;printf("\第一行像素数据为:\");printf("\每一行数据末尾补位的0为:%d字节", add_zero);printf("\\");for(i = 0; i < width; i++){printf("%02X, ", pData[i]);//使用printf打印出第一行的所有像素数据信息(包括补位的0)//分行显示num++;if(num%15==0)printf("\");}//写文件for(i = 0;i{pData[i] = 0;//将图像设为全黑}printf("\\");printf("please input the destination .bmp file name:\");scanf("%s",dstFile);dst_pfile = fopen(dstFile,"wb");if(NULL == dst_pfile){printf("file %s open fail!\", dstFile);}printf("\文件 %s 打开成功!\", dstFile);fwrite(&bitHead, 1, sizeof(bitHead), dst_pfile);//写位图文件头fwrite(&bitInfoHead, 1, sizeof(bitInfoHead), dst_pfile);//写位图信息头fwrite(pData, 1, nData, dst_pfile);//写位图像素数据free(pData);fclose(pfile);fclose(dst_pfile);printf("\文件写入成功!\");system("pause");return 0;}。