单目初始化以及通过三角化恢复出地图点

单目的初始化有专门的初始化器,只有连续的两帧特征点均>100个才能够成功构建初始化器。

// mvbPreMatched是第一帧中的所有特征点;mvIniMatches标记匹配状态,未匹配上的标为-1;如果返回nmatches<100,初始化失败,重新初始化过程
int nmatches = matcher.SearchForInitialization(mInitialFrame,mCurrentFrame,mvbPrevMatched,mvIniMatches,);

若成功获取满足特征点匹配条件的连续两帧,并行计算分解基础矩阵和单应矩阵(获取的点恰好位于同一个平面),得到帧间运动(位姿),vbTriangulated标记一组特征点能否进行三角化。mvIniP3D是cv::Point3f类型的一个容器,是个存放3D点的临时变量。

该函数对应Initialize.cpp文件,需要完成较多工作,后面再介绍。

mpInitializer->Initialize(mCurrentFrame, mvIniMatches, Rcw, tcw, mvIniP3D, vbTriangulated)

最后初始化两帧位姿并且将mvIniP3D中的点包装成MapPoint,构建初始地图。

mInitialFrame.SetPose(cv::Mat::eye(,,CV_32F));
mCurrentFrame.SetPose(Tcw);
CreateInitialMapMonocular();

构建初始地图就是将这两关键帧以及对应的地图点加入地图(mpMap)中,需要分别构造关键帧以及地图点

KeyFrame* pKFini = new KeyFrame(mInitialFrame,mpMap,mpKeyFrameDB);
KeyFrame* pKFcur = new KeyFrame(mCurrentFrame,mpMap,mpKeyFrameDB);

地图点中需要加入其一些属性:

1. 观测到该地图点的关键帧(对应的关键点);

2. 该MapPoint的描述子;

3. 该MapPoint的平均观测方向和观测距离。

for(size_t i=; i<mvIniMatches.size();i++)
{
if(mvIniMatches[i]<)
continue;
//Create MapPoint from mvIniP3D
cv::Mat worldPos(mvIniP3D[i]);
MapPoint* pMP = new MapPoint(worldPos,pKFcur,mpMap);
pKFini->AddMapPoint(pMP,i);
pKFcur->AddMapPoint(pMP,mvIniMatches[i]);
pMP->AddObservation(pKFini,i);
pMP->AddObservation(pKFcur,mvIniMatches[i]);
pMP->ComputeDistinctiveDescriptors();
pMP->UpdateNormalAndDepth();
mCurrentFrame.mvpMapPoints[mvIniMatches[i]] = pMP;
mCurrentFrame.mvbOutlier[mvIniMatches[i]] = false;
mpMap->AddMapPoint(pMP);
}

还需要更新关键帧之间连接关系(以共视地图点的数量作为权重):

pKFini->UpdateConnections();
pKFcur->UpdateConnections();

对这两帧姿态进行全局优化重投影误差(LM):

Optimizer::GlobalBundleAdjustemnt(mpMap,);

注意这里使用的是全局优化,和回环检测调整后的大回环优化使用的是同一个函数。

接下来,需要归一化第一帧中地图点深度的中位数;如果深度<0或者这时发现优化后第二帧追踪到的地图点<100,也需要重新初始化。

否则,将深度中值作为单位一,归一化第二帧的位姿与所有的地图点。

    float medianDepth = pKFini->ComputeSceneMedianDepth();
float invMedianDepth = 1.0f/medianDepth; if(medianDepth< || pKFcur->TrackedMapPoints()<)
{
cout << "Wrong initialization, reseting..." << endl;
Reset();
return;
} // Scale current pose
cv::Mat Tc2w = pKFcur->GetPose();
Tc2w.col().rowRange(,) = Tc2w.col().rowRange(,)*invMedianDepth;
pKFcur->SetPose(Tc2w); // Scale points
vector<MapPoint*> vpAllMapPoints = pKFini->GetMapPointMatches();
for(size_t iMP=; iMP<vpAllMapPoints.size(); iMP++)
{
if(vpAllMapPoints[iMP])
{
MapPoint* pMP = vpAllMapPoints[iMP];
pMP->SetWorldPos(pMP->GetWorldPos()*invMedianDepth);
}
}

最后和StereoInitialization()中一样,需要更新局部地图,局部关键帧和局部地图点;并且更新LastFrame,LastKeyFrame,以及当前帧的ReferenceKF(上一帧,上一关键帧,参考关键帧)。

这就是单目初始化的大体步骤,其中最关键算法是通过初始连续两帧的对极约束恢复出相机姿态和地图点的部分(Initializer.cpp)留在下一节说。

