OpenCV仿射变换和透视变换函数(C++)

文章目录

cpp 复制代码
**仿射变换相关函数**
cv::transform():对一组点进行仿射变换
cv::warpAffine():对整幅图像进行仿射变换
cv::getAffineTransform():从一组点计算仿射变换矩阵
cv::getRotationMatrix2D():计算旋转矩阵
**投影变换相关的函数**
cv::perspectiveTransform():对一组点进行透射变换/投影变换
cv::warpPerspective():对整幅图像进行透视变换/投影变换
cv::getPerspectiveTransform():获取透视变换/投影变换矩阵
cv::findHomography():计算单应性矩阵

引言

图像的几何变换通常包括拉伸、缩放、扭曲和旋转等操作。

对于平面区域来说,分为两类几何转换:

  • 仿射变换 (affine transform),基于2x3矩阵进行变换。指图像可以通过一系列的几何变换来实现平移、旋转等多种操作。该变换能够保持图像的平直性和平行性。平直性是指图像经过仿射变换后,直线仍然是直线;平行性是指图像在完成仿射变换后,平行线仍然是平行线
  • 透视变换 (perspective transform),基于3x3矩阵进行变换。透视变换将视锥体转换为长方体形状,视锥体的近端比远端小,具有扩大相机附近物体的效果。透视变换可以改变平行关系,将矩形映射为任意四边形。

图像仿射变换 warpAffine()

图像的旋转

getRotationMatrix2D()函数通过输入旋转中心、旋转角度、旋转过程两轴的比例因子,获得一个Mat类型的旋转矩阵对象:

cpp 复制代码
Mat cv::getRotationMatrix2D(Point2f center,
                            double angle,
                            double scale   //两轴的比例因子,输入1则不缩放
                           )    

旋转变换是仿射变换的一个特殊情况,将此矩阵用于仿射变换函数即可仅作图像旋转

仿射变换

仿射变换又称为三点变换。如果知道目标变换前后的三个像素点坐标之间的关系,即可求出仿射变换矩阵M。

opencv提供了getAffineTransform函数用于计算仿射变换矩阵:

cpp 复制代码
//只需要提供原图像和目标图像的三个点的坐标
Mat cv::getAffineTransform(const Point2f src[],
                           const Point2f dst[]   //输入点类数组
                          )
cpp 复制代码
void cv::warpAffine(InputArray src,
                    OutputArray dst,
                    InputArray M,        //仿射变换矩阵M
                    Size dsize,
                    int flags = INTER_LINEAR,    //插值方法
                    int borderMode = BORDER_CONSTANT,    //像素边界外推方法
                    const Scalar & nprderValue = Scalar()
                   )

注:仿射变换的矩阵M是2×3的矩阵

透视变换 warpPerspective()

透视变换:按照物体的成像投影规律将图像重新投影。常见用例是修正镜头与拍摄目标存在斜角时产生的图像畸变。

使用getPerspectiveTransform()函数获取变换矩阵

cpp 复制代码
//只需要提供原图像和目标图像的四个点的坐标
Mat cv::getPerspectiveTransform(const Point2f src[],
                                const Point2f dst[],
                                int solveMethod = DECOMP_LU //求解方法                             
                               )

在不知道四个坐标点的情况下,可以使用原图和目标图的匹配点计算变换矩阵:

cpp 复制代码
Mat cv::findHomography	(	InputArray 	srcPoints,
                                InputArray 	dstPoints,
                                int 	method = 0,
                                double 	ransacReprojThreshold = 3,
                                OutputArray 	mask = noArray(),
                                const int 	maxIters = 2000,
                                const double 	confidence = 0.995 
)

method参数详解:

cpp 复制代码
method	计算单应矩阵所使用的方法。不同的方法对应不同的参数,具体如下:
0 - 利用所有点的常规方法
RANSAC - RANSAC-基于RANSAC的鲁棒算法
LMEDS - 最小中值鲁棒算法
RHO - PROSAC-基于PROSAC的鲁棒算法

使用warpPerspective()函数应用透视变换

cpp 复制代码
void cv::warpPerspective(InputArray src,
                         OutputArray dst,
                         InputArray M,        //变换矩阵M
                         Size dsize,
                         int flags = INTER_LINEAR,    //插值方法
                         int borderMode = BORDER_CONSTANT,    //像素边界外推方法
                         const Scalar & nprderValue = Scalar()
                        )

