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

单目的初始化有专门的初始化器,只有连续的两帧特征点均>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. oozie fork join结点

    oozie可以用fork和join节点进行多任务并行处理,同时fork和join也是同时出现,缺一不可. 语法: <workflow-app name="[WF-DEF-NAME]&q ...

  2. python接口测试-项目实践(二)获取接口响应,取值(re、json)

    一 分别请求3个接口,获取响应. 第三方接口返回有两种:1 纯字符串  2 带bom头的json字串 import requests api1 = 'url1' response1 = request ...

  3. MySQL30条规范解读

    转载自:https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651959906&idx=1&sn=2cbdc66cfb ...

  4. Android(java)学习笔记28:泛型概述和基本使用

    1. 泛型的概述和基本使用: package cn.itcast_01; import java.util.ArrayList; import java.util.Iterator; /* * Arr ...

  5. html默认样式重置

    几个著名的重置css   goal https://meyerweb.com/eric/tools/css/reset/ 雅虎 https://yuilibrary.com/yui/docs/cssr ...

  6. httpServeltRequest和Model传值的区别

    需要将请求发过来的数据(或者说参数)传递到重定向的页面/转发的页面的时候,就要用到>>model.addAttribute("mine", UserUtils.getC ...

  7. ueditor1.2.6图片被压缩的解决办法

    修改文件路径: ueditor\dialogs\image\image.html 修改数值:

  8. mysql中set和enum使用(简单介绍)

    简单介绍 SET类型 在创建表时,就指定SET类型的取值范围. 属性名 SET('值1','值2','值3'...,'值n') 其中,“属性名”参数指字段的名称:“值n”参数表示列表中的第n个值,这些 ...

  9. 01_常用 Linux 命令的基本使用

    01. 学习 Linux 终端命令的原因 Linux 刚面世时并没有图形界面,所有的操作全靠命令完成,如 磁盘操作.文件存取.目录操作.进程管理.文件权限 设定等 在职场中,大量的 服务器维护工作 都 ...

  10. JavaScript js调用堆栈(一)

    本文主要介绍JavaScript程序内部的执行机制 首先先了解什么是执行上下文 执行上下文就是当前JavaScript代码被解析和执行是所在环境的抽象概念,JavaScript中运行任何的代码都是在执 ...