6 - 几何变换

参考资料:
C语言数字图像处理—1.5图像基本变换之平移缩放旋转
c语言数字图像处理(三):仿射变换
书籍:数字图像处理与机器视觉 —— Visual C++ 与 Matlab 实现

1、几何变换的介绍

         图像几何变换又称为图像的空间变换,它将一幅图像中的坐标位置映射到另一幅图像中的新坐标位置。几何变换的关键就是确定这种空间映射关系,以及映射过程中的变换参数。
         几何变换不改变图像的像素值,只是在图像平面上进行像素的重新安排。一个几何变换通常需要两个部分运算。

  1. 空间变换所需要的运算。例如,平移、镜像等。需要用它来表示输出图像与输入图像之间的像素映射关系。
  2. 插值算法。因为在计算变换关系的时候,有可能输出图像的像素会被映射到输入图像的非整数坐标上。

2、平移

1、公式说明:

平移公式

2、实现

/************************************************************
*Function:		inMove
*Description:	图像的平移
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*				x - 横轴平移的图像信息,正值表示向右平移,负值表示向左平移
*				y - 纵轴平移的图像信息,正值表示向下平移,负值表示向上平移
*Return:		outArr - 结果图像的有效二维数组
************************************************************/
uint8_t** inMove(uint8_t** inArray, uint32_t width, uint32_t height, int x, int y)
{
	// 生成结果图片的二维数组
	uint8_t** outArr = new uint8_t * [height];
	for (uint32_t i = 0; i < height; i++) {
		outArr[i] = new uint8_t[width];
	}

	// 平移
	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			int srcY = i - y, srcX = j - x;			// 映射的原始坐标计算
			outArr[i][j] = isInArray(srcX, srcY, width, height) ? inArray[srcY][srcX] : 0;
		}
	}

	return outArr;
}

3、镜像

1、公式说明

在这里插入图片描述 在这里插入图片描述

2、实现

/************************************************************
*Function:		horMirror
*Description:	图像的水平镜像
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*Return:		outArr - 结果图像的有效二维数组
************************************************************/
uint8_t** horMirror(uint8_t** inArray, uint32_t width, uint32_t height)
{
	uint8_t** outArr = new uint8_t * [height];
	for (uint32_t i = 0; i < height; i++) {
		outArr[i] = new uint8_t[width];
	}

	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			outArr[i][j] = inArray[i][width - 1 - j];
		}
	}

	return outArr;
}


/************************************************************
*Function:		verMirror
*Description:	图像的垂直镜像
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*Return:		outArr - 结果图像的有效二维数组
************************************************************/
uint8_t** verMirror(uint8_t** inArray, uint32_t width, uint32_t height)
{
	uint8_t** outArr = new uint8_t * [height];
	for (uint32_t i = 0; i < height; i++) {
		outArr[i] = new uint8_t[width];
	}

	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			outArr[i][j] = inArray[height - 1 - i][j];
		}
	}

	return outArr;
}

4、转置

1、公式说明

在这里插入图片描述 在这里插入图片描述

/************************************************************
*Function:		transpose
*Description:	图像的转置,x、y 的坐标相互转置为 y、x
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*Return:		outArr - 结果图像的有效二维数组
************************************************************/
uint8_t** transpose(uint8_t** inArray, uint32_t width, uint32_t height)
{
	uint32_t outHeight = width, outWidth = height;

	uint8_t** outArr = new uint8_t * [outHeight];
	for (uint32_t i = 0; i < outHeight; i++) {
		outArr[i] = new uint8_t[outWidth];
	}

	for (int i = 0; i < outHeight; i++) {
		for (int j = 0; j < outWidth; j++) {
			outArr[i][j] = inArray[j][i];
		}
	}

	return outArr;
}

5、缩放

1、公式说明


在这里插入图片描述

2、实现

