OpenCV相机标定与3D重建(37)计算两幅图像之间单应性矩阵(Homography Matrix)的函数findHomography()的使用

  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

找到两个平面之间的透视变换。
cv::findHomography 是 OpenCV 库中用于计算两幅图像之间单应性矩阵(Homography Matrix)的函数。单应性矩阵描述了两个平面之间的投影变换关系,它在计算机视觉中用于图像校正、拼接和增强现实等任务。

函数原型


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 
)		

参数

  • 参数srcPoints:原平面中点的坐标,可以是类型为 CV_32FC2 的矩阵或 vector。
  • 参数dstPoints:目标平面中点的坐标,可以是类型为 CV_32FC2 的矩阵或 vector。
  • 参数method:用于计算单应性矩阵的方法。可能的方法包括:
    • 0:常规方法,使用所有点,即最小二乘法。
    • RANSAC:基于RANSAC的稳健方法。
    • LMEDS:最小中值(Least-Median)稳健方法。
    • RHO:基于PROSAC的稳健方法。
  • ransacReprojThreshold:仅用于 RANSAC 和 RHO 方法。这是允许的最大重投影误差,用于将一对点视为内点。也就是说,如果
    ∥ dstPoints i − convertPointsHomogeneous ( H ⋅ srcPoints i ) ∥ 2 > ransacReprojThreshold \| \texttt{dstPoints} _i - \texttt{convertPointsHomogeneous} ( \texttt{H} \cdot \texttt{srcPoints} _i) \|_2 > \texttt{ransacReprojThreshold} dstPointsiconvertPointsHomogeneous(HsrcPointsi)2>ransacReprojThreshold
    则认为点 i 是离群点。如果 srcPoints 和 dstPoints 以像素为单位测量,则通常将此参数设置在1到10之间是有意义的。
  • 参数mask:由稳健方法(如 RANSAC 或 LMEDS)设置的可选输出掩码。注意输入掩码值被忽略。
  • 参数maxIters:RANSAC的最大迭代次数。
  • 参数confidence:置信水平,介于0和1之间。

该函数找到并返回源平面和目标平面之间的透视变换矩阵 H H H

s i [ x i ′ y i ′ 1 ] ∼ H [ x i y i 1 ] s_i \begin{bmatrix} x'_i \\ y'_i \\ 1 \end{bmatrix} \sim H \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix} si xiyi1 H xiyi1
从而最小化反投影误差:
∑ i ( x i ′ − ( h 11 x i + h 12 y i + h 13 ) h 31 x i + h 32 y i + h 33 ) 2 + ( y i ′ − ( h 21 x i + h 22 y i + h 23 ) h 31 x i + h 32 y i + h 33 ) 2 \sum_i \left( \frac{x'_i - (h_{11}x_i + h_{12}y_i + h_{13})}{h_{31}x_i + h_{32}y_i + h_{33}} \right)^2 + \left( \frac{y'_i - (h_{21}x_i + h_{22}y_i + h_{23})}{h_{31}x_i + h_{32}y_i + h_{33}} \right)^2 i(h31xi+h32yi+h33xi(h11xi+h12yi+h13))2+(h31xi+h32yi+h33yi(h21xi+h22yi+h23))2
如果 method 参数设置为默认值 0,则函数使用所有点对通过简单的最小二乘方案计算初始单应性估计。

然而,如果并非所有的点对(srcPoints_i, dstPoints_i)都符合刚性的透视变换(即存在一些离群点),这个初始估计将会较差。在这种情况下,你可以使用三种稳健方法之一。RANSAC、LMEDS 和 RHO 方法尝试许多不同的随机子集(每次四个点对,共线点对被丢弃),使用这个子集和简单的最小二乘算法估计单应性矩阵,然后计算所估计单应性的质量/优度(对于RANSAC来说是内点的数量,对于LMEDS来说是最小中值重投影误差)。最佳子集随后用于生成单应性矩阵的初始估计和内点/离群点的掩码。

无论是否使用稳健方法,计算出的单应性矩阵都会进一步优化(在稳健方法的情况下仅使用内点),以Levenberg-Marquardt方法减少重投影误差。

RANSAC 和 RHO 方法可以处理几乎任何比例的离群点,但需要一个阈值来区分内点和离群点。LMEDS 方法不需要任何阈值,但只有当内点超过50%时才能正确工作。最后,如果没有离群点且噪声较小,使用默认方法(method=0)。

该函数用于找到初始的内部和外部矩阵。单应性矩阵确定至一个尺度。因此,它被标准化以使 h 33 = 1 h_{33}=1 h33=1。需要注意的是,每当无法估计 H 矩阵时,将返回一个空矩阵。

