图像信息处理实验四

要求:

1.Translation

2.Rotation

3.Scale

4.Shear

5.Mirror


#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cmath>

#define Pi 3.14159
using namespace std;

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
WORD bfType;
int h,w;    //图像的高度和宽度
int size;   //像素个数
typedef struct tagIMAGEP  //每个像素
{
	BYTE blue;
	BYTE green;
	BYTE red;
}P;

typedef struct tagBITMAPINFOHEADER{
	DWORD biSize;//信息头大小
	DWORD biWidth;//图像宽度
	DWORD biHeight;//图像高度
	WORD biPlanes;//位平面数,必须为1
	WORD biBitCount;//每像素位数
	DWORD  biCompression; //压缩类型
	DWORD  biSizeImage; //压缩图像大小字节数
	DWORD  biXPelsPerMeter; //水平分辨率
	DWORD  biYPelsPerMeter; //垂直分辨率
	DWORD  biClrUsed; //位图实际用到的色彩数
	DWORD  biClrImportant; //本位图中重要的色彩数
}BITMAPINFOHEADER; //位图信息头定义

typedef struct  tagBITMAPFILEHEADER{
	DWORD bfSize;//文件大小
	WORD bfReserved1;//保留字
	WORD bfReserved2;//保留字
	DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数
}BITMAPFILEHEADER;

BITMAPFILEHEADER strHead;
BITMAPINFOHEADER strInfo;
int mW;   //取整的宽度
int cx,cy;  //中心宽度,高度坐标

void mirror(const P* before){
	P* Q = new P[size];
	memset(Q, 0, sizeof(P) * size);
	for (int i = 0; i < h; i++){
		for (int j = 0; j < mW; j++){
			Q[i*mW + j] = before[i*mW + mW - 1 - j];
		}
	}
    //建新文件
	FILE *fpo1;
	fpo1=fopen("mirr.bmp","wb");
	fwrite(&bfType,1,sizeof(WORD),fpo1);
	fwrite(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpo1);
	fwrite(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpo1);
	fwrite(Q,1,sizeof(P)*(size),fpo1);
	fclose(fpo1);
	delete[] Q;
}

void translation(const P* before, int x, int y){
	int moveX, moveY;
	//对4取整
	if(x % 4 == 0)
		moveX = x;
	else
		moveX = x/4*4;
	moveY = y;
    //新坐标
	int nH = h + moveY;
	int nW = mW + moveX;
	//新像素数
	int newSize = nH * nW;
	P* Q = new P[newSize];
	memset(Q, 0, sizeof(P)*newSize);
	//处理每个像素
	for (int i = 0; i < nH; i++){
		for (int j = 0; j < nW; j++){
			if(i < moveY){
				Q[i*nW + j].red = Q[i*nW + j].blue = Q[i*nW + j].green = 0;
				continue;
			}
			if(j < moveX)
				Q[i*nW + j].red = Q[i*nW + j].blue = Q[i*nW + j].green = 0;
			else
				Q[i*nW + j] = before[(i- moveY)*mW + (j - moveX)];
		}
	}
	//建立新的文件
	FILE *fpo1;
	fpo1=fopen("trans.bmp","wb");
	//新的文件头信息头
	BITMAPFILEHEADER nHead = strHead;
	BITMAPINFOHEADER newInfo = strInfo;
	//新的图像大小
	nHead.bfSize = (DWORD)(nHead.bfSize - size*3 + newSize*3);
	//新的图像高度和宽度
	newInfo.biHeight = (DWORD)nH;
	newInfo.biWidth = (DWORD)nW;
	newInfo.biSizeImage = (DWORD)(newSize * 3);
	fwrite(&bfType,1,sizeof(WORD),fpo1);
	fwrite(&nHead,1,sizeof(tagBITMAPFILEHEADER),fpo1);
	fwrite(&newInfo,1,sizeof(tagBITMAPINFOHEADER),fpo1);
	fwrite(Q,1,sizeof(P)*(newSize),fpo1);
	fclose(fpo1);
	//释放空间
	delete[] Q;
}
//坐标处理
double xAfterRot(int x, int y, double theta){
	x = x - cx;
	y = y - cy;
	double result = x * cos(theta) - y * sin(theta);
	return result += cx;
}
double yAfterRot(int x, int y, double theta){
	x = x - cx;
	y = y - cy;
	double result = x * sin(theta) + y * cos(theta);
	return result += cy;
}