/************************************************************
*Function:		NearInterpolation
*Description:	临近插值,图像的缩放
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*				outArray - 目标图像的有效二维数组
*				outWidth - 图像宽度
*				outHeight - 图像高度
*Return:		None
************************************************************/
void NearInterpolation(uint8_t** inArray, uint32_t width, uint32_t height, uint8_t** outArray, uint32_t outWidth, uint32_t outHeight)
{
	// 计算放大、缩小的倍数
	double heightTimes = (double)height / (double)outHeight;
    double widthTimes = (double)width / (double)outWidth;

	// 进行坐标计算
	for (uint32_t i = 0; i < outHeight; i++) {
		for (uint32_t j = 0; j < outWidth; j++) {
            int yPoint = Clipping((int)round(i * heightTimes), 0, height - 1);			// 临近插值,进行四舍五入、限幅之后计算原始坐标位置
			int xPoint = Clipping((int)round(j * widthTimes), 0, width - 1);
			outArray[i][j] = inArray[yPoint][xPoint];
		}
	}
}


/************************************************************
*Function:		BilinearInterpolation
*Description:	双线性插值,图像的缩放
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*				outArray - 目标图像的有效二维数组
*				outWidth - 图像宽度
*				outHeight - 图像高度
*Return:		None
************************************************************/
void BilinearInterpolation(uint8_t** inArray, uint32_t width, uint32_t height, uint8_t** outArray, uint32_t outWidth, uint32_t outHeight)
{
	// 计算放大、缩小的倍数
	double heightTimes = (double)height / (double)outHeight;
	double widthTimes = (double)width / (double)outWidth;

	// 定义相关变量
	double x = 0, y = 0;							// 定义 原始坐标对应位置
	int x1 = 0, y1 = 0, x2 = 0, y2 = 0;				// 对应范围的四个点的坐标(左上、右上、左下、右下)
	int w1 = 0, w2 = 0, w3 = 0, w4 = 0;				// 定义相关权值
	uint8_t f11 = 0, f12 = 0, f21 = 0, f22 = 0;		// 对应范围的四个点的像素值(左上、右上、左下、右下)

	// 循环计算
	for (uint32_t i = 0; i < outHeight; i++) {
		for (uint32_t j = 0; j < outWidth; j++) {

			// 像素信息
			x = widthTimes * (j + 0.5) - 0.5, y = heightTimes * (i + 0.5) - 0.5;	// 将起点转换为中心坐标
			x1 = (int)(x), x2 = (int)(x + 1);										// 计算	对应范围的四个点的坐标,并转换为整型变量
			y1 = (int)(y), y2 = (int)(y + 1);

			// 得到 对应范围的四个点的像素值,当该点不在范围内的时候,默认为 0 
			f11 = isInArray(x1, y1, width, height) ? inArray[y1][x1] : 0;
			f12 = isInArray(x1, y2, width, height) ? inArray[y2][x1] : 0;
			f21 = isInArray(x2, y1, width, height) ? inArray[y1][x2] : 0;
			f22 = isInArray(x2, y2, width, height) ? inArray[y2][x2] : 0;

			// 扩大取整后,进行移位计算,节省时间
			w1 = (int)((x - x1) * 2048), w2 = 2048 - w1;
			w3 = (int)((y - y1) * 2048), w4 = 2048 - w3;

			// 计算、限幅
			outArray[i][j] = (f11 * w2 * w4 + f21 * w1 * w4 + f12 * w2 * w3 + f22 * w1 * w3) >> 22;
			outArray[i][j] = Clipping(outArray[i][j], 0, 255);
		}
	}
}


/************************************************************
*Function:		resize
*Description:	图像的缩放
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*				outWidth - 缩放图像宽度
*				outHeight - 缩放图像高度
*				mode - 模式选择
*Return:		outArr - 结果图像的有效二维数组
************************************************************/
uint8_t** resize(uint8_t** inArray, uint32_t width, uint32_t height, uint32_t outWidth, uint32_t outHeight, int mode)
{
	// 生成结果图片的二维数组
	uint8_t** outArr = new uint8_t * [outHeight];
	for (uint32_t i = 0; i < outHeight; i++) {
		outArr[i] = new uint8_t[outWidth];
	}

	// 模式选择
	switch (mode)
	{
	case Near:
		NearInterpolation(inArray, width, height, outArr, outWidth, outHeight);
		break;
	default:
		BilinearInterpolation(inArray, width, height, outArr, outWidth, outHeight);
		break;
	}

	return outArr;
}

6、旋转

1、公式说明

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

