单目、双目和RGB-D视觉SLAM初始化比较
无论单目、双目还是RGB-D,首先是将从摄像头或者数据集中读入的图像封装成Frame类型对象:
首先都需要将彩色图像处理成灰度图像,继而将图片封装成帧。
(1) 单目
mCurrentFrame = Frame(mImGray, timestamp, mpIniORBextractor, mpORBextractor, mpORBVocabulary, mK, mDistCoef, mbf, mThDepth);
下面详细介绍一下单目创建帧的过程,首先来看Frame的数据结构,它有三个构造函数,分别对应单目、双目和RGB-D相机,重要的成员变量有:
public:
//字典,用于重定位检测和闭环检测 相关成员变量还有BowVec FeatVec
ORBVocabulary* mpORBVocabulary;
//特征提取器,只有双目的时候才会使用Right
//这里注意Tracking结构体中同样有这两个ORBextractor类,在主程序初始化Tracking的时候即创建个该成员类,并通过fSettings()函数将ORBextractor.nFeatures、ORBextractor.scaleFactor等参数传入其中
//所以在创建Frame类时,直接将Tracking类中的mpORBextractorLeft、mpORBextractorRight传入frame即可
ORBextractor* mpORBextractorLeft, *mpORBextracotrRight;
//时间戳
double mTimeStamp;
//原始关键点图像坐标
std::vector<cv::KeyPoint> mvKeys和mvKeysRight
//经过矫正模型矫正的关键点坐标
std::vector<cv::KeyPoint> mvKeysUn;
//ORB描述子,每行对应一个描述子
cv::Mat mDescriptors, mDescriptorsRight
//地图点,关联到每个关键点
std::vector<MapPoint*> mvpMapPoints;
//相机变换矩阵T
cv::Mat mTcw;
//当前帧id
long unsigned int mnId;
//参考关键帧
KeyFrame* mpReferenceKF;
private:
//旋转矩阵和平移向量
cv::Mat mRcw;
cv::Mat mtcw;
cv::Mat mRwc;
cv::Mat mOw;
创建帧的关键一步是ORB特征提取,ExtractORB()调用了ORBextractor类中的重载操作符void operator()。
ExtractORB(,imGray);
void Frame::ExtracORB(int flag, const cv::Mat &im)
{
if(flag==)
(*mpORBextractorLeft)(im, cv::Mat(), mvKeys, mDescriptors);
else
(*mpORBextractorLeft)(im, cv::Mat(), mvKeysRight, mDescriptorRight);
}
ExtractORB()调用了ORBextractor类中的重载操作符void operator(),完成特征提取,提取结果被保存在Frame类的成员变量std::vector<cv:KeyPoint> mvKeys和cv:Mat mDescriptors中。
void ORBextractor::operator()(InputArray_image, InputArray_mask, vector<KeyPoint>& _keypoints, OutputArray _descriptors);
得到关键帧之后便进行track(),首先是初始化。单目初始化是连续取两帧特征点数量超过100的图像帧,并且匹配点大于100,才可以开始初始化,否则重新接收数据帧。
//调用Initializer类中的初始化函数,只有单目才会调用该类
mpInitailizer->Initialize(mCurrent, mvIniMatches, Rcw, tcw, mvIniP3D, vbTriangulated);
1)初始化第一步,开启两个线程,分别对应两个运行模型,即通过求取H单应矩阵或F本质矩阵来得到R t,
thread threadH(&Initializer::FindHomography, this, ref(vbMatchesInliersH), ref(SH), ref(H));
thread threadF(&Initializer::FindFundamental, this, ref(vbMatchesInliersF), ref(SF), ref(F));
线程threadH调用Initializer::FindHomography函数,计算单应矩阵H,采用归一化的直接线性变换(normalized DLT)。线程threadF调用Initializer::FindFundamental函数计算基础矩阵F,采用方法为8点法。然后对结果进行评估,选择合适的模型来计算。
// Compute ratio of scores
float RH = SH/(SH+SF); // Try to reconstruct from homography or fundamental depending on the ratio (0.40-0.45)
if(RH>0.40)
return ReconstructH(vbMatchesInliersH,H,mK,R21,t21,vP3D,vbTriangulated,1.0,);
else //if(pF_HF>0.6)
return ReconstructF(vbMatchesInliersF,F,mK,R21,t21,vP3D,vbTriangulated,1.0,);
return false;
2)第二步,创建并添加关键帧和初始化地图点
void Tracking::CreateInitialMapMonocular()
//将关键帧中加入该地图点
pKFini->AddMapPoint(pMP,i);
pKFcur->AddMapPoint(pMP,mvIniMatches[i]); //将两个关键帧加入地图点中
pMP->AddObservation(pKFini,i);
pMP->AddObservation(pKFcur,mvIniMatches[i]); //选择地图点描述子
pMP->ComputeDistinctiveDescriptors();
//计算地图点深度
pMP->UpdateNormalAndDepth();
//将地图点加入mpMap
mpMap->AddMapPoint(pMP);
3) 第三步,优化位姿
Optimizer::GlobalBundleAdjustement(mpMap, );
4) 第四步,对相关数据赋值
//更新局部地图
mpLocalMapper->InsertKeyFrame(pKFini);
mpLocalMapper->InsertKeyFrame(pKFcur);
//更新当前帧位姿
mCurrentFrame.SetPose(pKFcur->GetPose()); mnLastKeyFrameId=mCurrentFrame.mnId;
mpLastKeyFrame = pKFcur;
//局部关键帧?
mvpLocalKeyFrames.push_back(pKFcur);
mvpLocalKeyFrames.push_back(pKFini); mvpLocalMapPoints=mpMap->GetAllMapPoints();
//更新参考关键帧
mpReferenceKF = pKFcur; mCurrentFrame.mpReferenceKF = pKFcur;
mLastFrame = Frame(mCurrentFrame);
mpMap->SetReferenceMapPoints(mvpLocalMapPoints);
至此,单目初始化成功!!!
(2) 双目
mCurrentFrame = Frame(mImGray, imGrayRight, timestamp, mpORBextractorLeft, mpORBextractorRight, mpORBVocabulary,mK, mDistCoef, mbf, mThDepth);
(3) RGB-D
mCurrentFrame = Frame(mImGray, imDepth, timestamp, mpORBextractorLeft, mpORBVocabulary, mK, mDistCoef, mbf, mThDepth);
由于双目和RGB-D相机不需要通过两个相邻帧来恢复地图点深度,所以初始化过程极其相似,只要当前到来帧满足条件即可开始初始化。初始化步骤如下:
1)第一步,如果满足条件,创建并添加关键帧和初始化地图点
if(mCurrentFrame.N>)
//后来帧都以该帧为参考
mCurrentFrame.SetPose(cv::Mat::eye(,,CV_32F));
//创建关键帧
KeyFrame* pKFini = new KeyFrame(mCurrentFrame, mpMap, mpKeyFrameDB);
//将关键帧插入地图
mpMap->AddKeyFrame(pKFini);
//初始化地图点并关联关键帧
for(int i=; i<mCurrentFrame.N;i++)
{
float z = mCurrentFrame.mvDepth[i];
if(z>)
{
cv::Mat x3D = mCurrentFrame.UnprojectStereo(i);
MapPoint* pNewMP = new MapPoint(x3D,pKFini,mpMap);
pNewMP->AddObservation(pKFini,i);
pKFini->AddMapPoint(pNewMP,i);
pNewMP->ComputeDistinctiveDescriptors();
pNewMP->UpdateNormalAndDepth();
mpMap->AddMapPoint(pNewMP);
mCurrentFrame.mvpMapPoints[i]=pNewMP;
}
}
2)第二步,对相关数据赋值
//更新局部地图
mpLocalMapper->InsertKeyFrame(pKFini);
//更新最后帧
mLastFrame = Frame(mCurrentFrame);
//更新最后关键帧
mnLastKeyFrameId=mCurrentFrame.mnId;
mpLastKeyFrame = pKFini;
//更新局部关键帧
mvpLocalKeyFrames.push_back(pKFini);
mvpLocalMapPoints=mpMap->GetAllMapPoints();
//更新参考帧
mpReferenceKF = pKFini;
mCurrentFrame.mpReferenceKF = pKFini; mpMap->SetReferenceMapPoints(mvpLocalMapPoints);
双目和RGB-D相机初始化即完成!!!
总结单目和双目、RGB-D相机初始化的不同:
1. 通过不断学习本人发现,初始化的目的是创建3d地图点,为后续跟踪提供初值。而单目通过一帧无法估计深度,所以初始化时需要使用两帧。
2. 单目算出相机变换矩阵之后,又进行了位姿优化BundleAdjustement。
初始化完成之后,即进入跟踪状态TrackWithMotionModel()、TrackReferenceKeyFrame()、Relocalization()等。。。
参考文献:
1. http://zhehangt.win/2018/01/11/SLAM/ORBSLAM/ORBSLAM2ORBExtractor/
2. https://blog.csdn.net/u010821666/article/details/52915238?locationNum=1&fps=1
3. https://www.cnblogs.com/shang-slam/p/6389129.html
4. https://blog.csdn.net/u010128736/article/details/53218140
单目、双目和RGB-D视觉SLAM初始化比较的更多相关文章
- UE4中VR模式下窗口单目双目的问题
如果要是单目的话使用HMD MIRROR MODE 3或者4
- 激光SLAM与视觉SLAM的特点
激光SLAM与视觉SLAM的特点 目前,SLAM技术被广泛运用于机器人.无人机.无人驾驶.AR.VR等领域,依靠传感器可实现机器的自主定位.建图.路径规划等功能.由于传感器不同,SLAM的实现方式也有 ...
- 教你如何认识人脸识别开发套件中的双目摄像、3D结构光摄像头、单目摄像头的区别及详细讲解
深圳市宁远电子提供的人脸识别模组可支持双目摄像头和3D结构光摄像头,在客户咨询中经常有被问到双目的为什么会比单目的成本高,区别在哪里,他们的适用于哪些场景呢?在此,深圳市宁远电子技术工程师就为大家详细 ...
- Semantic Monocular SLAM for Highly Dynamic Environments面向高动态环境的语义单目SLAM
一.摘要 当前单目SLAM系统能够实时稳定地在静态环境中运行,但是由于缺乏明显的动态异常处理能力,在动态场景变化与运动中往往会失败.作者为解决高度动态环境中的问题,提出一种语义单目SLAM架构,结合基 ...
- 高翔《视觉SLAM十四讲》从理论到实践
目录 第1讲 前言:本书讲什么:如何使用本书: 第2讲 初始SLAM:引子-小萝卜的例子:经典视觉SLAM框架:SLAM问题的数学表述:实践-编程基础: 第3讲 三维空间刚体运动 旋转矩阵:实践-Ei ...
- (转) SLAM系统的研究点介绍 与 Kinect视觉SLAM技术介绍
首页 视界智尚 算法技术 每日技术 来打我呀 注册 SLAM系统的研究点介绍 本文主要谈谈SLAM中的各个研究点,为研究生们(应该是博客的多数读者吧)作一个提纲挈领的摘要.然后,我 ...
- 视觉SLAM中相机详解
视觉SLAM中,通常是指使用相机来解决定位和建图问题. SLAM中使用的相机往往更加简单,不携带昂贵的镜头,以一定的速率拍摄周围的环境,形成一个连续的视频流. 相机分类: 单目相机:只是用一个摄像头进 ...
- 视觉SLAM的方案总结
MoNoSLAM:https://github.com/hanmekim/SceneLib2 以扩展卡尔曼滤波为后端,追踪前端非常稀疏的特征点,以相机的当前状态和所有路标点为状态量,更新其均值和协方差 ...
- 高博-《视觉SLAM十四讲》
0 讲座 (1)SLAM定义 对比雷达传感器和视觉传感器的优缺点(主要介绍视觉SLAM) 单目:不知道尺度信息 双目:知道尺度信息,但测量范围根据预定的基线相关 RGBD:知道深度信息,但是深度信息对 ...
随机推荐
- node express 跨域问题
express = require('express'); var app = express(); //设置跨域访问 app.all('*', function(req, res, next) { ...
- 【HAOI2010】工厂选址题解
题目描述 某地区有m座煤矿,其中第i号矿每年产量为ai吨,现有火力发电厂一个,每年需用煤b吨,每年运行的固定费用(包括折旧费,不包括煤的运费)为h元,每吨原煤从第i号矿运到原有发电厂的运费为Ci0(i ...
- 在.Net项目中使用Redis作为缓存服务
转自:http://www.cnblogs.com/hohoa/p/5771255.html 最近由于项目需要,在系统缓存服务部分上了redis,终于有机会在实际开发中玩一下,之前都是自己随便看看写写 ...
- Web网站高并发量的解决方案
摘要: 一个小型的网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单.随着互联网业务的不断丰富,网站相 ...
- 20145238-荆玉茗《网络对抗技术》MSF基础应用
20145238荆玉茗-<网络攻防>-MSF基础应用 实践过程 MS08_067漏洞渗透攻击实践(主动攻击) 实验工具: kali&windows xp 将xp的网络设为NAT模式 ...
- js 飞机大战
完整文件及代码可以在网盘下载,下载链接为:https://pan.baidu.com/s/1hs7sBUs 密码: d83x 飞机大战css定义: <style> #container{ ...
- easyui分页的使用方法
使用: $("#tt").datagrid("getPager").pagination(option); 例子: $("#tb").dat ...
- C# 局部类型 Partial
Partial是局部类型的意思.允许我们将一个类.结构或接口分成几个部分,分别实现在几个不同的.cs文件中.C#编译器在编译的时候仍会将各个部分的局部类型合并成一个完整的类 局部类型适用情况: (1) ...
- 【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)
洛谷P2023:https://www.luogu.org/problemnew/show/P2023 思路 需要2个Lazy-Tag 一个表示加的 一个表示乘的 需要先计算乘法 再计算加法 来自你谷 ...
- 课时25.a标签基本使用(掌握)
什么是a标签? 我们打开百度或者淘宝网页,观察任何一个超链接都会发现它有如下特质: 有下划线 移上去有小手指 可以点击 a标签的作用:就是用于控制页面与页面之间跳转的 a标签的格式:<a hre ...