ORB-SLAM2源码学习(六):相机跟踪(局部地图跟踪和关键帧创建)
目录
1.局部地图跟踪
1.1 更新局部关键帧UpdateLocalKeyFrames
1.2 更新局部地图点(来自局部关键帧)UpdateLocalPoints()
1.3 投影匹配
2. 对比四种跟踪方式以及使用的投影匹配
3.关键帧创建
3.1 判断是否需要创建新关键帧: NeedNewKeyFrame()
3.2 关键帧的创建CreateNewKeyFrame()
1.局部地图跟踪
当初始位姿估计成功(参考关键帧来跟踪、恒速模型跟踪、重定位跟踪跟踪成功)后需要进行局部地图跟踪TrackLocalMap()。
初始位姿估计只是跟踪一帧得到初始位姿,局部地图跟踪搜索局部关键帧、局部地图点,和当前帧进行投影匹配,得到更多匹配的MapPoints后进行位姿优化。
bOK = TrackLocalMap();
具体流程:
- 更新局部地图,包括局部关键帧和地图点;UpdateLocalKeyFrames() UpdateLocalPoints()
- 对局部MapPoints进行投影匹配 SearchLocalPoints()
- BA优化位姿(和初始位姿估计调用优化函数相同)
1.1 更新局部关键帧UpdateLocalKeyFrames

- 一级共视关键帧:KF1、KF2是F的一级共视关键帧
- 二级共视关键帧:KF1、KF2的共视关键帧(虚线框内)是F的二级共视关键帧
- 当前帧:mCurrentFrame
- 参考关键帧: 与当前帧共视程度最高的关键帧作为参考关键帧,mCurrentFrame.mpReferenceKF 在KeyFrame::UpdateConnections() 里确定关键帧的父子关系
- 父关键帧:和当前关键帧共视程度最高的关键帧
- 子关键帧:是上述父关键帧的子关键帧
局部关键帧的组成:
- 当前地图点的所有共视关键帧(邻居)。
- 1中所有关键帧共视关系前10大的共视关键帧(邻居的邻居)。
- 1中所有关键帧的父子关键帧(邻居的父母和孩子)。
最后将与当前帧共视关系最强的关键帧设为参考关键帧mpReferenceKF
1.2 更新局部地图点(来自局部关键帧)UpdateLocalPoints()
局部关键帧能够观测到的所有地图点,称为局部地图点。
1.3 投影匹配
将局部地图点进行投影匹配,得到更多的匹配关系(目的)。注意,局部地图点中已经是当前帧地图点的不需要再投影,只需要将此外的并且在视野范围内的点和当前帧进行投影匹配。
具体流程:
- 遍历当前帧的地图点,标记这些地图点不参与之后的投影搜索匹配;
- 判断所有局部地图点中除当前帧地图点外的点,是否在当前帧视野范围内;(是否在视野范围内有个单独函数 isInFrustum())
- 如果需要进行投影匹配的点的数目大于0,就进行投影匹配,增加更多的匹配关系。SearchByProjection()
2. 对比四种跟踪方式以及使用的投影匹配
①参考关键帧跟踪
通过词袋模型计算参考关键帧和当前帧的匹配特征点(没有用投影匹配),上一帧的位姿作为当前帧的初始位姿,然后进行BA求两帧之间的位姿变换。
应用场景:没有速度信息的时候、刚完成重定位、或者恒速模型跟踪失败后使用,大部分时间不用。只利用到了参考帧的信息(本质上是尝试和最近一个关键帧去做匹配)。

