diff --git a/output/bw2x3(output).bmp b/output/bw2x3(output).bmp index b56ab8a..1bd6edb 100644 Binary files a/output/bw2x3(output).bmp and b/output/bw2x3(output).bmp differ diff --git a/tempCodeRunnerFile.c b/tempCodeRunnerFile.c new file mode 100644 index 0000000..a1147f4 --- /dev/null +++ b/tempCodeRunnerFile.c @@ -0,0 +1,2 @@ + + *height = info_h.biHeight; \ No newline at end of file diff --git a/test/hello.bmp b/test/hello.bmp new file mode 100644 index 0000000..7c6eeea Binary files /dev/null and b/test/hello.bmp differ diff --git a/test/image.cpp b/test/image.cpp new file mode 100644 index 0000000..2a90733 --- /dev/null +++ b/test/image.cpp @@ -0,0 +1,619 @@ +#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; +} diff --git a/test/image.h b/test/image.h new file mode 100644 index 0000000..fbbf861 --- /dev/null +++ b/test/image.h @@ -0,0 +1,60 @@ +#ifndef IMAGE_H +#define IMAGE_H +#include "struct.h" + +class Image +{ +public: + //构造函数及其重载 + Image(){}//创建行列都为零的Image对象 + Image(int h, int w);//创建h行,w列的Image对象 + Image(int h, int w, unsigned char val); //创建的图像像素值都为val; + Image(const char* ImageName); //利用文件名从硬盘加载图像文件成为Image对象; + Image(unsigned char *m, int rows, int cols); //从一维静态数组创建Image对象,图像的行数和列数由后面两个参数给出; + Image(unsigned char m[][100], int rows); //从静态二维数组创建Image对象,图像的行数(二维数组的第一个维度)由第二个参数rows给出; + Image(unsigned char **m, int h, int w); //从动态数组(二级指针)创建Image对象,图像的行数和列数由后面两个参数给出; + Image(Image &im); //拷贝构造函数; + ~Image(); //析构函数; + + + void ReadBMP(const char* filename); //从BMP文件中读入图像数据; + void WriteBMP(const char* filename); //将图像数据保存为BMP图像文件; + void WriteBMP(const char *filename, unsigned char** data);//翻转时写图片 + void WriteBMP(const char *filename, unsigned char** data,//放缩时写图片 + BMPFILEHEADER bmpfileheader, BITMAPINFOHEADER bitmapinfoheader); + + + void ReadText(const char* filename); //从文本文件中读入图像数据; + void WriteText(const char* filename); //将图像数据保存为文本文件; + + + unsigned char& At(int row, int col); //获取第row行第col列的像素点的值; + void Set(int row, int col, unsigned char value); //设置像素(row,col)为某值; + void Set(unsigned char value); //设置图像所有像素为同一值; + + + void Flip(int code); //图像的翻转; 根据code的值:0:左右翻转,1:上下翻转; + void Resize(int code); //图像的缩放;根据code的值:0:缩小一倍,1:放大一倍; + + + void Cut(int x1, int y1, int x2, int y2);//裁剪点(x1,y1)到点(x2,y2)的图像 + + + void Rotate(int degree);//图像旋转的函数(简单起见,旋转角度为90度的整数倍) + + + void Mean_Variance(float &m, float &var);//求图像的均值和方差,利用参数输出 + + friend void Swap(Image &a, Image &b);//使用友元函数交换两个Image对象的数据 + void myFree(unsigned char** data, int h); + Image& operator=(Image& val);//重载操作符 + +private: + unsigned char **data; + int height; + int width; + BMPFILEHEADER bmpfileheader; + BITMAPINFOHEADER bitmapinfoheader; +}; + +#endif diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..7dd6237 --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,75 @@ +#include "image.h" +#include +#include + +int main(int argc, char* argv[]) +{ + Image img; //创建对象 + //读写BMP文件 + img.ReadBMP("hello.bmp"); + img.WriteBMP("FruitsCopy.bmp"); + img.WriteText("FruitsCopy.text"); + + + //读写text文件 + Image readtxtImage; + readtxtImage.ReadText("FruitsCopy.text"); + readtxtImage.WriteText("writeFruits.text"); + + + //图像的上下翻转,并保存结果图像文件 + img.Flip(true); + //图像的左右翻转,如img.Flip(true);并保存结果图像文件 + img.Flip(false); + //左右翻转需要注意,每个像数占3个字节,翻转时不能简单直接翻转, + //而需要每个字节对应地翻转 + + + //图像的缩放,并保存结果图像文件 + img.Resize(false);//图像缩小 + img.Resize(true);//图像放大 + //缩小时也需要注意,每个像数占3个字节,不能简单通过删除字节而缩小, + //而需要每个字节对应地删除 + //放大也是一样的道理 + + + //获取图像的某点的像素值,并修改, 并保存结果图像文件 + int row = 100; + int col = 100; + img.At(row, col); + img.Set(row, col, 10); + img.Set(100); + + + //使用拷贝构造函数创建新的对象 + Image new_img(img); + new_img.WriteBMP("new_img.bmp"); + + + //截取指定区域内的图像,并保存结果图像文件(x1,y1) (x2,y2) + new_img.Cut(120,120,360,360); + //需要保证 x2 > x1 && y2 > y1 + + + //顺时针旋转图像并保存结果图像文件(简单起见,旋转角度为90度的整数倍) + img.Rotate(90); + img.Rotate(180); + img.Rotate(270); + + + //求图像的均值和方差,并在命令行输出 + float ave = 0; + float vAve = 0; + img.Mean_Variance(ave, vAve); + printf("平均值为:%f\n方差为:%f\n", ave, vAve); + + + //交换两个图像的数据 + Image img1("Baboon.bmp"); + Image img2("Lena.bmp"); + Swap(img1, img2); + //保存交换完的结果图像文件 + img1.WriteBMP("S_img1_baboon.bmp"); + img2.WriteBMP("S_img2_lena.bmp"); + return 0; +} diff --git a/test/struct.h b/test/struct.h new file mode 100644 index 0000000..10216cd --- /dev/null +++ b/test/struct.h @@ -0,0 +1,35 @@ +#ifndef STRUCT_H +#define STRUCT_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; //本结构所占用字节数 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; //位图显示过程中重要的颜色数 +}; + +#endif + diff --git a/transfer.c b/transfer.c index 05141e0..677a1c2 100644 --- a/transfer.c +++ b/transfer.c @@ -185,9 +185,9 @@ int main(int argc, char const *argv[]) { // 建構 Imgraw img = {0, 0, 0, NULL}; // 讀圖 - Imgraw_Read(&img, "./input/bw2x3.bmp"); + Imgraw_Read(&img, "./input/bw2x1.bmp"); // 寫圖 - Imgraw_Writ(&img, "./output/bw2x3(output).bmp", radio_w, radio_h); + Imgraw_Writ(&img, "./output/bw2x1(output).bmp", radio_w, radio_h); return 0; } /*==============================================================*/ \ No newline at end of file diff --git a/transfer.exe b/transfer.exe new file mode 100644 index 0000000..b04c173 Binary files /dev/null and b/transfer.exe differ diff --git a/try.c b/try.c index 5a820ed..9a3c71e 100644 --- a/try.c +++ b/try.c @@ -36,7 +36,7 @@ float linear_single(float x, float x1, float x2, float f1, float f2){ // 鍙岀嚎鎬ф彃鍊煎嚱鏁 // 鍙傝 https://zh.wikipedia.org/wiki/%E5%8F%8C%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC -char linear_insert(uch** old_pixels, uint32_t row, uint32_t col, uint32_t old_width, uint32_t old_height, float radio_w, float radio_h){ +char** linear_insert(uch** old_pixels, uint32_t row, uint32_t col, uint32_t old_width, uint32_t old_height, float radio_w, float radio_h){ float x = row / radio_h; float y = col / radio_w; // 濡傛灉鏁存暟鏍肩偣灏辩洿鎺ヨ繑鍥 @@ -47,7 +47,9 @@ char linear_insert(uch** old_pixels, uint32_t row, uint32_t col, uint32_t old_wi if (x2 >= old_height){x2 = x1;} if (y2 >= old_width){y2 = y1;} - if (x1 == x2 && y1 == y2){return old_pixels[x1][y1];} + if (x1 == x2 && y1 == y2){ + uint32_t idx = x1*old_width+y1; + return old_pixels[x1][idx + 0], old_pixels[x1][idx + 1], old_pixels[x1][idx + 2];} if (x1 == x2){ int x = x1; uint32_t idx1 = x*old_width+y; @@ -156,7 +158,7 @@ void bmpWrite(const char* name, const uch* raw_img, uint32_t width, uint32_t hei for(unsigned i = 0; i < new_width; ++i) { uint32_t idx = j*new_width +i; if(bits == 24) { // RGB鍦栫墖 - char* r, g, b = linear_insert(&raw_img, j, i, width, height, radio_w, radio_h); + char** r, g, b = linear_insert(&(raw_img), j, i, width, height, radio_w, radio_h); fwrite(b, sizeof(char), sizeof(uch), pFile); fwrite(g, sizeof(char), sizeof(uch), pFile); fwrite(r, sizeof(char), sizeof(uch), pFile); @@ -198,7 +200,7 @@ void bmpRead(const char* name, uch** oldpixels, uint32_t* width, uint32_t* heigh *width = info_h.biWidth; *height = info_h.biHeight; *bits = info_h.biBitCount; - unsigned char **oldpixels=(unsigned char**)malloc((*width)*(*height)*3); + **oldpixels=(unsigned char**)malloc((*width)*(*height)*3); // size_t ImgSize = ((size_t)*width) * ((size_t)*height) * 3; // *raw_img = (uch*)calloc(ImgSize, sizeof(uch)); @@ -243,17 +245,17 @@ void bmpRead(const char* name, uch** oldpixels, uint32_t* width, uint32_t* heigh // fclose(pFile); //---------------------------------------------------------------------------- - // for(int j = *height-1; j >= 0; --j) { - // for(unsigned i = 0; i < *width; ++i) { - // uint32_t idx = j*(*width)+i; - // for(int k = 0; k < 3; k++){ - // printf((char*)&(*raw_img)[idx*3 + k]); - // printf("\t"); - // } - // printf("\t done \t"); - // } - // printf("\n"); - // } + for(int j = *height-1; j >= 0; --j) { + for(unsigned i = 0; i < *width; ++i) { + uint32_t idx = j*(*width)+i; + for(int k = 0; k < 3; k++){ + printf((char*)&(*oldpixels)[idx*3 + k]); + printf("\t"); + } + printf("\t done \t"); + } + printf("\n"); + } } // 鍦栧儚绲愭 @@ -278,7 +280,7 @@ int main(int argc, char const *argv[]) { scanf("%f", &radio_w); printf("Enter a radio of height :") ; scanf("%f", &radio_h); - printf("%f :: %f\n", radio_w, radio_h); + printf("\n"); // 寤烘 Imgraw img = {0, 0, 0, NULL}; // 璁鍦 diff --git a/try.exe b/try.exe new file mode 100644 index 0000000..1d98d5d Binary files /dev/null and b/try.exe differ