2、实现

/************************************************************
*Function:		originRotate
*Description:	以原点为中心进行旋转,临近插值,图片大小限制为原图的大小,超出范围的进行舍去
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*				angle - 角度
*Return:		outArr - 结果图像的有效二维数组
************************************************************/
uint8_t** originRotate(uint8_t** inArray, uint32_t width, uint32_t height, double angle)
{
	double Cos = cos(angle * PI / 180), Sin = sin(angle * PI / 180);
		
	uint8_t** outArr = new uint8_t * [height];
	for (uint32_t i = 0; i < height; i++) {
		outArr[i] = new uint8_t[width];
	}

	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			int xPoint = (int)(j * Cos + i * Sin + 0.5);
			int yPoint = (int)(i * Cos - j * Sin  + 0.5);
			outArr[i][j] = isInArray(xPoint, yPoint, width, height) ? inArray[yPoint][xPoint] : 0;
		}
	}

	return outArr;
}

/************************************************************
*Function:		centreRotate
*Description:	围绕图片中心进行旋转,双线性插值,图片大小保持原图的完整性
*Params:		inArray - 原始图像的有效二维数组
*				width - 图像宽度
*				height - 图像高度
*				rotateWidth - 结果图片宽度
*				rotateheight- 结果图片高度
*				angle - 角度
*Return:		outArr - 结果图像的有效二维数组
************************************************************/
uint8_t** centreRotate(uint8_t** inArray, uint32_t width, uint32_t height, uint32_t* rotateWidth, uint32_t* rotateheight, double angle)
{
	double Cos = cos(angle * PI / 180), Sin = sin(angle * PI / 180);

	int outWidth = width * Cos + height * Sin, outHeight = height * Cos + width * Sin;	
	*rotateWidth = outWidth;
	*rotateheight = outHeight;

	uint8_t** outArr = new uint8_t * [outHeight];
	for (uint32_t i = 0; i < outHeight; i++) {
		outArr[i] = new uint8_t[outWidth];
	}

	// 定义双线性插值相关变量
	double x = 0, y = 0;							// 定义 原始坐标对应位置
	int x1 = 0, y1 = 0, x2 = 0, y2 = 0;				// 对应范围的四个点的坐标(左上、右上、左下、右下)
	int w1 = 0, w2 = 0, w3 = 0, w4 = 0;				// 定义相关权值
	uint8_t f11 = 0, f12 = 0, f21 = 0, f22 = 0;		// 对应范围的四个点的像素值(左上、右上、左下、右下)

	// 定义 坐标旋转之后的常量
	double cx = -0.5 * outWidth * Cos - 0.5 * outHeight * Sin + 0.5 * width;
	double cy = 0.5 * outWidth * Sin - 0.5 * outHeight * Cos + 0.5 * height;

	for (int i = 0; i < outHeight; i++) {
		for (int j = 0; j < outWidth; j++) {
			x = Cos * j + Sin * i + cx;										// 计算真实的坐标位置
			y = Cos * i - Sin * j + cy;
			x1 = (int)(x), x2 = (int)(x + 1);								// 计算	对应范围的四个点的坐标,并转换为整型变量
			y1 = (int)(y), y2 = (int)(y + 1);

			// 得到 对应范围的四个点的像素值,当该点不在范围内的时候,默认为 0 
			f11 = isInArray(x1, y1, width, height) ? inArray[y1][x1] : 0;
			f12 = isInArray(x1, y2, width, height) ? inArray[y2][x1] : 0;
			f21 = isInArray(x2, y1, width, height) ? inArray[y1][x2] : 0;
			f22 = isInArray(x2, y2, width, height) ? inArray[y2][x2] : 0;

			// 扩大取整后,进行移位计算,节省时间
			w1 = (int)((x - x1) * 2048), w2 = 2048 - w1;
			w3 = (int)((y - y1) * 2048), w4 = 2048 - w3;

			// 计算、限幅
			outArr[i][j] = (f11 * w2 * w4 + f21 * w1 * w4 + f12 * w2 * w3 + f22 * w1 * w3) >> 22;
			outArr[i][j] = Clipping(outArr[i][j], 0, 255);
		}
	}

	return outArr;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值