②恒速模型跟踪
首先根据上上帧到上一帧的位姿,把上一帧的特征点像素坐标映射到当前帧,然后在映射后结果坐标周围进行搜索,找到与之匹配的特征点;根据速度得到当前帧的初始位姿,然后进行BA求两帧之间的位姿变换。
使用了投影匹配,由于恒速模型可以计算当前帧相对于上一帧的平移向量,根据相机的前进/后退来约束搜索尺度范围(在投影点多大的范围内进行匹配)。此外它是对上一帧的有效地图点(过滤外点)进行投影的。
投影匹配流程:1. 计算帧间平移 → 2. 投影上一帧地图点 → 3. 运动方向约束搜索尺度 → 4. 匹配并记录角度差 → 5. 旋转直方图剔除
尺度范围:
在进行投影匹配的时候会给定特征点的搜索范围,考虑到处于不同尺度(也就是距离相机远近,位于图像金字塔中不同图层)的特征点受到相机旋转的影响不同,因此会希望距离相机近的点的搜索范围更大一点,距离相机更远的点的搜索范围更小一点,所以要在这里,根据点到关键帧/帧的距离来估计它在当前的关键帧/帧中,会大概处于哪个尺度。
应用场景
大部分时间都用这个跟踪,只利用到了上一帧的信息。

③重定位
当TrackWithMotionModel 和 TrackReferenceKeyFrame 都没有跟踪成功,位置丢失后,需要在之前的关键帧中匹配相近的关键帧,然后使用3D-2D匹配点的 EPnP算法求初始位姿,之后再使用BA来优化位姿。
具体而言:用词袋找到与当前帧相似的候选关键帧(可能找到多个),再然后通过BoW加速计算每一个候选关键帧和当前帧的匹配特征点(这个过程和 参考关键帧跟踪中当前帧和参考帧匹配特征点一样),使用EPnP依次求初始位姿。每个位姿结果使用BA优化,选择内点数量大于50的作为初始位姿。
如果内点数量不够多呢?就通过投影匹配方式对之前未匹配的点进行匹配,再进行BA优化求解。由于进行重定位,上一帧没有意义,基于地图点距离预测尺度范围。
投影匹配流程:1. 遍历局部关键帧地图点 → 2. 过滤已匹配点 → 3. 投影并预测尺度 → 4. 多层级搜索 → 5. 最佳匹配筛选 → 6. 旋转直方图剔除
④局部地图跟踪
搜索局部关键帧、局部地图点,和当前帧进行投影匹配,得到更多匹配的地图点后进行位姿优化,初始位姿根据前面三种方法计算的到。
具体而言:根据当前帧的地图点来找能观测到当前帧的一级共视关键帧,将这些一级共视关键帧的二级关键共视帧、子关键帧、父关键帧一起作为局部关键帧;局部关键帧中所有的地图点作为局部地图点;局部地图点(去掉当前帧的地图点 和 不在当前帧视野范围内无效的地图点)投影到当前帧进行特征点匹配,匹配结果进行BA优化。
投影匹配的时候通过视角余弦(RadiusByViewingCos)和预测尺度(nPredictedLevel)调整搜索尺度范围。
总结:
四种跟踪方式对比:
相同点:本质上都是计算匹配点对以及初始位姿,然后使用BA进行位姿优化。
不同点:求解匹配特征点方法和当前帧的初始位姿设置不同
- 参考关键帧跟踪通过BoW计算当前帧和参考关键帧的匹配点对;初始位姿使用上一帧的位姿;
- 恒速运动模型通过投影匹配计算匹配点对;初始位姿通过速度(这里的速度是上一帧到当前帧的位姿Tcl)确定;
- 重定位 通过BoW计算每一个相似关键帧和当前帧 的匹配点对;初始位姿通过EPnP计算;
- 局部地图跟踪是将 局部地图点(来自局部关键帧)投影到当前帧计算匹配点对;初始位姿由前面三种方法确定。
3.关键帧创建
关键帧是取局部相近帧中最有代表性的一帧
选取的指标主要有:
- 距离上一关键帧的帧数是否足够多(时间)。比如我每隔固定帧数选择一个关键帧,这样编程简单但效果不好。比如运动很慢的时候,就会选择大量相似的关键帧,冗余,运动快的时候又丢失了很多重要的帧。
- 距离最近关键帧的距离是否足够远(空间)/运动。比如相邻帧根据pose计算运动的相对大小,可以是位移也可以是旋转或者两个都考虑,运动足够大(超过一定阈值)就新建一个关键帧,这种方法比第一种好。但问题是如果对着同一个物体来回扫就会出现大量相似关键帧。
- 跟踪局部地图质量(共视特征点数目)。记录当前视角下跟踪的特征点数或者比例,当相机离开当前场景时(双目或比例明显降低)才会新建关键帧,避免了第2种方法的问题。缺点是数据结构和逻辑比较复杂。
if(NeedNewKeyFrame())CreateNewKeyFrame();
3.1 判断是否需要创建新关键帧: NeedNewKeyFrame()
是否生成关键帧,需要考虑以下几个方面:
- 最近是否进行过重定位,重定位后位姿不会太准,不适合做参考帧;
- 当前系统的工作状态: 如果LocalMapping线程还有很多KeyFrame没处理的话,不适合再给它增加负担了;
- 距离上次创建关键帧经过的时间: 如果很长时间没创建关键帧了的话,就要抓紧创建关键帧了;
- 当前帧的质量: 当前帧观测到的地图点要足够多,同时与参考关键帧的重合程度不能太大。
3.2 关键帧的创建CreateNewKeyFrame()
注:双目和RGBD创建新的地图点,单目不会(单帧没有尺度)
具体流程:
- 将当前帧构造成关键帧;
- 将当前关键帧设置为当前帧的参考关键帧;
- 对于双目或rgbd摄像头,为当前帧生成新的地图点;单目无操作;
- 关键帧插入到链表 mlNewKeyFrames中,等待local mapping线程处理
思维导图:

