Opencv实现图像的仿射变换,平移、旋转、缩放

效果

↓ 旋转、平移、缩放 叠加之后的效果

在这里插入图片描述

原理 二维齐次变换矩阵

链接: 二维几何变换—矩阵表示和齐次坐标 中国龙-扬科.

实现

在这里插入图片描述 ↑ 将旋转、平移添加到二维齐次变换矩阵
在这里插入图片描述↑ 将缩放添加到二维其次变换矩阵

代码

1、只是初步实现了,存在一些小毛刺需要优化,优化问题有时间再水一篇;
2、为了处理速度尽可能快,几乎所有的运算都直接在原地做了;
3、图像旋转的本质还是求点的映射,这段代码理论上可以修改一下直接给点、轮廓等类型使用。

#include<iostream>
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace cv;
using namespace std;

const float PI = acos(-1); 

float rad(float angle){ return angle*PI / 180; } //求角度的弧度值
float deg(float radian){ return radian * 180 / PI; }//求弧度的角度值

/*
显示3×3矩阵
*/
void show(float *a)
{
	for (int i = 0; i < 9; ++i)
	{
		if (i && i % 3 == 0) cout << endl;
		cout << a[i] << "  ";
	}
	cout << endl;
}
/*
计算矩阵的左乘
@ lastMatrix		:输入左矩阵 3×3
@ currentMatrix	:输入右矩阵 和 输出 3×3
*/
void leftMult_3By3(float * lastMatrix,float * currentMatrix)
{
	float arrayCopy[9];
	memcpy(arrayCopy, currentMatrix, 9 * sizeof(float));
	for (int i = 0; i < 9; ++i)
	{
		int row = i / 3;
		int col = i % 3;
		currentMatrix[i] = 0;
		for (int j = 0; j < 3; ++j)
		{
			currentMatrix[i] += lastMatrix[row * 3 + j] * arrayCopy[j * 3 + col];
		}
	}
	return;
}
/*
计算矩阵的右乘
@ currentMatrix	:输入左矩阵 和 输出 3×3
@ nextMatrix		:输入右矩阵 3×3
*/
void rightMult_3By3(float * currentMatrix, float * nextMatrix)
{
	float arrayCopy[9];
	memcpy(arrayCopy, currentMatrix, 9 * sizeof(float));
	for (int i = 0; i < 9; ++i)
	{
		int row = i / 3;
		int col = i % 3;
		currentMatrix[i] = 0;
		for (int j = 0; j < 3; ++j)
		{
			currentMatrix[i] += arrayCopy[row * 3 + j] * nextMatrix[j * 3 + col];
		}
	}
	return;
}

/*
生成二维变换的齐次变换矩阵。

@ 返回值 : 三阶单位矩阵
*/
float * homTransMatrixIdentity()
{
	float * f_temp = new float[9];
	f_temp[0] = 1;
	f_temp[1] = 0;
	f_temp[2] = 0;

	f_temp[3] = 0;
	f_temp[4] = 1;
	f_temp[5] = 0;

	f_temp[6] = 0;
	f_temp[7] = 0;
	f_temp[8] = 1;
	return f_temp;
}

/*
释放二维变换的齐次变换矩阵。
@ hom2DTransMatrix 
*/
void  homTransMatrixRelease(float * hom2DTransMatrix){ delete hom2DTransMatrix; return; }

/*
向齐次二维变换矩阵添加一个平移。
@ dx :x方向上的平移
@ dy :y方向上的平移
@ hom2DTransMatrix :输入和输出变换矩阵
*/
void homTransMatrixTranslation(int dx, int dy, float * hom2DTransMatrix)
{
	hom2DTransMatrix[2] += dx;
	hom2DTransMatrix[5] += dy;
	return;
}

/*
向齐次二维变换矩阵添加一个旋转。
@ phiRad : 旋转的弧度
@ px :变换不动点的x坐标
@ py :变换不动点的y坐标
@ hom2DTransMatrix :输入和输出变换矩阵
*/
void homTransMatrixRotate(float phiRad, int px, int py, float * hom2DMatrixInputAndOutput)
{
	float fLeft[9] = {	1, 0, px, 0, 1, py, 0, 0, 1 };
	float fRight[9] = { 1, 0, -px, 0, 1, -py, 0, 0, 1 };
	float fRotate[9] = { cos(phiRad), -sin(phiRad), 0,sin(phiRad), cos(phiRad), 0,0, 0, 1 };
	leftMult_3By3(fLeft, fRotate);
	rightMult_3By3(fRotate, fRight);
	leftMult_3By3(fRotate, hom2DMatrixInputAndOutput);
	return;
}

