跟ORB-SLAM2对比看,添加了(1)Detector2D.cc(2)Detector3D.cc(3)PointcloudMapping.cc(4)ObjectDatabase.cc源代码文件。总体流程改进的主要还是在前端
红色部分是修改部分,目标检测线程以及语义建图线程都是添加的,并且在追踪线程中进行了一些更改。几何信息以及目标检测结果的结合的动态特征点提出策略。
2-D语义信息为动态特征拒绝策略提供先验动态对象信息。
与此同时,跟踪线程也开始从输入帧中提取ORB特征点。提取完成后,利用迭代的Lucas-Kanade光流法和金字塔算法对当前帧和前几帧之间的稀疏特征点进行匹配。然后,采用基于RANSAC的七点法计算两帧间的基本矩阵。这减少了由于动态区域中不正确的数据相关性而引起的不利影响。与特征提取和基本矩阵计算相比,目标检测任务更加耗时。由于跟踪线程采用对象检测而非语义分割,因此阻塞时间不会太长。这增强了系统的实时性能.接着,跟踪线程将核约束和2-D语义信息相结合以拒绝动态特征点。这是原文的流程,也是逻辑需要理清的地方。
想要了解流程,就得知道这些策略是用在什么地方,以及前端的哪个部分,因为如果要对其做出修改,得先知道改了什么部分,添加在什么步骤之后。根据文章的结构流程图可以看出前面的ORB特征点提取是没有进行修改的。
需要看的部分:语义信息提取之后、极限约束之后的代码。
需要搞懂,这些流程之间的数据通信,以及重要的流程的输入输出。
还有就是rgbd_tum.cc流程,应该是一个总体的。之后有细节的地方在后面再继续记录。
- rgbd_tum.cc
定义、初始化参数
定义存储RGB图像文件名、深度图像文件名和时间戳的向量
检查RGB图像和深度图像的数量是否一致,如果一致则继续,否则输出错误信息并退出程序
创建ORB-SLAM2系统的实例,初始化所有系统线程并准备处理帧,模式为RGB-D
定义存储跟踪时间的向量
输出开始处理序列的信息
定义RGB和深度图像的矩阵变量(接下来应该是主循环)
ros的一些设置,发布器的创建
主循环,处理每一帧的图像
{
从文件中读取RGB图像以及深度图像(前面关联文件已经加载过名字)
获取当前时间戳
判断是否读取图像成功
记录跟踪RGB-D图像开始的时间
使用ORB-SLAM2系统跟踪RGB-D图像,更新相机姿态
记录跟踪RGB-D图像结束的时间
计算跟踪RGB-D图像所用时间
将跟踪时间存储到向量中
发布相机姿态信息
计算下一个图像的时间间隔
如果跟踪所花费的时间小于时间间隔,休眠以匹配实际时间间隔
}
关闭系统的所有线程
计算并输出跟踪时间的统计信息
如果全局点云重建被启用,保存全局点云
主函数中有关键的跟踪SLAM.TrackRGBD,是写在system里的函数。应该看下在这个跟踪函数里面调用了什么函数,因为最后是直接返回了位姿信息。
那么就要着重来看TrackRGBD这个函数里面,怎么调用其他的函数了,以及一些重要的数据怎么传递。
主函数就是这样的流程,感觉对输入输出的理解可能没什么帮助,但是大致知道一整个流程是怎么走下来的。
Tracking线程,添加检测的函数以及检测流程的交互,传递指针给成员变量,方便系统之间的通信。添加了检测的标志判断,以及点云地图的一些初始化以及数据传入。在 这个线程里感觉没有核心的改进,目标是找到动态特征点提出策略的地方,并且进行改进。
Detector2D也是SG-SLAM添加的一个新的文件,里面使用NCNN进行目标检测
Detector2D::detect代码里面我看就将人作为了比较特殊的那一类,大于设置的动态特征阈值的话,mbHaveDynamicObjectForRmDynamicFeature = true;会把标志记录下来,意味着包含动态物体。先前会计算检测框,如果是动态的人的话,会把检测框添加到mvPotentialDynamicBorderForRmDynamicFeature中
Detector2D::draw_objects 只绘制置信度超过阈值的检测结果,绘制蓝色矩形框(BGR颜色空间,3像素线宽) ,格式化显示文本:类别名称 + 置信度百分比 添加文本显示,防止超出图像边界。清空图像缓存,准备接收下一帧数据。
Detector2D::Run()
循环,看是否有图像输入,有图像就对图像进行检测,然后添加完成检测的标志。
也可以看到,这个增添的文件,只是多了一个检测的线程,还要看到的是它最终检测的数据传到什么地方去了。
Detector3D这个部分暂时先不看,还是先看下与ORB-SLAM2对比的其他重要的地方。
改进都在Frame中,里面有极线约束检验,以及添加的动态特征剔除策略,然后中间计算两帧之间的位姿变化用的是稀疏光流的计算方法。
Viewer里面改了一点点,就是显示目标检测的框,添加了对那个2d里面的画框函数的调用。
ORBmatcher没做修改。大致可以确定前端的改进在什么地方了,主要的更改还是在Frame中以及Tracking中,如果我准备用这个SG-SLAM进行改进的话,应该会在Frame文件中进行修改。
找到这个动态剔除过程的流程记录一下,有些数据传输需要记录一下,方便下次查阅。
首先按照运行rgbd_tum.cc流程,主要的过程就是
Camera_Pose = SLAM.TrackRGBD(imRGB,imD,tframe);
因为是个循环,把每一张图像以及对应的深度图以及时间戳传入,进行跟踪计算位姿。之后跳转进入函数内部,一些流程就不赘述,关注主要的函数部分。
cv::Mat Tcw = mpTracker->GrabImageRGBD(im,depthmap,timestamp);这个函数里面重要的就是这个,三个传入的变量还是一样的,跟上一层传入的没有变化,依旧是图像以及对应的深度图以及时间戳。这个函数获取当前帧的相机位姿。再进行跳转,里面应该有对其他状态以及地图点的更新,我们这次先只关心位姿的计算。
同时在这个函数里,会把传入的图像复制给检测线程完成检测。
这个函数里面有先把图像转化成为灰度图像,并且调整了深度图像的数据类型和尺度。
mCurrentFrame = Frame(this,mImGray,mImDepth,timestamp,mpORBextractorLeft,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth,mLastFrame);
Track();
最关键的就是这两行了。
先来看当前帧的生成。当然这个Frame对应的应该是RGBD版本的帧,在Frame.cc里面有很多重载版本。
this
- 传入当前的Tracking
对象的指针,使得Frame
对象可以访问Tracking
类中的成员变量和函数。mImGray
- 传入灰度图像。mImDepth
- 传入深度图像。timestamp
- 传入当前帧的时间戳。mpORBextractorLeft
- 传入ORB特征点提取器。mpORBVocabulary
- 传入ORB词典。mK
- 传入相机的内参矩阵。mDistCoef
- 传入相机的畸变系数。mbf
- 传入相机的基线乘以焦距。mThDepth
- 传入深度阈值 (在构造函数里面计算了)mLastFrame
- 传入上一个处理的帧。
接下来跳转到帧生成构造函数中,添加了动态特征点剔除策略。
先提取ORB特征,计算出特征点和描述子。
cv::Mat imGrayT = imGray;
if(imGrayPre.data)
{
RmDynamicPointWithSemanticAndGeometry(imGrayPre,imGray);
std::swap(imGrayPre, imGrayT);
}
else;
{
std::swap(imGrayPre, imGrayT);
}
这部分是主要处理动态特征的流程,相对的,重要的就是RmDynamicPointWithSemanticAndGeometry(imGrayPre,imGray);
传入的是上一帧的图像,当前帧图像。将当前帧的特征点添加到curpoint中,先用反向光流计算上一帧特征点对应当前帧的位置,之后判断是否有潜在动态物体,剔除动态区域的点之后再进行基础矩阵的计算,这样保证几何约束的计算正确。
本质是时空一致性验证: 通过检查特征点在历史帧(prev)的位置是否位于历史动态区域,来推断该特征点是否属于动态物体 即使物体当前移出区域,只要它曾出现在动态区域就会被剔除
本来的改进想要针对的是相邻两帧的物体空间上的一个约束,发现如果只是有检测线程的话,不能做到有具体区分度的物体ID,要么引入实例分割模块,又或者进行改进的方案。
空间,时间这两个方向可以有更好的改进。然后就是想法是往概率上面去靠。感觉如何选出一个合适的概率模型比较重要,然后就是对参数的修改了。