CL关于ORB_SLAM的那些事(Frame)

Frame部分的学习

Frame中主要包括了不同传感器下的帧构造函数、提取ORB特征、计算词袋、设置传感器的姿态、更新位姿矩阵、获取传感器的中心、获取旋转矩阵的逆矩阵、判断地图点是否再被观测用于跟踪、计算关键点是否越过了栅格、获取关键点所在的区域、计算双目传感器的匹配、从深度图中计算得到右图的像素点位置、将关键点重投影到三维世界坐标系、获取去畸变的关键点、计算去畸变图像的边界、将特征点分配到某一个栅格中加速后期的特征点匹配。

Frame维护的变量

  1. 词袋类型的指针
  2. ORB特征提取类型的指针,包括左右特征特征提取器
  3. 相机的内参包括畸变参数
  4. 双目传感器的基线长度以及与焦距fx相乘的基线值
  5. 深度值 mthDepth
  6. 关键点的数目
  7. 没矫正前左右图像上提取的关键点和矫正过的关键点,矫正过的关键点才是slam系统中使用的
  8. 右图上的uv值和像素点的深度值
  9. 词袋的相关变量,词袋向量和特征向量
  10. 关键点和地图点之间的map关系
  11. 判断map关系是否out的标记位
  12. 关键点和某栅格的对应关系,减轻投影地图点时的匹配复杂度
  13. 传感器的位姿
  14. 当前和下一帧的帧号
  15. 在金字塔下的特征提取匹配的一些参数
  16. 无畸变的图像边界
  17. 是否为初始化计算的标记位
  18. 旋转、平移矩阵和传感器中心

Frame内功能函数的大致实现过程

静态变量的初始化 下一帧的帧号设置为0
初始化计算标记位设置为true
其他的一些变量,包括传感器的内参

Frame的拷贝构造函数,基本栅格内的信息以及当前帧的姿态

双目的Frame构造函数:

  1. 获取金字塔的层数等一些尺度信息
  2. 启动左右图特征点检测的线程
  3. 获取提取出的关键点的数目并进行判断,不能为0
  4. 对提取出的特征点的像素坐标进行矫正,获取无畸变的特征点的像素坐标
  5. 计算双目之间的左右图的匹配关系
  6. 如果是第一帧或者是传感器内参数发生变化时,都将计算图像的边界
  7. 最后将特征点分配到每一个栅格中

RGB_D相机的Frame构造函数(主要是区别部分):

  • 由于该传感器下只有一帧RGB图像,所以在特征点提取方面不需要开多线程进行提取

单目相机的Frame构造函数:

  • 由于单目缺少三维信息,所以对于右图以及深度方面,这边设置的时候都设置成了-1

三类构造函数的过程大致是这样的一个过程
下面来说怎么把这些提取出的关键点分配到某一个栅格内

AssignFeaturesToGrid()函数
其中涉及到了PoseInGrid()这个函数
PoseInGrid():判断该关键点是否在限定的栅格内
如果在栅格内的话,把该点的栅格位置内记录这个点的index
如果没有,这个关键点的index不会被记录

ExtractORB(int flag, const cv::Mat &im)函数
根据flag的标记位来进行左右图的特征点提取,这边主要是利用了ORBExtractor中重新定义的()运算符

SetPose(cv::Mat Tcw)
设置当前帧的姿态,这里涉及到了UpdatePoseMatrices()。
UpdatePoseMatrices():主要是获取了当前帧的旋转矩阵、旋转矩阵的逆、平移矩阵以及相机的中心坐标

isInFrustum()

  1. 设置MapPoint中的mbTrackInView变量为false
  2. 获取该点在世界坐标系中pose
  3. 将它转换到相机坐标系下的pose
  4. check它的z坐标是否为负数,如果是就直接return false;如果不是,函数将继续往下执行。
  5. 将该点进行投影获得相机坐标系下的坐标,判断其是否已经在图像区域外
  6. 获取该点的最大最小距离(点到相机中心的距离),判断其是否在该距离范围之内,如果不在,直接返回false
  7. 计算观测该点的视角的cos值,值较小说明视角越偏离相机中心,如果该值小于一定的阈值之后,直接返回false
  8. 预测在这个距离下的尺度
  9. 走完上面的所有判断之后,该点将被标记为可被跟踪
  10. 更新MapPoint中的跟踪标记位、投影之后的uv、投影之后的右图中的u、尺度和观测角Cos
  11. return ture

GetFeaturesInArea()

  1. 单纯看这个函数的话,暂时了解到该函数在某(x,y)出进行了r距离范围的搜索,得到在该区域内的特征点的index,这边的minLevel和maxLevel暂时不明白是啥,猜是金字塔的层数,后面看到了继续理解,判断给关键点所在的金字塔层数,只有在最大和最小层数范围内的关键点index才会被记录。
  2. 最后范围区域内搜索到的满足条件的关键点的index vector

ComputeBoW()
如果没进行词袋的计算,就进行词袋的计算,将描述子转化成描述向量,利用词袋库,将这些信息都转化成ORB的词汇信息。

UndistortKeyPoints()
对关键点进行取畸变

  1. 判断畸变参数是否为0,如果是,就不需要进行矫正,直接将提取出的关键点mvKeys赋值给mvKeysUn
  2. 将所有的关键点放进一个大矩阵中,利用opencv的畸变矫正点的函数,获得去畸变的关键点坐标。
  3. 通过循环将去畸变之后的点赋值给mvKeysUn

ComputeImageBounds(const cv::Mat &imLeft)
计算图像的边界
如果畸变参数为0,那么边界点就是(0,0)和(480,640);
不然,将理想的角点形成一个4×2的矩阵,也是通过opencv的undistortPoints进行去畸变,获取真实的图像的边界

ComputeStereoMatches()
计算双目的立体匹配,主要是获取双目传感器的视差图。之前实习了解过大部分的立体匹配算法,但是这边不具体展开,因为我现在用的传感器是单目和深度,所以…好!下一个函数

ComputeStereoFromRGBD(const cv::Mat &imDepth)
该函数利用了双目的特点,由于深度相机是直接一张彩色图和深度图,不存在右图这种东西。
它利用深度信息,一方面把深度信息存放在mvDepth中;另一方面,通过深度换算到双目的视差值,得到右图的x值。
只看这个函数,你也是不知道它为什么要这样做。接着往下看…

今天的最后一个函数
UnprojectStereo(const int &i)
传参进来的是某一特征点的索引,获取该index下的深度值,如果是有效的深度值(>0),获取其像素坐标以及相机坐标系下的(x,y),最后组合成相机坐标系下的三维坐标x3Dc,最后转换到世界坐标系下。

整个Frame.cpp的理解就差不多了,现在只是单个cpp的总结和自己的理解,有不到位的可以直接提出来。本人之前也大致看过ORB_SLAM的代码,这次想从每一个cpp入手,最后来一个大框架总结,搞懂更细节的一些问题。

时间:2019年08月07日
作者:hhuchen
机构:河海大学机电工程学院

你可能感兴趣的:(ORB_SLAM)