讲解关于slam一系列文章汇总链接:史上最全slam从零开始,针对于本栏目讲解的(01)ORB-SLAM2源码无死角解析链接如下(本文内容来自计算机视觉life ORB-SLAM2 课程课件): (01)ORB-SLAM2源码无死角解析-(00)目录_最新无死角讲解:https://blog.csdn.net/weixin_43013761/article/details/123092196 文末正下方中心提供了本人 联系方式, 点击本人照片即可显示 W X → 官方认证 {\color{blue}{文末正下方中心}提供了本人 \color{red} 联系方式,\color{blue}点击本人照片即可显示WX→官方认证} 文末正下方中心提供了本人联系方式,点击本人照片即可显示WX→官方认证
一、前言通过上一篇博客,已经知道什么时候需要关键帧,那么接下来就是创建关键帧。其核心函数位于 src/Tracking.cc 的 Tracking::CreateNewKeyFrame() 函数中,分析如下。
二、步骤
该函数主要的步骤如下:
1:将当前帧构造成关键帧
2:将当前关键帧设置为当前帧的参考关键帧
3:对于双目或rgbd摄像头,为当前帧生成新的MapPoints
三、源码注释
后面有细节分析,可以往下查看
/**
* @brief 创建新的关键帧
* 对于非单目的情况,同时创建新的MapPoints
*
* Step 1:将当前帧构造成关键帧
* Step 2:将当前关键帧设置为当前帧的参考关键帧
* Step 3:对于双目或rgbd摄像头,为当前帧生成新的MapPoints
*/
void Tracking::CreateNewKeyFrame()
{
// 如果局部建图线程关闭了,就无法插入关键帧
if(!mpLocalMapper->SetNotStop(true))
return;
// Step 1:将当前帧构造成关键帧
KeyFrame* pKF = new KeyFrame(mCurrentFrame,mpMap,mpKeyFrameDB);
// Step 2:将当前关键帧设置为当前帧的参考关键帧
// 在UpdateLocalKeyFrames函数中会将与当前关键帧共视程度最高的关键帧设定为当前帧的参考关键帧
mpReferenceKF = pKF;
mCurrentFrame.mpReferenceKF = pKF;
// 这段代码和 Tracking::UpdateLastFrame 中的那一部分代码功能相同
// Step 3:对于双目或rgbd摄像头,为当前帧生成新的地图点;单目无操作
if(mSensor!=System::MONOCULAR)
{
// 根据Tcw计算mRcw、mtcw和mRwc、mOw
mCurrentFrame.UpdatePoseMatrices();
// We sort points by the measured depth by the stereo/RGBD sensor.
// We create all those MapPoints whose depth < mThDepth.
// If there are less than 100 close points we create the 100 closest.
// Step 3.1:得到当前帧有深度值的特征点(不一定是地图点)
vector vDepthIdx;
vDepthIdx.reserve(mCurrentFrame.N);
for(int i=0; i0)
{
// 第一个元素是深度,第二个元素是对应的特征点的id
vDepthIdx.push_back(make_pair(z,i));
}
}
if(!vDepthIdx.empty())
{
// Step 3.2:按照深度从小到大排序
sort(vDepthIdx.begin(),vDepthIdx.end());
// Step 3.3:从中找出不是地图点的生成临时地图点
// 处理的近点的个数
int nPoints = 0;
for(size_t j=0; jObservations()AddObservation(pKF,i);
pKF->AddMapPoint(pNewMP,i);
pNewMP->ComputeDistinctiveDescriptors();
pNewMP->UpdateNormalAndDepth();
mpMap->AddMapPoint(pNewMP);
mCurrentFrame.mvpMapPoints[i]=pNewMP;
nPoints++;
}
else
{
// 因为从近到远排序,记录其中不需要创建地图点的个数
nPoints++;
}
// Step 3.4:停止新建地图点必须同时满足以下条件:
// 1、当前的点的深度已经超过了设定的深度阈值(35倍基线)
// 2、nPoints已经超过100个点,说明距离比较远了,可能不准确,停掉退出
if(vDepthIdx[j].first>mThDepth && nPoints>100)
break;
}
}
}
// Step 4:插入关键帧
// 关键帧插入到列表 mlNewKeyFrames中,等待local mapping线程临幸
mpLocalMapper->InsertKeyFrame(pKF);
// 插入好了,允许局部建图停止
mpLocalMapper->SetNotStop(false);
// 当前帧成为新的关键帧,更新
mnLastKeyFrameId = mCurrentFrame.mnId;
mpLastKeyFrame = pKF;
}
三、细节分析
( 1 ) : \color{blue}{(1)}: (1): KeyFrame pKF* = new KeyFrame(mCurrentFrame,mpMap,mpKeyFrameDB) 其首先是根据当前帧,全局地图,以及关键帧数据库创建一个关键帧
( 2 ) : \color{blue}{(2)}: (2): mCurrentFrame.mpReferenceKF = pKF; 把创建出来的关键帧赋值为追踪器的参考关键帧,同时赋值给当前帧的参考关键帧(其会在UpdateLocalKeyFrames函数中被更新,替换城与该关键帧共视程度最高的关键帧)。
( 3 ) : \color{blue}{(3)}: (3): mCurrentFrame.UpdatePoseMatrices(); mTcw→相机姿态 世界坐标系到相机坐标坐标系的变换矩阵,是我们常规理解中的相机位姿 根据mTcw可以计算出mOw(当前相机光心在世界坐标系下坐标),mRcw(世界坐标系到相机坐标系的旋转矩阵),mtcw(世界坐标系到相机坐标系的平移向量),mRwc(相机坐标系到世界坐标系的旋转矩阵)。
( 4 ) : \color{blue}{(4)}: (4): cv::Mat x3D = mCurrentFrame.UnprojectStereo(i); 当某个特征点的深度信息或者双目信息有效时,将它反投影到三维世界坐标系中。计算出特征点在世界坐标系下的3D坐标。
剩下一些之前讲解过的函数,这里就不再重复了
四、总结
通过上面的分析,可以知道创建关键帧的时候,如果是双目或者深度相机,会为其为当前帧生成新的地图点,单目无操作。创建关键帧之后,会把关键帧插入到列表 mlNewKeyFrames中,等待local mapping线程临幸。
本文内容来自计算机视觉life ORB-SLAM2 课程课件