【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语言建设社区生活缴费系统,实现社区生活缴费管理的信息化。则对于进一步提高社区生活缴费管理发展,丰富社区生活缴费管理经验能起到不少的促进…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
