实验目的
掌握类模板的定义和使用
实验内容
在之前的实验中,我们定义了一个矩阵类Matrix和其子类图像类Image。在数据的存储和处理过程中,我们用过unsigned char和double类型的data指针获取矩阵元素或者图像像素的值。但是现实中的矩阵或者图像数据并不仅仅使用浮点类型和8bits的无符号整数类型,比如有的单反相机可以拍摄32bits无符号整数像素值的图像(unsigned int);在图像处理中经常将图像灰度值缩放到区间[0,1]内的浮点数(double);再比如对图像进行傅里叶变换后,得到是复数。因此矩阵的数据类型可以有很多变化。为了实现代码的重用,现在我们使用类模板重构之前的类。
要求:
- 定义类模板Mat描述矩阵,矩阵元素的数据类型可以是任意类型,即二级指针data所指向的数据类型采用模板技术进行泛化。
- 参考之前的实验,实现Mat类模板的构造函数、析构函数、拷贝构造函数、运算符重载等各种函数。
- 使用“引用计数”机制,实现Mat对象间的“浅拷贝”和“浅赋值”。
- 实现该类模板的ReadBMP,WriteBMP等函数。在存储图像文件时,像素值一般选取 unsigned char类型(这也是我们前面实验使用该类型的原因)。但是我们的Mat模板类的数据范围不局限于此,因此需要在这两个函数体内完成数据类型转换操作。即把矩阵的元素转换成[0,255]区间内的整数,然后才能保存成BMP文件。通常的做法是计算所有矩阵元素的最大值和最小值,在WriteBMP函数内将对应的数据分别赋成255和0,其它中间的数据转换成0和255之间的无符号8bit整数。这么做仅仅是为了存储时迁就图片文件的格式要求,丢失了原来数据的精度。
- ReadText和WriteText函数把数据写入文本文件,这两个函数在实现时需要特别注意,思考如何才能把不同类型的数据合理在文本文件中写入和读取。先自行设计解决方案,更好的办法在实验10中实现。
- 定义成员函数Normalize,该函数返回以double特化的模板类对象,该对象将调用者的数据缩放到[0,1]区间。
- 将实验8的滤波器类进行模板化重构,能够适用于Mat类模板。
主函数中实现:
- 读入图像文件,并将数据缩放到[0,1]区间
- 将图像取反色,并输出显示。
- 获取矩阵中某个元素的值。
- 对矩阵进行旋转、缩放、裁剪、reshape等操作。
- 对矩阵进行加减等操作。
- 对矩阵进行滤波,显示并保存成图像文件。
- 计算原矩阵和滤波后矩阵的差,并把结果保存。
#ifndef MAT_H #define MAT_H #include <iostream> #include <cmath> #include <fstream> #pragma pack(push,1) struct BMPFILEHEADER { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; }; #pragma pack(pop) struct BITMAPINFOHEADER { unsigned long biSize; //本结构所占用字节数 40字节 long biWidth; //位图的宽度,以像素为单位 long biHeight; //位图的高度,以像素为单位 unsigned short biPlanes; //目标设备的级别,必须为1 unsigned short biBitCount; //每个像素所需的位数,必须是1(双色)、 //4(16色)、8(256色)或24(真彩色)之一 unsigned long biCompression; //位图压缩类型,必须是 0(BI_RGB不压缩)、 //1(BI_RLE8压缩类型) //2(BI_RLE压缩类型)之一 unsigned long biSizeImage; //位图的大小,以字节为单位 long biXPelsPerMeter; //位图水平分辨率,每米像素数 long biYPelsPerMeter; //位图垂直分辨率,每米像素数 unsigned long biClrUsed; //位图实际使用的颜色表中的颜色数 unsigned long biClrImportant; //位图显示过程中重要的颜色数 }; template< typename T> class Mat { public: Mat()//无参数的构造函数,创建行列都为零的Mat对象 { point->height=0; point->width=0; point->data=NULL; point->count=new int[1]; *point->count=1; } Mat(int h, int w)//构造函数重载,创建h行,w列的Mat对象 { point->height=h; point->width=w; point->data=new T*[h]; for(int i=0; i<point->height; i++) { point->data[i]=new T[w]; } point->count=new int[1]; *point->count=1; for(int i=0; i<h; i++) //赋值 { for(int j=0; j<w; j++) { point->data[i][j]=T(0); } } } Mat(int h, int w, T val) //构造函数重载,矩阵元素的值都为val; { point->height=h; point->width=w; point->data=new T*[h]; for(int i=0; i<point->height; i++) { point->data[i]=new T[w]; } point->count=new int[1]; *point->count=1; for(int i=0; i<h; i++) //赋值 { for(int j=0; j<w; j++) { point->data[i][j]=val; } } } Mat(const char* ImageName) //构造函数重载,利用文件名从硬盘加载图像文件成为Mat对象; { FILE* pfin = NULL; // 保存文件的文件指针 fopen_s(&pfin, ImageName, "rb"); // 二进制写入方式打开文件 BMPFILEHEADER fileheader; BITMAPINFOHEADER infoheader; fread(&fileheader, sizeof(BMPFILEHEADER), 1, pfin); fread(&infoheader, sizeof(BITMAPINFOHEADER), 1, pfin); point->height = infoheader.biHeight; point->width = infoheader.biWidth; int i, j; point->data = new T *[point->height];//动态内存开辟 for (i = 0; i < point->height; i++) { point->data[i] = new T[point->width]; } unsigned char a, b, c; for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { fread(&a, sizeof(unsigned char), 1, pfin); fread(&b, sizeof(unsigned char), 1, pfin); fread(&c, sizeof(unsigned char), 1, pfin);//读出三通道 point->data[i][j] = (static_cast<T>(a+b+c)) / 3; }//转为灰度图,存入数组,转double } fclose(pfin); point->count=new int[1]; *point->count=1; } Mat(T **m, int h, int w)//构造函数重载,从动态数组创建Mat对象; { point->height=h; point->width=w; point->data=new T*[h]; for(int i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } point->count=new int[1]; *point->count=1; for(int i=0; i<h; i++) //赋值 { for(int j=0; j<w; j++) { point->data[i][j]=m[i][j]; } } } Mat(const Mat &m) //拷贝构造函数; { point->count=m.point->count; *point->count++; point->height=m.point->height; point->width=m.point->width; point->data=m.point->data; } virtual ~Mat() //析构函数; { if(--(*point->count)==0)//无论如何count都减1 { for (int i = 0; i < point->height; i++)//释放二维数组空间 delete[] point->data[i]; delete[] point->data; delete point->count; } } void wcopy()//即时拷贝 { if(*point->count>1) { T **prep=new T*[point->height];//开辟新空间给prep for(int i=0; i<point->height; i++) { prep[i]=new T[point->width]; } for(int i=0; i<point->height; i++) //赋值 { for(int j=0; j<point->width; j++) { prep[i][j]=point->data[i][j]; } } *point->count--; //共用计数器-- int *prepint = new int[1]; *prepint = 1;//开辟一个新计数器 point->count=prepint; prepint=NULL; point->data=prep; prep=NULL; } } void clean(T **pdata, int h) { int i; for (i = 0; i < h; i++)//释放空间 delete[] pdata[i]; delete[] pdata; } void judge_delete()//判断是否有其他对象利用这块空间,若没有,便删除原来的空间,以便改变空间大小 { if(*point->count>1)//有其他对象利用这片空间 { *point->count--; //共用计数器减一 int *prepint = new int[1]; *prepint = 1;//开辟一个新计数器 point->count = prepint; prepint=NULL; } else//否则释放空间 { for(int i=0; i<point->height; i++) delete [] point->data[i]; delete [] point->data; } } void ReadBMP(const char *ImageName) //从硬盘文件中读入图像数据到一个对象 { int i, j; FILE* pfin = NULL; // 保存文件的文件指针 fopen_s(&pfin, ImageName, "rb"); // 二进制写入方式打开文件 BMPFILEHEADER fileheader; BITMAPINFOHEADER infoheader; fread(&fileheader, sizeof(BMPFILEHEADER), 1, pfin); fread(&infoheader, sizeof(BITMAPINFOHEADER), 1, pfin); point->height = infoheader.biHeight; point->width = infoheader.biWidth; if(*point->count>1) { point->data = new T *[point->height];//动态内存开辟,不破坏原来共享的空间 for (i = 0; i < point->height; i++) { point->data[i] = new T[point->width]; } *point->count--; //共用计数器减一 int *prepint = new int[1]; *prepint = 1;//开辟一个新计数器 point->count=prepint; } unsigned char a, b, c; for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { fread(&a, sizeof(unsigned char), 1, pfin); fread(&b, sizeof(unsigned char), 1, pfin); fread(&c, sizeof(unsigned char), 1, pfin);//读出三通道 point->data[i][j] = (static_cast<T>(a+b+c)) / 3; }//转为灰度图,存入数组,转double } fclose(pfin); } void WriteBMP(const char *filename)//将数据保存为图像文件 { FILE* pfout = NULL; // 保存文件的文件指针 fopen_s(&pfout, filename, "wb"); // 二进制写入方式打开文件 FILE* pfin = NULL; // 保存文件的文件指针 fopen_s(&pfin, "Fruits.bmp", "rb"); // 打开一个文件,获取文件头和信息头 BMPFILEHEADER fileheader; BITMAPINFOHEADER infoheader; fread(&fileheader, sizeof(BMPFILEHEADER), 1, pfin); fread(&infoheader, sizeof(BITMAPINFOHEADER), 1, pfin); bool flag = false; while (point->width % 4) { point->width++; } infoheader.biWidth = point->width; infoheader.biHeight = point->height; infoheader.biSizeImage = flag? ((((point->width * infoheader.biBitCount) + 31) / 32 * 4) * point->height) : point->width * point->height; fwrite(&fileheader, sizeof(fileheader), 1, pfout); fwrite(&infoheader, sizeof(infoheader), 1, pfout); enlarge();//判断数据范围,若在01之间,转为0到255之间 int i, j, k; for(i=0; i<point->height; i++) { for(j=0; j<point->width; j++) { if (point->data[i][j] > 255) point->data[i][j] = 255; if (point->data[i][j] < 0) point->data[i][j] = 0; } } unsigned char prep=0; for (i = 0; i < infoheader.biHeight; i++) { for (j = 0; j < infoheader.biWidth; j++) { prep=(unsigned char)(point->data[i][j]); for (k = 0; k < 3; k++) fwrite(&prep,1,1,pfout); } } fclose(pfout); fclose(pfin); } void WriteBMP(const char *filename, T** pdata, int h, int w) { FILE* pfout = NULL; // 保存文件的文件指针 fopen_s(&pfout, filename, "wb"); // 二进制写入方式打开文件 FILE* pfin = NULL; // 保存文件的文件指针 fopen_s(&pfin, "Fruits.bmp", "rb"); // 打开一个文件,获取文件头和信息头 BMPFILEHEADER fileheader; BITMAPINFOHEADER infoheader; fread(&fileheader, sizeof(BMPFILEHEADER), 1, pfin); fread(&infoheader, sizeof(BITMAPINFOHEADER), 1, pfin); bool flag = false; while (w % 4) { w++; } infoheader.biWidth = w; infoheader.biHeight = h; infoheader.biSizeImage = flag? ((((w * infoheader.biBitCount) + 31) / 32 * 4) * h) : w * h; fwrite(&fileheader, sizeof(fileheader), 1, pfout); fwrite(&infoheader, sizeof(infoheader), 1, pfout); int i, j, k; unsigned char prep=0; for (i = 0; i < infoheader.biHeight; i++) { for (j = 0; j < infoheader.biWidth; j++) { prep=(unsigned char)(pdata[i][j]); for (k = 0; k < 3; k++) fwrite(&prep,1,1,pfout); } } fclose(pfout); fclose(pfin); } // 下面2个读写文本文件的函数,需要考虑不同数据类型的存储 void ReadText(const char *fileName) //从文本文件中读入数据 { std::ifstream fin(fileName); while(!fin.eof()) { int i,j,k; judge_delete();//判断是否有其他对象利用这块空间,若没有,便删除原来的空间,以便改变空间大小 fin>>point->height; fin>>point->width; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } T a,b,c; for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { fin>>a; fin>>b; fin>>c; point->data[i][j]=(a+b+c)/3; } } } fin.close(); } void WriteText(const char *filename) //将数据保存为文本文件 { std::ofstream fout(filename); fout<<point->height; fout<<point->width; for(int i=0; i<point->height; i++) { for(int j=0; j<point->width; j++) { for (int k = 0; k < 3; k++) fout<<point->data[i][j]; } } fout.close(); } int Height()//得到矩阵高度 { return point->height; } int Height() const//得到矩阵高度 { return point->height; } int Width()//得到矩阵宽度 { return point->width; } int Width() const//得到矩阵宽度 { return point->width; } T Min() //得到矩阵元素的最小值 { T smallest=point->data[0][0]; for(int i=0; i<point->height; i++) { for(int j=0; j<point->width; j++) { if(point->data[i][j]<smallest) smallest=point->data[i][j]; } } return smallest; } T Min() const //得到矩阵元素的最小值 { T smallest=point->data[0][0]; for(int i=0; i<point->height; i++) { for(int j=0; j<point->width; j++) { if(point->data[i][j]<smallest) smallest=point->data[i][j]; } } return smallest; } T Max() //得到矩阵元素的最大值 { T biggest=point->data[0][0]; for(int i=0; i<point->height; i++) { for(int j=0; j<point->width; j++) { if(point->data[i][j]>biggest) biggest=point->data[i][j]; } } return biggest; } T Max() const //得到矩阵元素的最大值 { T biggest=point->data[0][0]; for(int i=0; i<point->height; i++) { for(int j=0; j<point->width; j++) { if(point->data[i][j]>biggest) biggest=point->data[i][j]; } } return biggest; } T& At(int row, int col) //获取某点的值 { return point->data[row][col]; } const T& At(int row, int col) const//获取某点的值,const重载 { return point->data[row][col]; } int Height() const { return point->height; } int Width() const { return point->width; } void Set(int row, int col, T value) //设置元素(row,col)为某值; { point->data[row][col]=value; } void Set(T value) //设置所有元素为同一值; { for(int i=0; i<point->height; i++) { for(int j=0; j<point->width; j++) { point->data[i][j]=value; } } } void Flip(int code) //翻转; 根据code的值:0:左右翻转,1:上下翻转; { int i, j; T **pdata = new T *[point->height];//中间数组 for (i = 0; i < point->height; i++) { pdata[i] = new T[point->width]; } if (code == 0) { for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { pdata[i][point->width - j - 1] = point->data[i][j]; } } wcopy();//即时拷贝 for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } WriteBMP("Flipliftright.bmp"); } if (code == 1) { for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { pdata[point->height - 1 - i][j] = point->data[i][j]; } } wcopy();//即时拷贝 for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } WriteBMP("Flipupdown.bmp"); } clean(pdata, point->height); } void Resize(int code) //缩放0小1大 { int i,j; if (code == 0) { T **pdata = new T *[point->height / 2];//中间数组 for (i = 0; i < point->height / 2; i++) { pdata[i] = new T[point->width / 2]; } for (i = 0; i * 2 < point->height; i++) { for (j = 0; j * 2 < point->width; j++) { pdata[i][j] = point->data[i * 2][j * 2]; } } judge_delete();//判断是否有其他对象利用这块空间,若没有,删除原来的空间,以便改变空间大小 point->height/=2; point->width/=2; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } WriteBMP("Resize smaller.bmp"); clean(pdata, point->height); } if (code == 1) { T **pdata = new T *[2 * point->height]; for (i = 0; i < 2 * point->height; i++) { pdata[i] = new T[2 * point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { pdata[i * 2][j * 2] = point->data[i][j]; pdata[i * 2 + 1][j * 2] = point->data[i][j]; pdata[i * 2][j * 2 + 1] = point->data[i][j]; pdata[i * 2 + 1][j * 2 + 1] = point->data[i][j]; //原来的一个像素变四个 } } judge_delete();//判断是否有其他对象利用这块空间,若没有,删除原来的空间,以便改变空间大小 point->height*=2; point->width*=2; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } WriteBMP("Resize bigger.bmp"); clean(pdata, point->height); } } void Resize(int h,int w) { int oldw = point->width; int oldh = point->height; int neww = w; int newh = h; if (ceil(neww * 1.0 / oldw) <= 2)//width满足条件,只考虑height { if (ceil(newh * 1.0 / oldh) <= 2)//height满足条件 { Resize(newh, neww, 1); } else//height不满足条件 { int cnt = newh / oldh;//需要循环次数 int temph = oldh;//另暂时的h等于原来的h for (int i = 0; i < cnt - 1; i++) { temph += oldh;//每次加上一个原来的h,就能保证满足条件 Resize(temph, neww, 1); } Resize(temph + (newh%oldh), neww, 1);//最后在加上多出来又不足一个h的部分 } } else//width不满足条件 { if (ceil(newh * 1.0 / oldh) <= 2)//height满足条件 { int cnt = neww / oldw; int tempw = oldw; for (int i = 0; i < cnt - 1; i++) { tempw += oldw; Resize(newh, tempw, 1); } Resize(newh, tempw + (neww%oldw), 1); } else//height不满足条件 { int cnt = newh / oldh; int temph = oldh; for (int i = 0; i < cnt - 1; i++) { temph += oldh; Resize(temph, oldw, 1); } Resize(temph + (newh%oldh), oldw, 1); cnt = neww / oldw; int tempw = oldw; for (int i = 0; i < cnt - 1; i++) { tempw += oldw; Resize(newh, tempw, 1); } Resize(newh, tempw + (neww%oldw), 1); } } } void Resize(int h,int w,int) { //记录原有的h,w int oldh = h; int oldw = w; //记录原来的尺寸 int width = point->width; int height = point->height; //新值与原值的差值 int dw = static_cast<int>(fabs(width - w)); int dh = static_cast<int>(fabs(height - h)); //插入的间隔 if (dw < 1)//防止dw == 0 { dw = 1; } if (dh < 1) { dh = 1; } int maxw = w > width ? w : width; int maxh = h > height ? h : height; int difw = maxw / dw; int difh = maxh / dh; T** data = new T*[h]; for(int i=0; i<h; i++) { data[i]=new T*[w]; } for (int i = 0, prii = 0; i < h; i++) { if ((i + 1) % difh == 0) { if (h < height) { prii++; } else { continue; } } for (int j = 0, prij = 0; j < w; j++) { if ((j + 1) % difw == 0) { if (w < width) { prij++;//指定 增/删 列跳过 } else { continue; } } data[i][j] = point->m_data[prii][prij]; if (prij < width - 1) prij++; } if (prii < height - 1) prii++; } //填充跳过的指定增行/列 if (w > width)//先填充列 { for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if ((j + 1) % difw == 0) { data[i][j] = data[i][j - 1];//指定 增 列填充 } } } } if (h > height)//再填充行 { for (int i = 0; i < h; i++) { if ((i + 1) % difh == 0)//指定 增 行填充 { for (int j = 0; j < w; j++) { data[i][j] = data[i - 1][j]; } } } } } void Crop(int x1, int y1, int x2, int y2) //裁剪点(x1,y1)到点(x2,y2) { if (x2 > x1 && y2 > y1) { int h = y2 - y1 + 1; int w = x2 - x1 + 1; while (w % 4) { w++; } int i, j; T **pdata = new T *[h]; for (i = 0; i < h; i++) { pdata[i] = new T[w]; } int m,n; for(i=y1,m=0; i<=y2; i++,m++) { for(j=x1,n=0; j<=x2; j++,n++) { pdata[m][n]=point->data[i][j]; } } judge_delete();//判断是否有其他对象利用这块空间,若没有,删除原来的空间,以便改变空间大小 point->height=h; point->width=w; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } WriteBMP("cutImage.bmp"); clean(pdata, h); } else { puts("输入坐标有误"); } } void Rotate(int degree) //旋转,90度的整数倍 { int i, j; if(degree%360==0)//还是原图 { WriteBMP("rotate0.bmp");//保存图片 } else if(degree<0) { if ((degree%90==0)&&(degree%180!=0)&&(degree%270!=0)) { T **pdata = new T *[point->width]; for (i = 0; i < point->width; i++) { pdata[i] = new T[point->height]; } for (i = 0; i < point->width; i++) { for (j = 0; j < point->height; j++) { pdata[i][j] = point->data[point->height - j - 1][i]; } } judge_delete(); int prep=point->height; //交换 point->height=point->width; point->width=prep; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } WriteBMP("rotate-90.bmp"); clean(pdata, point->width); } else if ((degree %180==0)&&(degree%270!=0)) { int i, j; T **pdata = new T *[point->height]; for (i = 0; i < point->height; i++) { pdata[i] = new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { pdata[point->height-i-1][point->width - j - 1] = point->data[i][j]; } } judge_delete(); point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } //保存图片 WriteBMP("rotate-180.bmp"); clean(pdata, point->height); } else if (degree %270==0) { T **pdata = new T *[point->width]; for (i = 0; i < point->width; i++) { pdata[i] = new T[point->height]; } for (int i = 0; i < point->width; i++) { for (int j = 0; j < point->height; j++) { pdata[i][j] = point->data[j][point->width - i - 1]; } } judge_delete(); int prep=point->height; //交换 point->height=point->width; point->width=prep; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } //保存图片 WriteBMP("rotate-270.bmp"); clean(pdata, point->width); } } else if(degree>0) { if ((degree%90==0)&&(degree%180!=0)&&(degree%270!=0)) { T **pdata = new T *[point->width]; for (i = 0; i < point->width; i++) { pdata[i] = new T[point->height]; } for (i = 0; i < point->width; i++) { for (j = 0; j < point->height; j++) { pdata[i][j] = point->data[j][point->width - i - 1]; } } judge_delete(); int prep=point->height; //交换 point->height=point->width; point->width=prep; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } //保存图片 WriteBMP("rotate90.bmp"); clean(pdata, point->width); } else if ((degree %180==0)&&(degree%270!=0)) { int i, j; T **pdata = new T *[point->height]; for (i = 0; i < point->height; i++) { pdata[i] = new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { pdata[point->height-i-1][point->width - j - 1] = point->data[i][j]; } } judge_delete(); point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } //保存图片 WriteBMP("rotate180.bmp", pdata, point->height, point->width); clean(pdata, point->height); } else if (degree %270==0) { T **pdata = new T *[point->width]; for (i = 0; i < point->width; i++) { pdata[i] = new T[point->height]; } for (int i = 0; i < point->width; i++) { for (int j = 0; j < point->height; j++) { pdata[i][j] = point->data[point->height - j - 1][i]; } } judge_delete(); int prep=point->height; //交换 point->height=point->width; point->width=prep; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } //保存图片 WriteBMP("rotate270.bmp"); clean(pdata, point->width); } } else { puts("输入的角度不是90的整数倍"); } } void Transpose() // 转置 { int i, j; T** pdata = new T*[point->width]; for (i = 0; i < point->width; i++) { pdata[i] = new T[point->height]; } for (i = 0; i < point->width; i++) { for (j = 0; j < point->height; j++) { pdata[i][j] = point->data[j][i]; } } judge_delete(); int prep=point->height; //交换 point->height=point->width; point->width=prep; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = pdata[i][j]; } } WriteBMP("transpose.bmp"); clean(pdata, point->width); } void Reshape(int h, int w) //在元素总数不变的情况下,将矩阵的行列变为参数给定的大小 { int i, j; int scale = h * w; if (scale == h * w) { T* a = new T[scale];//变量做大小得用动态内存开辟 for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { a[i*point->width + j] = point->data[i][j]; } } judge_delete(); point->height = h; point->width = w; point->data=new T*[point->height];//开辟新空间 for(i=0; i<point->height; i++) { point->data[i]=new T[point->width]; } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = a[i*point->width + j]; } } WriteBMP("Reshape.bmp"); delete[] a; } else printf("总数不一致"); } bool IsEmpty()// 判断是否为空矩阵 { if (point->width == 0 && point->height == 0) return 1; else return 0; } bool IsSquare()// 判断矩阵是否为方阵 { if (point->height = point->width) return 1; else return 0; } Mat<T> MajorDiagonal()// 求主对角线上的元素,输出一个N行1列的矩阵,N为主对角线上元素的个数 { Mat<T> prep(point->height,1); for (int i = 0; i < point->height; i++) { prep.point->data[i][0] = point->data[i][i]; } return prep; } Mat<T> MinorDiagonal()// 求副对角线上的元素,输出一个N行1列的矩阵,N为副对角线上元素的个数 { Mat<T> prep(point->height,1); for (int i = 0; i < point->height; i++) { for (int j = 0; j < point->width; j++) { if (j == point->width - i - 1) prep.point->data[i][0] = point->data[i][j]; } } return prep; } Mat<T> Row(int n)// 返回矩阵的第n行上的元素,组出一个1行N列的矩阵输出,N为第n行上元素的个数 { Mat<T> prep(1,point->width); for (int i = 0; i < point->height; i++) { for (int j = 0; j < point->width; j++) { if (i == n - 1) { for (j = 0; j < point->width; j++) prep.point->data[0][j] = point->data[i][j]; } } } return prep; } Mat<T> Column(int n)// 返回矩阵的第n列上的元素,组出一个N行1列的矩阵输出,N为第n列上元素的个数 { Mat<T> prep(point->height,1); for (int i = 0; i < point->height; i++) { for (int j = 0; j < point->width; j++) { if (i == n - 1) { if (j == n) prep.point->data[i][0] = point->data[i][j]; } } } return prep; } void Cat(Mat<T> &m, int code) // 将m与当前对象进行拼接,code代表拼接的方式 { int i, j, h, w; T **a = new T*[point->height]; for (i = 0; i < point->height; i++) a[i] = new T[point->width]; for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { a[i][j] = point->data[i][j];//保存原数组 } } judge_delete();//判断是否有其他对象利用这块空间,若没有,便删除原来的空间,以便改变空间大小 if (code == 1) { h = point->height; w = point->width; point->width = point->width + m.point->width; point->data = new T*[point->height]; for (i = 0; i < point->height; i++) point->data[i] = new T[point->width];//新空间 for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { point->data[i][j] = a[i][j];//第一个数组复制 } } for (i = 0; i < point->height; i++) { for (j = w; j < point->width; j++) { point->data[i][j] = m.point->data[i][j - w];//第二个数组复制 } } WriteBMP("Catliftright.bmp"); for (i = 0; i < point->height; i++) delete []a[i]; delete[]a; } if (code == 2) { h = point->height; w = point->width; point->height = point->height + m.point->height; point->data = new T*[point->height]; for (i = 0; i < point->height; i++) point->data[i] = new T[point->width];//新空间 for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { point->data[i][j] = a[i][j];//第一个数组复制 } } for (i = h; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j] = m.point->data[i - h][j];//第二个数组复制 } } WriteBMP("Catupdown"); for (i = 0; i < h; i++) delete []a[i]; delete[]a; } } void CopyTo(Mat<T> &m) // 将矩阵复制给m,完成深拷贝 { int i, j; m.point->height = point->height; m.point->width = point->width; m.point->data = new T*[point->height]; for (i = 0; i < point->height; i++) m.point->data[i] = new T[point->width]; for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { m.point->data[i][j] = point->data[i][j]; } } m.point->count=new int[1]; *m.point->count=1; } Mat<T> Clone() // 从当前对象拷贝创建一个新的矩阵,完成深拷贝 { int i,j; Mat<T> prep; prep.point->height=point->height; prep.point->width=point->width; prep.point->data = new T*[point->height];//开辟空间 for (i = 0; i < point->height; i++) prep.point->data[i] = new T[point->width]; for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { prep.point->data[i][j] = point->data[i][j]; } } prep.point->count=new int[1]; *prep.point->count=1; } Mat<double> Normalize()//将矩阵元素的值变换到0-1范围内,以double类型的Mat对象输出。注意:在这个函数里,无法访问Mat<double>类型的对象的私有成员data,需要调用其At函数获得某个元素。 { double mi = 0, ma = 0; int i, j; for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { if (At(i,j) > ma) { ma = At(i,j); } if (At(i,j) < mi) { mi = At(i,j); } } } for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { if (At(i,j) == mi) { At(i,j) = 0; } else if (At(i,j) == ma) { At(i,j) = 1; } else { At(i,j) = (At(i,j) - mi) / ma; } } } } void enlarge()//如果是01之间,放大到0-255 { int i,j; int flag=0; for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { if(point->data[i][j]>1) { flag=1; break;//判断是否在零一之间 } } } if(flag==0) { for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j]=point->data[i][j]*255; } } } } Mat<T>& operator=(const Mat<T> &m) //重载赋值运算符,完成对象间的拷贝; { if(this != &m) { if(*point->count>1)//还有对象使用 { *point->count--; } else//删除空间 { for(int i=0; i<point->height; i++) delete [] point->data[i]; delete [] point->data; } point->count=m.point->count; *m.point->count++; point->height=m.point->height; point->width=m.point->width; point->data=m.point->data; } return *this; } bool operator==(const Mat<T> &m) //判断两个Mat对象是否相等 { bool flag = 1; int i,j; if(point->height==m.point->height&&point->width==m.point->width) { for(i=0; i<point->height; i++) { for(j=0; j<point->width; j++) { if(point->data[i][j]!=m.point->data[i][j]) { flag=0; break; } } } } else { flag=0; } return flag; } friend Mat<T> operator+(const Mat<T> &lhs, const Mat<T> &rhs) //对应元素的数值相加; { int i,j; Mat<T> result(lhs.point->height, lhs.point->width); if(lhs.point->height==rhs.point->height&&lhs.point->width==rhs.point->width) { for(i=0; i<lhs.point->height; i++) { for(j=0; j<lhs.point->width; j++) { result.point->data[i][j]=lhs.point->data[i][j]+rhs.point->data[i][j]; } } } else printf("两矩阵尺寸不同"); return result; } friend Mat<T> operator-(const Mat<T> &lhs, const Mat<T> &rhs) //对应元素的数值相减; { int i,j; Mat<T> result(lhs.point->height, lhs.point->width); if(lhs.point->height==rhs.point->height&&lhs.point->width==rhs.point->width) { for(i=0; i<lhs.point->height; i++) { for(j=0; j<lhs.point->width; j++) { result.point->data[i][j]=lhs.point->data[i][j]-rhs.point->data[i][j]; } } } else printf("两矩阵尺寸不同"); return result; } Mat<T>& operator++() //前置自加; { int i,j; for(i=0; i<point->height; i++) { for(j=0; j<point->width; j++) { point->data[i][j]=point->data[i][j]+1; } } return *this; } Mat<T>& operator--() //前置自减; { int i,j; for(i=0; i<point->height; i++) { for(j=0; j<point->width; j++) { point->data[i][j]=point->data[i][j]-1; } } return *this; } Mat<T> operator ++(int) //后置自加; { Mat<T> old=*this; ++(*this); return old; } Mat<T> operator --(int) //后置自减; { Mat<T> old=*this; --(*this); return old; } Mat<double> operator-() // 取反;注意要把矩阵的数据规整到[0,1]区间后,再用1减 { int i,j; Normalize();//缩小到01之间 for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { point->data[i][j]=1-point->data[i][j]; } } return *this; } friend Mat<T> operator+(Mat<T> &m, T num) //所有元素加上同一数值; { int i,j; Mat<T> nummatrix(m.point->height,m.point->width,num);//实现对double型num的升级,使其成为Matrix对象 for(i=0; i<m.point->height; i++) { for(j=0; j<m.point->width; j++) { m.point->data[i][j]=m.point->data[i][j] + nummatrix->point->data[i][j]; } } return m; } friend Mat<T> operator-(Mat<T> &m, T num) //所有元素减去同一数值; { int i,j; Mat<T> nummatrix(m.point->height,m.point->width,num);//实现对double型num的升级,使其成为Matrix对象 for(i=0; i<m.point->height; i++) { for(j=0; j<m.point->width; j++) { m.point->data[i][j]=m.point->data[i][j] - nummatrix->point->data[i][j]; } } return m; } friend Mat<T> operator*(Mat<T> &m, T num) //所有元素乘上同一数值; { int i,j; Mat<T> nummatrix(m.point->height,m.point->width,num);//实现对double型num的升级,使其成为Matrix对象 for(i=0; i<m.point->height; i++) { for(j=0; j<m.point->width; j++) { m.point->data[i][j]=m.point->data[i][j] * nummatrix->point->data[i][j]; } } return m; } friend Mat<T> operator/(Mat<T> &m, T num) //所有元素除以同一数值; { int i,j; Mat<T> nummatrix(m.point->height,m.point->width,num);//实现对double型num的升级,使其成为Matrix对象 for(i=0; i<m.point->height; i++) { for(j=0; j<m.point->width; j++) { m.point->data[i][j]=m.point->data[i][j] / nummatrix->point->data[i][j]; } } return m; } //另外,用友元函数再写出一个T类型的数和一个Mat对象的加,减,乘,除 friend Mat<T> operator+(T num, Mat<T> &m) { int i,j; Mat<T> nummatrix(m.point->height,m.point->width,num);//实现对double型num的升级,使其成为Matrix对象 for(i=0; i<m.point->height; i++) { for(j=0; j<m.point->width; j++) { m.point->data[i][j]=m.point->data[i][j] + nummatrix->point->data[i][j]; } } return m; } friend Mat<T> operator-(T num, Mat<T> &m) { int i,j; Mat<T> nummatrix(m.point->height,m.point->width,num);//实现对double型num的升级,使其成为Matrix对象 for(i=0; i<m.point->height; i++) { for(j=0; j<m.point->width; j++) { m.point->data[i][j]=nummatrix->point->data[i][j] - m.point->data[i][j]; } } return m; } friend Mat<T> operator*(T num, Mat<T> &m) { int i,j; Mat<T> nummatrix(m.point->height,m.point->width,num);//实现对double型num的升级,使其成为Matrix对象 for(i=0; i<m.point->height; i++) { for(j=0; j<m.point->width; j++) { m.point->data[i][j]=nummatrix->point->data[i][j] * m.point->data[i][j]; } } return m; } friend Mat<T> operator/(T num, Mat<T> &m) { int i,j; Mat<T> nummatrix(m.point->height,m.point->width,num);//实现对double型num的升级,使其成为Matrix对象 for(i=0; i<m.point->height; i++) { for(j=0; j<m.point->width; j++) { m.point->data[i][j]=nummatrix->point->data[i][j] / m.point->data[i][j]; } } return m; } Mat<T> gray2bw(T t) //以给定阈值t进行二值化,返回结果对象 { int i,j; Normalize();//缩小到01之间 for (i = 0; i < point->height; i++) { for (j = 0; j < point->width; j++) { if(point->data[i][j]>=t) point->data[i][j]=1; else point->data[i][j]=0; } } return *this; } friend void Swap(Mat<T> &a, Mat<T> &b)//使用友元函数交换两个Mat对象 { int prep=a.point->height; a.point->height=b.point->height; b.point->height=a.point->height; prep=a.point->width; a.point->width=b.point->width; b.point->width=a.point->width; T **i=a.point->data; a.point->data=b.point->data; b.point->data=i; int **j=a.point->count; a.point->count=b.point->count; b.point->count=i; matrix_count *k=a.p; a.p=b.p; b.p=k; } protected: struct matrix_count { int height; int width; T **data; int *count; };// 自己实现一个结构体,来存储矩阵的行数、列数、引用计数和数据指针 struct matrix_count *point;// 这里需要声明指向该结构体的指针作为数据成员 }; #endif // MAT_H
#ifndef FILTER_H #define FILTER_H #include "Mat.h" template <class T> class Filter { public: Filter<T>(int size)//构造函数 { filterSize = size; } virtual ~Filter<T>() {}//析构函数 virtual Mat<T> Filtering(const Mat<T> &input) = 0; //滤波函数(纯虚函数); protected: int filterSize; }; //meanFilter类 template <class T> class MeanFilter : public Filter<T> { public: MeanFilter<T>(int size):Filter<T>(size) { } virtual ~MeanFilter<T>() { } virtual Mat<T> Filtering(const Mat<T> &input) //均值滤波函数 { Mat<T> prep(input); int i,j; double sum; double s=Filter<T>::filtersize*Filter<T>::filtersize; int l,m; int f=Filter<T>::filtersize; int w=(Filter<T>::filtersize-1)/2; int nh=input.Height()+2*(Filter<T>::filtersize-1); int nw=input.Width()+2*(Filter<T>::filtersize-1);//新长宽 Mat<T> p(nh,nw,T(1)); for(i=0; i<input.Height(); i++) //镜像拓展 { for(j=0; j<input.Width(); j++) { p.matrix.data[i+f-1][j+f-1]=input.matrix.data[i][j]; } } for(i=0; i<f-1; i++) { for(j=f-1; j<=nw-f; j++) { p.matrix.data[i][j]=p.matrix.data[2*(f-1)-1-i][j]; } } for(i=nh-f; i<nh-1; i++) { for(j=f-1; j<=nw-f; j++) { p.matrix.data[i][j]=p.matrix.data[2*nh-2*(f-1)-i-1][j]; } } for(i=0; i<nh-1; i++) { for(j=0; j<f-1; j++) { p.matrix.data[i][j]=p.matrix.data[i][2*(f-1)-1-j]; } } for(i=0; i<nh-1; i++) { for(j=nw-f+1; j<nw-1; j++) { p.matrix.data[i][j]=p.matrix.data[i][2*nw-2*(f-1)-j-1]; } } for(i=f-1; i<=nh-f; i++)//进行滤波 { for(j=f-1; j<=nw-f; j++) { sum=0; for(l=0; l<Filter<T>::filtersize; l++) { for(m=0; m<Filter<T>::filtersize; m++) { sum = sum+p.matrix.data[i-w+l][j-w+m]; } } prep.matrix.data[i-f+1][j-f+1]=sum/s; } } return prep; } }; //median类 template <class T> class MedianFilter : public Filter<T> { public: MedianFilter<T>(int size):Filter<T>(size) { } virtual ~MedianFilter() { } virtual Mat<T> Filtering(const Mat<T> &input) // 中值滤波器函数 { Mat<T> prep(input); int i,j; double sum; double s=Filter<T>::filtersize*Filter<T>::filtersize; T *array=new T[s];//开辟一个一维数组 int l,m; int f=Filter<T>::filtersize; int w=(Filter<T>::filtersize-1)/2; int nh=input.Height()+2*(Filter<T>::filtersize-1); int nw=input.Width()+2*(Filter<T>::filtersize-1);//新长宽 Mat<T> p(nh,nw,T(1)); for(i=0; i<input.Height(); i++) //镜像拓展 { for(j=0; j<input.Width(); j++) { p.matrix.data[i+f-1][j+f-1]=input.matrix.data[i][j]; } } for(i=0; i<f-1; i++) { for(j=f-1; j<=nw-f; j++) { p.matrix.data[i][j]=p.matrix.data[2*(f-1)-1-i][j]; } } for(i=nh-f; i<nh-1; i++) { for(j=f-1; j<=nw-f; j++) { p.matrix.data[i][j]=p.matrix.data[2*nh-2*(f-1)-i-1][j]; } } for(i=0; i<nh-1; i++) { for(j=0; j<f-1; j++) { p.matrix.data[i][j]=p.matrix.data[i][2*(f-1)-1-j]; } } for(i=0; i<nh-1; i++) { for(j=nw-f+1; j<nw-1; j++) { p.matrix.data[i][j]=p.matrix.data[i][2*nw-2*(f-1)-j-1]; } } for(i=f-1; i<=nh-f; i++) { for(j=f-1; j<=nw-f; j++) { int c=0; for(l=0; l<Filter<T>::filtersize; l++) //正方形区域内相加 { for(m=0; m<Filter<T>::filtersize; m++) { array[c]=p.matrix.data[i-w+l][j-w+m]; c++; } } prep.matrix.data[i-f+1][j-f+1] = sorted(array,s); } } return prep; } #endif // FILTER_H
#include "Mat.h" Mat::Mat() { //ctor } Mat::~Mat() { //dtor }
#include "Filter.h" Filter::Filter() { //ctor } Filter::~Filter() { //dtor }