news 2026/9/4 21:40:50

ORB_SLAM2: Tracking::Track()

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ORB_SLAM2: Tracking::Track()

Track是ORB-SLAM2跟踪线程的主循环入口函数,它负责处理每一帧输入图像,完成从状态管理位姿估计局部地图优化关键帧决策的全链路流程。下面详细介绍该函数:

Track() 入口 │ ├─> [状态初始化] NO_IMAGES_YET -> NOT_INITIALIZED │ ├─> [地图锁] 防止LocalMapping干扰 │ ├─> [初始化检查] │ ├─ 未初始化 -> StereoInitialization() / MonocularInitialization() │ └─ 已初始化 -> 进入跟踪 │ ├─> [粗略位姿估计] │ ├─ 正常模式: │ │ ├─ OK -> CheckReplaced -> (速度模型优先 -> 参考帧回退) │ │ └─ LOST -> 重定位 │ └─ 纯定位模式: │ ├─ LOST -> 重定位 │ └─ OK -> (mbVO ? 并行尝试 : 常规跟踪) │ ├─> [精细优化] 跟踪局部地图 TrackLocalMap (投影匹配 + Motion BA) │ ├─> [状态更新] bOK -> mState=OK / LOST │ ├─> [跟踪成功] │ ├─ 更新速度矩阵 (mVelocity) │ ├─ 清理临时点 │ ├─ 判断并创建新关键帧 │ └─ 剔除当前帧外点 │ ├─> [跟踪失败] 若地图过小则重置系统 │ └─> [轨迹记录] 存储 Tcr 用于绘图

阶段一:状态初始化与地图锁(线程安全保护)

if(mState==NO_IMAGES_YET) mState = NOT_INITIALIZED; unique_lock<mutex> lock(mpMap->mMutexMapUpdate);
  • 状态流转:系统刚启动时,mStateNO_IMAGES_YET,第一条指令将其切换为未初始化状态。

  • 加锁目的mMutexMapUpdate是地图的互斥锁,用于防止在跟踪当前帧的过程中,局部建图线程(LocalMapping)突然插入新关键帧或删除旧地图点,导致数据不一致。虽然是加锁,但跟踪阶段主要是特征匹配和矩阵运算(毫秒级),对实时性影响微乎其微。

阶段二:系统引导(双目/单目初始化)

详细步骤参考:ORB_SLAM2:单目初始化和双目初始化的区别-CSDN博客

阶段三:粗略位姿估计(核心决策树)

这部分分为两个模式:正常建图模式、纯定位模式

1. 正常建图模式 (!mbOnlyTracking)

状态OK:

首先调用CheckReplacedInLastFrame():检查上一帧的地图点是否被局部建图线程替换(融合或优化),保证指针有效性。

