【Opencv】三维重建之cv::recoverPose()函数(1)
官网链接
从估计的本质矩阵和两幅图像中的对应点恢复相机之间的旋转和平移,使用光束法则进行检验。返回通过检验的内点数目。
#include <opencv2/calib3d.hpp>
int cv::recoverPose ( InputArray E,
InputArray points1,
InputArray points2,
InputArray cameraMatrix,
OutputArray R,
OutputArray t,
InputOutputArray mask = noArray()
)
int recoverPose( InputArray E, InputArray points1, InputArray points2,OutputArray R, OutputArray t, double focal = 1.0,Point2d pp = Point2d(0, 0), InputOutputArray mask = noArray() );
int recoverPose( InputArray E, InputArray points1, InputArray points2,InputArray cameraMatrix, OutputArray R, OutputArray t, double distanceThresh, InputOutputArray mask = noArray(),OutputArray triangulatedPoints = noArray());
E:已经求解出来的本质矩阵,它是3x3的矩阵;
points1:第一张图片中的点;
points2:第二张图片中的点;
cameraMatrix:相机内参矩阵,它是3x3的矩阵;
R:求解出来的两帧图片之间的旋转矩阵;
t:求解出来的两帧图片之间的平移向量;
focal:相机焦距;
pp:像素坐标的原点;
distanceThresh:点的距离阈值,用来滤出距离较远的点;
triangulatedPoints:通过三角化还原点;
官方例子
// Example. Estimation of fundamental matrix using the RANSAC algorithm
int point_count = 100;
vector<Point2f> points1(point_count);
vector<Point2f> points2(point_count);
// initialize the points here ...
for( int i = 0; i < point_count; i++ )
{points1[i] = ...;points2[i] = ...;
}
// cametra matrix with both focal lengths = 1, and principal point = (0, 0)
Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
Mat E, R, t, mask;
E = findEssentialMat(points1, points2, cameraMatrix, RANSAC, 0.999, 1.0, mask);
recoverPose(E, points1, points2, cameraMatrix, R, t, mask);
**说明: **
1. 通过该函数求解出来的 R , t R,t R,t ,它表示的是points1到points2的变换,也就是 R 21 R_{21} R21 , t 21 t_{21} t21
2.该函数求解出来的 R 21 R_{21} R21 , t 21 t_{21} t21,已经是最合适已经通过内部的代码去掉了另外三种错误的解
3. cv::recoverPose()中points1和points2的输入顺序,必须也要和求本质矩阵时对函数cv::findEssentialMat()输入的顺序相同。
4. 使用方法,可以直接包含对应的头文件,也可以直接将函数的内部实现拷贝也可以自己实现(vins),如下:
int recoverPose( InputArray E, InputArray _points1, InputArray _points2, InputArray _cameraMatrix,OutputArray _R, OutputArray _t, InputOutputArray _mask){Mat points1, points2, cameraMatrix;_points1.getMat().convertTo(points1, CV_64F);_points2.getMat().convertTo(points2, CV_64F);_cameraMatrix.getMat().convertTo(cameraMatrix, CV_64F);int npoints = points1.checkVector(2);CV_Assert( npoints >= 0 && points2.checkVector(2) == npoints &&points1.type() == points2.type());CV_Assert(cameraMatrix.rows == 3 && cameraMatrix.cols == 3 && cameraMatrix.channels() == 1);if (points1.channels() > 1){points1 = points1.reshape(1, npoints);points2 = points2.reshape(1, npoints);}double fx = cameraMatrix.at<double>(0,0);double fy = cameraMatrix.at<double>(1,1);double cx = cameraMatrix.at<double>(0,2);double cy = cameraMatrix.at<double>(1,2);points1.col(0) = (points1.col(0) - cx) / fx;points2.col(0) = (points2.col(0) - cx) / fx;points1.col(1) = (points1.col(1) - cy) / fy;points2.col(1) = (points2.col(1) - cy) / fy;points1 = points1.t();points2 = points2.t();Mat R1, R2, t;decomposeEssentialMat(E, R1, R2, t);Mat P0 = Mat::eye(3, 4, R1.type());Mat P1(3, 4, R1.type()), P2(3, 4, R1.type()), P3(3, 4, R1.type()), P4(3, 4, R1.type());P1(Range::all(), Range(0, 3)) = R1 * 1.0; P1.col(3) = t * 1.0;P2(Range::all(), Range(0, 3)) = R2 * 1.0; P2.col(3) = t * 1.0;P3(Range::all(), Range(0, 3)) = R1 * 1.0; P3.col(3) = -t * 1.0;P4(Range::all(), Range(0, 3)) = R2 * 1.0; P4.col(3) = -t * 1.0;// Do the cheirality check.// Notice here a threshold dist is used to filter// out far away points (i.e. infinite points) since// there depth may vary between postive and negtive.double dist = 50.0;Mat Q;triangulatePoints(P0, P1, points1, points2, Q);Mat mask1 = Q.row(2).mul(Q.row(3)) > 0;Q.row(0) /= Q.row(3);Q.row(1) /= Q.row(3);Q.row(2) /= Q.row(3);Q.row(3) /= Q.row(3);mask1 = (Q.row(2) < dist) & mask1;Q = P1 * Q;mask1 = (Q.row(2) > 0) & mask1;mask1 = (Q.row(2) < dist) & mask1;triangulatePoints(P0, P2, points1, points2, Q);Mat mask2 = Q.row(2).mul(Q.row(3)) > 0;Q.row(0) /= Q.row(3);Q.row(1) /= Q.row(3);Q.row(2) /= Q.row(3);Q.row(3) /= Q.row(3);mask2 = (Q.row(2) < dist) & mask2;Q = P2 * Q;mask2 = (Q.row(2) > 0) & mask2;mask2 = (Q.row(2) < dist) & mask2;triangulatePoints(P0, P3, points1, points2, Q);Mat mask3 = Q.row(2).mul(Q.row(3)) > 0;Q.row(0) /= Q.row(3);Q.row(1) /= Q.row(3);Q.row(2) /= Q.row(3);Q.row(3) /= Q.row(3);mask3 = (Q.row(2) < dist) & mask3;Q = P3 * Q;mask3 = (Q.row(2) > 0) & mask3;mask3 = (Q.row(2) < dist) & mask3;triangulatePoints(P0, P4, points1, points2, Q);Mat mask4 = Q.row(2).mul(Q.row(3)) > 0;Q.row(0) /= Q.row(3);Q.row(1) /= Q.row(3);Q.row(2) /= Q.row(3);Q.row(3) /= Q.row(3);mask4 = (Q.row(2) < dist) & mask4;Q = P4 * Q;mask4 = (Q.row(2) > 0) & mask4;mask4 = (Q.row(2) < dist) & mask4;mask1 = mask1.t();mask2 = mask2.t();mask3 = mask3.t();mask4 = mask4.t();// If _mask is given, then use it to filter outliers.if (!_mask.empty()){Mat mask = _mask.getMat();CV_Assert(mask.size() == mask1.size());bitwise_and(mask, mask1, mask1);bitwise_and(mask, mask2, mask2);bitwise_and(mask, mask3, mask3);bitwise_and(mask, mask4, mask4);}if (_mask.empty() && _mask.needed()){_mask.create(mask1.size(), CV_8U);}CV_Assert(_R.needed() && _t.needed());_R.create(3, 3, R1.type());_t.create(3, 1, t.type());int good1 = countNonZero(mask1);int good2 = countNonZero(mask2);int good3 = countNonZero(mask3);int good4 = countNonZero(mask4);if (good1 >= good2 && good1 >= good3 && good1 >= good4){R1.copyTo(_R);t.copyTo(_t);if (_mask.needed()) mask1.copyTo(_mask);return good1;}else if (good2 >= good1 && good2 >= good3 && good2 >= good4){R2.copyTo(_R);t.copyTo(_t);if (_mask.needed()) mask2.copyTo(_mask);return good2;}else if (good3 >= good1 && good3 >= good2 && good3 >= good4){t = -t;R1.copyTo(_R);t.copyTo(_t);if (_mask.needed()) mask3.copyTo(_mask);return good3;}else{t = -t;R2.copyTo(_R);t.copyTo(_t);if (_mask.needed()) mask4.copyTo(_mask);return good4;}}int recoverPose( InputArray E, InputArray _points1, InputArray _points2, OutputArray _R,OutputArray _t, double focal, Point2d pp, InputOutputArray _mask){Mat cameraMatrix = (Mat_<double>(3,3) << focal, 0, pp.x, 0, focal, pp.y, 0, 0, 1);return cv::recoverPose(E, _points1, _points2, cameraMatrix, _R, _t, _mask);}
}相关文章:
【Opencv】三维重建之cv::recoverPose()函数(1)
官网链接 从估计的本质矩阵和两幅图像中的对应点恢复相机之间的旋转和平移,使用光束法则进行检验。返回通过检验的内点数目。 #include <opencv2/calib3d.hpp>int cv::recoverPose ( InputArray E, InputArray points1, InputArray points2, InputArray …...
Perl兼容正则表达式函数-PHP8知识详解
在php8中有两类正则表达式函数,一类是perl兼容正则表达式函数,另一类是posix扩展正则表达式函数。二者区别不大,我们推荐使用Perl兼容正则表达式函数。 1、使用正则表达式对字符串进行匹配 用正则表达式对目标字符串进行匹配是正则表达式的主…...
Python处理空值NaN
fork_address_tempread_excel_column_to_list(./eqp_info.xls,Sheet1,车辆地址)for i in fork_address_temp:print(type(i))fork_address[0 if address nan else address for address in fork_address_temp]fork_address结果 <class float><class float><class…...
软件机器人助力交通运输局数据录入,实现高效管理
随着科技的迅速发展,许多传统的行业正在寻求通过科技创新优化工作流程、提升效率。在这样的大背景下,交通运输部门也开始注重引入科技手段改善工作流程。博为小帮软件机器人正逐步改变着交通运输局的工作方式。 软件机器人:交通管理的利器 博…...
时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化
时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化 目录 时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SGMD分解算法(辛几何模态分解),分解结果可视…...
FinalShell报错:Swap file “.docker-compose.yml.swp“ already exists
FinalShell中编辑docker-compose.yml文件,保存时报错:Swap file ".docker-compose.yml.swp" already exists;报错信息截图如下: 问题原因:有人正在编辑docker-compose.yml文件或者上次编辑没有保存ÿ…...
卷积过程详细讲解
1:单通道卷积 以单通道卷积为例,输入为(1,5,5),分别表示1个通道,宽为5,高为5。假设卷积核大小为3x3,padding0,stride1。 卷积过程如下: 相应的卷积核不断…...
代码随想录第五十六天
代码随想录第五十六天 Leetcode 583. 两个字符串的删除操作Leetcode 72. 编辑距离 Leetcode 583. 两个字符串的删除操作 题目链接: 两个字符串的删除操作 自己的思路:想到了,但是初始化初始错了!!!! 思路1:直接动规五…...
.NET 最便捷的Log4Net日志记录器
最便捷的Log4Net使用方法 LOG4NET 配置日志记录器开始引用nuget LOG4NET 配置日志记录器 Apache log4net 库是一个帮助程序员将日志语句输出到各种的工具 的输出目标。log4net是优秀的Apachelog4j™框架的移植 Microsoft.NET 运行时。我们保持了与原始log4j相似的框架 同时利…...
深入探讨软件逆向工程:解密黑盒的奥秘
引言 逆向工程作为计算机科学领域中的一项关键技术,扮演着解密、漏洞分析、反病毒等诸多领域的重要角色。本文将深入探讨逆向工程的概念、应用领域以及一些常用的逆向工程技术。 什么是逆向工程? 逆向工程是指通过分析已有的程序或设备,推…...
利用tidevice+mysql+grafana实现ios性能测试
利用tidevicemysqlgrafana实现ios性能测试 1.什么是tidevice? tidevice是一个可以和ios设备进行通信的工具,提供以下功能: 截图获取手机信息ipa包的安装和卸载根据bundleID 启动和停止应用列出安装应用信息模拟Xcode运行XCTest,…...
内网安全:WMI协议与SMB协议横向移动
目录 网络拓扑图 网络环境说明 WMI协议 SMB协议 域内信息收集 WMI协议 - 横向移动 利用方式一:wmic命令 利用方式一:cscript 利用方式一:impacket SMB协议 - 横向移动 利用方式一:psexec 利用方式二:psexe…...
05-Numpy基础-用于数组的文件输入输出
np.save和np.load是读写磁盘数组数据的两个主要函数。默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为.npy的文件中的: 如果文件路径末尾没有扩展名.npy,则该扩展名会被自动加上。然后就可以通过np.load读取磁盘上的数组࿱…...
Docker微服务实战
文章目录 业务需求IDEA编写代码编写Dockerfile构建镜像运行容器网页端访问测试 业务需求 利用Docker部署应用服务,实现在网页端通过输入地址 ip:端口/hello/docker,页面显示hello docker ! IDEA编写代码 创建springboot项目 网上很多教程,此步骤省略……...
NLNet论文总结和代码实现
Non-local Neural Networks(非局部神经网络):使用自注意力机制捕获远程依赖。 论文: https://arxiv.org/pdf/1711.07971.pdf 源码: 长距离依赖关系,顾名思义,是要和远程建立关系,在l…...
数字 IC 设计职位经典笔/面试题(三)
共100道经典笔试、面试题目(文末可全领) 1. IC 设计中同步复位与异步复位的区别? 同步复位在时钟沿变化时,完成复位动作。异步复位不管时钟,只要复位信号满足条件,就完成复位动作。异步复位对复位信号要求…...
Matlab分割彩色图像
彩色图像 彩色图像除有亮度信息外,还包含有颜色信息。以最常见的RGB(红绿蓝)彩色空间为例来简要说明彩色图像: 彩色图像可按照颜色的数目来划分。例如,256色图像和真彩色图像(2的16次方=21677…...
[数据集][目标检测]垃圾目标检测数据集VOC格式14963张44类别
数据集格式:Pascal VOC格式(不包含分割的txt文件,仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数):14963 标注数量(xml文件个数):14963 标注类别数:44 标注类别名称:["toiletries","plastic utensi…...
MATLAB算法实战应用案例精讲-【深度学习】推荐系统模型DSSMDeepFM
目录 前言 DSSM 输入层 英文 中文 表示层 匹配层 优缺点 DeepFM模...
基于springboot的社区生活缴费系统/基于javaweb的水电缴费系统
摘 要 网络的广泛应用给生活带来了十分的便利。所以把社区生活缴费管理与现在网络相结合,利用java语言建设社区生活缴费系统,实现社区生活缴费管理的信息化。则对于进一步提高社区生活缴费管理发展,丰富社区生活缴费管理经验能起到不少的促进…...
程序员做量化交易详解
程序员做量化交易详解 量化交易是程序员将编程能力与金融市场相结合的典型应用场景。作为系统分析师,理解量化交易的全貌有助于在金融IT系统设计中把握关键要素。下面为你全面解析。 📌 一、什么是量化交易? 量化交易是指利用数学模型、统计方法和计算机技术,通过程序化…...
QwQ-32B多模态应用实践:文本与图像联合处理
QwQ-32B多模态应用实践:文本与图像联合处理 最近在折腾AI模型的时候,发现很多朋友对多模态应用特别感兴趣。所谓多模态,简单说就是让AI能同时理解文字和图片,甚至还能把两者结合起来处理。这听起来挺酷的,但实际操作起…...
医疗器械小白必看:B型、BF型、CF型设备到底怎么选?附真实医院案例解析
医疗器械采购指南:B型、BF型与CF型设备的实战选择策略 去年某三甲医院ICU因监护仪选型不当导致患者数据异常的事件,让医疗器械电气安全标准重新成为行业焦点。作为医疗设备采购人员,面对B型、BF型、CF型这些专业术语时,是否常感到…...
[Python3高阶编程] - 异步编程深度学习指南一: 基础知识( 源代码)
异步编程深度学习指南 原文: https://blog.csdn.net/andylin02/article/details/159649164?spm1001.2014.3001.5502 #!/home/admin/.pyenv/versions/3.9.12/bin/python # -*- coding: utf-8 -*-o import aiohttp import asyncio from asyncio import Semaphoreasync def fetc…...
革命性本地AI聊天应用ChatRTX:基于TensorRT-LLM和RAG的完整指南
革命性本地AI聊天应用ChatRTX:基于TensorRT-LLM和RAG的完整指南 【免费下载链接】trt-llm-rag-windows 项目地址: https://gitcode.com/gh_mirrors/tr/trt-llm-rag-windows ChatRTX是一款革命性的本地AI聊天应用程序,它基于NVIDIA的TensorRT-LLM…...
从‘虚拟’到‘物理’:程序员视角下的内存块、页框与页到底是怎么协作的?
从‘虚拟’到‘物理’:程序员视角下的内存块、页框与页到底是怎么协作的? 当你调试程序时遇到"Segmentation fault"或"Page fault"错误,是否好奇这些术语背后究竟发生了什么?作为开发者,我们每天都…...
Typora搭配PicGo实现Markdown图片自动上传到Gitee的保姆级教程
Typora与PicGo联动:打造Gitee图床自动化工作流 对于长期使用Markdown写作的技术博主和文档工程师来说,图片管理始终是个痛点。本地图片导致文档迁移困难,第三方图床存在失效风险,而手动上传又严重打断创作流程。这套基于TyporaPic…...
【esp32使用jtag下载和调试 Can‘t perform JTAG flash, because OpenOCD server is not running!】
ESP-IDF使用USB的JTAG下载调试时报错现象。 2026年初尝试了很多方法jtag下载,网上很多资料都有问题,以下实操烧录成功过程记录。 提示: Can’t perform JTAG flash, because OpenOCD server is not running! ❌ Error: libusb_open() faile…...
JIT 与 AOT 编译区别
注:本文为 “JIT 与 AOT ” 相关合辑。 英文引文,机翻未校。 中文引文,未整理去重。 图片清晰度受引文原图所限。 如有内容异常,请看原文。 JIT 与 AOT 区别 1 基本概念与典型实例 JIT (Just-In-Time):即时编译&#…...
【Java并发进阶】多线程案例核心解析(单例模式、阻塞队列、定时器、线程池...)
在实际开发中,多线程不仅仅是“会创建线程”那么简单。如何安全地共享数据、如何协调多个线程之间的协作、如何提升系统性能,才是工程中的重点。本文结合经典案例,深入理解:单例模式、生产者-消费者模型、阻塞队列、定时器、线程池…...
