头文件:
typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; typedef long LONG; //BMP文件头(14字节) typedef struct tagBITMAPFILEHEADER { //WORD bfType;//位图文件的类型,必须为BM(在结构体中读取会发生错误,所以在函数中读取) DWORD bfSize;//位图文件的大小,以字节为单位 WORD bfReserved1;//位图文件保留字,必须为0 WORD bfReserved2;//位图文件保留字,必须为0 DWORD bfOffBits;//位图数据的起始位置,以相对于位图文件头的偏移量表示,以字节为单位 }BITMAPFILEHEADER; //BMP信息头(40字节) typedef struct tagBITMAPINFOHEADER { DWORD biSize;//本结构所占用字节数 LONG biWidth;//位图的宽度,以像素为单位 LONG biHeight;//位图的高度,以像素为单位 WORD biPlanes;//目标设备的级别,必须为1 WORD biBitCount;//每个像素所需的位数,必须是1(双色),4(16色),8(256色)16(高彩色)或24(真彩色)之一 DWORD biCompression;//位图压缩类型,必须是0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位 LONG biXPelsPerMeter;//位图水平分辨率,每米像素数 LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数 DWORD biClrUsed;//位图实际使用的颜色表中的颜色数 DWORD biClrImportant;//位图显示过程中重要的颜色数 }BITMAPINFOHEADER; //调色板 //只有8位位图才用调色板,用像素值作为索引(0~255),调色板中RGB值都是一样的,范围是0~255 //一个unsigned char的范围刚好是0~255,所以用BYTE类型存储8位位图的像素 typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved;//保留,必须为0 }RGBQUAD; //像素信息 //8位BMP图1个字节代表一个像素,所以可以不用结构存储像素素组,直接用一个指针即可 typedef struct tagIMAGEDATA { BYTE blue; BYTE green; BYTE red; }IMAGEDATA;
源代码:
#include<iostream> #include"BMP.h"//自定义的头文件 using namespace std; //8位位图的类 class eightBitMap { private: char imageName[30];//图像名 int width, height;//图像的宽高 BITMAPFILEHEADER bmpHead;//文件头 BITMAPINFOHEADER bmpInfo;//信息头 BYTE *imagedata = NULL, *newimagedata = NULL;//存储图片像素信息的二维数组 RGBQUAD *pallet = new RGBQUAD[256];//调色板指针 FILE *fpin, *fpout;//文件指针 //平滑算子也是通过模板进行处理的,所以可以把平滑处理和锐化处理通过一个函数实现 int Template1[3][3]{ 1,1,1,1,1,1,1,1,1 };//平滑模板 int Template2[3][3]{ 0,-1,0,-1,5,-1,0,-1,0 };//laplace锐化模板,4邻域(原图减去轮廓) int Template3[3][3]{ -1,-1,-1,-1,9,-1,-1,-1,-1 };//laplace锐化模板,8邻域 public: bool readImage();//读取图片 bool writeImage();//保存图片 bool Operation(int x);//图像平滑和锐化处理 bool Operation(int Template[][3], int coefficient);//图像处理 bool Binarization();//二值化 void showBmpHead(BITMAPFILEHEADER BmpHead);//显示文件头 void showBmpInfo(tagBITMAPINFOHEADER BmpInfo);//显示信息头 }; bool eightBitMap::readImage() { cout << "输入要读取的图片名:"; cin >> imageName; if (!fopen_s(&fpin, imageName, "rb")) { //读取图片类型 WORD bfType; fread(&bfType, sizeof(WORD), 1, fpin);//fread()的使用 if (bfType != 0x4d42) { cout << "该图片不是BMP!" << endl; return false; } //读取文件头和信息头 fread(&bmpHead, sizeof(tagBITMAPFILEHEADER), 1, fpin); fread(&bmpInfo, sizeof(tagBITMAPINFOHEADER), 1, fpin); //检查是否是8位位图 if (bmpInfo.biBitCount != 8) { cout << "该图片不是8位!" << endl; return false; } //读取调色板 fread(pallet, sizeof(RGBQUAD), 256, fpin); //读取图片的像素信息 width = bmpInfo.biWidth; height = bmpInfo.biHeight; width = (width*sizeof(BYTE) + 3) / 4 * 4;//图像的每一行必须是4的整数倍 imagedata = new BYTE[width*height]; fread(imagedata, sizeof(BYTE)*width, height, fpin); //显示文件头和信息头 showBmpHead(bmpHead); showBmpInfo(bmpInfo); //关闭图片 fclose(fpin); } else { cout << "图片不存在!" << endl; return false; } return true; } bool eightBitMap::writeImage() { char imageName[30]; cout << "输入处理后的位图名:"; cin >> imageName; //创建位图文件 if (fopen_s(&fpout, imageName, "wb")) { cout << "创建文件失败!" << endl; return false; } //写入位图类型 WORD bfBYTE = 0x4d42; fwrite(&bfBYTE, 1, sizeof(WORD), fpout); //写入文件头和信息头 fwrite(&bmpHead, 1, sizeof(BITMAPFILEHEADER), fpout); fwrite(&bmpInfo, 1, sizeof(BITMAPINFOHEADER), fpout); //写入调色板 fwrite(pallet, sizeof(RGBQUAD), 256, fpout); //写入图像像素数据 fwrite(newimagedata, sizeof(BYTE)*width, height, fpout); //关闭图片 fclose(fpout); //释放内存 delete imagedata; delete newimagedata; delete pallet; return true; } bool eightBitMap::Operation(int x) { if (x == 1) return Operation(Template1, 9); else if (x == 2) return Operation(Template2, 1); else if (x == 3) return Operation(Template3, 1); else { cout << "模板调用错误!" << endl; return false; } } bool eightBitMap::Operation(int Template[][3], int coefficient) { //分配新像素素组的空间 newimagedata = new BYTE[width*height]; //进行模板操作 for (int i = 0; i < height; ++i) for (int j = 0; j < width; ++j) { if (i == 0 || j == 0 || i == height - 1 || j == width - 1) *(newimagedata + i*width + j) = *(imagedata + i*width + j); else { int sum = 0; for (int m = i - 1; m < i + 2; ++m) for (int n = j - 1; n < j + 2; ++n) { sum += (*(imagedata + m*width + n))*Template[n - j + 1][m - i + 1] / coefficient; } //8位BMP中一个像素值,对应调色板中索引号为该像素值的项所存放的RGB色彩 //所以像素值范围为0~255 //像素值小于0就取0,大于255就取255 sum = (sum >= 0) ? sum : 0; sum = ((sum + *(imagedata + i*width + j))>255) ? 255 : sum; *(newimagedata + i*width + j) = sum; } } //保存图片 if (writeImage()) { cout << "\n处理成功!" << endl; return true; } else { cout << "\n处理失败!" << endl; return false; } } bool eightBitMap::Binarization() { //分配新像素素组的空间 newimagedata = new BYTE[width*height]; //二值化操作 for (int i = 0; i < width*height; ++i) if (*(imagedata + i) > 128) *(newimagedata + i) = 255; else *(newimagedata + i) = 0; //保存图片 if (writeImage()) { cout << "\n处理成功!" << endl; return true; } else { cout << "\n处理失败!" << endl; return false; } } void eightBitMap::showBmpHead(BITMAPFILEHEADER BmpHead) { cout << "\n图片文件头:" << endl; cout << " 图片大小:" << BmpHead.bfSize << endl; cout << " 保留字_1:" << BmpHead.bfReserved1 << endl; cout << " 保留字_2:" << BmpHead.bfReserved2 << endl; cout << " 实际位图片数据的偏移字节数:" << BmpHead.bfOffBits << endl; } void eightBitMap::showBmpInfo(tagBITMAPINFOHEADER BmpInfo) { cout << "图片信息头:" << endl; cout << " 结构体的长度:" << BmpInfo.biSize << endl; cout << " 位图宽:" << BmpInfo.biWidth << endl; cout << " 位图高:" << BmpInfo.biHeight << endl; cout << " 平面数:" << BmpInfo.biPlanes << endl; cout << " 采用颜色位数:" << BmpInfo.biBitCount << endl; cout << " 压缩方式:" << BmpInfo.biCompression << endl; cout << " 实际位图数据占用的字节数:" << BmpInfo.biSizeImage << endl; cout << " X方向分辨率:" << BmpInfo.biXPelsPerMeter << endl; cout << " Y方向分辨率:" << BmpInfo.biYPelsPerMeter << endl; cout << " 使用的颜色数:" << BmpInfo.biClrUsed << endl; cout << " 重要颜色数:" << BmpInfo.biClrImportant << endl; } //24位位图的类 class twentyfourBitMap { char imageName[30];//图像名 int width, height;//图像的宽高 BITMAPFILEHEADER bmpHead;//文件头 BITMAPINFOHEADER bmpInfo;//信息头 IMAGEDATA *imagedata = NULL, *newimagedata = NULL;//存储图片像素信息的二维数组 FILE *fpin, *fpout;//文件指针 //平滑算子也是通过模板进行处理的,所以可以把平滑处理和锐化处理通过一个函数实现 int Template1[3][3]{ 1,1,1,1,1,1,1,1,1 };//平滑模板 int Template2[3][3]{ 0,-1,0,-1,5,-1,0,-1,0 };//laplace锐化模板,4邻域 int Template3[3][3]{ -1,-1,-1,-1,9,-1,-1,-1,-1 };//laplace锐化模板,8邻域 public: bool readImage();//读取图片 bool writeImage();//保存图片 bool Operation(int x);//图像平滑和锐化处理 bool Operation(int Template[][3], int coefficient);//图像处理 bool makeGray();//将彩色图转换为灰度图 bool Binarization();//二值化 void showBmpHead(BITMAPFILEHEADER BmpHead);//显示文件头 void showBmpInfo(tagBITMAPINFOHEADER BmpInfo);//显示信息头 }; bool twentyfourBitMap::readImage() { cout << "输入要读取的图片名:"; cin >> imageName; if (!fopen_s(&fpin, imageName, "rb")) { //读取图片类型 WORD bfType; fread(&bfType, sizeof(WORD), 1, fpin);//fread()的使用 if (bfType != 0x4d42) { cout << "该图片不是BMP!" << endl; return false; } //读取文件头和信息头 fread(&bmpHead, sizeof(tagBITMAPFILEHEADER), 1, fpin); fread(&bmpInfo, sizeof(tagBITMAPINFOHEADER), 1, fpin); //检查是否是24位位图 if (bmpInfo.biBitCount != 24) { cout << "该图片不是24位!" << endl; return false; } //读取图片的像素信息 width = bmpInfo.biWidth; height = bmpInfo.biHeight; width = (width*sizeof(IMAGEDATA) + 3) / 4 * 4;//图像的每一行必须是4的整数倍 imagedata = new IMAGEDATA[width*height]; fread(imagedata, sizeof(IMAGEDATA)*width, height, fpin); //显示文件头和信息头 showBmpHead(bmpHead); showBmpInfo(bmpInfo); //关闭图片 fclose(fpin); } else { cout << "图片不存在!" << endl; return false; } return true; } bool twentyfourBitMap::writeImage() { char imageName[30]; cout << "输入处理后的位图名:"; cin >> imageName; //创建位图文件 if (fopen_s(&fpout, imageName, "wb")) { cout << "创建文件失败!" << endl; return false; } //写入位图类型 WORD bfBYTE = 0x4d42; fwrite(&bfBYTE, 1, sizeof(WORD), fpout); //写入文件头和信息头 fwrite(&bmpHead, 1, sizeof(BITMAPFILEHEADER), fpout); fwrite(&bmpInfo, 1, sizeof(BITMAPINFOHEADER), fpout); //写入图像像素数据 fwrite(newimagedata, sizeof(IMAGEDATA)*width, height, fpout); //关闭图片 fclose(fpout); //释放内存 delete imagedata; delete newimagedata; return true; } bool twentyfourBitMap::Operation(int x) { if (x == 1) return Operation(Template1, 9); else if (x == 2) return Operation(Template2, 1); else if (x == 3) return Operation(Template3, 1); else { cout << "模板调用错误!" << endl; return false; } } bool twentyfourBitMap::Operation(int Template[][3], int coefficient) { //分配新像素素组的空间 newimagedata = new IMAGEDATA[width*height]; //进行模板操作 for (int i = 0; i < height; ++i) for (int j = 0; j < width; ++j) { if (i == 0 || j == 0 || i == height - 1 || j == width - 1) *(newimagedata + i*width + j) = *(imagedata + i*width + j); else { int sum = 0; for (int m = i - 1; m < i + 2; ++m) for (int n = j - 1; n < j + 2; ++n) { sum += ((*(imagedata + m*width + n)).blue)*Template[n - j + 1][m - i + 1] / coefficient; } //8位BMP中一个像素值,对应调色板中索引号为该像素值的项所存放的RGB色彩 //所以像素值范围为0~255 //像素值小于0就取0,大于255就取255 sum = (sum >= 0) ? sum : 0; sum = (sum + ((*(imagedata + i*width + j)).blue)>255) ? 255 : sum; //把新RGB值存入新数组 (*(newimagedata + i*width + j)).blue = sum; (*(newimagedata + i*width + j)).green = sum; (*(newimagedata + i*width + j)).red = sum; } } //保存图片 if (writeImage()) { cout << "\n处理成功!" << endl; return true; } else { cout << "\n处理失败!" << endl; return false; } } bool twentyfourBitMap::makeGray() { //分配新像素素组的空间 newimagedata = new IMAGEDATA[width*height]; //进行灰度化操作 int sum; for (int i = 0; i < width*height; ++i) { sum = (*(imagedata + i)).blue + (*(imagedata + i)).green + (*(imagedata + i)).red; (*(newimagedata + i)).blue = (*(newimagedata + i)).green = (*(newimagedata + i)).red = sum / 3; } //保存图片 if (writeImage()) { cout << "\n处理成功!" << endl; return true; } else { cout << "\n处理失败!" << endl; return false; } } bool twentyfourBitMap::Binarization() { //分配新像素素组的空间 newimagedata = new IMAGEDATA[width*height]; //二值化操作 for (int i = 0; i < width*height; ++i) if ((*(imagedata + i)).blue > 128) (*(newimagedata + i)).blue = (*(newimagedata + i)).green = (*(newimagedata + i)).red = 255; else (*(newimagedata + i)).blue = (*(newimagedata + i)).green = (*(newimagedata + i)).red = 0; //保存图片 if (writeImage()) { cout << "\n处理成功!" << endl; return true; } else { cout << "\n处理失败!" << endl; return false; } } void twentyfourBitMap::showBmpHead(BITMAPFILEHEADER BmpHead) { cout << "\n图片文件头:" << endl; cout << " 图片大小:" << BmpHead.bfSize << endl; cout << " 保留字_1:" << BmpHead.bfReserved1 << endl; cout << " 保留字_2:" << BmpHead.bfReserved2 << endl; cout << " 实际位图片数据的偏移字节数:" << BmpHead.bfOffBits << endl; } void twentyfourBitMap::showBmpInfo(tagBITMAPINFOHEADER BmpInfo) { cout << "图片信息头:" << endl; cout << " 结构体的长度:" << BmpInfo.biSize << endl; cout << " 位图宽:" << BmpInfo.biWidth << endl; cout << " 位图高:" << BmpInfo.biHeight << endl; cout << " 平面数:" << BmpInfo.biPlanes << endl; cout << " 采用颜色位数:" << BmpInfo.biBitCount << endl; cout << " 压缩方式:" << BmpInfo.biCompression << endl; cout << " 实际位图数据占用的字节数:" << BmpInfo.biSizeImage << endl; cout << " X方向分辨率:" << BmpInfo.biXPelsPerMeter << endl; cout << " Y方向分辨率:" << BmpInfo.biYPelsPerMeter << endl; cout << " 使用的颜色数:" << BmpInfo.biClrUsed << endl; cout << " 重要颜色数:" << BmpInfo.biClrImportant << endl; } int main() { int depth = 0; cout << "输入要处理的位图深度:"; cin >> depth; if (depth == 8) { eightBitMap Image; if (Image.readImage()) { int answer; cout << "\n1.平滑处理" << "\n2.4邻域锐化" << "\n3.8邻域锐化" << "\n4.二值化" << "\n选择处理方式:"; cin >> answer; switch (answer) { case 1: Image.Operation(1); break; case 2: Image.Operation(2); break; case 3: Image.Operation(3); break; case 4: Image.Binarization(); break; default: cout << "错误选择!" << endl; } } else cout << "位图读取错误!" << endl; } else if (depth == 24) { twentyfourBitMap Image; if (Image.readImage()) { int answer; cout << "\n1.平滑处理" << "\n2.4邻域锐化" << "\n3.8邻域锐化" << "\n4.彩色位图灰度化" << "\n5.二值化" << "\n选择处理方式:"; cin >> answer; switch (answer) { case 1: Image.Operation(1); break; case 2: Image.Operation(2); break; case 3: Image.Operation(3); break; case 4: Image.makeGray(); break; case 5: Image.Binarization(); break; default: cout << "错误选择!" << endl; } } else cout << "位图读取错误!" << endl; } else cout << "错误深度输入!" << endl; cin.get(); cin.get(); }
调试及测试(由于8位位图的处理和24位位图的处理在结果上差别不大,所以只用24位图做测试)
1.平滑处理
平滑处理前: 平滑处理后:
对比可以看出,平滑处理使图像更加模糊。
2.锐化处理(平滑后再锐化效果更好,所以使用平滑后的位图锐化。8邻域锐化比4邻域锐化效果好,所以只使用8邻域锐化)
8邻域锐化前: 8邻域锐化后:
对比可以看出,锐化后,图像的边缘更加明显
3.二值化
二值化处理前: 二值化处理后:
对比可以看出,二值化使图像只有黑白两色,没有灰色的过渡
4.彩色位图灰度化
灰度化处理前: 灰度化处理后:
对比可以看出,灰度化使彩色图像转换成灰度图像
时间: 2024-10-24 05:39:29