4.1ORB-SLAM3之处理缓存队列中的关键帧

news2024/10/7 11:27:19

0.简介

该函数主要包括以下几个部分:

  • 计算该关键帧特征点的Bow信息
  • 更新当前关键帧新增地图点的属性
  • 更新共视图中关键帧间的连接关系
  • 将该关键帧插入到地图中

1.计算该关键帧特征点的Bow信息ComputeBoW()

vector<cv::Mat> vCurrentDesc = Converter::toDescriptorVector(mDescriptors);
mpORBvocabulary->transform(vCurrentDesc, mBowVec, mFeatVec, 4);

将当前关键帧的所有描述子vCurrentDesc转换为词袋向量,主要用于加速特征匹配(跟踪参考关键帧)和计算两帧之间的相似性(重定位和回环检测)。前面已经讲过,在ORB特征检测后得到的描述子是一个N行的cv::Mat,N表示特征点的数量。为了方便将描述子进行词袋向量转换会对描述子进行一些转换,即将每个特征点对应的描述子拿出来放到vector容器中,得到一个cv::Mat类型的N维vector,其每个元素都表示一个特征点的描述子。

计算描述子函数的输出有两个:
mBowVec记录了由描述子转换得到的词袋向量信息以及每个单词的权重,这个主要用于计算两帧之间的图像相似性。

mFeatVec记录了每个特征点的索引以及该特征点对应单词在词袋树上的节点id,根据这一信息可以在寻找特征匹配时只对统一节点上的特征点寻找匹配关系,以实现加速匹配。

2.更新当前关键帧新增地图点的属性

参考链接:《ORB-SLAM2代码详解03: 地图点MapPoint》

  1. 为当前地图点添加观测
  2. 更新平均观测方向和观测距离范围
  3. 更新地图点的最佳描述子
if(!pMP->IsInKeyFrame(mpCurrentKeyFrame)){
   pMP->AddObservation(mpCurrentKeyFrame, i);
   pMP->UpdateNormalAndDepth();
   pMP->ComputeDistinctiveDescriptors();
}

2.1为当前地图点添加观测AddObservation

表示该地图点被当前关键帧观测到了,函数AddObservation()EraseObservation()同时维护两个成员变量mObservationsnObs以更新地图点的观测情况。

std::map<KeyFrame*,size_t> mObservations是一个map类型的容器,键KeyFrame*表示观测到该Mappoint的关键帧,值size_t表示该MapPoint在KF中的索引。通过函数GetIndexInKeyFrame()IsInKeyFrame()可以对mObservations进行简单查询。

nObs为int类型变量,记录了当前地图点被多少个关键帧相机观测到了(单目关键帧每次观测算1个相机,双目/RGBD帧每次观测算2个相机).

2.2更新平均观测方向和观测距离范围UpdateNormalAndDepth

函数UpdateNormalAndDepth()更新当前地图点的平均观测方向和距离.

1.观测方向:
其中平均观测方向是根据mObservations中所有观测到本地图点的关键帧取平均得到的,通过地图点与关键帧对应相机光心的连线可以得到该地图点的观测方向mWorldPos - pKF->GetCameraCenter(),然后计算该地图点在所有关键帧中的观测方向,并取平均值。

