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

news2025/5/15 8:07:06

文章目录

    • 引言
    • 图像仿射变换 warpAffine()
      • 图像的旋转
      • 仿射变换
    • 透视变换 warpPerspective()
    • 透视变换例子
    • 参考文献

**仿射变换相关函数**
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类型的旋转矩阵对象:

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

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

仿射变换

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

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

//只需要提供原图像和目标图像的三个点的坐标
Mat cv::getAffineTransform(const Point2f src[],
                           const Point2f dst[]   //输入点类数组
                          )
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()函数获取变换矩阵

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

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

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参数详解:

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

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

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的矩阵

透视变换例子

#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的单应性矩阵

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2120050.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[基于 Vue CLI 5 + Vue 3 + Ant Design Vue 4 搭建项目] 01 安装 nodejs 环境

文章目录 下载安装测试 这里让我们去看看如何安装一下 nodejs 的环境 下载 通过官网进行下载安装包 官网 https://nodejs.org/zh-cn点击 下载 Node.js (LTS) 开始下载 安装 下载完成之后&#xff0c;双击进行安装 开始进行安装了 这样&#xff0c;node.js 就安装好了 测试 …

Ubuntu下使用Cron定时任务

Ubuntu下使用Cron定时任务 文章目录 Ubuntu下使用Cron定时任务概述Cron 工作原理crontab的基本指令使用Cron 定时任务语法用户的crontab 文件系统的crontab 文件cron 任务设置环境变量1. 直接在 crontab 中声明变量2. 将变量声明为命令的一部分3. 从文件加载变量使用环境变量控…

网络基础入门指南(二)

一、什么是交换机 交换机&#xff0c;Switch 用于将多台计算机/交换机连接到一起&#xff0c;组建网络 交换机负责为其中任意两台计算机提供独享线路进行通信类型&#xff1a; 非网管&#xff08;即插即用&#xff09;&#xff0c;便宜&#xff0c;不可管理 网管&#xff0…

CCF推荐C类会议和期刊总结:(计算机体系结构/并行与分布计算/存储系统领域)

中国计算机学会&#xff08;CCF&#xff09;在计算机体系结构、并行与分布计算、存储系统领域推荐了一系列C类会议和期刊。此汇总涵盖了各期刊和会议的全称、出版社、dblp文献网址及研究领域&#xff0c;为学者和研究人员提供了重要的学术交流资源。列表包括《ACM Journal on E…

Javase复习day21算法、arrays、Lamdba表达式

