ORB-SLAM3算法和代码学习——跟踪参考关键帧TrackReferenceKeyFrame

news2024/11/19 6:39:28

0总述

无论是跟踪恒速运动模型还是跟踪参考关键帧,本质上都是基于帧间匹配跟踪。

跟踪恒速模型是当前帧和上一帧之间的匹配,使用基于恒速模型计算得到的位姿作为优化的初始位姿,基于网格和搜索半径寻找匹配关系。

跟踪参考关键帧是当前帧和参考关键帧之间的匹配,虽然在时序上两个图像帧不连续,但是在空间上参考关键帧和当前帧的视野具有极高的重合度,因此可以作为投影匹配的参与对象,和跟踪恒速运动模型不同的是跟踪参考关键帧使用词袋向量搜索匹配关系,并使用上一帧lastframe的位姿作为当前帧位姿优化的初始位姿。

在得到两帧之间的匹配之后,跟踪恒速模型和跟踪参考关键帧的步骤基本就类似了,首先基于非线性优化计算当前帧的位姿,并过滤匹配误差较大的外点,得到最终的匹配数量,根据匹配数量是否满足要求判断是否跟踪成功。

进入跟踪参考关键帧TrackReferenceKeyFrame()函数的条件:

  • 当前恒速模型为空且IMU没有初始化
  • 或者当前帧距离重定位不久,与重定位只相差两帧
if((!mbVelocity && !pCurrentMap->isImuInitialized()) || mCurrentFrame.mnId<mnLastRelocFrameId+2)
{
   // 跟踪参考关键帧
   bOK = TrackReferenceKeyFrame();
}

1.参考关键帧的确定与更新

首先捋一下参考关键帧mpReferenceKF的确定与更新。

双目或单目初始化成功后,将初始帧设置为第一个参考关键帧,此后在此基础上进行更新。

如果跟踪彻底跪了或者接收到reset的命令,到了重新创建子地图CreateMapInAtlas()这一步,会先将参考关键帧设置为空,然后等着初始化再进行更新。

每当新创建关键帧时CreateNewKeyFrame(),会即时更新当前帧的参考关键帧

在跟踪局部地图时,更新局部地图中的关键帧UpdateLocalKeyFrames()后会将与当前图像帧共视程度最高的关键帧设置为当前帧的参考关键帧和最新关键帧

2.将当前帧的描述子转化为BoW向量

mCurrentFrame.ComputeBoW();

主要使用DBOW库的函数,具体不进行深究了,最终输出的是一个词袋向量记录当前图像包含的单词,以及特征向量即根据描述子计算得到的每个特征点对应的节点信息(该信息用于加速特征匹配)

mpORBvocabulary->transform(vCurrentDesc,// 当前的描述子vector
                                    mBowVec,// 输出,词袋向量,记录的是单词的id及其对应权重TF-IDF值
                                    mFeatVec,// 输出,记录node id及其对应的图像 feature对应的索引
                                    4);// 4表示从叶节点向前数的层数

3.通过词袋BoW加速当前帧与参考帧之间的特征点匹配

int nmatches = matcher.SearchByBoW(mpReferenceKF,mCurrentFrame,vpMapPointMatches);

这一步的作用等同于跟踪恒速运动模型中的SearchByProjection,目的在于寻找当前帧与参考关键帧之间存在的匹配关系,只不过这里使用的是基于词袋向量快速查找的方法。

3.1单词与词典树

参考链接:https://blog.csdn.net/u011341856/article/details/109405181

视觉词典的本质是一个通过聚类得到的KD树,通过离线训练,对各种类型的特征点对应的描述子进行聚类,划分成不同的簇,然后以簇的聚类中心作为子节点,再对子节点中的描述子进行聚类划分子节点的子节点,以此循环,直到满足条件。

1.词典的创建
在这里插入图片描述

如上图所示,假设在训练时一共使用了1000个描述子,首先我们将这1000个描述子进行聚类划分成3个簇,每个簇分别有200,300,500个元素,其中每个簇对应的聚类中心作为kd树第一层的字节点。

然后再对每个字节点对应的簇继续聚类,各自再划分为3个簇,然后形成第二层的9个子节点。

如果不再继续聚类的话,最终我们得到一个分支为3深度为2的kd树。而最下面一层,每个簇的聚类中心被曾为单词,即该图的kd树有9个单词。

当我们保存整个训练好的词汇树时,只要把树的结构和聚类中心都保存下来就行了,其中那些用来训练的描述子都可以扔掉了。

整个过程总结如下:

  • step1.在根节点将样本聚为k类
  • step2.对第一层的每个节点,把属于该节点的样本再聚为k类
  • step3.重复step2,最后得到叶子层,每个叶子对应一个word,最终得到的树就是vocabulary tree

2.基于词袋向量搜索的特征匹配

