BMP头文件:
- #ifndef BMP_H//预处理器
- #define BMP_H
- 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;
- #endif
8位BMP头文件:
- #ifndef EIGHTBITMAP_H//预处理器
- #define EIGHTBITMAP_H
- #include<iostream>
- #include"BMP.h"
- using namespace std;
- 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;
- }
- #endif
24位BMP头文件:
- #ifndef TWENTYFOURBITMAP_H
- #define TWENTYDOURBITMAP_H
- #include <iostream>
- #include "BMP.h"
- using namespace std;
- 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(BYTE) + 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;
- }
- #endif
源代码:
- 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.彩色位图灰度化
灰度化处理前: 灰度化处理后:
对比可以看出,灰度化使彩色图像转换成灰度图像