ORB-SLAM(五)KeyFrame类
KeyFrame类利用Frame类来构造。对于什么样的Frame可以认为是关键帧以及何时需要加入关键帧,是实现在tracking模块中的。
由于KeyFrame中一部分数据会被多个线程访问修改,因此需要在这些成员中加线程锁,保证同一时间只有一个线程有访问权。涉及线程安全的有:
关键帧位姿的设置(lock(mMutexPose));
关键帧间连接关系的设置(lock(mMutexConnections));
关键帧对应地图点的操作(lock(mMutexFeatures)),包括通过地图点计算相连关键帧之间的权重。
1. 设置相机位姿参数:设置KeyFrame中成员变量mTcw,mTwc,Ow(左目相机中心坐标),和Cw(双目相机baseline中点坐标),相机坐标Z朝北,X朝东,Y朝地。
并给出了get函数获取姿态参数。
注意
- 这里的Ow等价于twc,表示当前相机光心在世界坐标系下的三维坐标
- Tcw直接求逆计算量比较大,一般矩阵求逆在实现时都会用等价的矩阵表达式去表示,这里Ow就对应Tcw-1中的平移向量-RTt.
void KeyFrame::SetPose(const cv::Mat &Tcw_)
{
unique_lock<mutex> lock(mMutexPose);
Tcw_.copyTo(Tcw);
cv::Mat Rcw = Tcw.rowRange(,).colRange(,);
cv::Mat tcw = Tcw.rowRange(,).col();
cv::Mat Rwc = Rcw.t();
Ow = -Rwc*tcw; Twc = cv::Mat::eye(,,Tcw.type());
Rwc.copyTo(Twc.rowRange(,).colRange(,));
Ow.copyTo(Twc.rowRange(,).col());
cv::Mat center = (cv::Mat_<float>(,) << mHalfBaseline, , , );
Cw = Twc*center;
}
2. 为关键帧之间添加连接,通过关键帧之间的weight连接,weight指的是两个关键帧之间共同观测到的地图点:(注意这里都是接口函数,真实的建立连接关系使用的是void KeyFrame::UpdateConnections()函数)
使用的数据结构是:
std::map<KeyFrame*,int> mConnectedKeyFrameWeights
每一个关键帧都会维护一个自己的map,其中记录了与其他关键帧之间的weight。每次为当前关键帧添加新的连接关键帧后,都需要根据weight对map结构重新排序,
UpdateBestCovisibles();
并更新这两个向量:
mvpOrderedConnectedKeyFrames
mvOrderedWeights
由于map结构没有sort函数,需要将元素取出放入一个pair组成的vector中,排序后放入上面这两个向量中
vector<pair<int,KeyFrame*> > vPairs;
vPairs.reserve(mConnectedKeyFrameWeights.size());
for(map<KeyFrame*,int>::iterator mit=mConnectedKeyFrameWeights.begin(), mend=mConnectedKeyFrameWeights.end(); mit!=mend; mit++)
vPairs.push_back(make_pair(mit->second,mit->first)); sort(vPairs.begin(),vPairs.end());
list<KeyFrame*> lKFs; // keyframe
list<int> lWs; // weight
for(size_t i=, iend=vPairs.size(); i<iend;i++)
{
lKFs.push_front(vPairs[i].second);
lWs.push_front(vPairs[i].first);
} mvpOrderedConnectedKeyFrames = vector<KeyFrame*>(lKFs.begin(),lKFs.end());
mvOrderedWeights = vector<int>(lWs.begin(), lWs.end());
还有几个相关的API:
set<KeyFrame*> KeyFrame::GetConnectedKeyFrames();
vector<KeyFrame*> KeyFrame::GetVectorCovisibleKeyFrames(); vector<KeyFrame*> KeyFrame::GetBestCovisibilityKeyFrames(const int &N);
vector<KeyFrame*> KeyFrame::GetCovisiblesByWeight(const int &w); int KeyFrame::GetWeight(KeyFrame *pKF);
都是返回连接的关键帧;
前两个返回所有连接的关键帧,区别在于一个未排序(set),一个排序(vector)。// set是关联容器 vector是顺序容器
中间两个返回满足一定阈值(前N个,权重大于等于w)的关键帧,最后一个返回指定帧与当前帧间的权重。
3. 当前帧对应的地图点的指针均存放在mvpMapPoints(mvp代表:member、vector、pointer)向量中,通过对mvpMapPoints操作封装,可以得到以下API:
void KeyFrame::AddMapPoint(MapPoint *pMP, const size_t &idx);
void KeyFrame::EraseMapPointMatch(const size_t &idx);
void KeyFrame::EraseMapPointMatch(MapPoint* pMP);
void KeyFrame::ReplaceMapPointMatch(const size_t &idx, MapPoint* pMP); // 注意区别下面两个
set<MapPoint*> KeyFrame::GetMapPoints();
vector<MapPoint*> KeyFrame::GetMapPointMatches();
MapPoint* KeyFrame::GetMapPoint(const size_t &idx); // 返回高质量MapPoints(被至少minObs个关键帧观察到)的数量,其中会判断MapPoint的Observations()属性,对比给出的阈值
int KeyFrame::TrackedMapPoints(const int &minObs);
mvpMapPoints初始化在Frame.cpp中:
mvpMapPoints = vector<MapPoint*>(N,static_cast<MapPoint*>(NULL));
其中有N个空指针,因此有的位置上的MapPoint并没有指向实际的地图点(虽然对应有特征点,有索引idx,但是是外点),获取时需要注意。
4. UpdateConnections()函数:建立关键帧之间的连接关系
ORB-SLAM(五)KeyFrame类的更多相关文章
- (转)Qt Model/View 学习笔记 (五)——View 类
Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...
- Typescript 学习笔记五:类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- ORB-SLAM(五)KeyFrame类-最小生成树
KeyFrame中维护了一个map,保存了与当前帧共视的KeyFrame*与权重(共视MapPonits数量).对关键帧之间关系是用加权有向图来完成的,那么理解其spanning tree生成树的原理 ...
- c++ 吕凤翥 第五章 类对象一
一 类的声明和实现 1. class tdate //声明部分 { public: void setdate(int y,int m,int d); int isleapyear(); voi ...
- Java基础复习笔记系列 五 常用类
Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ...
- Java编程思想学习(五) 复用类
1.继承与组合 复用类的方法有两种:继承与组合.继承就不多说了,组合就是直接在类中new一个对象. 数组也是对象,使用数组也是组合的一种. 2.初始化基类 当创建一个导出类的对象时,该对象包含一个基类 ...
- C#基础(五)——类中私有构造函数作用
如果类成员有private修饰符,就不允许在类范围以外访问这个类成员.对类构造函数应用private修饰符时,则禁止外部类创建该类的实例.尽管看上去有些不好理解(既然不能实例化,那么这个类还有什么用处 ...
- Java解惑五:类之谜
本文是依据JAVA解惑这本书,做的笔记.电子书见:http://download.csdn.net/detail/u010378705/7527721 谜题46 函数重载的问题. JAVA重载解析过程 ...
- PHP学习笔记二十五【类的继承】
<?php //定义父类 class Stu{ public $name; protected $age; protected $grade; private $address;//私有变量不会 ...
随机推荐
- Android(java)学习笔记50:通过反射获取成员变量和成员方法并且使用
1. 反射获取成员变量并且使用: (1)获取字节码文件对象: Class c = Class.forName("cn.itcast_01.Person"); (2) ...
- React中的响应式设计思想和事件绑定
这两个点是react入门非常重要的两个点,以前我们是直接操作dom的形式去做,react的设计思想和以前直接操作dom是完全不同的,react是一个响应式的框架,他在做编程的时候,强调的是我们不要直接 ...
- 学大伟业 Day 4 培训总结
今天讲的全是dp... 不多废话,先看一道经典的模板LIS(最长不下降子序列) 一.LIS 给定一个长度为N的数列,求最长上升子序列 例:1 7 2 8 3 4 答案:1 2 3 4 代码: #inc ...
- Android学习笔记_55_Tween动画 (渐变、缩放、位移、旋转)
Android 平台提供了两类动画. 一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转.平移.放缩和渐变).第二类就是 Frame动画,即顺序的播放事先做好的图像,与gi ...
- python—迭代器
迭代器 这些可以直接作用于for循环的对象统称为可迭代对象:Iterable. 可以使用isinstance()判断一个对象是否是Iterable对象: >>> from colle ...
- vue2.0移除或更改的一些东西
一.vue2.0移除了$index和$key 虽然说现在很多文章说他们的代码是vue2.0版本的,但是有一些仔细一看,发现并不全是2.0版本,有些语法还是1.0的版本,比如这个$index,$key, ...
- HTML5笔记——第一节
我的第一个网页 <!--html的基础模板--><!--html hyperText markup Language--><!--声明文档类型--><!DOC ...
- oracle中lock和latch的用途
本文向各位阐述Oracle的Latch机制,Latch,用金山词霸翻译是门插栓,闭锁,专业术语叫锁存器,我开始接触时就不大明白为什么不写Lock,不都是锁吗?只是翻译不同而以?研究过后才知道两者有很大 ...
- 核心动画(UIView封装动画)-转
一.UIView动画(首尾) 1.简单说明 UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画支持. 执行动画所需要的工作由UIView类自动完成 ...
- 【网络流】EK算法及其优化
今天上午我仿佛知道了什么叫做网络流,这里推荐一篇博客,大家入门网络流的可以看一下这篇博客,保证一看就懂! 博客链接: 网络流入门 这里有一篇经过我改过的EK带注释代码(博客里也有一样的,只是加了一些注 ...