如何使用evo工具评估LeGO-LOAM跑KITTI数据集的结果

2023-10-08 09:40

本文主要是介绍如何使用evo工具评估LeGO-LOAM跑KITTI数据集的结果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如何使用evo工具评估LeGO-LOAM跑KITTI数据集的结果

  • 下载KITTI数据集
  • 安装kitti2bag
  • 修改LeGO-LOAM代码
    • utility.h
    • imageProjection.cpp
    • transformFusion.cpp
  • 安装evo
  • 最终结果

下载KITTI数据集

官方链接:KITTI官网
我们只用得到点云数据集和groundtruth,也就是odometry data set (velodyne laser data, 80 GB)和odometry ground truth poses (4 MB),不过我自己也没下成功那个80G的包,而是在raw data选项卡里找了00-10对应的包来下,要下的是包的scnced+rectified data与calibration两项,如图:
在这里插入图片描述这里给出groundtruth的00-10对应的数据集的名字(图来自CSDN博主学无止境的小龟):
在这里插入图片描述

安装kitti2bag

这个工具是用来把我们上一步中下的KITTI数据集转化成bag文件形式,直接pip安装就行。

pip install kitti2bag

把上一步中的数据集解压并如下合并:
在这里插入图片描述
(那个bag文件是我生成的,不用管)
然后在2011_09_30所在文件夹(即当前文件夹下)运行:

kitti2bag -t 2011_09_30 -r 0018 raw_synced

注意标号一定是要和你下的数据集的号对应,比如我这里就是0018(之前没注意这个就总运行错误,排查半天发现命令没打对)。
成功之后就会把文件夹转化成kitti_2011_09_30_drive_0018_synced.bag。

修改LeGO-LOAM代码

utility.h

原代码中是设置为16线的,不适配KITTI数据集的64线,以及其他一些参数也需要修改,所以在原代码中修改如下:

// VLP-16
//extern const int N_SCAN = 16;
//extern const int Horizon_SCAN = 1800;
//extern const float ang_res_x = 0.2;
//extern const float ang_res_y = 2.0;
//extern const float ang_bottom = 15.0+0.1;
//extern const int groundScanInd = 7;extern const int N_SCAN = 64;
extern const int Horizon_SCAN = 2083;
extern const float ang_res_x = 360.0/float(Horizon_SCAN);
extern const float ang_res_y = 26.8/float(N_SCAN-1);
extern const float ang_bottom = 24.8;
extern const int groundScanInd = 55;

注释掉的是原来的代码,便于找到并对应。
此外,还修改imuTopic:

extern const string imuTopic = "/kitti/oxts/imu";

不过我跑的过程中发现没有imu反而效果会更好,就没有用其实。(看到别的博文说是因为KITTI数据集imu本身的问题,会飘)

imageProjection.cpp

需要在imageProjection.cpp中修改雷达topic的名字:

        subLaserCloud = nh.subscribe<sensor_msgs::PointCloud2>("/kitti/velo/pointcloud", 1, &ImageProjection::cloudHandler, this);

或者直接remap改也是一样的。

transformFusion.cpp

其实这里主要是需要生成轨迹记录文件以用于后续evo的评估,我的做法是直接用了kitti-lego-loam(链接:kitti-lego-loam)代码中保存轨迹的做法,之前在网上找的别的方法都出现了奇奇怪怪的偏差……比如:
在这里插入图片描述(挠头.gif)于是自己找了kitti-lego-loam代码里的生成轨迹部分加上去。

在transformFusion.cpp中的TransformFusion类的private变量中加上:

    int init_flag=true;Eigen::Matrix4f H;Eigen::Matrix4f H_init;Eigen::Matrix4f H_rot;const string RESULT_PATH = "/media/cairui/Backup Plus/ubuntu20/KITTI/myRes.txt";

这个RESULT_PATH就是你要生成的轨迹文件,记得自行创建并修改这个变量哦。

