ORB-SLAM3算法和代码学习—跟踪恒速运动模型TrackWithMotionModel()

news2025/1/17 15:17:29

0总述

跟踪运动模型核心思想:假设在极短时间内,相机的运动相同。设相邻时刻的三帧图像分别为k-2帧,k-1帧,k帧,则认为k-2帧到k-1帧相机的运动T_delta1和k-1帧到k帧相机的运动T_delta2相等,如下图所示。当相机运动到当前帧图像时,可以由T_delta1和k-1帧时相机的位姿计算当前帧的位姿,为投影匹配和优化提供初值。
在这里插入图片描述
跟踪恒速运动模型主要分为以下几步:

  • 更新上一帧的位姿
  • 根据预积分或者恒速模型得到当前帧初始位姿
  • 使用上一帧的地图点和初始位姿进行投影匹配
  • 利用3D-2D的重投影误差对当前图像帧的位姿进行优化
  • 剔除当前帧地图点中的外点

1.更新上一帧的位姿

上一帧的位姿通过上一帧参考关键帧位姿以及和参考关键帧之间的变换关系给出

// 上一帧的位姿 = Tlr * 上一帧参考关键帧位姿
Sophus::SE3f Tlr = mlRelativeFramePoses.back();
mLastFrame.SetPose(Tlr * pRef->GetPose());

对于双目或rgbd相机,为上一帧生成新的临时地图点,对生成的地图点通过阈值进行了限制,选择距离相机较近的前100个点,距离较远时精度会较低。

2.根据预积分或者恒速模型得到当前帧初始位姿

如果是IMU模式,会直接通过预积分结果设置当前帧的位姿,并返回该位姿。

    if (mpAtlas->isImuInitialized() && (mCurrentFrame.mnId > mnLastRelocFrameId + mnFramesToResetIMU))
    {
        // Predict state with IMU if it is initialized and it doesnt need reset
        // 如果是IMU模式 && IMU已经初始化了 && 距离重定位挺久不需要重置IMU,用IMU来估计位姿
        // 基于IMU估计位姿后直接返回,不需要再进行计算投影和优化
        PredictStateIMU();
        return true;
    }

如果是纯视觉模式,或者不满足IMU的使用条件,则选择恒速模型估计相机运动,得到一个初始的相机位姿。

mCurrentFrame.SetPose(mVelocity * mLastFrame.GetPose());

3.使用上一帧的地图点和初始位姿进行投影匹配

这一步只查找匹配,判断一下当前帧是否能正常跟踪,如果和上一帧的匹配较多满足条件才有下一步优化的必要,但不涉及位姿的计算。

int nmatches = matcher.SearchByProjection(mCurrentFrame,mLastFrame,th,mSensor==System::MONOCULAR || mSensor==System::IMU_MONOCULAR);

1.首先,将lastframe的3D地图点由世界坐标系转换到currentframe对应的相机坐标系

Eigen::Vector3f x3Dw = pMP->GetWorldPos();// 获取3D点转换到世界坐标系
Eigen::Vector3f x3Dc = Tcw * x3Dw;// 将3D点由世界坐标系转换到currentFrame的相机坐标系,Tcw是当前帧位姿

2.然后,根据相机内参将该3D点投影到当前帧图像坐标系上,得到投影坐标(u,v),对投影后的2D像素坐标和图像边界进行比较,筛掉超出边界的点

// 反投影
Eigen::Vector2f uv = CurrentFrame.mpCamera->project(x3Dc);
// 边界判断
if(uv(0)<CurrentFrame.mnMinX || uv(0)>CurrentFrame.mnMaxX)
    continue;
if(uv(1)<CurrentFrame.mnMinY || uv(1)>CurrentFrame.mnMaxY)
    continue;

3.然后,根据特征点的尺度信息确定在当前帧图像上的搜索半径,尺度越大搜索半径就越大,根据搜索半径可以确定该半径范围内所有的网格(在图像帧创建时给每个特征点都分配了网格),将对应尺度的对应网格中的特征点对应id取出,作为候选的匹配特征点

// 确定搜索半径,每个特征点重投影的搜索半径和其尺度有关
// 尺度越大,搜索范围越大
float radius = th*CurrentFrame.mvScaleFactors[nLastOctave];
// 记录候选匹配点的id
vector<size_t> vIndices2;
// 根据相机的前后前进方向来判断搜索尺度以及范围。
// 以下可以这么理解,例如一个有一定面积的圆点,在某个尺度n下它是一个特征点
// 当相机前进时,圆点的面积增大,在某个尺度m下它是一个特征点,由于面积增大,则需要在更高的尺度下才能检测出来
// 当相机后退时,圆点的面积减小,在某个尺度m下它是一个特征点,由于面积减小,则需要在更低的尺度下才能检测出来                    
if(bForward)// 前进,则上一帧兴趣点在所在的尺度nLastOctave<=nCurOctave
    vIndices2 = CurrentFrame.GetFeaturesInArea(uv(0),uv(1), radius, nLastOctave);