/*
向齐次二维变换矩阵添加一个缩放。
@ sx : x方向伸缩比例
@ sy : y方向伸缩比例
@ px :变换不动点的x坐标
@ py :变换不动点的y坐标
@ hom2DTransMatrix :输入和输出变换矩阵
*/
void homTransMatrixScale(float sx, float sy, int px, int py, float * hom2DMatrixInputAndOutput)
{
	float fLeft[9] = { 1, 0, px, 0, 1, py, 0, 0, 1 };
	float fRight[9] = { 1, 0, -px, 0, 1, -py, 0, 0, 1 };
	float fScale[9] = { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
	leftMult_3By3(fLeft, fScale);
	rightMult_3By3(fScale, fRight);
	leftMult_3By3(fScale, hom2DMatrixInputAndOutput);
	return;
}

/*
对图像应用任意仿射2D变换。
@ src : 输入图像
@ dst : 输出图像
@ hom2DMatrix :输入变换矩阵
*/
void affineImage(const Mat & src, Mat & dst, const float * hom2DMatrix)
{
	//P1求矩阵的逆矩阵 
	//https://www.shuxuele.com/algebra/matrix-inverse-minors-cofactors-adjugate.html
	float InverseMatrix[9];
	memcpy(InverseMatrix, hom2DMatrix, 9 * sizeof(float));
	//求矩阵的行列式
	float det = hom2DMatrix[0] * hom2DMatrix[4] * hom2DMatrix[8] +
		hom2DMatrix[1] * hom2DMatrix[5] * hom2DMatrix[6] +
		hom2DMatrix[2] * hom2DMatrix[3] * hom2DMatrix[7] -
		hom2DMatrix[2] * hom2DMatrix[4] * hom2DMatrix[6] -
		hom2DMatrix[0] * hom2DMatrix[5] * hom2DMatrix[7] -
		hom2DMatrix[1] * hom2DMatrix[3] * hom2DMatrix[8];

	//P1 求矩阵的余子式矩阵和代数余子式阵列 求伴随矩阵
	InverseMatrix[0] = (hom2DMatrix[4] * hom2DMatrix[8] - hom2DMatrix[5] * hom2DMatrix[7]) / det;
	InverseMatrix[3] = (hom2DMatrix[5] * hom2DMatrix[6] - hom2DMatrix[3] * hom2DMatrix[8]) / det;
	InverseMatrix[6] = (hom2DMatrix[3] * hom2DMatrix[7] - hom2DMatrix[4] * hom2DMatrix[6]) / det;

	InverseMatrix[1] = (hom2DMatrix[2] * hom2DMatrix[7] - hom2DMatrix[1] * hom2DMatrix[8]) / det;
	InverseMatrix[4] = (hom2DMatrix[0] * hom2DMatrix[8] - hom2DMatrix[2] * hom2DMatrix[6]) / det;
	InverseMatrix[7] = (hom2DMatrix[1] * hom2DMatrix[6] - hom2DMatrix[0] * hom2DMatrix[7]) / det;

	InverseMatrix[2] = (hom2DMatrix[1] * hom2DMatrix[5] - hom2DMatrix[2] * hom2DMatrix[4]) / det;
	InverseMatrix[5] = (hom2DMatrix[2] * hom2DMatrix[3] - hom2DMatrix[0] * hom2DMatrix[5]) / det;
	InverseMatrix[8] = (hom2DMatrix[0] * hom2DMatrix[4] - hom2DMatrix[1] * hom2DMatrix[3]) / det;
 
	//P2 获取像素在src的位置,赋值像素
	dst = Mat::zeros(src.size(), CV_8UC3);
	for (int row = 0; row < dst.rows; ++row)
	{ 
		for (int col = 0; col < dst.cols; ++col)
		{
			int colFrom = round(col*InverseMatrix[0] + row*InverseMatrix[1] + InverseMatrix[2]);
			if ((colFrom < 0 || colFrom >= src.cols)) continue;
			
			int rowFrom = round(col*InverseMatrix[3] + row*InverseMatrix[4] + InverseMatrix[5]);
			if (rowFrom < 0 || rowFrom >= src.rows)
			{
				continue;
			}
			dst.at<Vec3b>(row, col) = src.at<Vec3b>(rowFrom, colFrom);
		}
	}
}



void test1()
{
	float * e = homTransMatrixIdentity();
	homTransMatrixRotate(rad(-45), 100, 100, e);
	homTransMatrixTranslation(100, 100, e);
	homTransMatrixScale(0.8, 0.75, 200, 200, e);
	show(e);

	Mat imageImput = imread("5.jpg");
	Mat imageAffine;

	affineImage(imageImput, imageAffine, e);

	imshow("imageImput", imageImput);
	imshow("imageAffine", imageAffine);

	homTransMatrixRelease(e);
	waitKey();

	return;
}

int main()
{

	test1();


	return 0;	
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值