Experimental purpose
Master operator overloading
Implement operator overloading of Matrix class
Experimental content
In previous experiments, we implemented Matrix and its subclass Image. In this experiment, we add some overloaded operators to the Matrix class, including the assignment operator "=", the "+", "-", "*", "/" (all operations between the corresponding elements of the Matrix, rather than the multiplication and division of the Matrix), self addition and self subtraction, and the "=", "+", "-", "*", "/" operations of the Matrix (or Image) object and a number (scalar), "= =" to judge whether two matrices (or images) are equal.
Add a monocular operator "-" to the Image class to reverse the pixel value of the Image, that is, the black becomes white and the white becomes black. Then add a member function gray2bw to the Image class, which converts the gray Image into a binary Image with a given threshold parameter. Assuming that the pixel value range of the Image is a real number between [0,1], the threshold double t ∈ [0,1] is given. This function processes all pixels in the Image as follows: if the pixel value of the pixel is less than t, the corresponding pixel value of the output Image is assigned as 0; if the pixel value of the pixel is greater than or equal to t, the corresponding pixel of the output Image is assigned as 1. The output Image object of this function only contains 0 and 1 pixel values, so this operation is called "binarization" operation or "threshold segmentation" in Image processing.
Note: these two functions assume that the data of the operand is a real number between [0,1]. However, the element value of the actual object may not be within this range. Therefore, within these two functions, you need to normalize the range of all elements to the [0,1] interval, and then do the corresponding operations. Similarly, when saving the result as BMP image, reduce the range to the integer range of [0255], and pay attention to relevant operations.
There are two scene pictures scene2 in the pictures given to you before_ bg. BMP and scene2_fg.bmp requires image subtraction and threshold segmentation to separate foreground objects.
- Overload operators in the Matrix class and add some operator overloaded functions (some are member functions and some are friend functions. Think about which are suitable for using member functions and which are suitable for using friend functions?):
- Overload the assignment operator "=" of two Matrix objects to complete operations like a=b. Deep copy of data is required. And overload the assignment operator again, so that the right operand can be a double type number, and complete the assignment of all elements of the Matrix to this number, such as a=128.
- Overload the "= =" operator to judge whether two Matrix objects are equal. The condition for the equality of two matrices is that the row and column sizes are the same and the values of all elements are the same.
- Overload the "+" operator to complete the addition of corresponding element values for two matrices with the same size.
- Overload the "+" operator to add the same value to all elements of a matrix.
- Overload the "-" operator to subtract element values for two matrices with the same size.
- Overload the "-" operator to subtract the same value from all elements of a matrix.
- Overload the "*" operator to multiply the element values for two matrices with the same size.
- Overload the "*" operator to multiply all elements of a matrix by the same value.
- Overloaded "/" operator to divide element values for two matrices with the same size; Design your own processing method when the divisor is 0.
- Overloaded "/" operator to divide all elements of a matrix by the same value; Design your own processing method when the divisor is 0.
- In the Image class, implement the following operators and functions:
- Overload the "-" unary operator to "negate" all elements of an Image object.
- Implement the function gray2bw to binarize the Image with a given threshold, and the function returns the result Image object.
- Overload the "+ +" operator to add 1 to all elements of a matrix (pre version and Post version respectively). Note that the pixel value range of the object using this operator should be [0255]. If it is between [0,1], it should first be extended to [0255], then add 1, and then normalize back to [0,1].
- Overload the "--" operator to reduce all elements of a matrix by 1 (pre version and Post version respectively). Note that the pixel value range of the object using this operator should be [0255]. If it is between [0,1], it should first be extended to [0255], then add 1, and then normalize back to [0,1].
- Test all implemented functions in the main function, such as separating foreground objects mentioned earlier.
Create Image objects img1 and img2 and read in two images scene2 respectively_ FG and scene2_bg. Create a new Image object sub, use the "-" operator to subtract img1 and img2, and save. Call the gray2bw function on the sub for threshold segmentation and save the results.
//Matrix.h #ifndef MATRIX_H #define MATRIX_H #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; //The number of bytes occupied by this structure is 40 bytes long biWidth; //The width of the bitmap, in pixels long biHeight; //The height of the bitmap, in pixels unsigned short biPlanes; //The level of the target device must be 1 unsigned short biBitCount; //The number of bits required for each pixel must be 1 (two-color) //One of 4 (16 colors), 8 (256 colors), or 24 (true colors) unsigned long biCompression; //Bitmap compression type, which must be 0 (BI_RGB is not compressed) //1 (BI_RLE8 compression type) //2 (BI_RLE compression type) unsigned long biSizeImage; //The size of the bitmap in bytes long biXPelsPerMeter; //Bitmap horizontal resolution, pixels per meter long biYPelsPerMeter; //Bitmap vertical resolution, pixels per meter unsigned long biClrUsed; //The number of colors in the color table actually used by the bitmap unsigned long biClrImportant; //Number of important colors in bitmap display }; class Matrix { public: Matrix(); Matrix(int h,int w); Matrix(int h, int w, double val); Matrix(const Matrix &m); virtual ~Matrix(); void Normalize(); // This function linearly scales the data of the matrix to the [0,1] interval, that is, the minimum value min of all elements of the current matrix becomes 0, the maximum value Max becomes 1, and the values of other elements linearly change to the [0,1] interval. The formula is: t '= (t-min)/max; //Operator overloading function; Matrix& operator=(double val); Matrix& operator=(const Matrix &m); //Overload the assignment operator to complete the deep copy between objects; bool operator==(const Matrix &m); //Determine whether two Matrix objects are equal Matrix& operator++(); //Pre self addition; Matrix& operator--(); //Pre self subtraction; Matrix operator++(int); //Post self adding; Matrix operator--(int); //Post self subtraction; //For two matrices with the same size, the values of the corresponding elements are added; friend Matrix operator+(const Matrix &m1, const Matrix &m2); //Add the same value to all elements; friend Matrix operator+(Matrix &m, double num); //For two matrices with the same size, the values of the corresponding elements are subtracted; friend Matrix operator-(const Matrix &m1, const Matrix &m2); //All elements minus the same value; friend Matrix operator-(Matrix &m, double num); //Two matrices with the same size are multiplied by the values of the corresponding elements; friend Matrix operator*(const Matrix &m1, const Matrix &m2); //Multiply all elements by the same value; friend Matrix operator*(Matrix &m, double num); //Two matrices with the same size are divided by the values of the corresponding elements; friend Matrix operator/( const Matrix &m1, const Matrix &m2); //All elements divided by the same value; friend Matrix operator/(Matrix &m, double num); //The above friend functions implement the addition, subtraction, multiplication and division of a Matrix object and a number. What should I do if I exchange these two operands, that is, the addition, subtraction, multiplication and division of a number and a Matrix object? Please write the relevant code yourself. protected: int height; int width; double **data; }; #endif
//Image.h #ifndef Image_H #define Image_H #include "Matrix.h" class Image : public Matrix { public: Image(); //Constructor to create an Image object with zero rows and columns Image(int h, int w); //The constructor is overloaded to create the Image object of row h and column w Image(int h, int w, double val); //Constructor overload, the created image pixel values are val; Image(const char* ImageName); //Constructor overload, use the file name to load the Image file from the hard disk to become the Image object; Image(unsigned char *m, int rows, int cols); Image(unsigned char m[][100], int n); //Constructor overload to create an Image object from a static array; Image(unsigned char **m, int h, int w); //Constructor overload to create an Image object from a dynamic array; Image(const Matrix &m); //Constructor overload, and the Image class object is constructed from the Matrix class object Image(const Image &im); //Copy constructor; virtual ~Image(); //Destructor; void ReadBMP(const char* ImageName); //Reading image data from hard disk file; void WriteBMP(const char* filename); //Saving image data as an image file; void WriteBMP(const char *filename, double** pdata, BMPFILEHEADER pfileheader, BITMAPINFOHEADER pinfoheader); void wfree(double** data, int h); Image& operator++(); //Pre self addition; Image& operator--(); //Pre self subtraction; Image operator++(int); //Post self adding; Image operator--(int); //Post self subtraction; Image operator-(); //Invert the image, normalize the values of all pixels to between [0,1], and then each pixel is subtracted by 1.0 Image gray2bw(double t); //Binarize the image with a given threshold t and return the result image object; void enlarge();//If it is between 01, zoom in to 0-255 Image& operator=(double val); BMPFILEHEADER fileheader; BITMAPINFOHEADER infoheader; }; #endif
//Matrix.cpp #include "Matrix.h" #include <iostream> Matrix::Matrix() { height = 0; width = 0; data = NULL; } //Overloading Constructors Matrix::Matrix(int h, int w) { height = h; width = w; int i, j; data = new double *[height];//Dynamic memory development for (i = 0; i < height; i++) { data[i] = new double[width]; } for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { data[i][j] = 0; } } } Matrix::Matrix(int h, int w, double val) //Constructor overload, the created image pixel values are val; { height = h; width = w; int i, j; data = new double *[height];//Dynamic memory development for (i = 0; i < height; i++) { data[i] = new double[width]; } for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { data[i][j] = val; } } } Matrix::Matrix(const Matrix &m)//Deep copy { this->height = m.height; this->width = m.width; int i, j; data = new double *[m.height];//Dynamic memory development for (i = 0; i < m.height; i++) { data[i] = new double[m.width]; } for (i = 0; i < m.height; i++) { for (j = 0; j < m.width; j++) { data[i][j] = m.data[i][j]; } } } Matrix::~Matrix() { int i; for (i = 0; i < height; i++)//Free up space delete[] data[i]; delete[] data; } void Matrix::Normalize()// This function linearly scales the data of the matrix to the [0,1] interval, that is, the minimum value min of all elements of the current matrix becomes 0, the maximum value Max becomes 1, and the values of other elements linearly change to the [0,1] interval. The formula is: t '= (t-min)/max; { double mi = data[0][0], ma = data[0][0]; int i, j; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if (data[i][j] > ma) { ma = data[i][j]; } if (data[i][j] < mi) { mi = data[i][j]; } } } for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if (data[i][j] == mi) { data[i][j] = 0; } else if (data[i][j] == ma) { data[i][j] = 1; } else { data[i][j] = (data[i][j] - mi) / ma; } } } } Matrix& Matrix::operator=(const Matrix &m) //Overload the assignment operator to complete the deep copy between objects; { if(m->data==this->data) { return *this; } else { int i,j; if(this->data!=NULL) { for(i=0;i<this->height;i++) delete [] this->data[i]; delete [] this->data; } height=m.height; width=m.width; data=new double*[m.height]; for(i=0; i<m.height; i++) data[i]=new double[m.width]; for (i = 0; i < m.height; i++) { for (j = 0; j < m.width; j++) { data[i][j] = m.data[i][j]; } } return *this; } } Matrix& Matrix::operator=(double val) //Overload the assignment operator to complete the deep copy between objects; { int i,j; Matrix nummatrix(height,width,val);//Upgrade the double num to become a Matrix object for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { data[i][j] = nummatrix.data[i][j]; } } return *this; } bool Matrix::operator==(const Matrix &m)//Determine whether two Matrix objects are equal { bool flag = 1; int i,j; if(height==m.height&&width==m.width) { for(i=0; i<height; i++) { for(j=0; j<width; j++) { if(data[i][j]!=m.data[i][j]) { flag=0; break; } } } } else { flag=0; } return flag; } Matrix& Matrix::operator++() //Pre self addition; { int i,j; for(i=0; i<height; i++) { for(j=0; j<width; j++) { data[i][j]++; } } return *this; } Matrix& Matrix::operator--() //Pre self subtraction; { int i,j; for(i=0; i<height; i++) { for(j=0; j<width; j++) { data[i][j]--; } } return *this; } Matrix Matrix::operator++(int) //Post self adding; { Matrix old=*this; ++(*this); return old; } Matrix Matrix::operator--(int) //Post self subtraction; { Matrix old=*this; --(*this); return old; } //For two matrices with the same size, the values of the corresponding elements are added; Matrix operator+(const Matrix &m1, const Matrix &m2) { int i,j; Matrix result(m1.height,m1.width); if(m1.height==m2.height&&m1.width==m2.width) { for(i=0; i<m1.height; i++) { for(j=0; j<m1.width; j++) { result.data[i][j]=m1.data[i][j]+m2.data[i][j]; } } } else printf("The two matrices are different in size"); return result; } //Add the same value to all elements; Matrix operator+(Matrix &m, double num) { int i,j; Matrix nummatrix(m.height,m.width,num);//Upgrade the double num to become a Matrix object for(i=0; i<m.height; i++) { for(j=0; j<m.width; j++) { m.data[i][j]=m.data[i][j]+nummatrix.data[i][j]; } } return m; } //For two matrices with the same size, the values of the corresponding elements are subtracted; Matrix operator-(const Matrix &m1, const Matrix &m2) { int i,j; Matrix result(m1.height,m1.width); if(m1.height==m2.height&&m1.width==m2.width) { for(i=0; i<m1.height; i++) { for(j=0; j<m1.width; j++) { result.data[i][j]=m1.data[i][j]-m2.data[i][j]; } } } else printf("The two matrices are different in size"); return result; } //All elements minus the same value; Matrix operator-(Matrix &m, double num) { int i,j; Matrix nummatrix(m.height,m.width,num);//Upgrade the double num to become a Matrix object for(i=0; i<m.height; i++) { for(j=0; j<m.width; j++) { m.data[i][j]=m.data[i][j]-nummatrix.data[i][j]; } } return m; } //Two matrices with the same size are multiplied by the values of the corresponding elements; Matrix operator*(const Matrix &m1, const Matrix &m2) { int i,j; Matrix result(m1.height,m1.width); if(m1.height==m2.height&&m1.width==m2.width) { for(i=0; i<m1.height; i++) { for(j=0; j<m1.width; j++) { result.data[i][j]=m1.data[i][j]*m2.data[i][j]; } } } else printf("The two matrices are different in size"); return result; } //Multiply all elements by the same value; Matrix operator*(Matrix &m, double num) { int i,j; for(i=0; i<m.height; i++) { for(j=0; j<m.width; j++) { m.data[i][j]*=num; } } return m; } //Two matrices with the same size are divided by the values of the corresponding elements; Matrix operator/( const Matrix &m1, const Matrix &m2) { int i,j; Matrix result(m1.height,m1.width); if(m1.height==m2.height&&m1.width==m2.width) { for(i=0; i<m1.height; i++) { for(j=0; j<m1.width; j++) { result.data[i][j]=m1.data[i][j]/m2.data[i][j]; } } } else printf("The two matrices are different in size"); return result; } //All elements divided by the same value; Matrix operator/(Matrix &m, double num) { int i,j; for(i=0; i<m.height; i++) { for(j=0; j<m.width; j++) { m.data[i][j]/=num; } } return m; }
//Image.cpp #include <iostream> #include <stdlib.h> #include "Image.h" #include <cmath> using namespace std; //Constructor Image::Image(int h, int w):Matrix(h,w) { } Image::Image(int h, int w, double val): Matrix(h, w, val)//Constructor overload, the created image pixel values are val; { } Image::Image(const char* ImageName)//Constructor overload, use the file name to load the Image file from the hard disk to become the Image object; { ReadBMP(ImageName); } Image::Image(unsigned char *m, int rows, int cols)//Constructor overload to create an Image object from a one-dimensional static array. The number of rows and columns of the Image are given by the following two parameters; { height = rows; width = cols; int i, j; data = new double *[height];//Dynamic memory development for (i = 0; i < height; i++) { data[i] = new double[width]; } for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { data[i][j] = m[i*height + j * width]; } } } Image::Image(unsigned char m[][100], int rows)//Constructor overload to create an Image object from a static two-dimensional array. The number of rows of the Image (the first dimension of the two-dimensional array) is given by the second parameter rows; { width = 100; height = rows; int i, j; data = new double *[height];//Dynamic memory development for (i = 0; i < height; i++) { data[i] = new double[width]; } for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { data[i][j] =static_cast<unsigned char>(m[i][j]); } } } Image::Image(unsigned char **m, int h, int w)//Constructor overload to create an Image object from a dynamic array (secondary pointer). The number of rows and columns of the Image is given by the following two parameters; { height = h; width = w; int i, j; data = new double *[height];//Dynamic memory development for (i = 0; i < height; i++) { data[i] = new double[width]; } for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { data[i][j] = static_cast<unsigned char>(m[i][j]); } } } Image::Image(const Matrix &m) :Matrix(m) { FILE* pfin = NULL; // File pointer to save file fopen_s(&pfin, "Fruits.bmp", "rb"); // Open file in binary write mode fread(&fileheader, sizeof(BMPFILEHEADER), 1, pfin); fread(&infoheader, sizeof(BITMAPINFOHEADER), 1, pfin); } //copy constructor Image::Image(const Image &im):Matrix(im)//Deep copy { fileheader=im.fileheader; infoheader=im.infoheader; } void Image::wfree(double** data, int h) { int i; for (i = 0; i < h; i++)//Free up space delete[] data[i]; delete[] data; } //Destructor Image::~Image() { } //Read the image file from the hard disk; void Image::ReadBMP(const char* filename) { FILE* pfin = NULL; // File pointer to save file fopen_s(&pfin, filename, "rb"); // Open file in binary write mode fread(&fileheader, sizeof(BMPFILEHEADER), 1, pfin); fread(&infoheader, sizeof(BITMAPINFOHEADER), 1, pfin); height = infoheader.biHeight; width = infoheader.biWidth; int i, j; data = new double *[height];//Dynamic memory development for (i = 0; i < height; i++) { data[i] = new double[width]; } unsigned char a, b, c; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { fread(&a, sizeof(unsigned char), 1, pfin); fread(&b, sizeof(unsigned char), 1, pfin); fread(&c, sizeof(unsigned char), 1, pfin);//Read out three channels data[i][j] = (static_cast<double>(a+b+c)) / 3; }//Convert to grayscale image, store in array, and convert to double } fclose(pfin); } //Save the image; void Image::WriteBMP(const char *filename) { FILE* pfout = NULL; // File pointer to save file fopen_s(&pfout, filename, "wb"); // Open file in binary write mode bool flag = false; while (width % 4) { width++; } infoheader.biWidth = width; infoheader.biHeight = height; infoheader.biSizeImage = flag? ((((width * infoheader.biBitCount) + 31) / 32 * 4) * height) : width * height; fwrite(&fileheader, sizeof(fileheader), 1, pfout); fwrite(&infoheader, sizeof(infoheader), 1, pfout); enlarge(); int i, j, k; for(i=0;i<height;i++) { for(j=0;j<width;j++) { if (data[i][j] > 255) data[i][j] = 255; if (data[i][j] < 0) 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)(data[i][j]); for (k = 0; k < 3; k++) fwrite(&prep,1,1,pfout); } } fclose(pfout); } void Image::WriteBMP(const char *filename, double** pdata, BMPFILEHEADER pfileheader, BITMAPINFOHEADER pinfoheader) { FILE* pfout = NULL; // File pointer to save file fopen_s(&pfout, filename, "wb"); // Open file in binary write mode bool flag = false; while (width % 4) { width++; } pinfoheader.biSizeImage = flag? ((((width * infoheader.biBitCount) + 31) / 32 * 4) * height) : width * height; pinfoheader.biSizeImage = width*height; fwrite(&pfileheader, sizeof(pfileheader), 1, pfout); fwrite(&pinfoheader, sizeof(pinfoheader), 1, pfout); int i,j,k; enlarge(); for(i=0;i<height;i++) { for(j=0;j<width;j++) { if (data[i][j] > 255) data[i][j] = 255; if (data[i][j] < 0) data[i][j] = 0; } } unsigned char prep=0; for (i = 0; i < pinfoheader.biHeight; i++) { for (j = 0; j < pinfoheader.biWidth; j++) { prep=(unsigned char)(pdata[i][j]); for (k = 0; k < 3; k++) fwrite(&prep,1,1,pfout); } } fclose(pfout); } Image& Image::operator++() //Pre self addition; { int i,j; int flag=0; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if(data[i][j]>1) { flag=1; break;//Judge whether it is between zero and one } } } if(flag==1)//0-255 { for(i=0; i<height; i++) { for(j=0; j<width; j++) { data[i][j]++; } } } if(flag==0)//0-1 { for(i=0; i<height; i++) { for(j=0; j<width; j++) { data[i][j]=data[i][j]*255+1;//Zoom in to 255 plus one } } Normalize(); } return *this; } Image& Image::operator--() //Pre self subtraction; { int i,j; int flag=0; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if(data[i][j]>1) { flag=1; break;//Judge whether it is between zero and one } } } if(flag==1)//0-255 { for(i=0; i<height; i++) { for(j=0; j<width; j++) { data[i][j]--; } } } if(flag==0)//0-1 { for(i=0; i<height; i++) { for(j=0; j<width; j++) { data[i][j]=data[i][j]*255-1;//Zoom in to 255 and subtract one } } Normalize(); } return *this; } Image Image::operator++(int) //Post self adding; { Image old=*this; ++(*this); return old; } Image Image::operator--(int) //Post self subtraction; { Image old=*this; --(*this); return old; } void Image::enlarge()//If it is between 01, zoom in to 0-255 { int i,j; int flag=0; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if(data[i][j]>1) { flag=1; break;//Judge whether it is between zero and one } } } if(flag==0) { for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { data[i][j]=data[i][j]*255; } } } } Image Image::gray2bw(double t) //Binarize the image with the given threshold t and return the result image object: { int i,j; Normalize();//Zoom out to between 01 for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if(data[i][j]>=t) data[i][j]=1; else data[i][j]=0; } } return *this; } Image Image::operator-()//Invert the image, normalize the values of all pixels to between [0,1], and then each pixel is subtracted by 1.0 { int i,j; Normalize();//Zoom out to between 01 for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { data[i][j]=1-data[i][j]; } } return *this; } Image& Image::operator=(double val) //Overload the assignment operator to complete the deep copy between objects; { int i,j; Image numImage(height,width,val);//Upgrade the double num to become a Matrix object for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { data[i][j] = numImage.data[i][j]; } } return *this; }
#include <iostream> #include "Image.h" using namespace std; int main() { Image im("Fruits.bmp"); Image p=im; p.WriteBMP("=fruits.bmp"); Image p1=p-im; p1.WriteBMP("add1.bmp"); Image p2=p; for(int i;i<100;i++) { p2++; p2--; } //p2=100.0; //Matrix a(100,100,2.0); //a=1.0; //printf("%lf",a.data[10][10]); p2.WriteBMP("add2.bmp"); //p2=-p2; //p2.WriteBMP("fu.bmp"); double t=0.5; p2=p2.gray2bw(t); p2.WriteBMP("fenge.bmp"); if(p2==im) printf("1"); else printf("2"); Image im1("scene2_fg.bmp"); Image im2("scene2_bg.bmp"); Image sub=im1-im2; sub.WriteBMP("zuihouyige.bmp"); return 0; }