能跑kitti数据集的单目视觉里程计有哪些?比如ORB-SLAM
最好带有回环检测的
开源能用的
以下
ORB-SLAM2
SVO
DSO
PTAM
LDSO
VISO2
OKVIS
ROVIO
MSCKF
SLAM++
我们采用mono_kitti.cc
来开始程序,也就是针对单目kitti数据集来研究。
进入main
函数,定义了两个容器来存放每张图片的路径和时间戳:
// Retrieve paths to images
vector<string> vstrImageFilenames; //图像序列中每张图片存放路径
vector<double> vTimestamps; //图像序列中每张图片时间戳
然后执行LoadImages
函数:
//!这是一个非常关键的读文件函数
//argv[3]存放的是图像序列的存放路径,是从外界输入的路径
LoadImages(string(argv[3]), vstrImageFilenames, vTimestamps);
该函数也在mono_kitti.cc
文件中,函数定义如下:
//以下为LoadImages函数定义,这是该文件夹唯一的函数
// 函数定义:获取图像序列中每一张图像的访问路径和时间戳
void LoadImages(const string &strPathToSequence, vector<string> &vstrImageFilenames, vector<double> &vTimestamps)
{
// step 1 读取时间戳文件
ifstream fTimes; //定义一个输入流fTimes来读取文件中的时间戳(ifstream用来读取)
//调用数据集中的时间戳文件
string strPathTimeFile = strPathToSequence + "/times.txt"; //strPathTimeFile是一个路径,末位追踪到time.txt
//c_str是string类的一个函数,可以把string类型变量转换成char*变量
//open()要求的是一个char*字符串
//当文件名是string时需要转换,当文件名是字符数组型时就不需要此转换
fTimes.open(strPathTimeFile.c_str()); //使用输入流读取文件,调用了open()函数
while (!fTimes.eof()) //.eof()函数判断文件夹是否读到最后
{
string s;
getline(fTimes, s); //自动读取下一行时间戳文件
// 如果该行字符串不是空的,就写进流,读成double类型放入vector(用来改变数据类型)
if (!s.empty())
{
//流对象,用于流的输入输出
stringstream ss;
ss << s;
double t;
ss >> t;
// 保存时间戳
vTimestamps.push_back(t);
//!至此,vTimestamps储存了所有的时间戳
}
}
// step 1 使用左目图像, 生成左目图像序列中的每一张图像的文件名
//组装mono_kitti数据集中image_0目录的路径
string strPrefixLeft = strPathToSequence + "/image_0/";
const int nTimes = vTimestamps.size(); //有多少个时间戳
vstrImageFilenames.resize(nTimes); //重定义有多少个时间戳就有多少个图像,保持维度的一致性,但是之前也没规定有多少少图像
for (int i = 0; i < nTimes; i++)
{
stringstream ss;
//std::setw :需要填充多少个字符,默认填充的字符为' '空格
//std::setfill:设置std::setw将填充什么样的字符,如:std::setfill('*')
//ss总共为6位,i之外的前边几位用0来填充,得到的结果为000001 000099之类
ss << setfill('0') << setw(6) << i; //填6个0,如果来了个i,则代替0的位置,也就是总共有6位,末尾是i,其他用0填充
vstrImageFilenames[i] = strPrefixLeft + ss.str() + ".png";
//!至此,组装形成包含图像路径和编号的vector
}
}
执行完该函数后,成功将每张图片的路径及时间戳读取到刚刚定义的两个vector
容器中main
函数继续执行,定义了变量nImages
来存储有多少个图片:
int nImages = vstrImageFilenames.size(); //有nImages个图片
main
函数继续执行,实例化一个SLAM对象:
//!实例化SLAM对象
// Create SLAM system. It initializes all system threads and gets ready to process frames.
//argv1是词袋地址,argv2是配置文件的地址,第三个参数是传感器类型,第四个参数为是否选择使用可视化界面
//argv[1]为vocfile 里边存储的是词汇
//argv[2]为settingfile 里边存储摄像机校准和畸变参数和ORB相关参数
//这里创建了System类型的SLAM对象,SLAM构造函数中初始化了系统所有线程和相关参数,并准备好处理帧,代码留待后边详细分析
//读入词包路径,读入YAML配置文件,设置SLAM为mono状态,启用viewer的线程简要说明
ORB_SLAM2::System SLAM(argv[1], argv[2], ORB_SLAM2::System::MONOCULAR, true);
这里说是实例化SLAM对象,其实是指创建了一个System
类的对象,并取名为SLAM
,该类的定义在System.cc
文件