相关文章:
ORB-SLAM2源码学习(六):相机跟踪(局部地图跟踪和关键帧创建)
目录 1.局部地图跟踪 1.1 更新局部关键帧UpdateLocalKeyFrames 1.2 更新局部地图点(来自局部关键帧)UpdateLocalPoints() 1.3 投影匹配 2. 对比四种跟踪方式以及使用的投影匹配 3.关键帧创建 3.1 判断是否需要创建新关键帧: NeedNewKeyFrame() 3…...
视频格式有哪些视频格式汇总
视频格式是指视频文件的编码和封装方式,不同的格式适用于不同的应用场景。以下是一些常见的视频格式及其特点: 1. MP4(MPEG-4 Part 14) 特点:最流行的视频格式之一,支持多种视频编码标准(如H.…...
【极客时间】浏览器工作原理与实践-2 宏观视角下的浏览器 (6讲) - 2.6 渲染流程(下):HTML、CSS和JavaScript,是如何变成页面的?
https://time.geekbang.org/column/article/118826 2.6 渲染流程(下):HTML、CSS和JavaScript,是如何变成页面的? 2.5介绍了渲染流水线中的 DOM 生成、样式计算和布局三个阶段,2.6讲解渲染流水线后面的阶段…...
浏览器WEB播放RTSP
注意:浏览器不能直接播放RTSP,必须转换后才能播放。这一点所有的播放都是如此。 参考 https://github.com/kyriesent/node-rtsp-stream GitHub - phoboslab/jsmpeg: MPEG1 Video Decoder in JavaScript 相关文件方便下载 https://download.csdn.net…...
DeepSeek开源Day4:DualPipeEPLB技术详解
2 月 24 日,DeepSeek 启动 “开源周”,第四个开源的代码库为 DualPipe 与 EPLB(一下发布了两个)。DualPipe 与 EPLB 依然使用了大量与 Hopper 架构绑定的技术。 DualPipe 是由 DeepSeek-AI 团队开发的一种双向流水线并行通信算法&…...
阿里推出全新推理模型(因果语言模型),仅1/20参数媲美DeepSeek R1
阿里Qwen 团队正式发布了他们最新的研究成果——QwQ-32B大语言模型!这款模型不仅名字萌萌哒(QwQ),实力更是不容小觑!😎 QwQ-32B 已在 Hugging Face 和 ModelScope 开源,采用了 Apache 2.0 开源协议。大家可通过 Qwen C…...
vue实现一个pdf在线预览,pdf选择文本并提取复制文字触发弹窗效果
[TOC] 一、文件预览 1、安装依赖包 这里安装了disjs-dist2.16版本,安装过程中报错缺少worker-loader npm i pdfjs-dist2.16.105 worker-loader3.0.8 2、模板部分 <template><div id"pdf-view"><canvas v-for"page in pdfPages&qu…...
Unity自定义渲染管线(Scriptable Render Pipeline)架构设计与实现指南
一、SRP技术体系概述 1. 核心设计理念 全托管渲染控制:通过C#脚本完全掌控渲染流程 模块化架构:将渲染流程拆分为可组合的RenderPass GPU友好设计:支持CommandBuffer与Compute Shader混合编程 对惹,这里有一个游戏开发交流小组…...
时间复杂度分析与递归,以新南UNSW的COMP2521作业题为例
作者:Smooth(连接教育高级讲师) 首发于:UNSW学习知识库(UNSW Study Wiki) 创作时间:2025年3月5日 如何测度算法的时间性能?理论分析Theoretical Analysis 测度算法时…...
RxJS与Redux革命性协同:打造高效、解耦的前端状态管理方案
摘要 本文探讨RxJS与Redux的融合应用,通过真实用户场景揭示其必要性,系统讲解整合策略,从基础到高级涵盖响应式编程优化、异步操作处理、状态流控制等核心主题。提供可落地的架构方案与性能优化技巧,包含10可复用代码示例和20实战…...
蓝桥杯P1259-奇怪的馈赠 (贪心题解)
题目:奇怪的捐赠 题目来源:1.奇怪的捐赠 - 蓝桥云课 题目描述 需要将 100 万(1,000,000)正好分成若干个 7 的次方形式的数(如 7^01, 7^17, 7^249 等),且每种金额(即每个 7 的次方…...
todo: 使用融云imserve做登录(android)
使用融云做登录注册思路 注册界面需要name, email, password考虑到融云注册用户的post格式 POST http://api.rong-api.com/user/getToken.json?userId1690544550qqcom&nameIronman这里的userId可以使用用户的email,但是要截断和 . 符号,即1690544…...
如何设置爬虫的User-Agent?
在爬虫开发中,设置合适的 User-Agent 是非常重要的一步。User-Agent 是 HTTP 请求头中的一个字段,用于标识客户端(通常是浏览器)的类型、版本、操作系统等信息。通过设置 User-Agent,可以模拟正常的浏览器访问行为&…...
C++ 二叉搜索树代码
C 二叉搜索树代码 #include <iostream> using namespace std;template<typename T> struct TreeNode{T val;TreeNode *left;TreeNode *right;TreeNode():val(0), left(NULL), right(NULL){}TreeNode(T x):val(x), left(NULL), right(NULL){} };template<typena…...
OpenAI Whisper:开启语音转文本的智能时代
在人工智能技术飞速发展的今天,OpenAI推出的Whisper语音识别系统正悄然改变着人类与机器的交互方式。作为一款开源的AI驱动语音转文本工具,Whisper凭借其跨语言能力、高精度识别和灵活的生态系统,成为开发者和普通用户共同追捧的技术标杆。 核心技术与突破 Whisper基于深度…...
基于CSDN资源,搭建AI赋能农业典型场景落地方案
农业场景,不但是信息化、自动化等薄弱的产业,更是AI落地困难的场景。基于此,想通过这篇文章查找一个CSDN相关资源,论证一下AI赋能农业三个典型场景的实现思路。 场景1:水质-土壤智能调控 **痛点:**水质恶…...
python量化交易——金融数据管理最佳实践——使用qteasy大批量自动拉取金融数据
文章目录 使用数据获取渠道自动填充数据QTEASY数据拉取功能数据拉取接口refill_data_source()数据拉取API的功能特性多渠道拉取数据实现下载流量控制实现错误重试日志记录其他功能 qteasy是一个功能全面且易用的量化交易策略框架, Github地址在这里。使用它&#x…...
RoboBrain:从抽象到具体的机器人操作统一大脑模型
25年2月来自北大、北京智源、中科院自动化所等的论文“RoboBrain: A Unified Brain Model for Robotic Manipulation from Abstract to Concrete”。 目前的多模态大语言模型(MLLM) 缺少三项必备的机器人大脑能力:规划能力,将复杂…...
DeepSeek本地接口调用(Ollama)
前言 上篇博文,我们通过Ollama搭建了本地的DeepSeek模型,本文主要是方便开发人员,如何通过代码或工具,通过API接口调用本地deepSeek模型 前文:DeepSeek-R1本地搭建_deepseek 本地部署-CSDN博客 注:本文不仅…...
数据库索引的作用:提升数据检索效率的关键
在数据库管理系统中,数据如同浩瀚海洋中的宝藏,如何快速准确地找到所需信息,成为了一个关键问题。这时候,数据库索引就如同一张精确的航海图,指引着我们高效地定位数据。那么,数据库索引究竟是什么…...
高效便捷的 Spring Boot 通用控制器框架
✨高效便捷的 Spring Boot 通用控制器框架✨ 一、简介 在 Java 开发中,重复性的基础接口编写工作常令人头疼。本框架基于 Spring Boot 与 MyBatis-Plus,精心构建通用控制器类BaseController,旨在为开发者排忧解难,极大减少繁琐的…...
SQL_语法
1 数据库 1.1 新增 create database [if not exists] 数据库名; 1.2 删除 drop database [if exists] 数据库名; 1.3 查询 (1) 查看所有数据库 show databases; (2) 查看当前数据库下的所有表 show tables; 2 数据表 2.1 新增 (1) 创建表 create table [if not exists…...
在 CentOS 上,常用几种方法来确保 Python 脚本在断开终端后继续运行
在 CentOS 上,你可以使用以下几种方法来确保 Python 脚本在断开终端后继续运行: 1. 使用 nohup 命令 nohup 命令可以让进程在终端关闭后继续运行。 nohup python main.py > output.log 2>&1 &nohup:忽略挂断信号,…...
全面回顾复习——C++语法篇1(基于牛客网C++题库)
注:牛客网允许使用万能头文件#include<bits/stdc.h> 1、求类型长度——sizeof()函数 2、将浮点数四舍五入——round()函数——前面如果加上static_cast会更安全一些 在C语言中可以使用printf(“.0l…...
一、数据库 MySQL 基础学习 (上)
一、数据库的概念 DB 数据库(database):存储数据的“仓库”,保存一系列有组织的数据 DBMS:数据库管理系统(Database Management System)。数据库是通过 DBMS 创建和操作的容器 创建的 DBMS: MySQL、Oracl…...
基于Django创建一个WEB后端框架(DjangoRestFramework+MySQL)流程
一、Django项目初始化 1.创建Django项目 Django-admin startproject 项目名 2.安装 djangorestframework pip install djangorestframework 解释: Django REST Framework (DRF) 是基于 Django 框架的一个强大的 Web API 框架,提供了多种工具和库来构建 RESTf…...
AutoGen学习笔记系列(七)Tutorial - Managing State
这篇文章瞄准的是AutoGen框架官方教程中的 Tutorial 章节中的 Managing State 小节,主要介绍了如何对Team内的状态管理,特别是如何 保存 与 加载 状态,这对于Agent系统而言非常重要。 官网链接:https://microsoft.github.io/auto…...
Redis渐进式遍历数据库
目录 渐进式遍历 数据库 渐进式遍历 keys*可以一次性的把整个redis中所有key都获取到,这个操作是非常危险的,因为可能一下获取到太多的key,阻塞redis服务器。要想很好的获取到所有的key,又不想出现卡死的情况,就可以…...
机器学习中的线性代数:奇异值分解 SVD
线性代数 奇异值分解(SVD) 参考资料: 超详细!彻底搞懂矩阵奇异值分解(SVD)本质计算应用!_哔哩哔哩_bilibili 非常好的视频,本文内容主要来自于该视频,在此表示感谢&#…...
【每日八股】计算机网络篇(三):IP
目录 DNS 查询服务器的基本流程DNS 采用 TCP 还是 UDP,为什么?默认使用 UDP 的原因需要使用 TCP 的场景?总结 DNS 劫持是什么?解决办法?浏览器输入一个 URL 到显示器显示的过程?URL 解析TCP 连接HTTP 请求页…...
