下面是两点非常重要的注意事项:
1.windows 读取BMP文件是从下到上(此模式下Info.Height>0),从左到右的 2.windows 扫描BMP文件是每行以4个字节(0)为单位进行补齐,当我们处理24位位图时,要考虑此问题 例如 24位位图 宽度为 3 则实际每行内存占用位 3*24/8 + 3 字节
以下是24位 位图比较的代码,和上一篇文章的代码类似,主要是新增了BMP内存补齐检测。
//#pragma comment( linker, "/subsystem:windows" ) #include <fstream> #include <map> #include <string> #include <iostream> #include <windows.h> using namespace std; typedef unsigned char uvar8; typedef unsigned int uvar32; typedef unsigned short int uvar16; typedef struct { uvar8 Blue; /*蓝色所占比重*/ uvar8 Green; /*绿色所占比重*/ uvar8 Red; /*红色所占比重*/ uvar8 Reserved; } Palette; //定义bmp结构 uvar8 bfType[2]; /* 类型标志,总是BM */ typedef struct { uvar32 bfSize; /* 文件大小 */ uvar32 bfReserved1; uvar32 bfOffBits; /* 位图点阵偏移量*/ }HEAD; typedef struct { uvar32 biSize; /* 结构体字节总数 */ uvar32 biWidth; /* 图像宽度 */ uvar32 biHeight; /*图像高度 */ uvar16 biPlanes; /* 必须为1 */ uvar16 biBitCount; /* 每个像素所占二进制位数,可能是1,4,8或 24 */ uvar32 biCompress; /*压缩方式*/ uvar32 biSizeImage; /*像素点阵大小 */ uvar32 biXPelsPerMeter; /* 水平像素数*/ uvar32 biYPelsPerMeter; /* 垂直像素数 */ uvar32 biClrUsed; /*使用的颜色数 */ uvar32 biClrImportant; /*重要颜色数 */ }INFO; bool ReadBMP(string strFileUrl,uvar32* & pImgData,int& iSum) { HEAD strHead; INFO strInfo; uvar8 type[2]; //uvar32 imdata[256][256]; Palette Rgbquad; ifstream fin; fin.open(strFileUrl.c_str(),ios_base::in | ios_base::binary); /*以二进制读方式打开该文件,一定要二进制的!*/ if(!fin) { cout<<"No this file!/n"; return false; } fin.read((char*)&bfType,2); fin.read((char*)&strHead,sizeof(strHead)); fin.read((char*)&strInfo,sizeof(strInfo)); fin.seekg(strHead.bfOffBits,ios::beg); if (strInfo.biBitCount == 24) { //pImgData = (uvar8*)pImgData; pImgData = new uvar32[strInfo.biWidth*strInfo.biHeight]; } else return false; uvar8 varHead; uvar8 varMid; uvar8 varTail; //Windows规定一个扫描行所占的字节数必须是 // 4的倍数(即以long为单位),不足的以0填充, // 一个扫描行所占的字节数 uvar32 varBytePerLine = (strInfo.biWidth * strInfo.biBitCount+31)/8; varBytePerLine = varBytePerLine/4 *4; uvar32 varBitPerLine = varBytePerLine * 8; uvar32 varByteDistance = (varBytePerLine * 8 - strInfo.biWidth * strInfo.biBitCount)/8; uvar8 * varDistance = NULL; if (varByteDistance != 0) varDistance = new uvar8[varByteDistance]; for (int i =1; i<=strInfo.biWidth * strInfo.biHeight; i++) { fin.read((char*)&varHead, sizeof uvar8); fin.read((char*)&varMid, sizeof uvar8); fin.read((char*)&varTail, sizeof uvar8); //fin.read((char*)&varTmp,sizeof uvar8); pImgData[i] = (uvar16)varHead *1000*1000 + (uvar16)varMid* 1000 + (uvar16)varTail; //读取填补的0 if (varByteDistance != 0 && (i+strInfo.biWidth)%strInfo.biWidth == 0) fin.read((char*)(varDistance),varByteDistance); } delete[] varDistance; fin.close(); iSum = strInfo.biWidth * strInfo.biHeight; return true; } int main() { uvar32 *pImgData1 =NULL ,*pImgData2 = NULL; int i,iSum1,iSum2; while(1) { string url1; string url2; cout<<"cin bmp file name"<<endl; cin>> url1 >> url2; if(!ReadBMP(url1,pImgData1,iSum1)) exit(0); if(!ReadBMP(url2,pImgData2,iSum2)) exit(0); map<int,int> Map1,Map2; for (i=0;i<iSum1;i++) { // if (Map1.find(pImgData1[i])!=Map1.end()) Map1[pImgData1[i]]++; // else // Map1[pImgData1[i]] = 1; } for (i=0;i<iSum2;i++) { // if (Map2.find(pImgData2[i])!=Map2.end()) Map2[pImgData2[i]]++; // else // Map2[pImgData2[i]] = 1; } int iSum = 0; for (map<int,int>::iterator it = Map1.begin(); it!= Map1.end(); it++) { iSum += Map1[it->first] < Map2[it->first] ? Map1[it->first] : Map2[it->first]; } double dResult = (double) iSum / iSum1 > (double) iSum / iSum2 ? (double) iSum / iSum1:(double) iSum / iSum2; //----------------- cout<<endl; cout<<"special dots the sum of pic1 the sum of pic2"<<endl; for (map<int,int>::iterator it1 = Map1.begin(); it1!= Map1.end(); it1++) { cout<<it1->first<<" "<<it1->second<<" "<<Map2[it1->first]<<endl; } cout<<"******************************************"<<endl; cout<<"conculsion:"<<endl; cout<< "The sum of dots in Pic1: "<< iSum1<<endl; cout<< "The sum of dots in Pic2: "<< iSum2<<endl; cout<< "The similar dots betwwen pic1 and pic2 : "<<iSum<<endl; cout<<"The rate of simliar betwwen the above two pictures: " << dResult <<endl<<endl; delete[] pImgData1; delete[] pImgData2; } getchar(); return 0; }