代码示例


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

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    // 创建虚拟的匹配点数据(假设我们有4对匹配点)
    vector< Point2f > srcPoints = { Point2f( 56.0f, 65.0f ), Point2f( 368.0f, 52.0f ), Point2f( 28.0f, 387.0f ), Point2f( 389.0f, 390.0f ) };

    vector< Point2f > dstPoints = { Point2f( 0.0f, 0.0f ), Point2f( 300.0f, 0.0f ), Point2f( 0.0f, 300.0f ), Point2f( 300.0f, 300.0f ) };

    // 定义输出的单应性矩阵和掩码
    Mat homographyMatrix, mask;

    // 使用 RANSAC 方法计算单应性矩阵
    homographyMatrix = findHomography( srcPoints, dstPoints,
                                       RANSAC,   // 使用RANSAC方法
                                       3.0,      // 点到投影模型的最大重投影误差
                                       mask,     // 输出掩码
                                       2000,     // 最大迭代次数
                                       0.995 );  // 置信水平

    // 打印结果
    cout << "Homography Matrix:\n" << homographyMatrix << endl;

    // 打印哪些点被认为是内点
    cout << "Inliers mask:\n";
    for ( size_t i = 0; i < mask.total(); ++i )
    {
        if ( mask.at< uchar >( i ) )
        {
            cout << "Point " << i + 1 << " is an inlier." << endl;
        }
        else
        {
            cout << "Point " << i + 1 << " is an outlier." << endl;
        }
    }

    return 0;
}

运行结果

Homography Matrix:
[1.055873761296419, 0.09181510967794945, -65.09691276166618;
 0.04690100493754324, 1.125624118501043, -75.79202397907012;
 0.0001832514481695185, 0.0005133370013304123, 0.9999999999999999]
Inliers mask:
Point 1 is an inlier.
Point 2 is an inlier.
Point 3 is an inlier.
Point 4 is an inlier.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT集成IntelRealSense双目摄像头2,集成OpenGL

上一篇文章写了如何把IntelRealSense摄像头的SDK集成到QT项目&#xff0c;并成功采集数据&#xff0c;在没有用OpenCV的情况下完成色彩数据&#xff0c;以及深度数据的显示。 具体地址&#xff1a;https://blog.csdn.net/qujia121qu/article/details/144734163 本次主要写如何…

数据分析的分类和EDIT思维框架

为了服务于企业不同层次的决策&#xff0c;商业数据分析过程需要提供相应的数据科学产出物。 一般而言&#xff0c;数据分析需要经历从需求层、数据层、分析层到输出层四个阶段。 第一个阶段是需求层——确定目标&#xff0c;具体目标需要依据具体的层次进行分析&#xff1a…

面试场景题系列:设计URL短链

1.场景需求界定 1.缩短URL&#xff1a;提供一个长URL&#xff0c;返回一个短很多的URL。 2.重定向URL&#xff1a;提供一个缩短了的URL&#xff0c;重定向到原URL。 3.高可用、可扩展性和容错性考量。 •写操作&#xff1a;每天生成1亿个URL。 •每秒的写操作数&#xff1a…

Linux 基本指令

目录 1.常见指令 1.1 ls指令 1.2 pwd指令 1.3 cd指令 1.4 touch指令 1.5 mkdir指令 1.6 rm和rmdir指令 1.7 man指令 1.8 cp指令 1.9 mv指令 ​编辑 1.10 cat指令 1.11 more指令 1.12 less指令 1.13 head指令 1.14.tail指令 1.15 时间相关的指令 1.16 cal…

WEB UI 创建视图

1 视图名称 (点第1创建视图) 2 模型节点 可以空 3 上下文节点 4 新增节点下的属性 &#xff0c;参考结构(先建好的结构) 5 选择视图类型&#xff1a;&#xff08;表单&#xff0c; 列表&#xff09; 表单 &#xff1a;单条数据 列表 &#xff1a;多条数据&#xff08;表格…

redis cluster实验详解

华子目录 实验环境准备部署redis cluster添加节点删除节点redis cluster集群维护 实验 环境准备 再开3台主机 先把之前3台源码编译的redis删除 [rootredis-node1 ~]# cd /usr/local/redis/ [rootredis-node1 redis]# make uninstall[rootredis-node2 ~]# cd /usr/local/redi…

【详细讲解】hive优化

1、开启本地模式 大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过&#xff0c;有时Hive的输入数据量是非常小的。在这种情况下&#xff0c;为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况&#xff0c;Hive可…

Unity3d UGUI如何优雅的实现Web框架(Vue/Rect)类似数据绑定功能(含源码)

前言 Unity3d的UGUI系统与Web前端开发中常见的数据绑定和属性绑定机制有所不同。UGUI是一个相对简单和基础的UI系统&#xff0c;并不内置像Web前端&#xff08;例如 Vue.js或React中&#xff09;那样的双向数据绑定或自动更新UI的机制。UGUI是一种比较传统的 UI 系统&#xff…

828华为云征文|使用sysbench对Flexus X实例对mysql进行性能测评

