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;//私有变量不会 ...
随机推荐
- [18/11/28]Java中的包(package)
一.为何引入包? 包机制是Java中管理类的重要手段. 开发中,我们会遇到大量同名的类,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理. 包对于类,相当于文件夹对于文件的作用.(同一文件 ...
- 【题解】洛谷P2421[NOI2002]荒岛野人 (Exgcd)
洛谷P2421:https://www.luogu.org/problemnew/show/P2421 思路 从洞的最大编号开始增大枚举答案 对于每一个枚举的ans要满足Ci+k*Pi≡Cj+k*Pj ...
- Mysql之inner join,left join,right join详解
首先借用官方的解释下: inner join(等值连接):只返回两个表中联结字段相等的行: left join(左联接):返回包括左表中的所有记录和右表中联结字段相等的记录: right join(右 ...
- mysql replace()用法
mysql replace实例说明: UPDATE tb1 SET f1=REPLACE(f1, 'abc', 'def'); 释:表tb1中字段f1中为abc的值更新为def.一般用于某字段中值存在 ...
- CentOS 7设置网卡开机自动启用
一.查看网卡配置 root权限 [root@dbsyn ~]# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue ...
- ABAP术语-Accounting Document
Accounting Document 原文:http://www.cnblogs.com/qiangsheng/archive/2007/12/12/991731.html Accounting d ...
- 使用DOM对表格进行增删
---恢复内容开始--- 声明本文旨在练习dom 其中可以链接数据 或者使用ajax 实现的我全用的dom因为我在学dom. 一. 表格构建 <section id="section_ ...
- Ubuntu16.04采用FastCGI方式部署Flask web框架
1 部署nginx 1.1 安装nginx服务 root@desktop:~# apt-get install nginx -y 1.2 验证nginx服务是否启动 root@des ...
- H5混合开发进阶
混合开发: 原生app里面,IOS 安卓的原生app里面,嵌套h5界面. 通过原生app里的一个webView盒子进行交互.webView是原生app内置的一个XXX,里面可以放置h5界面.可以相互调 ...
- pyqt5--学习资料
http://zetcode.com/gui/pyqt5/ http://www.thehackeruniversity.com/2014/01/23/pyqt5-beginner-tutorial/ ...