else if(bBackward)// 后退,则上一帧兴趣点在所在的尺度0<=nCurOctave<=nLastOctave
    vIndices2 = CurrentFrame.GetFeaturesInArea(uv(0),uv(1), radius, 0, nLastOctave);
else// 如果当前帧在z方向上的移动距离小于基线,即没有明显的运动,那么就在[nLastOctave-1, nLastOctave+1]中搜索
    vIndices2 = CurrentFrame.GetFeaturesInArea(uv(0),uv(1), radius, nLastOctave-1, nLastOctave+1);

4.然后,遍历所有候选特征点(根据id信息),计算每个特征点描述子和当前3D地图点描述子的距离,将最小距离对应的特征点作为最佳匹配,同时匹配特征点的角度之差

5.然后,对所有匹配点对的旋转角度之差进行直方图统计,选择直方图最高的3个对应特征点作为本次匹配查找的最终结果,这一步称为旋转一致性检验

//  Step 7 进行旋转一致检测,剔除不一致的匹配
if(mbCheckOrientation)
{
    int ind1=-1;
    int ind2=-1;
    int ind3=-1;
    ComputeThreeMaxima(rotHist,HISTO_LENGTH,ind1,ind2,ind3);
    for(int i=0; i<HISTO_LENGTH; i++){
        // 对于数量不是前3个的点对,剔除
        if(i!=ind1 && i!=ind2 && i!=ind3){
            for(size_t j=0, jend=rotHist[i].size(); j<jend; j++){
                CurrentFrame.mvpMapPoints[rotHist[i][j]]=static_cast<MapPoint*>(NULL);
                nmatches--;}}}
}

6.最后,如果匹配结果较少就加大搜索半径再进行一次查找,若匹配数量依然不满足条件,跟踪恒速运动模型就此失败

4.利用3D-2D的重投影误差对当前图像帧的位姿进行优化

Optimizer::PoseOptimization(&mCurrentFrame);

使用g2o进行优化,使用基于恒速模型计算得到的当前帧位姿作为优化迭代的初始值,当前帧位姿在函数中隐式地更新。

在优化时会对未能成功匹配的外点进行判断,这个判断根据投影误差进行筛选,如果最终优化后得到的外点太多,好的匹配太少就会判定跟踪失败

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

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

相关文章

K8S概述及用途

K8S概述 1.K8S说明 K8S(Kubernetes) 是一个可移植的、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、支持和工具广泛可用。 Kubernetes 这个名字源…

海量数据存储面临的问题

海量数据存储面临的问题海量数据存储面临的问题成本高性能低可扩展性差如何实现分布式文件存储如何支撑高效率的计算分析如何解决海量数据存储的问题如何解决海量数据文件查询便捷问题如何解决大文件传输效率慢的问题如何解决硬件故障数据丢失问题如何解决用户查询视角统一规整…

pyhon把程序打包为whl

首先需要一个库&#xff1a;setuptools如果是conda环境的话&#xff0c;这个包是自带的&#xff0c;不需要另外安装。首先把需要打包的py文件放在一个文件夹内&#xff08;我的文件夹名为coordTrans&#xff0c;记住这个名字&#xff0c;后面要用&#xff09;。同时&#xff0c…

dll修复工具下载,dll修复工具注意事项

Dll文件的缺失相信很多人都遇见过吧&#xff0c;只要缺失了一个这样的dll文件&#xff0c;我们的游戏或者软件程序就启动不了了&#xff0c;所以我们就需要去修复它&#xff0c;目前修复有几种方法&#xff0c;最简单的&#xff0c;最适合电脑小白的&#xff0c;那就是dll修复工…

Vue3——第四章(响应式基础:reactive、ref)

一、用reactive()声明响应式状态 我们可以使用 reactive() 函数创建一个响应式对象或数组&#xff1a; 响应式对象其实是 JavaScript Proxy&#xff0c;其行为表现与一般对象相似。不同之处在于 Vue 能够跟踪对响应式对象属性的访问与更改操作。 要在组件模板中使用响应式状…

java后端第六阶段:SpringMVC

1、Spring IoC&#xff08;Inversion of Controller&#xff09;控制反转 使用对象时&#xff0c;由主动new产生对象转换为由外部提供对象&#xff0c;此过程中对象中创建控制权由程序转移到外部&#xff0c;此思想称为控制反转 Spring技术对IoC思想进行了实现 Spring提供了一…

第四十九讲:神州路由器IPv6 OSPFv3和RIPng路由的配置

神州路由器支持IPv6的内部网关路由协议常用的有OPSFv3和RIPng。 实验拓扑图如下所示 配置要求&#xff1a;在两台路由器上启用IPv6 routing&#xff0c; 在接口上配子ipv6协议后&#xff0c;通过配置RIPng和OSPFv3相关命令&#xff0c;观察学习到的路由。 配置步骤&#xff1…