假设对于当前帧图像提取了1000个特征点,对应的有1000个描述子,在ComputeBoW()函数中我们已经将整幅图像中的描述子转化为了词袋向量,同时记录了每个描述子对应的叶节点id。至于怎么计算的每个描述子对应的节点信息,就是和每一层节点(聚类中心描述子)计算描述子距离,和哪个节点的描述子距离最近该描述子就属于哪个节点。

在进行特征匹配时,为了加速匹配只计算属于同一节点的描述子以寻找匹配关系,这样就将1000对1000的暴力匹配转换为某个节点的小范围暴力匹配,节省计算时间。

每完成一个节点中的特征匹配,就要对这些匹配进行验证:

  • 相互匹配的两个特征点的描述子距离要小于设定的阈值
  • 最佳匹配的描述子距离要比较明显的小于次佳匹配的描述子距离(在SearchByBoW中最佳距离要小于0.7倍的次佳距离)

最后完成所有的特征匹配后需要对匹配的特征旋转偏差进行旋转一致性验证,然后记录最终的匹配关系,用于后续的非线性优化。

3.基于词袋向量的回环检测和重定位

参考链接:https://zhuanlan.zhihu.com/p/354616831

回环检测和重定位在本质上都是场景识别,在这两个模块中都使用了词袋向量进行了加速匹配。上面我们介绍了怎么为每一个特征点对应的描述子寻找对应的叶节点(也就是单词),假如我们在一张图像中提取了1000个特征点,对应1000个描述子,通过计算我们将这1000个描述子分别找到了对应的叶节点或者说单词,这样最终一帧图像可以用若干个单词进行表示。

随着SLAM过程的进行会不断的创建关键帧,同时会将关键帧转化为词袋向量,在进行回环检测和重定位时会遍历所有关键帧,其中和当前帧公共单词数最多的关键帧就是当前帧的最佳候选关键帧。

这里只简单叙述一下原理,在后面重定位和回环检测部分代码解析时再进行详细分析。

4.基于非线性优化的位姿估计

在拿到匹配关系之后就是和跟踪恒速模型一样的老三样了,只不过位姿优化的初始值是上一帧的位姿,而非借助恒速模型

mCurrentFrame.SetPose(mLastFrame.GetPose());

非线性优化和跟踪恒速运动模型使用同一个优化函数

Optimizer::PoseOptimization(&mCurrentFrame);

在非线性优化函数中,会根据投影误差筛选外点,最后根据投影匹配的内点数量决定当前是否匹配成功。

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

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

相关文章

SpringCloudAlibabaSentinel实现网关动态限流

目录 1.SpringCloudAlibabaSentinel实现网关动态限流 1.概念和来历 2.概览及控制台搭建 3.控制台有哪些能力 4.功能及设计理念 5.限流的几种方法 2.SpringCloud Alibaba Sentinel 的降级功能 1.yml中添加配置 2.编写配置类 3.编写兜底工具类 3.Sentinel还对Feigin实…

代码整洁之道,好的代码就是为了更美好的生活

概述 美国童子军有一条简单的军规&#xff1a;让营地比你来时更干净。当梳理代码时&#xff0c;坚守此军规&#xff1a;每次 review 代码&#xff0c;让代码比你发现它时更整洁。 一位大神说过&#xff1a;“衡量代码质量的唯一有效标准&#xff1a;WTF/min”&#xff0c;并配…

14.Isaac教程--Jetbot应用示例

Jetbot应用示例 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 本节介绍如何将 Isaac SDK 与 NVIDIA 新的高性能模拟平台 Omniverse 集成&#xff0c;以让 Jetbot 在模拟中跟随球。 本节作为使用三个 Jetbot 应用程序进入 Omniverse 和 Isaac …

国产的蓝光存储设备能算信创产品吗?

这个问题是客户前几天问我的&#xff0c;笔者只能实事求是的告诉他&#xff1a;目前还不能算&#xff01;首先蓝光存储产品暂时未被列入信创名录&#xff0c;其次蓝光存储中最核心的读写设备&#xff08;蓝光光驱&#xff09;的技术专利和生产工艺基本被日本企业&#xff08;索…

LeetCode 101. 对称二叉树

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 欢迎来到茶色岛独家岛屿&#xff0c;本期将为大家揭晓LeetCode 101. 对称二叉树&#xff0c;做好准备了么&#xff0c;那么开始吧。 &#x1f332;&#x1f332;&#x1f434;&#x1f434; 一、题目名称 LeetCode 1…

高端运动耳机哪个品牌最好、公认最好的跑步耳机品牌排名

在健身、运动的时候&#xff0c;过程往往是很枯燥的&#xff0c;这时候&#xff0c;如果能有动感的音乐在旁&#xff0c;调动我们的积极性&#xff0c;就再好不过了&#xff0c;所以很多人在运动的时候都会选择佩戴一款运动蓝牙耳机。不过适合运动的蓝牙耳机少之又少&#xff0…

七、MySQL 多表查询详解(附练习题及答案----超详细)

