7.6透视变换

news2024/9/28 6:22:37

基本概念

在计算机视觉和图像处理领域中,透视变换(Perspective Transformation)是一种重要的几何变换,用于模拟从一个视角到另一个视角的变换,比如从鸟瞰视角到正面视角的变换。透视变换通常用于图像配准、增强现实、三维重建等场景。

透视变换的基本概念

透视变换是一种非线性的几何变换,它通过一个3x3的矩阵来描述,这个矩阵可以将一个平面的坐标映射到另一个平面上。

OpenCV中的透视变换

在OpenCV中,透视变换可以通过 warpPerspective 函数来实现。这个函数需要一个3x3的变换矩阵来指定变换。

函数原型

void warpPerspective(
    InputArray src,
    OutputArray dst,
    InputArray M,
    Size dsize,
    int flags = INTER_LINEAR,
    int borderMode = BORDER_CONSTANT,
    const Scalar& borderValue = Scalar()
);

参数说明
•src:输入图像。
•dst:输出图像。
•M:一个3x3的透视变换矩阵。
•dsize:输出图像的大小。
•flags:插值方法,默认为 INTER_LINEAR(双线性插值)。
•borderMode:边界处理方法,默认为 BORDER_CONSTANT。
•borderValue:如果使用了 BORDER_CONSTANT,则需要指定边界值。

创建透视变换矩阵

透视变换矩阵通常是通过一组对应点来计算的。给定四组对应点,可以使用 findHomography 或 getPerspectiveTransform 函数来计算变换矩阵。

示例代码1

下面是一个使用OpenCV C++实现透视变换的示例代码:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

// 定义透视变换
void applyPerspectiveTransform(const Mat &src, Mat &dst, const Mat &M, Size dsize) 
{
	warpPerspective(src, dst, M, dsize, INTER_LINEAR, BORDER_CONSTANT, Scalar(0));
}

int main(int argc, char** argv) 
{
	//if (argc != 2)
	//{
	//	cout << "Usage: ./PerspectiveTransform <Image Path>" << endl;
	//	return -1;
	//}

	// 加载图像
	Mat img = imread("586.jpeg");
	if (!img.data) 
	{
		cout << "Error opening image" << endl;
		return -1;
	}

	// 定义对应点
	vector<Point2f> pts1, pts2;

	// 输入图像的四个角点
	pts1.push_back(Point2f(0, 0));
	pts1.push_back(Point2f(img.cols, 0));
	pts1.push_back(Point2f(img.cols, img.rows));
	pts1.push_back(Point2f(0, img.rows));

	// 输出图像的目标四个角点
	pts2.push_back(Point2f(0, 0));
	pts2.push_back(Point2f(img.cols / 2, 0));
	pts2.push_back(Point2f(img.cols / 2, img.rows));
	pts2.push_back(Point2f(0, img.rows));

	// 计算透视变换矩阵
	Mat M = getPerspectiveTransform(pts1, pts2);

	// 定义输出图像大小
	Size dsize(img.cols, img.rows);

	// 初始化输出矩阵
	Mat transformed;

	// 应用透视变换
	applyPerspectiveTransform(img, transformed, M, dsize);

	// 显示结果
	namedWindow("Original Image", WINDOW_NORMAL);
	imshow("Original Image", img);
	namedWindow("Flipped Center", WINDOW_NORMAL);
	imshow("Flipped Center", transformed);

	waitKey(0);
	destroyAllWindows();

	return 0;
}


代码解释
1. 加载图像:使用 imread 函数加载图像。
2. 定义对应点:定义输入图像的四个角点和输出图像的目标四个角点。
3. 计算透视变换矩阵:使用 getPerspectiveTransform 函数计算透视变换矩阵。
4. 定义输出图像大小:保持输出图像大小不变。
5. 初始化输出矩阵:创建一个新的矩阵来存储变换后的图像。
6. 应用透视变换:使用 warpPerspective 函数应用透视变换。
7. 显示结果:使用 imshow 函数显示原始图像和变换后的图像。

运行结果1

在OpenCV中,透视变换是一种非常强大的图像处理技术,它允许你在二维平面上模拟三维空间中的视点变化。这种变换特别适用于需要进行图像校正或模拟不同视角的应用场景,例如文档扫描、图像拼接等。

透视变换通常涉及一个3x3的矩阵,该矩阵可以将输入图像中的四点映射到输出图像中的另外四点。在C++中使用OpenCV进行透视变换的基本步骤如下:

在C++中使用OpenCV进行透视变换的基本步骤如下:

1. 导入必要的头文件
首先确保你的项目中包含了OpenCV的头文件。
#include <opencv2/opencv.hpp>
using namespace cv;

