1.简介

  本文使用手机采集视频数据,制作TUM通用格式的数据集,并用ORB-SLAM2系统运行测试了该数据。需要注意的是,由于无法获得手机相机的真实轨迹,故所制作数据集不包含Groundtruth.txt。将录制好的视频制作成数据集的格式调用,也可以:1.调用ROS接口获取电脑相机的图像topic话题实时运行(需要安装相机的ROS驱动);2.直接用opencv调用电脑相机实时运行(需要在主函数mono_tum.cc中做相应修改);3.用opencv获取mp4视频中的图像数据运行(需要在主函数mono_tum.cc中做相应修改)。
  相关链接:
  TUM数据集格式介绍: https://www.guyuehome.com/35828
  rosbag数据集转TUM格式: https://www.guyuehome.com/35920
  ROS下使用电脑相机运行ORB-SLAM2: https://blog.csdn.net/qinqinxiansheng/article/details/107079265
  opencv调用相机运行ORB-SLAM2: https://blog.csdn.net/zhangqian_shai/article/details/88406981

2.TUM数据集制作

  首先用手机相机录制一段视频,用下列C++程序将mp4视频转换成TUM数据集的格式,以供ORB-SLAM2调用。之前的博文 https://www.guyuehome.com/35828 已经介绍了TUM数据集的格式,我们需要提取视频中的图片,以其时间戳命名并保存图片,最后将图像的路径记录在rgb.txt文件中。
  该程序和之前博文有些类似https://www.guyuehome.com/35920 。程序中首先加载了mp4格式的手机视频,然后获取了图像的尺寸信息;然后对于每一帧图像,获取图像拍摄的时间信息,以其作为名称将图像保存,并将图像的路径保存在rgb.txt文件中。
 

#include <iostream>
#include <fstream>
#include <string>
#include <opencv2\opencv.hpp>
#include <stdio.h>

using namespace cv;
using namespace std;

int main()
{  
    Mat frame;
    double time;
    int width, high;
    VideoCapture capture("test.mp4");//录制的视频,注意文件的路径
    //获取图像的尺寸
    width = capture.get(CV_CAP_PROP_FRAME_WIDTH);
    high = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
    cout<<"原图像宽度width: "<<width<<endl;
    cout<<"原图像高度high:  "<<high<<endl;

    //文件输出流
    ofstream of;
    of.open("rgb.txt", std::ios_base::app);
    if(of.fail()){
           cout<<"Fail to opencv file!!";
           return 0;
    }else{
      of<<"#------------------start a new video------------------------"<<endl;
    }

    while (true)
    {
        //获取图片帧
        capture >> frame;
        if(frame.empty()) break;
        time = capture.get(CV_CAP_PROP_POS_MSEC);//获取图像的拍摄时间
        cout<<  std::fixed <<"time:"<<time<<endl;

        //对视频进行降采样
        //resize(frame, frame, Size(frame.cols*0.5, frame.rows*0.5));//降采样
        //imshow("手势识别结果",frame);
        //waitKey(10);

        //保存图片与路径
        std::ostringstream osf;
        osf<< "rgb/" <<std::fixed <<time << ".png";//图像以时间戳命名
        cv::imwrite(osf.str(), frame);
        of<<std::fixed<< time <<" "<< "rgb/" <<time<<".png"<<endl; 
       }
    of.close();//关闭视频流
    capture.release();//释放资源
    system("pause");
    return 0;
    }

 
  所生成的rgb.txt文件如图所示,左侧一些为图像的时间信息,右侧一列为图像的路径。需要指出的是,在使用前需要先建立rbg文件夹,使用过程中rgb.txt文件不会被覆盖,也就是每运行一次程序,都会向文件末尾添加这些。所以运行程序之前记得包上次的结果删除或者剪切到其他位置。



图1 生成的rgb.txt文件

3.相机内参标定

1.参考网上其他博文的教程,制作一个标定板,板子越大越好。
2.用手机从各个角度录制一段标定板的视频,然后用上面的程序保存成图片。记住不要直接用手机进行拍照,否则相机参数会发生变化。
3.认真挑选一些不同视角下的图片15-30张左右,这里我挑选了45张图片。有些图片比较模糊,Matlab相机工具会自动剔除一些质量的高的图片。



图2 用于相机标定的图像集合

4.打开Matlab应用程序中的相机标定工具。



图3 打开Matlab相机标定工具

5.点击添加图片,导入所挑选的图片,并设置标定板方格的尺寸,这里我的网格尺寸为31.8mm。



图4 加载图像并设置标定板尺寸

6.点击Calibrate按钮进行标定。左边区域为检测角点成功的图像列表,中间区域为图像角点的检测结果,右下角区域为估计的图像拍摄位置(即相机的外参)右上角区域为每张图像的误差,可以通过少出误差特别大的图像来提高相机参数标定的精度,比如这里需要将误差为0.5的图像删去。



图5 相机标定结果

7.在工作空间中,cameraParams中的IndexMatrx即为相机内参(R的转置,包括fx, fy, cx, cy),除了相机内参外,还可以对相机的畸变参数进行标定(包括k1, k2 ,k3, p1 ,p2)。
 



图7 相机内参标定结果

4.运行ORB-SLAM2系统

  在运行ORB-SLAM2系统之前,要根据根据相机标定的结果制作我们的yaml参数文件,修改相应相机内参、相机畸变参数、图像尺寸等信息。



图8 修改.yaml相应参数


  由于手机相机拍摄的图像为单目图像,所以运行单目的样例。我的运行命令如下所示,所保存的相机参数文件为Honor10.yaml,所制作的数据集吗,名为test。

./Examples/Monocular/mono_tum Vocabulary/ORBvoc.txt Examples/Monocular/Honor10.yaml datasets/test

  然后根据数据集和相机参数的路径运行ORB-SLAM2即可。有很多人运行的过程中,可视化界面会卡在第一帧,这是由于手机相机的频率问题,我们需要将读取的时间戳做相应的调整即可,比如我将时间乘以了十倍
 

for(int ni=0; ni<nImages-1; ni++)
{
    //Read image from file
    im = cv::imread(string(argv[3])+"/"+vstrImageFilenames[ni], CV_LOAD_IMAGE_UNCHANGED);
    //double tframe = vTimestamps[ni];//原始代码
    double tframe = vTimestamps[ni]*10;//时间调整后的代码
}

 
  最后系统的运行效果如下图所示。