#include "image.h" #include #include #include #include using namespace std; //普通构造函数 Image::Image(int h, int w) :height(h), width(w) { this->height = h; this->width = w; // 动态分配二维数组存储像素数据,注意先申请一个存放指针的数组, data = (unsigned char **)malloc(sizeof(unsigned char*) * this->height); //其大小为sizeof(unsigned char*) * bitmapinfoheader.biHeight,这点很容易错 //申请行指针 for (int i = 0; i < this->height; i++) { //注意3通道,每个像素3个字节 data[i] = (unsigned char *)malloc(this->width * 3); // 读取像素数据 for (int j = 0; j < this->width; j++) { data[i][j] = 0; } } } Image::Image(int h, int w, unsigned char val)//创建的图像像素值都为val; { this->height = h; this->width = w; // 动态分配二维数组存储像素数据,注意先申请一个存放指针的数组, data = (unsigned char **)malloc(sizeof(unsigned char*) * this->height); //其大小为sizeof(unsigned char*) * bitmapinfoheader.biHeight,这点很容易错 //申请行指针 for (int i = 0; i < this->height; i++) { //注意3通道,每个像素3个字节 data[i] = (unsigned char *)malloc(this->width * 3); // 读取像素数据 for (int j = 0; j < this->width; j++) { data[i][j] = val; } } } Image::Image(const char* ImageName)//利用文件名从硬盘加载图像文件成为Image对象; { this->ReadBMP(ImageName); } Image::Image(unsigned char *m, int rows, int cols)//从一维静态数组创建Image对象,图像的行数和列数由后面两个参数给出; { this->height = rows; this->width = cols; // 动态分配二维数组存储像素数据,注意先申请一个存放指针的数组, data = (unsigned char **)malloc(sizeof(unsigned char*) * this->height); //其大小为sizeof(unsigned char*) * bitmapinfoheader.biHeight,这点很容易错 //申请行指针 for (int i = 0; i < this->height; i++) { //注意3通道,每个像素3个字节 data[i] = (unsigned char *)malloc(this->width * 3); // 读取像素数据 for (int j = 0; j < this->width; j++) { data[i][j] = *m; m++; } } } Image::Image(unsigned char m[][100], int rows)//从静态二维数组创建Image对象,图像的行数(二维数组的第一个维度)由第二个参数rows给出; { this->height = rows; this->width = 100; // 动态分配二维数组存储像素数据,注意先申请一个存放指针的数组, data = (unsigned char **)malloc(sizeof(unsigned char*) * this->height); //其大小为sizeof(unsigned char*) * bitmapinfoheader.biHeight,这点很容易错 //申请行指针 for (int i = 0; i < this->height; i++) { //注意3通道,每个像素3个字节 data[i] = (unsigned char *)malloc(this->width * 3); // 读取像素数据 for (int j = 0; j < this->width; j++) { data[i][j] = m[i][j]; } } } Image::Image(unsigned char **m, int h, int w)//从动态数组(二级指针)创建Image对象,图像的行数和列数由后面两个参数给出; { this->height = h; this->width = w; // 动态分配二维数组存储像素数据,注意先申请一个存放指针的数组, data = (unsigned char **)malloc(sizeof(unsigned char*) * this->height); //其大小为sizeof(unsigned char*) * bitmapinfoheader.biHeight,这点很容易错 //申请行指针 for (int i = 0; i < this->height; i++) { //注意3通道,每个像素3个字节 data[i] = (unsigned char *)malloc(this->width * 3); // 读取像素数据 for (int j = 0; j < this->width; j++) { data[i][j] = m[i][j]; } } } //拷贝构造函数 Image::Image(Image &im) { if (this->data) { delete[] this->data; this->data = NULL; } *this = im; } //释放堆区数据 void Image::myFree(unsigned char** data, int h) { for (int i = 0; i < h; i++) { free(data[i]); data[i] = NULL; } free(data); data = NULL; puts("释放堆区数据"); } //析构函数 Image::~Image() { this->myFree(this->data, this->height); } //从硬盘读入图像文件,存储到image类中 void Image::ReadBMP(const char* filename) { FILE* fp = NULL; // C标准库的文件指针 fp = fopen(filename, "rb"); // 二进制读取方式打开文件 // 读取文件头 fread(&bmpfileheader, sizeof(bmpfileheader), 1, fp); // 读取信息头 fread(&bitmapinfoheader, sizeof(bitmapinfoheader), 1, fp); // 动态分配二维数组存储像素数据,注意先申请一个存放指针的数组, data = (unsigned char **)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight); //其大小为sizeof(unsigned char*) * bitmapinfoheader.biHeight,这点很容易错 //申请行指针 for (int i = 0; i < bitmapinfoheader.biHeight; i++) { //注意3通道,每个像素3个字节 data[i] = (unsigned char *)malloc(bitmapinfoheader.biWidth * 3); // 读取像素数据 for (int j = 0; j < bitmapinfoheader.biWidth * 3; j++) { fread(&data[i][j], 1, 1, fp); } } this->height = this->bitmapinfoheader.biHeight; this->width = this->bitmapinfoheader.biWidth; printf("height = %d width = %d\n",this->height,this->width); // 关闭读取的文件 fclose(fp); } //保存bmp图像 void Image::WriteBMP(const char *filename) { FILE* fp = NULL; // 保存文件的文件指针 fp = fopen(filename, "wb"); // 二进制写入方式打开文件 // 写入文件头 fwrite(&bmpfileheader, sizeof(bmpfileheader), 1, fp); // 写入信息头 fwrite(&bitmapinfoheader, sizeof(bitmapinfoheader), 1, fp); // 写入数据 for (int i = 0; i < bitmapinfoheader.biHeight; i++) { fwrite(data[i], bitmapinfoheader.biWidth * 3, 1, fp); } // 关闭写入的文件 fclose(fp); } //保存bmp图像 void Image::WriteBMP(const char *filename, unsigned char** data) { FILE* fp = NULL; // 保存文件的文件指针 fp = fopen(filename, "wb"); // 二进制写入方式打开文件 // 写入文件头 fwrite(&bmpfileheader, sizeof(bmpfileheader), 1, fp); // 写入信息头 fwrite(&bitmapinfoheader, sizeof(bitmapinfoheader), 1, fp); // 写入数据 for (int i = 0; i < bitmapinfoheader.biHeight; i++) { fwrite(data[i], bitmapinfoheader.biWidth * 3, 1, fp); } // 关闭写入的文件 fclose(fp); } //保存bmp图像 void Image::WriteBMP(const char *filename, unsigned char** t_data, BMPFILEHEADER bmpfileheader, BITMAPINFOHEADER t_bitmapinfoheader) { FILE* fp = NULL; // 保存文件的文件指针 fp = fopen(filename, "wb"); // 二进制写入方式打开文件 // 写入文件头 fwrite(&bmpfileheader, sizeof(bmpfileheader), 1, fp); // 写入信息头 fwrite(&t_bitmapinfoheader, sizeof(t_bitmapinfoheader), 1, fp); // 写入数据 for (int i = 0; i < t_bitmapinfoheader.biHeight; i++) { fwrite(t_data[i], t_bitmapinfoheader.biWidth * 3, 1, fp); } // 关闭写入的文件 fclose(fp); } //从文本文件读取 void Image::ReadText(const char* filename) { FILE* fp = NULL; // C标准库的文件指针 fp = fopen(filename, "rb"); // 二进制读取方式打开文件 fread(&bitmapinfoheader.biHeight, sizeof(bitmapinfoheader.biHeight), 1, fp); fread(&bitmapinfoheader.biWidth, sizeof(bitmapinfoheader.biWidth), 1, fp); // 动态分配二维数组存储像素数据,注意先申请一个存放指针的数组, data = (unsigned char **)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight); //其大小为sizeof(unsigned char*) * bitmapinfoheader.biHeight,这点很容易错 //申请行指针 for (int i = 0; i < bitmapinfoheader.biHeight; i++) { //注意3通道,每个像素3个字节 data[i] = (unsigned char *)malloc(bitmapinfoheader.biWidth * 3); // 读取像素数据 for (int j = 0; j < bitmapinfoheader.biWidth * 3; j++) { fread(&data[i][j], 1, 1, fp); } } // 关闭读取的文件 fclose(fp); } //保存成文本文件 void Image::WriteText(const char *filename) { FILE* fp = NULL; // 保存文件的文件指针 fp = fopen(filename, "wb"); // 二进制写入方式打开文件 // 写入信息头 fwrite(&bitmapinfoheader.biHeight, sizeof(bitmapinfoheader.biHeight), 1, fp); fwrite(&bitmapinfoheader.biWidth, sizeof(bitmapinfoheader.biWidth), 1, fp); // 写入数据 for (int i = 0; i < bitmapinfoheader.biHeight; i++) { fwrite(data[i], bitmapinfoheader.biWidth * 3, 1, fp); } // 关闭写入的文件 fclose(fp); } //获取图像中指定点的值 unsigned char& Image::At(int row, int col) { return this->data[row * 3][col * 3]; } //设置像素(row,col)为某值 void Image::Set(int row, int col, unsigned char value) { //重新读取数据 unsigned char** t_data = (unsigned char**)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight); for (int i = 0; i < bitmapinfoheader.biHeight; i++) { t_data[i] = (unsigned char*)malloc(bitmapinfoheader.biWidth * 3); for (int j = 0; j < bitmapinfoheader.biWidth * 3; j++) { t_data[i][j] = data[i][j]; } } //修改像数值 for (int i = 0; i < 3; i++) { t_data[row * 3 + i][col * 3 + i] = value; } //保存图像 this->WriteBMP("setImg.bmp", t_data); myFree(t_data, bitmapinfoheader.biHeight); } //设置图像所有像素为同一值 void Image::Set(unsigned char value) { //重新读取数据 unsigned char** t_data = (unsigned char**)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight); for (int i = 0; i < bitmapinfoheader.biHeight; i++) { t_data[i] = (unsigned char*)malloc(bitmapinfoheader.biWidth * 3); for (int j = 0; j < bitmapinfoheader.biWidth * 3; j++) { t_data[i][j] = data[i][j]; } } //修改像数值 for (int i = 0; i < this->bitmapinfoheader.biHeight; i++) { for (int j = 0; j < this->bitmapinfoheader.biWidth * 3; j++) { t_data[i][j] = value; } } //保存图像 this->WriteBMP("setAllImg.bmp", t_data); myFree(t_data, bitmapinfoheader.biHeight); } //false 左右,true 上下 void Image::Flip(int code) { //重新读取数据 unsigned char** t_data = (unsigned char**)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight); for (int i = 0; i < bitmapinfoheader.biHeight; i++) { t_data[i] = (unsigned char*)malloc(bitmapinfoheader.biWidth * 3); for (int j = 0; j < bitmapinfoheader.biWidth * 3; j++) { t_data[i][j] = data[i][j]; } } if (code) { //上下翻转图片 for (int i = 0; i < bitmapinfoheader.biHeight / 2; i++) { unsigned char* temp = t_data[i]; t_data[i] = t_data[bitmapinfoheader.biHeight - 1 - i]; t_data[bitmapinfoheader.biHeight - 1 - i] = temp; } this->WriteBMP("flipImageUpDown.bmp",t_data); } else { //左右翻转图片 for (int i = 0; i < bitmapinfoheader.biHeight; i++) { for (int j = 0; j < bitmapinfoheader.biWidth * 3 / 2; j += 3) { unsigned char temp = t_data[i][j]; t_data[i][j] = t_data[i][bitmapinfoheader.biWidth * 3 - 1 - j - 2]; t_data[i][bitmapinfoheader.biWidth * 3 - 1 - j - 2] = temp; unsigned char temp1 = t_data[i][j+1]; t_data[i][j + 1] = t_data[i][bitmapinfoheader.biWidth * 3 - 1 - j - 1]; t_data[i][bitmapinfoheader.biWidth * 3 - 1 - j - 1] = temp1; unsigned char temp2 = t_data[i][j + 2]; t_data[i][j+2] = t_data[i][bitmapinfoheader.biWidth * 3 - 1 - j]; t_data[i][bitmapinfoheader.biWidth * 3 - 1 - j] = temp2; } } this->WriteBMP("flipImageLeftRight.bmp",t_data); } this->myFree(t_data, this->bitmapinfoheader.biHeight); } //图像缩小,放大 //false缩小,true放大 void Image::Resize(int code) { if (code)//放大 { /* * *难点主要在于对索引的控制, *因为这里需要两个索引控制四个变量,需要找到它们对应的关系式 */ unsigned char** t_data = (unsigned char**)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight * 2); for (int i = 0; i < bitmapinfoheader.biHeight ; i++) { t_data[2 * i] = (unsigned char*)malloc(bitmapinfoheader.biWidth * 3 * 2); for (int j = 0; j < bitmapinfoheader.biWidth; j++) { t_data[2 * i][6 * j] = data[i][3 * j]; t_data[2 * i][6 * j + 1] = data[i][3 * j + 1]; t_data[2 * i][6 * j + 2] = data[i][3 * j + 2]; t_data[2 * i][6 * j + 3] = data[i][3 * j]; t_data[2 * i][6 * j + 3 + 1] = data[i][3 * j + 1]; t_data[2 * i][6 * j + 3 + 2] = data[i][3 * j + 2]; } t_data[2 * i + 1] = (unsigned char*)malloc(bitmapinfoheader.biWidth * 3 * 2); for (int j = 0; j < bitmapinfoheader .biWidth * 6; j++) { t_data[2 * i + 1][j] = t_data[2 * i][j]; } } BMPFILEHEADER t_bmpfileheader = this->bmpfileheader; BITMAPINFOHEADER t_bitmapinfoheader = this->bitmapinfoheader; t_bitmapinfoheader.biHeight *= 2; t_bitmapinfoheader.biWidth *= 2; t_bitmapinfoheader.biSizeImage *= 4; this->WriteBMP("magnifyImage.bmp", t_data, t_bmpfileheader, t_bitmapinfoheader); this->myFree(t_data, t_bitmapinfoheader.biHeight);//释放内存 } else//缩小 { unsigned char** t_data = (unsigned char**)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight / 2); for (int i = 0; i < bitmapinfoheader.biHeight / 2; i++) { t_data[i] = (unsigned char*)malloc(bitmapinfoheader.biWidth * 3 / 2); for (int j = 0, index = 0; j < bitmapinfoheader.biWidth / 2; j++) { t_data[i][index++] = data[2 * i][6 * j]; t_data[i][index++] = data[2 * i][6 * j + 1]; t_data[i][index++] = data[2 * i][6 * j + 2]; } } BMPFILEHEADER t_bmpfileheader = this->bmpfileheader; BITMAPINFOHEADER t_bitmapinfoheader = this->bitmapinfoheader; t_bitmapinfoheader.biHeight /= 2; t_bitmapinfoheader.biWidth /= 2; t_bitmapinfoheader.biSizeImage /= 4; this->WriteBMP("shrinkImage.bmp", t_data, t_bmpfileheader, t_bitmapinfoheader); this->myFree(t_data, t_bitmapinfoheader.biHeight);//释放内存 } } //图像裁剪的函数 void Image::Cut(int x1, int y1, int x2, int y2) {//裁剪点(x1,y1)到点(x2,y2)的图像——(0,120) (512,360) h = y2 - y1 = 240, w = x2 - x1 = 512 if (x2 > x1 && y2 > y1) { int h = y2 - y1 + 1; int w = x2 - x1 + 1; while (w % 4) { w++; } //重新载入数据 unsigned char **t_data = (unsigned char**)malloc(h * sizeof(unsigned char*)); //m,n控制t_data的下标,i,j控制data下标 for (int i = y1,m = 0; i <= y2; i++, m++) { t_data[m] = (unsigned char*)malloc(w * 3); memset(t_data[m],0, w * 3); for (int j = x1*3, n = 0; j <= x2*3 + 2; j++, n++) { t_data[m][n] = data[i][j]; } } //重新载入头文件 BMPFILEHEADER t_bmpfileheader = this->bmpfileheader; BITMAPINFOHEADER t_bitmapinfoheader = this->bitmapinfoheader; t_bitmapinfoheader.biHeight = h; t_bitmapinfoheader.biWidth = w; //通过公式重新计算biSize t_bitmapinfoheader.biSizeImage = (((w*t_bitmapinfoheader.biBitCount) + 31) / 32 * 4)*h; //保存数据 WriteBMP("cutImage.bmp", t_data, t_bmpfileheader, t_bitmapinfoheader); //释放数据 myFree(t_data, h); } else { puts("输入坐标有误"); } } //图像旋转的函数 void Image::Rotate(int degree)//图像旋转的函数(简单起见,旋转角度为90度的整数倍) { BMPFILEHEADER t_bmpfileheader = this->bmpfileheader; BITMAPINFOHEADER t_bitmapinfoheader = this->bitmapinfoheader; if (degree == 90) { unsigned char** t_data = (unsigned char**)malloc(sizeof(unsigned char*) * bitmapinfoheader.biWidth); for (int i = 0; i < bitmapinfoheader.biWidth; i++) { t_data[i] = (unsigned char*)malloc(bitmapinfoheader.biHeight * 3); for (int j = 0; j < bitmapinfoheader.biHeight; j++) { t_data[i][j * 3] = data[bitmapinfoheader.biHeight - j - 1][3 * i]; t_data[i][j * 3 + 1] = data[bitmapinfoheader.biHeight - j - 1][3 * i + 1]; t_data[i][j * 3 + 2] = data[bitmapinfoheader.biHeight - j - 1][3 * i + 2]; } } //重写信息头 t_bitmapinfoheader.biHeight = this->bitmapinfoheader.biWidth; t_bitmapinfoheader.biWidth = this->bitmapinfoheader.biHeight; //保存图片 this->WriteBMP("rotate90.bmp", t_data, t_bmpfileheader, t_bitmapinfoheader); this->myFree(t_data, t_bitmapinfoheader.biHeight); } else if (degree == 180) { unsigned char** t_data = (unsigned char**)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight); for (int i = 0; i < bitmapinfoheader.biHeight; i++) { t_data[i] = (unsigned char*)malloc(bitmapinfoheader.biWidth * 3); for (int j = 0; j < bitmapinfoheader.biWidth; j++) { t_data[i][j * 3] = data[bitmapinfoheader.biHeight - i - 1][bitmapinfoheader.biWidth * 3 - j * 3 - 3]; t_data[i][j * 3 + 1] = data[bitmapinfoheader.biHeight - i - 1][bitmapinfoheader.biWidth * 3 - j * 3 - 3 + 1]; t_data[i][j * 3 + 2] = data[bitmapinfoheader.biHeight - i - 1][bitmapinfoheader.biWidth * 3 - j * 3 - 3 + 2]; } } //保存图片 this->WriteBMP("rotate180.bmp", t_data); this->myFree(t_data, t_bitmapinfoheader.biHeight); } else if (degree == 270) { unsigned char** t_data = (unsigned char**)malloc(sizeof(unsigned char*) * bitmapinfoheader.biWidth); for (int i = 0; i < bitmapinfoheader.biWidth; i++) { t_data[i] = (unsigned char*)malloc(bitmapinfoheader.biHeight * 3); for (int j = 0; j < bitmapinfoheader.biHeight; j++) { t_data[i][j * 3] = data[j][bitmapinfoheader.biWidth * 3 - 3 -i * 3]; t_data[i][j * 3 + 1] = data[j][bitmapinfoheader.biWidth * 3 - 3 - i * 3 + 1]; t_data[i][j * 3 + 2] = data[j][bitmapinfoheader.biWidth * 3 - 3 - i * 3 + 2]; } } //重写信息头 t_bitmapinfoheader.biHeight = this->bitmapinfoheader.biWidth; t_bitmapinfoheader.biWidth = this->bitmapinfoheader.biHeight; //保存图片 this->WriteBMP("rotate270.bmp", t_data, t_bmpfileheader, t_bitmapinfoheader); this->myFree(t_data, t_bitmapinfoheader.biHeight); } else { puts("输入的角度不符合要求"); } } //求均值方差 void Image::Mean_Variance(float &m, float &var)//求图像的均值和方差,利用参数输出 { float sum = 0; float ave = 0; float vSum = 0; float vAve = 0; for (int i = 0; i < bitmapinfoheader.biHeight; i++) { for (int j = 0; j < bitmapinfoheader.biWidth * 3; j++) { sum += this->data[i][j]; } } ave = sum / (bitmapinfoheader.biHeight*bitmapinfoheader.biWidth * 3); for (int i = 0; i < bitmapinfoheader.biHeight; i++) { for (int j = 0; j < bitmapinfoheader.biWidth * 3; j++) { vSum += (data[i][j] - ave)*(data[i][j] - ave); } } vAve = vSum / (bitmapinfoheader.biHeight*bitmapinfoheader.biWidth * 3); m = ave; var = vAve; } Image& Image::operator=(Image& val)//重载操作符 { this->bitmapinfoheader = val.bitmapinfoheader; this->bmpfileheader = val.bmpfileheader; this->height = val.height; this->width = val.width; // 动态分配二维数组存储像素数据,注意先申请一个存放指针的数组, this->data = (unsigned char **)malloc(sizeof(unsigned char*) * bitmapinfoheader.biHeight); //其大小为sizeof(unsigned char*) * bitmapinfoheader.biHeight,这点很容易错 //申请行指针 for (int i = 0; i < bitmapinfoheader.biHeight; i++) { //注意3通道,每个像素3个字节 this->data[i] = (unsigned char *)malloc(bitmapinfoheader.biWidth * 3); // 读取像素数据 for (int j = 0; j < bitmapinfoheader.biWidth * 3; j++) { this->data[i][j] = val.data[i][j]; } } return *this; } //实现友元函数,交换两个Image对象的数据 void Swap(Image &a, Image &b) { Image t(a); a = b; b = t; }