2. 加载图像
使用imread函数读取一幅图像,并检查是否正确加载。
Mat src = imread("path/to/image.jpg");
if (src.empty()) {
    std::cout << "Error: Image not found or unable to open" << std::endl;
    return -1;
}

3. 定义源点和目标点
你需要定义源图像上的四个角点以及目标图像上的对应位置。这些点应该按照顺序(例如顺时针或逆时针)指定。
Point2f src_pts[4];
Point2f dst_pts[4];

// 源点
src_pts[0] = Point2f(0, 0);
src_pts[1] = Point2f(src.cols - 1, 0);
src_pts[2] = Point2f(src.cols - 1, src.rows - 1);
src_pts[3] = Point2f(0, src.rows - 1);

// 目标点
dst_pts[0] = Point2f(0, 0);
dst_pts[1] = Point2f(dst.cols - 1, 0);
dst_pts[2] = Point2f(dst.cols - 1, dst.rows - 1);
dst_pts[3] = Point2f(0, dst.rows - 1);

4. 计算透视变换矩阵
使用getPerspectiveTransform函数来计算从源点到目标点的透视变换矩阵。
Mat M = getPerspectiveTransform(src_pts, dst_pts);

5. 应用透视变换
利用warpPerspective函数应用计算出的变换矩阵来对原始图像进行变形。
Mat dst;
warpPerspective(src, dst, M, Size(dst.cols, dst.rows));

6. 显示结果
最后,你可以使用imshow函数显示变换后的图像,并等待用户按键后退出。
namedWindow("Result", WINDOW_NORMAL);
imshow("Result", dst);
waitKey(0); // Wait for a keystroke in the window

请注意,上述代码示例中的目标图像尺寸(dst.cols 和 dst.rows)需要根据实际情况设定。如果你想要创建一个新的大小,而不是直接复制源图像的大小,可以在调用warpPerspective时指定新的尺寸。

透视变换的原理较为复杂,涉及到线性代数中的矩阵运算,如果你对数学原理感兴趣,建议深入学习相关的数学背景知识。

示例代码2


#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{

	Mat src = imread("89.jpeg");
	if (src.empty())
	{
		std::cout << "Error: Image not found or unable to open" << std::endl;
		return -1;
	}


	Point2f src_pts[4];
	Point2f dst_pts[4];

	//Mat dst(src.cols / 2, src.rows/2,CV_8SC3);
	// 源点
	src_pts[0] = Point2f(0, 0);
	src_pts[1] = Point2f(src.cols - 1, 0);
	src_pts[2] = Point2f(src.cols - 1, src.rows - 1);
	src_pts[3] = Point2f(0, src.rows - 1);

	// 目标点
	dst_pts[0] = Point2f(0, 0);
//	dst_pts[1] = Point2f(dst.cols - 1, 0);
//dst_pts[2] = Point2f(dst.cols - 1, dst.rows - 1);
//	dst_pts[3] = Point2f(0, dst.rows - 1);

	dst_pts[1] = Point2f(src.cols/2 - 1, 0);
	dst_pts[2] = Point2f(src.cols / 2 - 1, src.rows/2 - 1);
	dst_pts[3] = Point2f(0, src.rows / 2 - 1);


	Mat M = getPerspectiveTransform(src_pts, dst_pts);


	Mat dst;
	warpPerspective(src, dst, M, Size(dst.cols, dst.rows));


	namedWindow("源图", WINDOW_NORMAL);
	imshow("源图", src);

	namedWindow("Result", WINDOW_NORMAL);
	imshow("Result", dst);
	waitKey(0); // Wait for a keystroke in the window


	return 0;
}

运行结果2

透视变换的常见应用场景

•图像配准:将两张或多张图像对齐,使它们之间的相对位置一致。

•三维重建:通过多视角的图像重建三维模型。

•增强现实:在实时视频流中添加虚拟对象,使其看起来像是在现实世界中存在。

示例代码3

计算透视变换矩阵的示例

下面是使用 findHomography 计算透视变换矩阵的示例代码:
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void calculatePerspectiveTransform(const Mat &src, Mat &M, const vector<Point2f> &pts1, const vector<Point2f> &pts2)
{
	// 使用findHomography计算透视变换矩阵
	M = findHomography(pts1, pts2);
}

// 定义透视变换
void applyPerspectiveTransform(const Mat &src, Mat &dst, const Mat &M, Size dsize)
{
	warpPerspective(src, dst, M, dsize, INTER_LINEAR, BORDER_CONSTANT, Scalar(0));
}