产品试用记录

某产品试用记录 还可以选屏哦

【PWA学习】3. 让你的 WebApp 离线可用

引言 PWA 其中一个令人着迷的能力就是离线(offline)可用 即使在离线状态下&#xff0c;依然可以访问的 PWA离线只是它的一种功能表现而已&#xff0c;具体说来&#xff0c;它可以&#xff1a; 让我们的Web App在无网(offline)情况下可以访问&#xff0c;甚至使用部分功能&#…

Redis哨兵模式搭建

以下配置机器部署ip为 a、b、c&#xff0c;其中a为master节点 需提前创建 /app/user/oms/redis/data 目录 1.1上传 redis-5.0.5.zip 到对应目录&#xff0c;解压 unzip redis-5.0.5.zip # 生成 redis-5.0.5 目录 1.2 修改配置文件 maxclients 10000 #20000 &#xff0…

接口测试实战| GET/POST 请求区别详解

在日常的工作当中&#xff0c;HTTP 请求中使用最多的就是 GET 和 POST 这两种请求方式。深度掌握这两种请求方式的原理以及异同之处&#xff0c;也是之后做接口测试一个重要基础。GET、POST 的区别总结请求行的 method 不同&#xff1b;POST 可以附加 div&#xff0c;可以支持 …

概率论【离散型二维变量与连续性二维变量(下)】--猴博士爱讲课

6.连续型二维变量&#xff08;下&#xff09; 1/7 求边缘分布函数 边缘概率密度 边缘概率密度 2/7 求边缘密度函数 边缘概率密度 3/7 判断连续型二维变量的独立性 F(x,y) Fx(X) * Fy(Y)那么X、Y互相独立 f(x,y) fx(X) * fy(Y)那么X、Y互相独立 这种题目带入验证就可以了 先求…

百度举办首个人机共创大会,最强技术天团邀约全球开发者

1月10日&#xff0c;百度举办Create AI开发者大会&#xff08;下称“Create大会”&#xff09;。作为首个“人机共创大会”&#xff0c;AIGC&#xff08;利用AI技术自动生成内容的生产方式&#xff09;技术被深度应用&#xff0c;创造、搭建、连接了多个科技感爆棚的数字化演讲…

powershell ISE 多个选项卡,替换命令行黑窗口

安装powershell ISE设置权限解决方案1.管理员打开PowerShell2. 执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser运行脚本自定义函数&#xff0c;function start_service([string]$Name,$p,$r) {$NewTab $psISE.PowerShellTabs.Add()$NewTab.Displa…

ES之module

模块&#xff1a;一个一个的局部作用域的代码块 模块系统需要解决的主要问题 模块化的问题消除全局变量管理加载顺序 Module的基本用法 模块里面都是局部无法访问 切换幻灯片示例 Base.js // 默认参数 const DEFAULTS {// 初始索引initialIndex: 0,// 切换时是否有动画a…

Repvgg推理时融合BN

Batch Normalization是谷歌研究员于2015年提出的一种归一化方法&#xff0c;其思想非常简单&#xff0c;一句话概括就是&#xff0c;对一个神经元&#xff08;或者一个卷积核&#xff09;的输出减去统计得到的均值&#xff0c;除以标准差&#xff0c;然后乘以一个可学习的系数&…

数字孪生|可视化图表之堆叠面积图

上一篇文章为大家介绍了分组条形图的相关内容&#xff0c;本文介绍的是堆叠面积图。 堆叠面积图是一种特殊的面积图&#xff0c;可以用来比较在一个区间内的多个变量。堆叠面积图和普通的面积图基本一样&#xff0c;唯一的区别就是堆叠面积图每个数据系列的起点都是基于前一个数…

再学C语言30:函数——ANSI C的函数原型

一、ANSI C关于函数原型的规则 ANSI C在函数声明中同事说明所使用的的参数类型&#xff0c;即在函数原型中声明返回值类型、参数、参数个数、参数类型 int function(int a, int b); // 形式一 int function(int, int); // 形式二// 以上两种形式的定义均满足规范要求 好…

基于无线通信物联网的水库安全监测系统

水库安全监测一直是我国防洪防汛工作的重点&#xff0c;库区的雨量、水位的实时监测&#xff0c;建立水库监测系统能够有效防止洪涝灾害的发生&#xff0c;确保水库和下游地区的安全。 物通博联推出的水库安全监测系统是基于无线通信物联网技术打造的系统平台&#xff0c;由雨…

路由器基础

交换机基本功能 1.基于源MAC地址学习2.基于目标MAC地址转发3.数据过滤4.防环 交换机基于MAC地址表进行转发&#xff0c;MAC地址表默认自动产生&#xff0c;MAC地址组成三元组&#xff1a;Mac地址、端口、VLAN。默认MAC条目信息存活时间为300s并且可以修改 泛洪&#xff08;洪…