常见算法 查找算法 基本查找 package search;public class BasicSearchDemo1 {public static void main(String[] args) {//基本算法&#xff08;顺序查找&#xff09;int[] arr {131,23,57,37,95,48,57,43};System.out.println(basicSearch(arr, 43));}public static boo…

基于PINN 进行混合流体中的热量与质量扩散预测

近年来&#xff0c;物理信息神经网络&#xff08;PINN&#xff0c;Physics-Informed Neural Networks&#xff09;成为解决复杂物理问题的一种强大工具。PINN 的核心在于结合物理定律和机器学习的能力&#xff0c;直接从偏微分方程&#xff08;PDEs&#xff09;出发&#xff0c…

LDtk to Unity 大致流程和一些注意点

因为自己也还在探索中&#xff0c;所以有点杂乱&#xff0c;后续有其他的东西还会继续更。 制作 先套用这个模板&#xff0c;确定基础的循环。再去丰富。 LDtk一小时完全入门教程_哔哩哔哩_bilibili To Unity 安装包 LDtk To Unity 输出 图集 在Run after saving运行 ../../Lib…

Arch - 架构安全性_凭证(Credentials)

文章目录 OverView凭证&#xff08;Credentials&#xff09;1. 传统认证授权方式&#xff1a;Cookie-Session 机制2. OAuth2 令牌概述什么是 JWTJWT 令牌 结构HeaderPayloadSignature JWT的优劣势无状态架构的挑战 3. JWT 与 Cookie-Session 的对比 OverView 即使只限定在“软…

rustDesk远程软件,强的可怕

背景 最近在做一个机房的远程运维&#xff0c;对面系统都是windows的&#xff0c;远程本来采用的向日葵&#xff0c;开两三个窗口就不能再多开了&#xff0c;没办法冲了年费瓜子会员&#xff0c;开通会员之后&#xff0c;确实好很多。 随后又增加了一个值班人员&#xff0c;我…

HarmonyOs 应用基础--ArkTS-核心-基础

目录 八. ArkTS-语句-类型进阶与渲染控制 1. 对象进阶 1.1. 定义对象数组 1.2. 使用对象数组 2. 渲染控制 - ForEach 2.1. ForEach语法 2.2. ForEach使用优化代码 2.3. 案例-学生档案 实现思路 3. Math对象 4. 综合案例 -- 抽奖卡案例 4.1. 初始页面布局&#xff08;静…

手机到了外地ip地址就变了吗

手机到了外地IP地址就变了吗&#xff1f;随着智能手机的普及&#xff0c;人们越来越频繁地使用手机进行各种网络活动。然而&#xff0c;关于手机IP地址是否会随着地理位置的变化而改变&#xff0c;许多用户仍心存疑惑。本文将深入探讨这一问题&#xff0c;揭示IP地址变化的奥秘…

【C++ 09】继承

文章目录 &#x1f308; 一、继承的概念及定义⭐ 1. 继承的概念⭐ 2. 继承的定义&#x1f319; 2.1 定义格式&#x1f319; 2.2 继承方式和访问限定符&#x1f319; 2.3 继承父类成员访问方式的变化&#x1f319; 2.4 默认继承方式 &#x1f308; 二、父类和子类对象赋值转换⭐…

分布式通信:多计算平台的任务分配

目录 1. 分布式通信 1.1 树莓派配置流程​编辑 1.2 树莓派和laptop处于同一网络​编辑 1.3 laptop配置 1.4 通信测试 1.5 分组通信 ​编辑 1.6 分布式通信测试 ​编辑参考资料 1. 分布式通信 机器人体积较小&#xff0c;采用树莓派作为控制器&#xff0c;实现传感器处…

仿某皮影狸app官网源码 不错的APP下载官网单页源码 HTML源码

分享一款不错的APP下载官网单页源码&#xff0c;直接修改index.html即可 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89731228 更多资源下载&#xff1a;关注我。

OFDM系统PAPR算法的MATLAB仿真,对比SLM,PTS以及CAF,对比不同傅里叶变换长度

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1、选择映射&#xff08;SLM&#xff09; 4.2 相位截断星座图&#xff08;PTS&#xff09; 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 mat…

极狐GitLab 新一代容器镜像仓库正式上线啦!

从极狐GitLab 17.3 开始&#xff0c;私有化部署实例也可以使用新一代容器镜像仓库啦&#xff01;新一代容器镜像仓库具有更高效的零宕机垃圾收集功能和其他优势。 从去年开始&#xff0c;极狐GitLab 就启动了重构容器镜像仓库的计划&#xff0c;用以构建具有更强功能的镜像仓库…

就服务器而言,ARM架构与X86架构有什么区别?各自的优势在哪里?

一、服务器架构概述 在数字化时代&#xff0c;服务器架构至关重要。服务器是网络核心节点&#xff0c;存储、处理和提供数据与服务&#xff0c;是企业和组织信息化、数字化的关键基础设施。ARM 和 x86 架构为服务器领域两大主要架构&#xff0c;x86 架构服务器在市场占主导&…

弹框调取阿里云播放器一直报错 TypeError: 没有为播放器指定容器

弹框调取阿里云播放器一直报错 TypeError: 没有为播放器指定容器 <template><el-dialogv-model"dialogpeopleVisible":before-close"handleClose"class"aliyunplayDialog"><!-- :show-close "false" --><div&g…

2024年企业级电脑监控软件推荐,精选的电脑监控软件

随着企业信息化程度的不断提高&#xff0c;如何有效监控和管理企业电脑成为许多企业主和IT管理员的重要任务。企业级电脑监控软件不仅可以帮助企业提高工作效率&#xff0c;保障数据安全&#xff0c;还能够防止内部数据泄露和违规操作。在2024年&#xff0c;有多款优秀的电脑监…

一帧图像绘制过程(详解)

一帧图像的起始 手机流畅使用会带来良好的用户体验&#xff0c;而流畅的手机画面是通过屏幕刷新频率和稳定的帧率相配合实现。过高或过低的帧率会造成资源的浪费&#xff0c;不稳定的帧率造成卡顿等现象&#xff0c;影响用户体验。那么稳定的帧率如何实现&#xff1f;或者说一帧…