注:透视变换的矩阵M是3×3的矩阵

透视变换例子

cpp 复制代码
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

struct callbackP
{
	Mat src;
	int clickTimes = 0;        //在图像上单击次数
	vector<Point2f> srcTri;
};

void onMouse(int event, int x, int y, int flags, void *utsc)
{
	callbackP cp = *(callbackP*)utsc;  // 先转换类型,再取数据

	if (event == EVENT_LBUTTONUP)      //响应鼠标左键事件
	{
		circle((*(callbackP*)utsc).src, Point(x, y), 2, Scalar(0, 0, 255), 2);  //标记选中点
		imshow("wait ", (*(callbackP*)utsc).src);
		(*(callbackP*)utsc).srcTri.push_back(Point2f(x, y));
		cout << "x:" << x << " " << "y:" << y << endl;
		(*(callbackP*)utsc).clickTimes++;

		if ((*(callbackP*)utsc).clickTimes == 4)
		{
			cout << "按任意键继续!" << endl;
		}
	}
}

int main(int argc, char *argv[])
{
	vector<Point2f> dstTri(4);
	Mat dst;
	callbackP utsc;

	utsc.src = imread("tt.jpg");
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", utsc.src);
	cout << "从需要透视变换区域的左上角开始,顺时针依次点矩形的四个角!" << endl;
	setMouseCallback("src", onMouse, (void*)&utsc);  //类型转换
	waitKey();

	if (utsc.clickTimes == 4)
	{
		dstTri[0].x = 0;
		dstTri[0].y = 0;
		dstTri[1].x = utsc.srcTri[1].x - utsc.srcTri[0].x;
		dstTri[1].y = 0;
		dstTri[2].x = utsc.srcTri[1].x - utsc.srcTri[0].x;
		dstTri[2].y = utsc.srcTri[2].y - utsc.srcTri[1].y;
		dstTri[3].x = 0;
		dstTri[3].y = utsc.srcTri[2].y - utsc.srcTri[1].y;

		//计算透视矩阵
		Mat M = findHomography(utsc.srcTri, dstTri, RANSAC);
		//图像透视变换
		warpPerspective(utsc.src, dst, M, Size((utsc.srcTri[1].x - utsc.srcTri[0].x), (utsc.srcTri[2].y - utsc.srcTri[1].y)));
		
		imshow("output", dst);
		imwrite("3p.jpg", dst);
		cout << "透视变换矩阵:" << M << endl;
		waitKey();
	}
	else
	{
		cout << "需要从左上角开始,顺时针依次点矩形的四个角!" << endl;
		cout << "现在点击了" << utsc.clickTimes << "次" << endl;
	}在这里插入图片描述

	cv::destroyAllWindows();

	return 0;
}

参考文献

图像几何变换(仿射变换和透视变换...)及python-opencv实现
OpenCV学习笔记 02
opencv的单应性矩阵

相关推荐
GOTXX6 分钟前
基于Opencv的图像处理软件
图像处理·人工智能·深度学习·opencv·卷积神经网络
IT古董10 分钟前
【人工智能】Python在机器学习与人工智能中的应用
开发语言·人工智能·python·机器学习
CV学术叫叫兽25 分钟前
快速图像识别:落叶植物叶片分类
人工智能·分类·数据挖掘
烦躁的大鼻嘎30 分钟前
模拟算法实例讲解:从理论到实践的编程之旅
数据结构·c++·算法·leetcode
嵌入式大圣33 分钟前
单片机结合OpenCV
单片机·嵌入式硬件·opencv
IU宝34 分钟前
C/C++内存管理
java·c语言·c++
fhvyxyci35 分钟前
【C++之STL】摸清 string 的模拟实现(下)
开发语言·c++·string
C++忠实粉丝1 小时前
计算机网络socket编程(4)_TCP socket API 详解
网络·数据结构·c++·网络协议·tcp/ip·计算机网络·算法
WeeJot嵌入式1 小时前
卷积神经网络:深度学习中的图像识别利器
人工智能
古月居GYH1 小时前
在C++上实现反射用法
java·开发语言·c++