bmp_v1/test/image.cpp

620 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "image.h"
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
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;
}