文章目录一、笛卡尔积&#xff08;或交叉连接&#xff09;的理解二、多表查询分类讲解2.1 分类1&#xff1a;等值连接 vs 非等值连接2.2 分类2&#xff1a;自连接 vs 非自连接2.3 分类3&#xff1a;内连接 vs 外连接2.4 SQL99语法实现多表查询2.4.1 内连接2.4.2 左连接2.4.3 右…

System Description 步骤

纲要&#xff1a; 在有了Composition以后&#xff0c;下一步就是把它分配到ECU里面。 1. Create System Description Import DBC file, select ECUs and CAN Frames under the DBC. Then it will create "SystemDescription.arxml" file. [1] 2. Check the content…

地图下载器代码结构设计及功能实现

jcef包引入表结构设计后台关键代码结构前端关键代码结构功能展示启动页底图切换绘制选择下载区域行政区划切换选择下载区域下载关键代码import { InnerMqClient } from ../../rx/inner-mq.service;import { SubmitService } from ../../service/submit.service;import { MapBas…

马蹄集 字符判断

字符判断 难度&#xff1a;白银 时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 输入一个字符&#xff0c;判断是数字字符、大写字母、小写字母、算术运算符、 关系运算符、逻辑运算符&#xff0c;还是其他字符&#xff0c;分别输出Number?”, "Capital letter?”,…

Springboot集成knife4j文档时,接口信息没有显示

我使用的 SpringBoot、knife4j 版本jar包如下所示&#xff1a;<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.5.RELEASE</version><relativePath/> …

kube-bench初体验

kube-bench是一个通过运行CIS Kubernetes benchmark中记录的checker来检查Kubernetes是否安全部署的工具。测试&#xff0c;找gap&#xff0c;audit&#xff0c;都可以啊关于CIS k8s benchmark 参见 CIS Kubernetes Benchmarks (cisecurity.org)就是说&#xff0c;想做k8s加固&…

再学C语言32:函数——多源代码文件程序及其编译

使用多个函数时&#xff0c;最简单的方法是将所有函数放在同一文件中&#xff0c;就像编译单个函数的文件一样对该文件进行编译 具体的编译过程根据操作系统不同而具有差异性 Window系统下的编译器是面向工程的 工程&#xff08;project&#xff09;&#xff1a;描述了一个特…

【Linux】项目自动化构建工具—make/makefile

文章目录1. 什么是make/makefile&#xff1f;2. make/makefile的使用2.1 实例代码2.2 依赖关系和依赖方法2.3 项目清理2.4 make是如何确定是否编译的3. Linux第一个小程序—进度条3.1 \r 和 \n3.2 进度条小程序1. 什么是make/makefile&#xff1f; make是一个命令工具&#xf…

【Spring6源码・IOC】Bean的初始化 - 终结篇

前面两篇&#xff0c;我们着重讲解了一下《BeanDefinition的加载》和《bean的实例化》。 这一篇我们来讲解一下bean的初始化。 我们这里的案例依旧是以SpringBoot3.0、JDK17为前提&#xff0c;案例代码如下&#xff1a; Component public class A {Autowiredprivate B b;}Com…

Windows+iis+php+mysql搭建wordpress

准备工作 WindowsServer一台 IIS&#xff0c;在Server上开启 PHP:PHP: Downloads Mysql:MySQL :: MySQL Downloads wordpress下载 | WordPress.org China 简体中文 PHP程序在IIS上以fastcgi方式运行&#xff0c;在安装mysql和php之前确保vc库已安装。 IIS确保开启CGI模块…

JAVA开发(AOP之ProceedingJoinPoint)

我们在开发过程中经常使用到自定义注解来实现在一些类或者方法执行过程中切面&#xff0c;统一实现某些业务操作。例如自定义注解import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang…

YOLOv7:面向实时检测的目标检测器 | 附结构图

YOLOv7 在 5 FPS 到 160 FPS 范围内的速度和准确度都超过了所有已知的目标检测器&#xff0c;并且在 GPU V100 上 30 FPS 或更高的所有已知实时目标检测器中具有最高的准确度 56.8% AP。 YOLOv7-E6 目标检测器&#xff08;56 FPS V100&#xff0c;55.9% AP&#xff09;比基于Tr…

小孩护眼灯什么牌子的好?分享四款最好的台灯品牌

最近发现&#xff0c;在接送我家神兽上下学时&#xff0c;小朋友们会揉眼睛&#xff0c;眼睛始终没睁开的感觉&#xff0c;还有不少小学就戴上了眼镜&#xff0c;我深知戴眼镜&#xff0c;真的很麻烦&#xff0c;所以更加看重孩子的护眼工作。市面上越来越多护眼灯&#xff0c;…

Java高手速成 | 实现人物拼图游戏

拼图游戏指将一幅图片分割成若干拼块&#xff0c;并随机打乱顺序&#xff0c;当将所有拼块都放回原位置时就完成了拼图(游戏结束)。 01、游戏介绍 在游戏中&#xff0c;拼块以随机顺序排列&#xff0c;网格上有一个位置是空的。完成拼图的方法是利用这个空位置移动拼块&#xf…