// UpdateNormalAndDepth()
for(map<KeyFrame*,tuple<int,int>>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
{
   KeyFrame* pKF = mit->first;

   tuple<int,int> indexes = mit -> second;
   int leftIndex = get<0>(indexes), rightIndex = get<1>(indexes);

   if(leftIndex != -1){
      Eigen::Vector3f Owi = pKF->GetCameraCenter();// 获得光心相机坐标
      Eigen::Vector3f normali = Pos - Owi;// 计算到光心的向量也即观测方向
      normal = normal + normali / normali.norm();// 对每个方向向量进行归一化然后相加,最终得到综合方向向量
      n++;
   }
   if(rightIndex != -1){// 针对双单目组合模式
      Eigen::Vector3f Owi = pKF->GetRightCameraCenter();
      Eigen::Vector3f normali = Pos - Owi;
      normal = normal + normali / normali.norm();
      n++;
   }
}

(2)观测距离:
平均观测距离是根据参考关键帧得到的,观测距离指的是该3D点到参考关键帧光心的距离。

Eigen::Vector3f PC = Pos - pRefKF->GetCameraCenter();
const float dist = PC.norm();

...

{
   unique_lock<mutex> lock3(mMutexPos);
   mfMaxDistance = dist*levelScaleFactor;// 计算距离上限
   mfMinDistance = mfMaxDistance/pRefKF->mvScaleFactors[nLevels-1];// 计算距离下限
   mNormalVector = normal/n;// 计算平均观测距离
}

除了更新观测距离外还会更新该3D点观测距离的上下限:mfMinDistancemfMaxDistance,用于判断某个特征点在反投影后是否真正在视野范围内,其计算方式金字塔图像的尺度有关。

如下图,mfMaxDistance表示若地图点匹配在某特征提取器图像金字塔第7层上的某特征点,观测距离值;mfMinDistance表示若地图点匹配在某特征提取器图像金字塔第0层上的某特征点,观测距离值;
在这里插入图片描述

反过来,也可以根据平均观测距离和该特征点的观测距离上限推测特征点所在的金字塔图像的level.
在这里插入图片描述

计算公式如下:
在这里插入图片描述

2.3更新地图点的最佳描述子ComputeDistinctiveDescriptors

对于某个3D地图点会在多个时刻下被相机观测到,因此同一3D地图点会被多个关键帧观测到,也即该3D点是多个特征点的反投影点,该3D点的描述子也由与其对应特征点的描述子决定。假设该3D点存在N个对应的特征点,计算方式如下:

  • 统计该3D点所有对应特征点的描述子
  • 计算这些描述子两两之间的距离,则可以得到一个关于描述子距离NxN的矩阵
  • 每个描述子对应N个与其他描述子的距离,对于每个描述子取出其与其他描述子距离的中位数
  • 对N个中位数进行排序,选择中位数最小时对应的描述子作为3D点的描述子

3.3 更新共视图中关键帧间的连接关系

void KeyFrame::UpdateConnections(bool upParent)

在没有执行这个函数前,关键帧只和MapPoints之间有连接关系(将观测信息进行关联),这个函数可以更新关键帧之间的连接关系。

  1. 首先获得该关键帧的所有MapPoint点,统计有多少关键帧与当前关键帧存在共视关系(是否观测到了同一个3D点),统计结果放在KFcounter(可以通过地图点的observations属性获得)。
  2. 只要共视点数量大于阈值th=15,就为关键帧与当前帧互相添加连接关系,边的权重为共视点的数量。
  3. 如果遍历完所有的共视关键帧,没有连接到关键帧(权重超过阈值),则对权重最大的关键帧建立连接关系

前面三步都是为了寻找满足要求的关键帧,找到有资格和当前KF建立连接关系的共视关键帧,添加关键帧的核心函数如下:

void KeyFrame::AddConnection(KeyFrame *pKF, const int &weight)
{
    {
        unique_lock<mutex> lock(mMutexConnections);
        if(!mConnectedKeyFrameWeights.count(pKF))// 如果没建立共视关系则直接建立连接关系,本质上是一个map类型的变量
            mConnectedKeyFrameWeights[pKF]=weight;
        else if(mConnectedKeyFrameWeights[pKF]!=weight)// 如果已经建立共视关系了更新权重(共视点的数量)
            mConnectedKeyFrameWeights[pKF]=weight;
        else
            return;
    }

   // 按照权重对当前关键帧的共视关键帧进行排序
   UpdateBestCovisibles();
}
  1. 更新生成树的连接,初始化该关键帧的父关键帧为共视程度最高的那个关键帧,将当前关键帧作为其子关键帧

4.将该关键帧插入到地图中

本质上就是将该关键帧KF插入到当前活跃子地图对应成员变量的容器中

void Map::AddKeyFrame(KeyFrame *pKF){
   ...
   mspKeyFrames.insert(pKF);
   ...
}

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

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

相关文章

ModaHub魔搭社区:向量数据库功能主要特点和应用场景

目录 主要特点 向量数据库功能 高性能向量搜索 低延迟高召回率 多向量搜索索引 向量数据库可以帮助的领域 图像相似性搜索 视频相似性搜索 音频相似性搜索 主要特点 向量数据库功能 高性能向量搜索 存储、索引和管理由深度神经网络和其他机器学习&#xff08;ML&…

Matlab论文插图绘制模板第106期—带误差棒的堆叠柱状图

在之前的文章中&#xff0c;分享了Matlab带误差棒的折线图绘制模板&#xff1a; 带误差棒的柱状图绘制模板&#xff1a; 进一步&#xff0c;再来分享一下带误差棒的堆叠柱状图的绘制模板。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源…

管理类联考——数学——技巧篇——公式——几何题

三角形 三角形面积公式 S 1 2 b c s i n A 1 2 a c s i n B 1 2 a b s i n C S\frac{1}{2}bcsinA\frac{1}{2}acsinB\frac{1}{2}absinC S21​bcsinA21​acsinB21​absinC(正弦定理)&#xff1b; S p ( p − a ) ( p − b ) ( p − c ) S\sqrt{p(p-a)(p-b)(p-c)} Sp(p−a)…

JAVA-编程基础-06-数组

Lison <dreamlison163.com>, v1.0.0, 2023.03.22 JAVA-编程基础-06-数组 什么是数组 ​ 数组是一种线性数据结构&#xff0c;是一个使用连续的内存空间存放相同的数据类型的集合容器&#xff0c;与其他容器相比&#xff0c;数组的区别主要在于性能与保存基本类型的能力…

ASUS华硕天选air笔记本FX516P原装出厂原厂Win10系统镜像

ASUS华硕笔记本天选air FX516P原厂Windows10系统恢复原装出厂OEM预装自带系统 系统自带所有驱动、出厂主题壁纸LOGO、Office办公软件、华硕电脑管家、奥创控制中心等预装程序 链接&#xff1a;https://pan.baidu.com/s/150QimXQfATAhzxNCl690Nw?pwdhvj6 提取码&#xff1a;h…

10年来测试行业所遇问题,功能/接口/自动化测试?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 10年来测试行业发…

Apache Doris (八) :Doris分布式部署(五) Broker部署及Doris集群启动脚本

目录 1.Broker部署及扩缩容 1.1 BROKER 部署 1.2 BROKER 扩缩容 2. Apache Doris集群启停脚本 进入正文之前&#xff0c;欢迎订阅专题、对博文点赞、评论、收藏&#xff0c;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; 1.Broker部署及扩缩容 Broker 是 Doris 集…

【系统架构】第六章-数据库设计基础知识(数据库基本概念、关系数据库)

软考-系统架构设计师知识点提炼-系统架构设计师教程&#xff08;第2版&#xff09; 数据库基本概念 数据库的基础结构是数据模型&#xff0c;数据模型的三要素是数据结构、数据操作和数据的约束条件 数据库三级模式&#xff1a;视图层、逻辑层、物理层 视图层&#xff1a;最高…

Day.2 LeetCode刷题练习(螺旋矩阵)

题目&#xff1a; 例子&#xff1a; 分析题目&#xff1a; 本题给了一个值n要生成一个n*n的矩形&#xff0c;并且是螺旋的生成值。 这样我们可以把它分层来看如n 4时生成一个4*4的矩形由两层矩形构成&#xff0c;这样就能先遍历生成最外面的一层后再去生成里面的一层 那如何…

【VSCODE】4、vscode git pull/push 报错 remote: HTTP Basic: Access denied

一、报错示例 在执行 git pull/push 的时候报错如下 二、解决方式 该问题来自 vscode 的身份验证 打开 vscode →code → 首选项 → 设置搜索 git.terminalAuthentication取消选中该选项重启终端即可

2023黑马头条.微服务项目.跟学笔记(一)

前言 黑马头条一直是黑马培训班内部的项目&#xff0c;应该是今年推出了天机学堂的项目&#xff0c;所以这个头条微服务项目就被公布了&#xff0c;整体上看技术架构丰富&#xff0c;很适合微服务练手和补足。有些技术栈的版本可能是前几年的&#xff0c;不过这个不影响&#x…

医药销售数据分析

阅读原文 一、数据源 来自某医药公司的产品销售数据&#xff0c;时间为 3 月到 5 月&#xff0c;共 48 个 Excel 表格。包含订单信息、售后信息、用户信息以及对应销售人员信息等。 加载合并后得到的原始数据如下&#xff1a; 二、数据清洗 清洗流程以及对应细节 加载数据源 …

多表查询(JOIN)

数据准备 我们需要两个表 student 和 student_score CREATE TABLE student (student_id int NOT NULL,name varchar(45) NOT NULL,PRIMARY KEY (student_id) );CREATE TABLE student_score (student_id int NOT NULL,subject varchar(45) NOT NULL,score int NOT NULL ); 然后…

Linux中tail命令的使用

tail 命令可用于查看文件的内容&#xff0c;有一个常用的参数 -f 常用于查阅正在改变的日志文件。 tail -f filename 会把 filename 文件里的最尾部的内容显示在屏幕上&#xff0c;并且不断刷新&#xff0c;只要 filename 更新就可以看到最新的文件内容。 tail [参数] [文件] …

553、Vue 3 学习笔记 -【创建Vue 3.0工程(一)】 2023.06.30

目录 一、Vue 3 介绍1. Vue 3 官方文档2. Vue 3带来了什么1.1 性能的提升1.2 源码的升级1.3 拥抱TypeScript1.4 新的特性 二、创建Vue3.0工程1. 使用 vue-cli创建2. 使用vite创建3. 分析工程结构 三、参考链接 一、Vue 3 介绍 1. Vue 3 官方文档 Vue 3 官方的文档地址 2. Vu…

复杂onnx解决方案(以sparseconv为例)

目录 前言1. 稀疏卷积2. Sparse Convolution Model2.1 输入数据模型2.2 卷积核2.3 输出的定义2.4 计算流程2.4.1 构建 hash table2.4.2 构建 Rulebook2.4.3 在GPU上计算Pipeline 2.5 Summary 3. SCN导出3.1 实现trace3.2 导出onnx3.3 CenterPoint SCN导出3.4 执行图的构建3.5 o…

Swagger|SpringBoot集成Swagger用以生成API文档

框架简介 Swagger的作用&#xff1a; 自动生成强大的RESTful API文档&#xff0c;减少开发人员的工作量。使用Swagger&#xff0c;只需在代码中添加一些注解即可生成API接口文档&#xff0c;不需要手动编写API接口文档&#xff0c;这减少了开发人员的工作量。 提供API文档的同步…

西安石油大学 C++期末考试 重点知识点+题目复习(下)

析构函数调用顺序 析构函数的调用顺序与对象的创建和销毁顺序相反。 对于单个对象&#xff0c;当对象的生命周期结束时&#xff08;例如离开作用域&#xff09;&#xff0c;会调用其析构函数。因此&#xff0c;析构函数会在对象销毁之前被调用。 对于类的成员对象&#xff0…

软件工程期末复习-软件设计模式与体系结构-体系结构

目录 软件体系结构概述一、调用-返回风格软件体系结构概念主程序-子程序软件体系结构自顶向下的设计方法的问题结构化设计的优缺点面向对象体系结构面向对象设计的优缺点主程序-子程序与面向对象体系结构相似差异 课程作业 二、数据流风格软件体系结构概念控制流 vs. 数据流数据…

【第一章 flutter学习入门之环境配置】

flutter环境安装 文章目录 flutter环境安装前言一、环境变量配置二、下载Flutter SDK三.排除错误 安装依赖四. 设置Android模拟器五.安装插件VScode打开flutter项目 前言 本文是针对Windows系统环境配置flutter 需要git环境依赖&#xff0c;这里就不做过多赘述 一、环境变量配…