在laserOdometryHandler函数修改如下:

    void laserOdometryHandler(const nav_msgs::Odometry::ConstPtr& laserOdometry){currentHeader = laserOdometry->header;double roll, pitch, yaw;geometry_msgs::Quaternion geoQuat = laserOdometry->pose.pose.orientation;tf::Matrix3x3(tf::Quaternion(geoQuat.z, -geoQuat.x, -geoQuat.y, geoQuat.w)).getRPY(roll, pitch, yaw);transformSum[0] = -pitch;transformSum[1] = -yaw;transformSum[2] = roll;transformSum[3] = laserOdometry->pose.pose.position.x;transformSum[4] = laserOdometry->pose.pose.position.y;transformSum[5] = laserOdometry->pose.pose.position.z;transformAssociateToMap();geoQuat = tf::createQuaternionMsgFromRollPitchYaw(transformMapped[2], -transformMapped[0], -transformMapped[1]);laserOdometry2.header.stamp = laserOdometry->header.stamp;laserOdometry2.pose.pose.orientation.x = -geoQuat.y;laserOdometry2.pose.pose.orientation.y = -geoQuat.z;laserOdometry2.pose.pose.orientation.z = geoQuat.x;laserOdometry2.pose.pose.orientation.w = geoQuat.w;laserOdometry2.pose.pose.position.x = transformMapped[3];laserOdometry2.pose.pose.position.y = transformMapped[4];laserOdometry2.pose.pose.position.z = transformMapped[5];pubLaserOdometry2.publish(laserOdometry2);Eigen::Quaterniond q;q.w()=laserOdometry2.pose.pose.orientation.w;q.x()=laserOdometry2.pose.pose.orientation.x;q.y()=laserOdometry2.pose.pose.orientation.y;q.z()=laserOdometry2.pose.pose.orientation.z;Eigen::Matrix3d R = q.toRotationMatrix();if (init_flag==true){H_init<< R.row(0)[0],R.row(0)[1],R.row(0)[2],transformMapped[3],R.row(1)[0],R.row(1)[1],R.row(1)[2],transformMapped[4],R.row(2)[0],R.row(2)[1],R.row(2)[2],transformMapped[5],0,0,0,1;init_flag=false;std::cout<<"surf_th : "<<surfThreshold<<endl;}H_rot<<	-1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1;H<<  R.row(0)[0],R.row(0)[1],R.row(0)[2],transformMapped[3],R.row(1)[0],R.row(1)[1],R.row(1)[2],transformMapped[4],R.row(2)[0],R.row(2)[1],R.row(2)[2],transformMapped[5],0,0,0,1;H = H_rot*H_init.inverse()*H; //to get H12 = H10*H02 , 180 rot according to z axisstd::ofstream foutC(RESULT_PATH, std::ios::app);foutC.setf(std::ios::scientific, std::ios::floatfield);foutC.precision(6);//foutC << R[0] << " "<<transformMapped[3]<<" "<< R.row(1) <<" "<<transformMapped[4] <<" "<<  R.row(2) <<" "<< transformMapped[5] << endl;for (int i = 0; i < 3; ++i){for (int j = 0; j < 4; ++j){if(i==2 && j==3){foutC <<H.row(i)[j]<< endl ;}else{foutC <<H.row(i)[j]<< " " ;}}}foutC.close();laserOdometryTrans2.stamp_ = laserOdometry->header.stamp;laserOdometryTrans2.setRotation(tf::Quaternion(-geoQuat.y, -geoQuat.z, geoQuat.x, geoQuat.w));laserOdometryTrans2.setOrigin(tf::Vector3(transformMapped[3], transformMapped[4], transformMapped[5]));tfBroadcaster2.sendTransform(laserOdometryTrans2);}

直接把整个函数复制上来了,直接替换就不会找不到要改的啦(懒鬼发言)

安装evo

先安装依赖:

pip3 install --user numpy 
pip3 install --user scipy 
pip3 install --user matplotlib

git源代码并安装:

git clone https://github.com/MichaelGrupp/evo
cd evo 
pip3 install --user --editable . --upgrade --no-binary evo

安装之后可以先测试一下自带的test:

cd test/data 
evo_traj kitti KITTI_00_ORB.txt KITTI_00_SPTAM.txt --ref=KITTI_00_gt.txt -p --plot_mode=xz

出现下图就说明安装成功了。
在这里插入图片描述

这里顺便记录一些常用的evo命令,来自知乎大佬SLAM评估工具-EVO使用(二):
①evo_traj指令可以将各个算法估计出的路径和真实路径画在同一幅图中。
例:evo_traj kitti tra1.txt tra2.txt tra3.txt --ref=ground_truth.txt -va --plot --plot_mode xy
kitti表明处理的是kitti数据集的相关结果,这里也可以替换为tum和euroc;
tra1.txt tra2.txt tra3.txt表示的是不同算法所估计出的轨迹,这里可以列举多个文件每个文件名之间用一个空格隔开;
–ref=ground_truth.txt指明参考轨迹即真实轨迹;
-va包含两部分;1.-v或–verbose指明输出文件数据的相关信息;2.-a或–align指明对轨迹进行配准;
–plot表示画图;
–plot_mode xy表示图像投影在xoy平面上,其余可选参数为:xz,yx,yz,zx,zy,xyz;

②evo_ape计算轨迹的绝对位姿误差
绝对位姿误差,用于比较估计轨迹和参考轨迹并计算整个轨迹的统计数据,常用于评估测试轨迹的全局一致性。这里还是以kitti为例,tum和euroc格式相同。
evo_ape kitti ground_truth.txt tra1.txt -r full -va --plot --plot_mode xyz --save_plot ./tra1plot --save_results ./tra1.zip
kitti表明处理的是kitti数据集的相关结果,这里也可以替换为tum和euroc;
ground_truth.txt代表真实轨迹的数据;
tra1.txt代表估计轨迹的数据;
-r full表示同时考虑旋转和平移误差得到的ape,无单位(unit-less);
另外:
-r trans_part表示考虑平移部分得到的ape,单位为m;
-r rot_part表示考虑旋转部分得到的ape,无单位(unit-less);
-r angle_deg表示考虑旋转角得到的ape,单位°(deg);
-r angle_rad表示考虑旋转角得到的ape,单位弧度(rad);
-va包含两部分;1.-v或–verbose指明输出文件数据的相关信息;2.-a或–align指明对轨迹进行配准;
–plot表示画图;
–plot_mode xy表示图像投影在xoy平面上,其余可选参数为:xz,yx,yz,zx,zy,xyz;
–save_plot ./tra1plot表示保存生成的图片,./tra1plot这里写自己保存的地址;
–save_results ./tra1.zip表示保存计算结果,./tra1.zip这里写自己保存的地址;

③evo_rpe 计算相对位姿误差
相对位姿误差不进行绝对位姿的比较,相对位姿误差比较运动(姿态增量)。相对位姿误差可以给出局部精度,例如SLAM系统每米的平移或者旋转漂移量。这里还是以kitti为例,tum和euroc格式相同。
evo_rpe kitti ground_truth.txt tra1.txt -r full -va --plot --plot_mode xyz --save_plot ./tra1plot --save_results ./tra1.zip
kitti表明处理的是kitti数据集的相关结果,这里也可以替换为tum和euroc;
ground_truth.txt代表真实轨迹的数据;
tra1.txt代表估计轨迹的数据;
-r full表示同时考虑旋转和平移误差得到的ape,无单位(unit-less);
另外:
-r trans_part表示考虑平移部分得到的ape,单位为m;
-r rot_part表示考虑旋转部分得到的ape,无单位(unit-less);
-r angle_deg表示考虑旋转角得到的ape,单位°(deg);
-r angle_rad表示考虑旋转角得到的ape,单位弧度(rad);
-va包含两部分;
1.-v或–verbose指明输出文件数据的相关信息;2.-a或–align指明对轨迹进行配准;
–plot表示画图;
–plot_mode xy表示图像投影在xoy平面上,其余可选参数为:xz,yx,yz,zx,zy,xyz;
–save_plot ./tra1plot表示保存生成的图片,./tra1plot这里写自己保存的地址;
–save_results ./tra1.zip表示保存计算结果,./tra1.zip这里写自己保存的地址;

最终结果

我用的是09数据集,也就是kitti_2011_09_30_drive_0033_synced.bag,跑完之后把生成的myRes.txt与之前我们下的odometry ground truth poses 解压出来的09.txt拷贝到同个文件夹下,然后运行:

evo_traj kitti myRes.txt --ref=09.txt -p --plot_mode=xz

得到:
在这里插入图片描述就成功啦,吃饭去了:D

这篇关于如何使用evo工具评估LeGO-LOAM跑KITTI数据集的结果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/164374

相关文章

如何使用CSS3实现波浪式图片墙

《如何使用CSS3实现波浪式图片墙》:本文主要介绍了如何使用CSS3的transform属性和动画技巧实现波浪式图片墙,通过设置图片的垂直偏移量,并使用动画使其周期性地改变位置,可以创建出动态且具有波浪效果的图片墙,同时,还强调了响应式设计的重要性,以确保图片墙在不同设备上都能良好显示,详细内容请阅读本文,希望能对你有所帮助...

Rust中的注释使用解读

《Rust中的注释使用解读》本文介绍了Rust中的行注释、块注释和文档注释的使用方法,通过示例展示了如何在实际代码中应用这些注释,以提高代码的可读性和可维护性... 目录Rust 中的注释使用指南1. 行注释示例:行注释2. 块注释示例:块注释3. 文档注释示例:文档注释4. 综合示例总结Rust 中的注释

MobaXterm远程登录工具功能与应用小结

《MobaXterm远程登录工具功能与应用小结》MobaXterm是一款功能强大的远程终端软件,主要支持SSH登录,拥有多种远程协议,实现跨平台访问,它包括多会话管理、本地命令行执行、图形化界面集成和... 目录1. 远程终端软件概述1.1 远程终端软件的定义与用途1.2 远程终端软件的关键特性2. 支持的

Linux使用cut进行文本提取的操作方法

《Linux使用cut进行文本提取的操作方法》Linux中的cut命令是一个命令行实用程序,用于从文件或标准输入中提取文本行的部分,本文给大家介绍了Linux使用cut进行文本提取的操作方法,文中有详... 目录简介基础语法常用选项范围选择示例用法-f:字段选择-d:分隔符-c:字符选择-b:字节选择--c

Rust中的BoxT之堆上的数据与递归类型详解

《Rust中的BoxT之堆上的数据与递归类型详解》本文介绍了Rust中的BoxT类型,包括其在堆与栈之间的内存分配,性能优势,以及如何利用BoxT来实现递归类型和处理大小未知类型,通过BoxT,Rus... 目录1. Box<T> 的基础知识1.1 堆与栈的分工1.2 性能优势2.1 递归类型的问题2.2

使用Go语言开发一个命令行文件管理工具

《使用Go语言开发一个命令行文件管理工具》这篇文章主要为大家详细介绍了如何使用Go语言开发一款命令行文件管理工具,支持批量重命名,删除,创建,移动文件,需要的小伙伴可以了解下... 目录一、工具功能一览二、核心代码解析1. 主程序结构2. 批量重命名3. 批量删除4. 创建文件/目录5. 批量移动三、如何安

springboot的调度服务与异步服务使用详解

《springboot的调度服务与异步服务使用详解》本文主要介绍了Java的ScheduledExecutorService接口和SpringBoot中如何使用调度线程池,包括核心参数、创建方式、自定... 目录1.调度服务1.1.JDK之ScheduledExecutorService1.2.spring

Java使用Tesseract-OCR实战教程

《Java使用Tesseract-OCR实战教程》本文介绍了如何在Java中使用Tesseract-OCR进行文本提取,包括Tesseract-OCR的安装、中文训练库的配置、依赖库的引入以及具体的代... 目录Java使用Tesseract-OCRTesseract-OCR安装配置中文训练库引入依赖代码实

Python使用Pandas对比两列数据取最大值的五种方法

《Python使用Pandas对比两列数据取最大值的五种方法》本文主要介绍使用Pandas对比两列数据取最大值的五种方法,包括使用max方法、apply方法结合lambda函数、函数、clip方法、w... 目录引言一、使用max方法二、使用apply方法结合lambda函数三、使用np.maximum函数

Qt 中集成mqtt协议的使用方法

《Qt中集成mqtt协议的使用方法》文章介绍了如何在工程中引入qmqtt库,并通过声明一个单例类来暴露订阅到的主题数据,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录一,引入qmqtt 库二,使用一,引入qmqtt 库我是将整个头文件/源文件都添加到了工程中进行编译,这样 跨平台