目录 一、Flexus X实例概述 1.1?Flexus X实例 1.2?在mysql方面的优势 二、在服务器上安装MySQL 2.1 在宝塔上安装docker 2.2 使用宝塔安装mysql 2.3 准备测试数据库和数据库表 三、安装sysbench并进行性能测试 3.1 使用yum命令sysbench 3.2?运行?sysbench 并进行…

影刀进阶指令 | Kimi (对标ChatGPT)

文章目录 影刀进阶指令 | Kimi &#xff08;对标ChatGPT&#xff09;一. 需求二. 流程三. 实现3.1 流程概览3.2 流程步骤讲解1\. 确定问题2\. 填写问题并发送3\. 检测答案是否出完 四. 运维 影刀进阶指令 | Kimi &#xff08;对标ChatGPT&#xff09; 简单讲讲RPA调用kimi实现…

【教程】通过Docker运行AnythingLLM

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 官方教程&#xff1a;Local Docker Installation ~ AnythingLLM 1、先创建一个目录用于保存anythingllm的持久化文件&#xff1a; sudo mkdir /app su…

游戏引擎学习第65天

回顾我们在模拟区域更改方面的进展 目前我们正在进行游戏的架构调整&#xff0c;目标是建立一个引擎架构。我们正在实施的一个关键变化是引入模拟区域的概念&#xff0c;这样我们可以创建非常大的游戏世界&#xff0c;而这些世界的跨度不必受限于单个浮点变量。 通过这种方式…

【从零开始入门unity游戏开发之——C#篇35】C#自定义类实现Sort自定义排序

文章目录 一、List<T>自带的排序方法1、List<T>调用Sort()排序2、 能够使用 Sort() 方法进行排序的本质 二、自定义类的排序1、通过实现泛型IComparable<T> 接口&#xff08;1&#xff09;示例&#xff08;2&#xff09;直接调用 int 类型的 CompareTo 方法进…

YOLO系列正传(五)YOLOv4论文精解(上):从CSPNet、SPP、PANet到CSPDarknet-53

系列文章 YOLO系列基础 YOLO系列基础合集——小白也看得懂的论文精解-CSDN博客 YOLO系列正传 YOLO系列正传&#xff08;一&#xff09;类别损失与MSE损失函数、交叉熵损失函数-CSDN博客 YOLO系列正传&#xff08;二&#xff09;YOLOv3论文精解(上)——从FPN到darknet-53-C…

Redis 实战篇 ——《黑马点评》(上)

《引言》 在进行了前面关于 Redis 基础篇及其客户端的学习之后&#xff0c;开始着手进行实战篇的学习。因内容很多&#xff0c;所以将会分为【 上 中 下 】三篇记录学习的内容与在学习的过程中解决问题的方法。Redis 实战篇的内容我写的很详细&#xff0c;为了能写的更好也付出…

DevOps实战:用Kubernetes和Argo打造自动化CI/CD流程(2)

DevOps实战&#xff1a;用Kubernetes和Argo打造自动化CI/CD流程&#xff08;2&#xff09; 背景 Tips 翻遍国内外的文档&#xff0c;关于 Argo 作为 CI/CD 当前所有开源的文档&#xff0c;博客&#xff0c;argo官方文档。得出的结论是&#xff1a; argo官方给出的例子都相对…

探索Flink动态CEP:杭州银行的实战案例

摘要&#xff1a;本文撰写自杭州银行大数据工程师唐占峰、欧阳武林老师。将介绍 Flink 动态 CEP的定义与核心概念、应用场景、并深入探讨其技术实现并介绍使用方式。主要分为以下几个内容&#xff1a; Flink动态CEP简介 Flink动态CEP的应用场景 Flink动态CEP的技术实现 Flin…

STM32F103RCT6学习之三:串口

1.串口基础 2.串口发送 1&#xff09;基本配置 注意&#xff1a;实现串口通信功能需在keil中设置打开Use Micro LIB&#xff0c;才能通过串口助手观察到串口信息 2)编辑代码 int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration-------------…

Python中构建终端应用界面利器——Blessed模块

在现代开发中&#xff0c;命令行应用已经不再仅仅是一个简单的文本输入输出工具。随着需求的复杂化和用户体验的重视&#xff0c;终端界面也逐渐成为一个不可忽视的设计环节。 如果你曾经尝试过开发终端UI&#xff0c;可能对传统的 print() 或者 input() 函数感到不满足&#…

OpenHarmony-5.PM 子系统(2)

电池服务组件OpenHarmony-4.1-Release 1.电池服务组件 Battery Manager 提供了电池信息查询的接口&#xff0c;同时开发者也可以通过公共事件监听电池状态和充放电状态的变化。电池服务组件提供如下功能&#xff1a; 电池信息查询。充放电状态查询。关机充电。 电池服务组件架…