ORB-SLAM (四)tracking单目初始化的更多相关文章

  1. ORB-SLAM3 细读单目初始化过程(上)

    作者:乔不思 来源:微信公众号|3D视觉工坊(系投稿) 3D视觉精品文章汇总:https://github.com/qxiaofan/awesome-3D-Vision-Papers/ 点击上方&qu ...

  2. ORBSLAM2单目初始化过程

    ORBSLAM2单目初始化过程 转自博客:https://blog.csdn.net/zhubaohua_bupt/article/details/78560966 ORB单目模式的初始化过程可以分为 ...

  3. ORB-SLAM2 论文&代码学习 —— 单目初始化

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要点: ORB-SLAM2 单目初始化 ...

  4. ORB-SLAM (四)Initializer单目初始化

    一. 通过对极约束并行计算F和H矩阵初始化 VO初始化目的是为了获得准确的帧间相对位姿,并通过三角化恢复出初始地图点.初始化方法要求适用于不同的场景(特别是平面场景),并且不要进行人为的干涉,例如选取 ...

  5. 单目、双目和RGB-D视觉SLAM初始化比较

    无论单目.双目还是RGB-D,首先是将从摄像头或者数据集中读入的图像封装成Frame类型对象: 首先都需要将彩色图像处理成灰度图像,继而将图片封装成帧. (1) 单目 mCurrentFrame = ...

  6. Semantic Monocular SLAM for Highly Dynamic Environments面向高动态环境的语义单目SLAM

    一.摘要 当前单目SLAM系统能够实时稳定地在静态环境中运行,但是由于缺乏明显的动态异常处理能力,在动态场景变化与运动中往往会失败.作者为解决高度动态环境中的问题,提出一种语义单目SLAM架构,结合基 ...

  7. 从零开始一起学习SLAM | 神奇的单应矩阵

    小白最近在看文献时总是碰到一个奇怪的词叫“homography matrix”,查看了翻译,一般都称作“单应矩阵”,更迷糊了.正所谓:“每个字都认识,连在一块却不认识”就是小白的内心独白.查了一下书上 ...

  8. 三角化---深度滤波器---单目稠密重建(高翔slam---十三讲)

    一.三角化 [1]三角化得到空间点的三维信息(深度值) (1)三角化的提出 三角化最早由高斯提出,并应用于测量学中.简单来讲就是:在不同的位置观测同一个三维点P(x, y, z),已知在不同位置处观察 ...

  9. Ubuntu16.04下编译安装及运行单目ORBSLAM2

    官网有源代码和配置教程,地址是 https://github.com/raulmur/ORB_SLAM2 1 安装必要工具 首先,有两个工具是需要提前安装的.即cmake和Git. sudo apt- ...

随机推荐

  1. Hybris ECP(Enterprise Commerce Platform)的调试

    This blog is written to demonstrate how to setup debug environment for Hybris ECP(Enterprise Commerc ...

  2. angular2 里父子组件传值的坑

    1.如果传的是基本类型的值,子组件里改变该值,父组件无变化 2.如果传的是对象,子组件里改变对象里的变量,父组件会变化 3.如果传的是函数,this不会继续指向父组件对象了,如果需要this指向父组件 ...

  3. Uva 10294 Polya

    #include <bits/stdc++.h> using namespace std; typedef long long LL; int gcd(int a,int b) { ? a ...

  4. 基础算法之Dijkstra最短路径

    核心思想:以起始原点为中心,想外层扩展,知道扩展到重点为止. 设到A点的最短路径上,A点前驱节点为B,则该路径包含到达节点B的最短路径. S集合代表已经探索过的节点,U集合表示未探索过的节点. 时间复 ...

  5. JDBC执行存储过程的四种情况 (转)

    本文主要是总结 如何实现 JDBC调用Oracle的存储过程,从以下情况分别介绍: [1].只有输入IN参数,没有输出OUT参数 [2].既有输入IN参数,也有输出OUT参数,输出是简单值(非列表) ...

  6. 【题解】洛谷P1445 [Violet]樱花 (推导+约数和)

    洛谷P1445:https://www.luogu.org/problemnew/show/P1445 推导过程 1/x+1/y=1/n! 设y=n!+k(k∈N∗) 1/x​+1/(n!+k)​=1 ...

  7. 基于Cent os 云服务器中SVN 服务器的搭建---具体实践是可行的 一次备注便于后续查找

    https://blog.csdn.net/shadowyingjian/article/details/80588544http://www.hongyanliren.com/2015m04/329 ...

  8. center os 文件读写权限

    五.使用chmod和数字改变文件或目录的访问权限文件和目录的权限表示,是用rwx这三个字符来代表所有者.用户组和其他用户的权限.有时候,字符似乎过于麻烦,因此还有另外一种方法是以数字来表示权限,而且仅 ...

  9. 跨域-iframe

    跨域 同源策略:为保障用户信息安全,防止恶意网站窃取数据的一种安全策略. "同源":协议相同.域名相同.端口号相同 "非同源": 1.Cookie.LocalS ...

  10. Reverse a String-freecodecamp算法题目

    Reverse a String(翻转字符串) 题目要求: 把字符串转化成数组 借助数组的reverse方法翻转数组顺序 把数组转化成字符串 思路: 用.split('')将字符串转换成单个字母组成的 ...