int main(int argc, char** argv)
{
	/*if (argc != 2)
	{
		cout << "Usage: ./PerspectiveTransform <Image Path>" << endl;
		return -1;
	}*/

	// 加载图像
	Mat img = imread("896.png");
	if (!img.data) 
   {
		cout << "Error opening image" << endl;
		return -1;
	}

	// 定义对应点
	vector<Point2f> pts1, pts2;

	// 输入图像的四个角点
	pts1.push_back(Point2f(0, 0));
	pts1.push_back(Point2f(img.cols, 0));
	pts1.push_back(Point2f(img.cols, img.rows));
	pts1.push_back(Point2f(0, img.rows));

	// 输出图像的目标四个角点
	pts2.push_back(Point2f(0, 0));
	pts2.push_back(Point2f(img.cols / 2, 0));
	pts2.push_back(Point2f(img.cols / 2, img.rows));
	pts2.push_back(Point2f(0, img.rows));

	// 计算透视变换矩阵
	Mat M;
	calculatePerspectiveTransform(img, M, pts1, pts2);

	// 定义输出图像大小
	Size dsize(img.cols, img.rows);

	// 初始化输出矩阵
	Mat transformed;

	// 应用透视变换
	applyPerspectiveTransform(img, transformed, M, dsize);

	// 显示结果
	namedWindow("Original Image", WINDOW_NORMAL);
	imshow("Original Image", img);
	namedWindow("Transformed Image", WINDOW_NORMAL);
	imshow("Transformed Image", transformed);

	waitKey(0);
	destroyAllWindows();

	return 0;
}

代码解释
1. 加载图像:使用 imread 函数加载图像。
2. 定义对应点:定义输入图像的四个角点和输出图像的目标四个角点。
3. 计算透视变换矩阵:使用 findHomography 函数计算透视变换矩阵。
4. 定义输出图像大小:保持输出图像大小不变。
5. 初始化输出矩阵:创建一个新的矩阵来存储变换后的图像。
6. 应用透视变换:使用 warpPerspective 函数应用透视变换。
7. 显示结果:使用 imshow 函数显示原始图像和变换后的图像。

运行结果3

通过这些示例,你应该能够理解如何在OpenCV中使用C++实现透视变换。透视变换是一个强大的工具,用于模拟复杂的视角变换。

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

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

相关文章

ubuntu报错you don‘t have enough free space in /var/cache/apt/archivers.

使用df -h命令查看&#xff1b; 扩充前&#xff0c;dev/sda2的大小&#xff1a; 使用gparted工具对dev/sda2进行扩容

Steam黑神话悟空禁止更新进入游戏的解决方案

首先打开该网站&#xff1a;https://steamdb.info/app/2358720/ 2358720即为游戏ID 网页下翻&#xff0c;找到更新历史&#xff1a;https://steamdb.info/app/2358720/history/ 然后在Steam的steamapps下&#xff0c;找到后缀为2358720的文件&#xff0c;右击记事本打开 将St…

老照片修复工具有哪些?怎么让老照片焕发新光彩?

在那些泛黄的相框中&#xff0c;珍藏着我们最珍贵的记忆。 岁月流转&#xff0c;照片上的影像逐渐模糊&#xff0c;但那份情感却愈发深刻。 如何让这些老照片恢复往日的光彩&#xff0c;让那些珍贵的瞬间再次清晰呈现&#xff1f; 本文将带你探索老照片修复高清的技巧&#…

SpringMVC源码-SpringMVC框架中Spring父容器和SpringMVC子容器加载的流程以及SpringMVC九大内置组件的初始

一、Spring父容器启动 SpringMVC 的项目结构如下: applicationContext.xml spring的配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.o…

Spring Boot 进阶-如何自定义SpringBoot日志配置?

在之前的文章中我们介绍了Spring Boot中的日志框架,并且也介绍了SpringBoot日志框架中日志级别的调整。这篇文章我们主要来介绍关于如何让日志框架更加符合我们自己的需求。那么首先我们就来看一下日志文件输出路径的配置。 如何指定日志文件的输出位置 在Spring Boot中日志是…

Keepalived+MySQL 高可用集群

基础架构如下 准备干净的实验环境 [rootmysql1 ~]# systemctl stop firewalld [rootmysql1 ~]# cat /etc/sysconfig/selinux |grep "SELINUXdisabled" SELINUXdisabled [rootmysql1 ~]# setenforce 0 setenforce: SELinux is disabled [rootmysql1 ~…

动静态库(Linux)

文章目录 前言一、静态库二、动态库三、深入理解动态库总结 前言 我们之前用过c语言的库.Linux中默认的都是使用动态库&#xff0c;如果想要使用静态库&#xff0c;就必须加上-static选项。默认都是安装的动态库&#xff0c;系统中一般没有静态库&#xff0c;如果要使用&#…

算法复杂度之时间复杂度