void tXY(int &x, int &y, double theta){
	double tmpX[4],tmpY[4];
	double minX = 999999, minY = 999999, maxX = 0, maxY = 0;

	tmpX[0] = xAfterRot(0, 0, theta);
	tmpY[0] = yAfterRot(0, 0, theta);
	tmpX[1] = xAfterRot(mW, 0, theta);
	tmpY[1] = yAfterRot(mW, 0, theta);
	tmpX[2] = xAfterRot(mW, h, theta);
	tmpY[2] = yAfterRot(mW, h, theta);
	tmpX[3] = xAfterRot(0, h, theta);
	tmpY[3] = yAfterRot(0, h, theta);

	for(int i = 0; i < 4; i++){
		minX = min(tmpX[i], minX);
		maxX = max(tmpX[i], maxX);
		minY = min(tmpY[i], minY);
		maxY = max(tmpY[i], maxY);
	}
	x = (int)(maxX - minX + 2);
	y = (int)(maxY - minY + 2);
}

void rotation(const P* before, double theta){
	int nH;
	int nW;
	tXY(nW, nH, theta);
	if(nW % 4 !=0)
		nW = (nW / 4 + 1) * 4;
	int newSize = nH * nW;
	P* Q = new P[newSize];
	int* tK = new int[newSize];
	int* minIndexX = new int[nH];
	int* maxIndexX = new int[nH];
	int* minIndexY = new int[nW];
	int* maxIndexY = new int[nW];

	memset(Q, 0, sizeof(P)*newSize);
	for(int i = 0 ; i < nH; i++)
		minIndexX[i] = 999999;
	for(int i = 0; i < nW; i++)
		minIndexY[i] = 999999;
	memset(maxIndexX, 0, sizeof(int)*nH);
	memset(maxIndexY, 0, sizeof(int)*nW);

	for(int i = 0; i < newSize; i++)
		tK[i] = 1;

	int moveX = (nW - mW)/2;
	int moveY = (nH - h)/2;

	for(int i = 0; i < h; i++){
		for(int j = 0; j < mW; j++){
			int tmpX = (int)xAfterRot(j, i, theta) + moveX;
			int tmpY = (int)yAfterRot(j, i, theta) + moveY;
			Q[tmpY*nW + tmpX] = before[i*mW + j];
			tK[tmpY*nW + tmpX] = 0;
			minIndexX[tmpY] = min(tmpX,minIndexX[tmpY]);
			maxIndexX[tmpY] = max(tmpX,maxIndexX[tmpY]);
			minIndexY[tmpX] = min(tmpY,minIndexY[tmpX]);
			maxIndexY[tmpX] = max(tmpY,maxIndexY[tmpX]);
		}
	}

	//first do the horizontal interpolation
	for(int i = 0; i < nH; i++){
		int last = -1;
		for(int j = 0; j < nW; j++){
			if(j < minIndexX[i] || j > maxIndexX[i]){
				Q[i*nW + j].red = 255;
				Q[i*nW + j].green = 255;
				Q[i*nW + j].blue = 255;
				continue;
			}
			if(tK[i*nW + j] == 0){
				last = j;
				continue;
			}
			else{
				int k = j;
				//find next position which has value
				while(k < nW && tK[i*nW + k] == 1){
					k++;
				}
				if(k >= nW){			//in the last position of the line
					if(last == -1)
						break;
					Q[i*nW + j] = Q[i*nW + last];
				}
				else{
					if(last == -1){		//in the first position of the line
						Q[i*nW + j] = Q[i*nW + k];
					}
					else{				//in the middle
						float coe = (j-last)*1.0/(k-last);
						Q[i*nW + j].red = (BYTE)(((int)Q[i*nW + k].red - (int)Q[i*nW + last].red)*coe + (int)Q[i*nW + last].red);
						Q[i*nW + j].blue = (BYTE)(((int)Q[i*nW + k].blue - (int)Q[i*nW + last].blue)*coe + (int)Q[i*nW + last].blue);
						Q[i*nW + j].green = (BYTE)(((int)Q[i*nW + k].green - (int)Q[i*nW + last].green)*coe + (int)Q[i*nW + last].green);
					}
				}
			}
			tK[i*nW + j] = 0;
		}
	}
	//then do the vertical interpolation
	for(int i = 0; i < nW; i++){
		int last = -1;
		for(int j = 0; j < nH; j++){
			if(j < minIndexY[i] || j > maxIndexY[i]){
				continue;
			}
			if(tK[j*nW + i] == 0){
				last = j;
				continue;
			}
			else{
				int k = j;
				//find next position which has value
				while(k < nH && tK[k*nW + i] == 1){
					k++;
				}
				if(k >= nH){			//in the last position of the line
					if(last == -1)
						break;
					Q[j*nW + i] = Q[last*nW + i];
				}
				else{
					if(last == -1){		//in the first position of the line
						Q[j*nW + i] = Q[k*nW + i];
					}
					else{				//in the middle
						float coe = (j-last)*1.0/(k-last);
						Q[j*nW + i].red = (BYTE)(((int)Q[k*nW + i].red - (int)Q[last*nW + i].red)*coe + (int)Q[last*nW + i].red);
						Q[j*nW + i].blue = (BYTE)(((int)Q[k*nW + i].blue - (int)Q[last*nW + i].blue)*coe + (int)Q[last*nW + i].blue);
						Q[j*nW + i].green = (BYTE)(((int)Q[k*nW + i].green - (int)Q[last*nW + i].green)*coe + (int)Q[last*nW + i].green);
					}
				}
			}
			tK[j*nW + i] = 0;
		}
	}

    //把新生成的数据写入文件
	FILE *fpo1;
	fpo1=fopen("rotat.bmp","wb");
	BITMAPFILEHEADER nHead = strHead;
	BITMAPINFOHEADER newInfo = strInfo;
	nHead.bfSize = (DWORD)(nHead.bfSize - size*3 + newSize*3);
	newInfo.biHeight = (DWORD)nH;
	newInfo.biWidth = (DWORD)nW;
	newInfo.biSizeImage = (DWORD)(newSize * 3);
	fwrite(&bfType,1,sizeof(WORD),fpo1);
	fwrite(&nHead,1,sizeof(tagBITMAPFILEHEADER),fpo1);
	fwrite(&newInfo,1,sizeof(tagBITMAPINFOHEADER),fpo1);
	fwrite(Q,1,sizeof(P)*(newSize),fpo1);
	fclose(fpo1);
	delete[] Q;
	delete[] tK;
}