if(mVelocity.empty() || mCurrentFrame.mnId<mnLastRelocFrameId+2) { //使用关键帧追踪 bOK = TrackReferenceKeyFrame(); } else { //使用运动模型追踪 bOK = TrackWithMotionModel(); if(!bOK) bOK = TrackReferenceKeyFrame(); }
子条件含义触发场景
mVelocity.empty()速度矩阵为空(未初始化)系统刚启动、刚完成初始化、或者上一帧跟踪失败导致速度未更新
mCurrentFrame.mnId < mnLastRelocFrameId + 2当前帧的ID小于“最近一次重定位帧ID + 2”刚完成重定位(Relocalization)后的前两帧

运动模型追踪原理

它假设相机在短时间内做匀速运动,用上一帧的位姿和速度去预测当前帧的位姿。

这个假设成立的前提是:

  • 上一帧的位姿T_{cw}^{last}是准确可靠的。

  • 上一帧到当前帧的速度mVelocity是有效的。

  • 相机的运动确实是平滑且连续变化的

当系统刚启动或者刚刚进行重定位时(重定位意味之前的跟踪丢了),不能使用匀速模型进行计算。

状态Lost:

直接调用重定位Relocalization()(利用词袋模型在整个地图中寻找相似关键帧,通过EPnP求解位姿)。

2. 纯定位模式 (mbOnlyTracking)

该模式不建图,仅跟踪。代码引入了mbVO(Visual Odometry)标志,表示当前帧与地图匹配的内点很少,主要靠视觉里程计推算。

  • false:上一帧跟踪良好,有足够多的地图点(MapPoint)匹配。

  • true:上一帧跟踪质量差,主要靠临时点(VO点)勉强维持。

状态Lost:

跟踪丢失,只能进行重定位

状态OK:

上一帧状态良好:

优先使用运动模型,速度无效使用参考关键帧追踪

if(!mbVO) // 上一帧跟踪到了足够多的地图点(状态良好) { // 优先尝试运动模型跟踪(恒速模型) if(!mVelocity.empty()) { bOK = TrackWithMotionModel(); // ⚠️ 这里缺少了失败后的回退机制! } else { // 速度无效,直接用参考关键帧跟踪 bOK = TrackReferenceKeyFrame(); } }
上一帧状态不好:

使用匀速和重定位分别计算一遍,然后结果择优录取

先进行变量声明

// 通过运动模型进行跟踪的结果 bool bOKMM = false; // 通过重定位方法进行跟踪的结果 bool bOKReloc = false; // 运动模型跟踪得到的临时结果(用于后续回滚) vector<MapPoint*> vpMPsMM; // 当前帧关联的地图点 vector<bool> vbOutMM; // 每个特征点是否为外点 cv::Mat TcwMM; // 运动模型算出的位姿

如果速度非空,先用匀速模型预测当前位姿,并暂存结果到vpMPsMM 、vbOutMM 、TcwMM。

然后再使用重定位:

  • 利用词袋模型(BoW)在当前帧和整个地图的所有关键帧之间快速搜索,找到最相似的候选帧。

  • 通过EPnP(高效PnP算法)计算当前帧位姿,并用RANSAC筛选内点。

  • 如果匹配到的内点数足够多(> 50 个),则重定位成功。

场景1:运动模型成功 + 重定位失败

if(bOKMM && !bOKReloc) { // 回退到运动模型的结果 mCurrentFrame.SetPose(TcwMM); mCurrentFrame.mvpMapPoints = vpMPsMM; mCurrentFrame.mvbOutlier = vbOutMM; // 增加地图点的被观测次数(提升其权重) if(mbVO) { for(int i =0; i<mCurrentFrame.N; i++) { if(mCurrentFrame.mvpMapPoints[i] && !mCurrentFrame.mvbOutlier[i]) { mCurrentFrame.mvpMapPoints[i]->IncreaseFound(); } } } }

场景2:重定位成功(无论运动模型是否成功)

else if(bOKReloc) { // 只要重定位成功,就认为系统恢复正常 mbVO = false; }

阶段四:跟踪局部地图

if(!mbOnlyTracking) { if(bOK) bOK = TrackLocalMap(); } else { if(bOK && !mbVO) bOK = TrackLocalMap(); }

无论上一步哪种方法估计出位姿,只要bOK == true,都会进入此环节。

  • 作用:上一步仅使用了上一帧或参考帧的少量地图点。这一步会将当前帧能看到的所有局部地图点(当前关键帧及其共视关键帧中的所有3D点)投影到当前帧进行匹配。

  • 核心优化(仅运动BA)
    固定所有地图点 Pi的坐标,仅优化当前帧位姿 Tcw,使重投影误差最小化:

其中 π(⋅) 是投影函数,ρ是Huber核函数(用于削弱外点影响)。

  • 意义:这是提升跟踪精度的关键,使位姿与周围地图达到几何最优。

阶段五:跟踪成功后的善后工作(更新与决策)

如果bOK为真,执行以下重要维护:

  1. 更新运动模型速度(供下一帧使用):

mVelocity = mCurrentFrame.mTcw * LastTwc;
  • 这计算了当前帧相对于上一帧的变换矩阵,作为下一帧匀速运动预测的依据。

  • 清理无效地图点:删除观测次数为 0 的临时地图点,释放内存。

  • 关键帧决策(NeedNewKeyFrame()+CreateNewKeyFrame()
    根据距离上一关键帧的帧数局部建图线程是否空闲跟踪质量等条件,决定是否创建新关键帧。决策是多因子加权的结果(无固定数学公式,基于工程经验)。

  • 剔除离群点:将在TrackLocalMap优化中被标记为外点(mvbOutlier[i]=true)的地图点从当前帧清掉,防止错误点影响下一帧。

阶段六:失联恢复机制(防止刚启动就崩溃)

if(mState==LOST) { if(mpMap->KeyFramesInMap()<=5) { mpSystem->Reset(); return; } }
  • 场景:如果系统刚初始化完(地图中仅有 ≤5 个关键帧),但因为剧烈运动或弱纹理瞬间丢失。

  • 策略:此时地图太小,重定位极易失败,直接重置整个系统(推倒重来),比强行在微弱地图中挣扎更高效。

阶段七:轨迹记录(用于可视化与保存)

cv::Mat Tcr = mCurrentFrame.mTcw * mCurrentFrame.mpReferenceKF->GetPoseInverse(); mlRelativeFramePoses.push_back(Tcr);
  • Tcr表示当前帧相对于其参考关键帧的位姿变换。这个向量序列被存储下来,用于在FrameDrawerMapDrawer中绘制相机的实时运动轨迹。

  • 即使跟踪丢失,也会用上一帧的数据填充(保持轨迹连续性,但标记为mlbLost.push_back(true))。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 21:39:52

423道 GIT 测试题(含解释) 01 - 20 题

为方便阅读,这里整理了整个系列的索引导航。本系列共 423 道 git 测试题(含简单的题目解释),按每 20 题为一篇进行连载,点击下方链接即可跳转到对应章节,方便你按需查阅、系统复习。 423道 GIT 测试题(含解释) 01 - 20 题 423道 GIT 测试题(含解释) 21 - 40 题 423道…

作者头像 李华
网站建设 2026/9/4 21:39:04

手把手:论文的干预方案手册怎么分步编制

论文做了干预实验&#xff0c;评审时却拿不出可复现的方案说明——不少同学都卡在这里&#xff1a;方法部分只有"对实验组实施了为期 8 周的干预"一两句带过&#xff0c;执行者根本不知道具体该做什么。本文把干预方案手册的编制拆成 6 个可执行步骤&#xff0c;每步…

作者头像 李华
网站建设 2026/9/4 21:38:00

基于BLIP模型实现本地化AI图片描述生成:从环境搭建到生产部署全流程

在实际开发中&#xff0c;我们经常遇到需要为图片、视频或特定场景自动生成描述性文字的需求。无论是内容平台的智能配文、电商产品的自动标题生成&#xff0c;还是辅助工具的无障碍描述&#xff0c;将AI能力集成到文字生成流程中&#xff0c;已经成为提升效率和用户体验的关键…

作者头像 李华
网站建设 2026/9/4 21:34:58

JSP+Servlet项目实战复盘:从经典MVC到安全加固的演进之路

简介&#xff1a;这是一套基于Java Web技术栈开发的志愿者服务管理平台源码&#xff0c;面向高校课程设计、毕业设计及中小型公益组织信息化建设需求&#xff0c;解决志愿者招募、培训、项目跟踪、服务时长统计与表彰激励等全流程数字化管理问题。资源包共953个文件&#xff0c…

作者头像 李华
网站建设 2026/9/4 21:34:32

CrewAI多智能体开发实战:核心概念、任务编排与工作流构建

在实际的 AI 应用开发中&#xff0c;多智能体系统已经不是概念阶段的东西&#xff0c;而是一类可落地的工程范式。CrewAI 是其中使用成本较低、理解门槛也较友好的 Python 框架&#xff1a;开发者可以把一个复杂目标拆成多个带身份的 AI 智能体&#xff0c;每个智能体负责一个明…

作者头像 李华
网站建设 2026/9/4 21:34:07

重磅版本发布|AllData可定义数据中台建设AI多模态数据资产与治理平台,涵盖12+模块与43+核心功能,直播分享源码架构与全流程产品演示!

►顶部微信名片可直接添加市场总监&#xff0c;商务咨询、方案沟通即时响应 ►点击链接了解更新详情&#xff1a;演示体验、社群咨询、商务采购&#xff1a;https://docs.qq.com/doc/DVHlkSEtvVXVCdEFo 演讲人&#xff1a;巫林壕&#xff0c;杭州奥零数据科技公司创始人、AllD…

作者头像 李华