一 . 数据结构前言 1.1 数据结构 数据结构(Data structure) 是计算机存储&#xff0c;组织数据的方式&#xff0c;指互相之间存在一种或多种特定关系的数据元素的集合。没有一种单一的数据结构对所有用途都有用&#xff0c;所以要学习各式各样的数据结构&#xff0c;如&#…

使用kaggle命令下载数据集

目录 报错 解决方案 报错 使用kaggle命令下载数据集报错了&#xff0c; 解决方案 &#xff08;1&#xff09;首先&#xff0c;确保已经安装 Python 和包管理器 pip。 运行以下命令以使用命令行访问 Kaggle API&#xff1a; pip install kaggle 可能需要在 Mac/Linux 上执行…

【BurpSuite】SQL注入 | SQL injection(1-2)

&#x1f3d8;️个人主页&#xff1a; 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞&#x1f44d;收藏&#x1f497;支持一下哦 【BurpSuite】SQL注入 | SQL injection&#xff08;1-2&#xff09; 实验一 Lab: SQL injection vulnerability in WHERE clause…

Maven项目常见各类 QA

一、pom.xml文件 1.1 there is no POM in this directory [ERROR] The goal you specified requires a project to execute but there is no POM in this directory (/home/cys/SEtesting/example/smartut-report). Please verify you invoked Maven from the correct directo…

如何实现工业设备联网?天拓四方

一、引言 随着信息技术的快速发展&#xff0c;工业设备联网已成为推动工业4.0和智能制造的核心技术之一。工业设备联网通过将传统的工业设备与互联网、云计算、大数据等技术相结合&#xff0c;实现了设备之间的互联互通&#xff0c;数据共享与智能分析&#xff0c;极大地提高了…

【计算机网络 - 基础问题】每日 3 题(二十七)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

机器学习-KNN

KNN&#xff1a;K最邻近算法&#xff08;K-Nearest Neighbor,KNN&#xff09; 用特征空间中距离待分类对象的最近的K个样例点的类别来预测。 投票法&#xff1a;K 个样例的对数类别。 k1:最近邻分类 k 通常是奇数&#xff08;因为我们根据这个K数据判断类别&#xff0c;如果…

敏感字段加密 - 华为OD统一考试(E卷)

2024华为OD机试(E卷+D卷+C卷)最新题库【超值优惠】Java/Python/C++合集 题目描述 【敏感字段加密】给定一个由多个命令字组成的命令字符串: 1、字符串长度小于等于127字节,只包含大小写字母,数字,下划线和偶数个双引号; 2、命令字之间以一个或多个下划线 进行分割; 3、可…

Spring Cloud Gateway接入WebSocket:实现实时通信

在现代的微服务架构中&#xff0c;实时通信变得越来越重要。Spring Cloud Gateway作为Spring Cloud生态中的API网关&#xff0c;提供了动态路由、监控、弹性、安全等功能。本文将介绍如何通过Spring Cloud Gateway接入WebSocket&#xff0c;实现服务之间的实时通信。 为什么需…

1. AOSP源码导入到AndroidStudio

1. AOSP源码导入到AndroidStudio 原文地址:http://www.androidcrack.com/index.php/archives/6/ ⚠️ 在执行一下操作前, 请先完整的编译一次系统, 若不清楚如何编译系统. 请访问下面文章 http://www.androidcrack.com/index.php/archives/3/ 1. 生成idegen.jar source build…

Python中流行的开源OCR项目

以下是一些Python中流行的开源OCR项目&#xff1a; PaddleOCR&#xff1a;由百度开发的OCR工具库&#xff0c;支持多种语言的文字识别&#xff0c;包括中英文&#xff0c;同时支持倾斜、竖排等多种方向的文字识别。它提供了超轻量级的PP-OCRv3模型&#xff0c;适合在资源受限的…

EasyExcel使用介绍

EasyExcel使用 1、EasyExcel介绍 1.1 官网介绍 传统操作Excel大多都是利用Apach POI进行操作的&#xff0c;但是POI框架并不完善&#xff0c;使用过程非常繁琐且有较多的缺陷&#xff1a; 动态操作Excel非常繁琐,对于新手来说&#xff0c;很难在短时间内上手;读写时需要占用…

助力企业信息化,开源免费工作流引擎AntFlow推出重榜功能tidb支持,为工作流引擎水平扩展提供无限可能

在现代企业管理中&#xff0c;流程审批的高效性直接影响到工作的流畅度与生产力。选择一款高效的、现代的、合适企业办公特点的流程引擎到头重要。AntFlow是一款结合中国式办公精心打造的、设计上仿钉钉的工作流引擎。后端即可嵌入到现有业务系统&#xff0c;也可以做为独立的流…