void shear(const P* before, double angle){
	int nH, nW ,newSize;
	P* Q;
	int* tK;

	nW = mW;

	nH = h + tan(angle)*mW;
	newSize = nW * nH;
	Q = new P[newSize];
	tK = new int[newSize];
    //判断所有像素是否已经有信息的标记数组
	for(int i = 0; i < newSize; i++)
		tK[i] = 1;
    //原来的
	for(int i = 0; i < h; i++){
		for(int j = 0; j < mW; j++){
            //求变换后的横纵坐标,并赋值对应的像素
			int tmpX = j;
			int tmpY = (int)(i + tan(angle)*j);
			Q[tmpY * nW + tmpX] = before[i*mW + j];
            //有信息后标记为0
			tK[tmpY * nW + tmpX] = 0;
		}
	}
    //没图像的位置都用白色填充
	for(int i = 0; i < newSize; i++)
		if(tK[i] == 1)
			Q[i].red = Q[i].green = Q[i].blue = 255;
    //新文件
	FILE *fpo1;
	fpo1=fopen("shear.bmp","wb");
	BITMAPFILEHEADER nHead = strHead;
	BITMAPINFOHEADER newInfo = strInfo;
	nHead.bfSize = (DWORD)(nHead.bfSize - size*3 + newSize*3);
	newInfo.biHeight = (DWORD)nH;
	newInfo.biWidth = (DWORD)nW;
	newInfo.biSizeImage = (DWORD)(newSize * 3);
	fwrite(&bfType,1,sizeof(WORD),fpo1);
	fwrite(&nHead,1,sizeof(tagBITMAPFILEHEADER),fpo1);
	fwrite(&newInfo,1,sizeof(tagBITMAPINFOHEADER),fpo1);
	fwrite(Q,1,sizeof(P)*(newSize),fpo1);
	fclose(fpo1);
	delete[] Q;
	delete[] tK;
}
//缩小放大
void scale(const P* before, float x, float y){
    //新的图像高度和宽度
	int nH = (int)(h * y);
	int tW = (int)(w * x);
	int nW;
	//对4取整
	if(tW % 4 == 0)
		nW = tW;
	else
		nW = (tW / 4 + 1) * 4;
	//新的图像大小
	int newSize = nH * nW;
	P* Q = new P[newSize];
	int* tK = new int[newSize];
	//先把整个图像置0
	memset(Q, 0, sizeof(P)*newSize);
	memset(tK, 0, sizeof(int)*newSize);
	//扫描需要的新图像
	for(int i = 0; i < nH; i++){
		for(int j = 0; j < nW; j++){
			float tX,tY;
			int intX,intY;
			//scale之后的坐标
			tX = (j*1.0/x);
			tY = (i*1.0/y);
			intX = (int)tX;
			intY = (int)tY;

			if(tX >= mW || tY >= h)
				Q[i*nW+j].red = Q[i*nW+j].green = Q[i*nW+j].blue = 255;
			else if(tX - intX > 0 || tY - intY > 0){
				Q[i*nW+j].red = Q[i*nW+j].green = Q[i*nW+j].blue = 255;
				tK[i*nW+j] = 1;
			}
			else
				Q[i*nW+j] = before[intY*mW + intX];
		}
	}
	//水平scale
	for(int i = 0; i < nH; i++){
		int last = -1;
		for(int j = 0; j < nW; j++){
			if(tK[i*nW + j] == 0){
				last = j;
				continue;
			}
			else{
				int k = j;
				//找到下一个有值的地方
				while(k < nW &&tK[i*nW + k] == 1 )
					k++;
				if(k >= nW){			//行最后
					if(last == -1)
						break;
					Q[i*nW + j] = Q[i*nW + last];
				}
				else{
					if(last == -1)	//行头
						Q[i*nW + j] = Q[i*nW + k];
					else{
						float coe = (j-last)*1.0/(k-last);
						Q[i*nW + j].red = (BYTE)(((int)Q[i*nW + k].red - (int)Q[i*nW + last].red)*coe + (int)Q[i*nW + last].red);
						Q[i*nW + j].blue = (BYTE)(((int)Q[i*nW + k].blue - (int)Q[i*nW + last].blue)*coe + (int)Q[i*nW + last].blue);
						Q[i*nW + j].green = (BYTE)(((int)Q[i*nW + k].green - (int)Q[i*nW + last].green)*coe + (int)Q[i*nW + last].green);
					}
				}
			}
			tK[i*nW + j] = 0;
		}
	}
	//竖直scale,这次没有
	for(int i = 0; i < nW; i++){
		int last = -1;
		for(int j = 0; j < nH; j++){
			if(tK[j*nW + i] == 0){
				last = j;
				continue;
			}
			else{
				int k = j;
				//find next position which has value
				while(k < nH && tK[k*nW + i] == 1){
					k++;
				}
				if(k >= nH){			//行最后
					if(last == -1)
						break;
					Q[j*nW + i] = Q[last*nW + i];
				}
				else{
					if(last == -1){		//行头
						Q[j*nW + i] = Q[k*nW + i];
					}
					else{
						float coe = (j-last)*1.0/(k-last);
						Q[j*nW + i].red = (BYTE)(((int)Q[k*nW + i].red - (int)Q[last*nW + i].red)*coe + (int)Q[last*nW + i].red);
						Q[j*nW + i].blue = (BYTE)(((int)Q[k*nW + i].blue - (int)Q[last*nW + i].blue)*coe + (int)Q[last*nW + i].blue);
						Q[j*nW + i].green = (BYTE)(((int)Q[k*nW + i].green - (int)Q[last*nW + i].green)*coe + (int)Q[last*nW + i].green);
					}
				}
			}
			tK[j*nW + i] = 0;
		}
	}
    //新文件
	FILE *fpo1;
	fpo1=fopen("scale.bmp","wb");
	BITMAPFILEHEADER nHead = strHead;
	BITMAPINFOHEADER newInfo = strInfo;
	nHead.bfSize = (DWORD)(nHead.bfSize - size*3 + newSize*3);
	newInfo.biHeight = (DWORD)nH;
	newInfo.biWidth = (DWORD)nW;
	newInfo.biSizeImage = (DWORD)(newSize * 3);
	fwrite(&bfType,1,sizeof(WORD),fpo1);
	fwrite(&nHead,1,sizeof(tagBITMAPFILEHEADER),fpo1);
	fwrite(&newInfo,1,sizeof(tagBITMAPINFOHEADER),fpo1);
	fwrite(Q,1,sizeof(P)*(newSize),fpo1);
	fclose(fpo1);
	delete[] Q;
	delete[] tK;
}

int main(){
	FILE *fpi;
	fpi=fopen("a.bmp","rb");
	if(fpi != NULL){
		//先读取文件类型
		fread(&bfType,1,sizeof(WORD),fpi);
		if(0x4d42!=bfType) {
			printf("不是bmp图像");
			return 0;
		}
		//读取bmp文件的文件头和信息头
		fread(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpi);
		fread(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpi);
       	h=strInfo.biHeight;
       	w=strInfo.biWidth;
       	//如果图像宽度不是4的倍数要取整
       	if(w % 4 == 0)
       		mW = w;
       	else
       		mW = (w/4+1)*4;
        //图像像素数
       	size=strInfo.biSizeImage/3;
        //一个图像所有像素存在数组里
        P *imgP=new P[size];
        //读取bmp数据信息
		fread(imgP,1,sizeof(P)*size,fpi);
		fclose(fpi);
		cx = mW / 2;
		cy = h / 2;
		int x,y;
		//5个操作
		translation(imgP, 90, 0);
		mirror(imgP);
		scale(imgP, 0.5, 1);
		rotation(imgP, 45.0 / 180 * Pi);
		shear(imgP,25.0 / 180 * Pi);
		delete[] imgP;
	}
	else
		printf("fail to open the file");
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水木流年追梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值