KITTI数据集之点云地图构建

2023-11-08

本文描述了如何通过KITTI数据集,读取激光雷达点云数据,并通过ground truth,对前后两帧点云进行旋转变换,使得二者统一坐标系,不断叠加点云进行点云建图的过程。使用的是KITTI odometry中的07号数据集。

其主要内容包括:

1)点云文件的格式转换

2)点云转换矩阵的推导

3)代码以及文件资源链接

有关KITTI数据集的介绍请看参考链接或者KITTI官网

参考链接

1、坐标系的转换

2、KITTI数据集数据初体验

3、KITTI odometry数据集下载

4、本文数据下载

1、点云建图效果

图1 odometry数据集07

 

图2 map 细节图

2、数据处理

我们的目的是利用GT_{cam}(ground truth)中的旋转矩阵,直接读取velodyne采集得到的点云并根据GT_{cam}进行旋转,不断叠加得到点云地图。

那么我们需要的数据有:

1)点云数据

2)以velodyne中心为坐标轴的旋转矩阵

需要的工具:

1)pcl点云库

2.1、点云数据处理

官网给出的点云数据是通过二进制的.bin文件格式保存的,而pcl库能处理的是以.pcd或.ply文件保存的。其.pcd文件格式见pcl官网介绍。因此,为了使用点云,我们需要对odometry中的velodyne数据进行转换,kitti官网已经给出我们bin转为pcd格式的代码了,详细的可以参考odometry中development kit里面的readme文件关于点云文件的描述,也可以参考我贴出的点云转换代码。 

图3 readme file in the development kit
        int32_t num = 1000000;
        int distance_threshold=20;
	float *data = (float*)malloc(num * sizeof(float));
	// 
	float *px = data + 0;
	float *py = data + 1;
	float *pz = data + 2;
	float *pr = data + 3;//
	// 
	FILE *stream;
	fopen_s(&stream, inptfile, "rb");
	num = fread(data, sizeof(float), num, stream) / 4;//
	fclose(stream);
	int32_t after_erase_num = 0;
	int distance_threshold=20;
	float *px_t = px;
	float *py_t = py;
	float *pz_t = pz;
	float *pr_t = pr;//
	for (int32_t i = 0; i < num; i++)
	{	
		//setting a threshold according to the distance between the point and centre to decrease the points 
		double distance = sqrt((*px_t)*(*px_t) + (*py_t)*(*py_t) + (*pz_t)*(*pz_t));
		if (distance < distance_threshold) {
			fprintf(writePCDStream, "%f %f %f %f\n", *px, *py, *pz, *pr);
		}
		px_t += 4; py_t += 4; pz_t += 4; pr_t += 4;

	}
        fclose(writePCDStream);

 上述代码中,为了减小点云量,过滤掉比较远的误差大的点云,我设置了一个阈值,只保存距离中心点20m以内的点云。

 处理完后,得到的点云文件见图4,它们可以通过notepad++直接打开,看到里面的点云数据。

图4 转换后点云图片

之后,我们就可以通过点云库pcl直接读取pcd文件,为我们后续的点云坐标转换以及建图做准备。

2.2、旋转矩阵的转换

根据kitti官网的数据集中的readme文件介绍,odometry中的GT_{cam}(ground truth)并不是以velodyne为坐标系的,而是以采集设备中的0号相机为坐标系,且二者x,y,z三轴的顺序和方向都不一样,详细见下图:

图5 kitti采集车传感器标定图​​​​​

根据上图,我们可以看到,如果我们要利用velodyne进行建图,则必须将GT_{cam}转换到以velodyne为中心的坐标系下,变为GT_{velo}。其实不转换也可以,只是为了效果的话,我们直接将读取的点云根据GT_{cam}进行旋转就行了。但是,为了严谨,以及了解标定中的坐标系之间的变换,我们还是按标准来。

对于GT_{cam}的pose文件,它以txt文件存储,文件中一行数据代表一个pose,每个pose包含旋转和坐标位置两个部分。其中,第4、8、12代表了相机坐标系的x,y,z三个坐标值,也就是位置。1~3、5~7、9~12这九个数据按顺序组成了一个旋转矩阵,这个旋转矩阵描述了当前这一行的pose与起点pose之间的旋转关系(注意,不是前后两个连续的pose之间的旋转关系)。我们可以将两个部分合起来,并添加一行,形成4x4的旋转矩阵,如下公式1所示:

公式1  由pose组成的旋转矩阵

上述Ri和ti即第i个pose与第0个pose之间的旋转和位置平移关系。但是,上述旋转矩阵是基于相机坐标系的,我们需要将其转换到velodyne的坐标系下,根据图5,可以得到cam坐标系和velo坐标系之间的关系:

公式2 相机到激光雷达的坐标转换矩阵

 上面0.08表示的是相机坐标系与激光雷达坐标系中,z轴方向上的高度差,可以从图5看出,相机坐标系高度为1.65m,而激光雷达坐标系高度为1.73m,这个0.08就是补上二者差值。

此外,我们还需要激光雷达到相机的坐标转换矩阵,如下:

公式3 激光雷达到相机的坐标转换矩阵

为了得到点云与点云之间的转换矩阵,我们需要对公式1中的T_{cam}进行转换。假设我们首先将点云转换到相机坐标系下,那么转换后的点云设为Pc ,转换前的为Pv,那么二者之间的关系为:

Pc=velo2cam\times Pv

将点云转换到相机坐标系下后,就可以而通过GT_{cam}中的T来转换点云,假设转换后的点云为Pc',那么转换前后的关系为:

Pc'=T\times Pc

此后,我们将在相机坐标系下通过相机转换矩阵得到的点云再变换回激光雷达坐标系下,设转换后的为点云Pv'变换关系为:

Pv'=cam2velo\times Pc'

通过上面三个关系,我们可以得到两个pose的点云之间的变换矩阵,这样,我们就将以相机为坐标系的GT_{cam}转换为以激光雷达的为坐标系的GT_{velo}。设此转换矩阵为T_{velo},则可得:

Pv'=T_{velo}\times Pv

T_{velo}=cam2velo\times T_{cam}\times velo2cam

公式4

 转换后,我们单独提取两个坐标系下的pose中的坐标值,并将散点图画出来,如下图所示:

图6 pose转换后的GT散点对比图

 上图中,蓝色为相机坐标系的GT_{cam},绿色为激光雷达的GT_{velo},对比图5中的两个坐标系关系,我们可以发现,相机坐标系中的前向与激光雷达中的前向旋转90°得到。

在代码中,我们使用Eigen库中的矩阵,利用pcl库中的点云变换函数,遍历所有点云文件,即可得到完整的点云地图。主要代码如下:

        pcl::PointCloud<PointIoType>::Ptr map(new pcl::PointCloud<PointIoType>());
	pcl::PointCloud<PointIoType>::Ptr target(new pcl::PointCloud<PointIoType>());
	pcl::PointCloud<PointIoType>::Ptr source(new pcl::PointCloud<PointIoType>());	
	string load_path;
	// traverse point cloud to transform,the total is 1101,the interval is 10,you can change it by yourself.
	for (int i =0; i <1100;i+=10) {
		load_path = PCD_OUTPUT_PATH + pcd_filename[i];
		//load pcd to a pointcloud name map
		if (pcl::io::loadPCDFile(load_path, *source) == -1)
			return (-1);
		//transform the pointcloud pose according the transform to the cloud_transfrom
		pcl::transformPointCloud(*source, *target, transform[i]);
		//add the cloud_transfrom to map 
		*map = *map + *target;
		cout << "process the " << i << "th pointcloud" << endl;
	}
	//down sampling the points cloud to decrease the memeory
	pcl::VoxelGrid<pcl::PointXYZ> filter;
	filter.setInputCloud(map);
	filter.setLeafSize(0.1f, 0.1f, 0.1f);
	filter.filter(*map);
	//save the map
	pcl::io::savePCDFileASCII(PCD_MAP_PATH, *map);

其中,transform[i]即根据公式4的来。

        Eigen::Matrix4d pose_data2;
	Eigen::Matrix4d velo2cam, cam2velo;
	cam2velo << 0, 0, 1, 0,
		-1, 0, 0, 0,
		0, -1, 0, 0.08,
		0, 0, 0, 1;
	velo2cam << 0, -1, 0, 0,
		0, 0, -1, 0,
		1, 0, 0, -0.08,
		0, 0, 0, 1;
        ...
        pose_data2 = cam2velo * pose_data2 * velo2cam;

其中,pose_data2就是转换矩阵transform[i]。 

最后,如果你还没有装pcl,但仍然想先看一看点云地图,那么你可以到我提供的资源链接里面下载,资源中包含本文中提到的点云地图数据以及数据集07中的pose,还有完整的代码。点云地图可以安装cloudcompare软件显示。

总结

本文主要讲的是如何利用KITTI数据集中的GT以及点云创建点云地图的,其中最主要的部分是点云的格式转换和点云旋转矩阵的推导和使用。在这个过程中,旋转矩阵的推导花了我很多心思,因为对数据集中的转换关系并不是很了解,踩了不少坑。其中一个坑就是误以为图5中的velo-to-cam这一旋转矩阵就是我上文提到的velo2cam,结果根据KITTI给的标定数据一直得不到想要的结果。以至于后来想通过ICP算法进行帧间匹配,然后得到旋转矩阵进行建图,说好听点,就是ICP-SLAM。但是这种帧间匹配效果并不好,以至于变成一坨鬼一样的东西,没法用。最后没办法,再仔细想了一下坐标轴的变换关系,才搞定的。

 

资源链接

点这里

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

KITTI数据集之点云地图构建 的相关文章

  • 点云配准注意的地方

    1 法向量是局部坐标系的概念 因此要将点云中心移到原点 再计算法向量 类似于先平移再旋转 而不是先旋转再平移 2 用kdtree时 用近邻点个数 而不是距离 因为点云各个不同 3 变换矩阵的对角线是目标与源点云的相似度 位移为0 x det
  • Error in: PCL_DEPRECATED_HEADER(1, 15, “Please include pcl/common/io.h directly.“)

    error error expected constructor destructor or type conversion before token PCL DEPRECATED HEADER 1 15 Please include pc
  • python机器人编程——差速AGV机器、基于视觉和预测控制的循迹、自动行驶(下篇)

    目录 一 前言 二 基于轨迹与路面重心偏离度误差的预测自动差速小车循迹控制策略 三 轨迹图像的处理要点 四 本篇部分核心控制策略python代码 五 结论 一 前言 基于最近的测试 得到了一种粗略控制的算法 其控制效果适合单线路和急转弯的情
  • PCL去除地面

    如图所示 分别是 原图 gt 直通滤波后 gt 取地面的图 gt 取地面的凹凸四边行加地面上的物体图
  • ROS 笔记(01)— Ubuntu 20.04 ROS 环境搭建

    ROS 官网 https www ros org ROS 中文官网 http wiki ros org cn 1 系统和 ROS 版本 不同的 ROS 版本所需的 ubuntu 版本不同 每一版 ROS 都有其对应版本的 Ubuntu 切记
  • 自动驾驶是用Python实现的?你敢用吗?

    一 安装环境 gym是用于开发和比较强化学习算法的工具包 在python中安装gym库和其中子场景都较为简便 安装gym pip install gym 安装自动驾驶模块 这里使用Edouard Leurent发布在github上的包hig
  • Apollo平台计算框架CyberRT

    Cyber RT 框架 Cyber RT Robotic Technology 是一种基于ROS Robot Operating System 的开发框架 专门设计用于构建高性能 实时性要求较高的机器人应用程序 旨在提供一套可靠 高效 灵活
  • pcl入门笔记1:pcl的安装

    前言 最近刚入坑pcl 打算记录一下自己的学习历程 安装pcl前的准备 本教程使用的是windows下的预编译包安装 要想顺利编译程序 需要安装好微软的Visual Studio IDE和cmake 这两者安装过程笔者不详细介绍 读者可以自
  • 自动驾驶数据闭环,要么被高估了,要么被低估了?

    在和身边的人沟通自动驾驶的数据闭环时 会碰到两类典型的人 第一类 当你给他讲数据闭环的时候 他的眼神是迷茫的 好像没有引起太多的重视和共鸣 甚至有人会反馈 嗯 这个没什么 我们以前干的差不多 第二类 他会觉得数据闭环 能解决一切问题 而且
  • A-LOAM总结-(前端+后端)算法流程分析

    文章目录 scanRegistration cpp 雷达信息预处理进程 laserOdometry cpp laserMapping cpp A LOAM算法流程 主要运行以下3个cpp文件 流程框图在文末 scanRegistration
  • 如何使用PCL将XYZRGB点云转换为彩色mesh模型

    如何使用PCL将XYZRGB点云转换为彩色mesh模型 最近完成了一个使用RGBD传感器 构建物体模型的小demo 其中有点难的最后一步是如何将获得的物体点云变成彩色mesh模型 效果图如下 从点云变成彩色mesh 其实整体的步骤可以总结如
  • 单个IMU实现精确的轨迹重构

    惯性传感器 IMU 被广泛用于导航 运动状态研究 人体运动和步态分析等领域 然而 由于IMU的固有误差和测量误差 尤其是漂移误差 很少有人尝试基于IMU实现精确的轨迹重建 尤其是使用单个IMU 尽管如此 与视觉 红外线和超声波定位技术相比
  • 开环端到端自动驾驶: 从入门到放弃

    作者 木子士心王大可 编辑 汽车人 原文链接 https zhuanlan zhihu com p 669454065 点击下方 卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 点击进入 自动驾驶之心 端到端自动驾驶 技术交流
  • 超越其它所有SOTA!Drive-WM:与现有端到端规划兼容的第一个自动驾驶世界模型!...

    点击下方 卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 gt gt 点击进入 自动驾驶之心 世界模型 技术交流群 论文作者 汽车人 编辑 自动驾驶之心 最近世界模型的工作好多 今天分享一个与现有端到端规划模型兼容的驾驶世界模
  • 自动驾驶轨迹/行为/运动/交通预测综述论文总结

    作者 eyesighting 编辑 汽车人 原文链接 https zhuanlan zhihu com p 664213622 点击下方 卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 点击进入 自动驾驶之心 轨迹预测 技术交
  • 2023年度盘点:智能汽车、自动驾驶、车联网必读书单

    文末送书 今天推荐几本自动驾驶领域优质书籍 前言 2023年 智能驾驶和新能源汽车行业仍然有着肉眼可见的新进展 自动驾驶技术继续尝试从辅助驾驶向自动驾驶的过渡 更重要的是相关技术成本的下降 根据 全球电动汽车展望2023 等行业报告 预计2
  • 自动驾驶从业者顶流学习笔记,值得收藏!

    自动驾驶之心的兄弟号 自动驾驶Daily后面将会正式投入运营使用 主要关注行业 最新技术分享等 第一次介绍 自动驾驶Daily为大家整理了多个领域方向的数据集 综述 经典论文 视频教程 供大家学习 主要涉及目标检测 语义分割 全景 实例分割
  • 自动驾驶多传感器融合学习笔记

    目录 BevFusion liar radar BevFusion BevFusion是一种多传感器融合技术 它可以将来自不同传感器 如LiDAR和相机 的数据融合到一个统一的BEV表示中 BevFusion的优点在于它能够结合多种传感器的
  • 实现深度增强学习在自动驾驶领域的应用

    自动驾驶技术作为人工智能领域的热门应用之一 正逐渐改变着我们的出行方式 随着深度学习的快速发展 深度增强学习作为一种结合了深度学习和增强学习的方法 为自动驾驶带来了更高的智能化水平 本文将介绍深度增强学习在自动驾驶领域的应用 并探讨其对未来
  • 对 pcl::StatisticalOutlierRemoval 滤波器的理解

    对 pcl StatisticalOutlierRemoval 滤波器的理解 注 以下内容基于与 GPT 4 的交流并结合个人理解整理而成 若有描述不准确或模糊之处 欢迎指正 参数配置 setMeanK int meanK 此参数设置每个点

随机推荐

  • Python下的图像处理库,你要选哪个?

    欢迎大家关注微信公众号 baihuaML 白话机器学习 码字不易 如转载请私信我 在这里 我们一起分享AI的故事 您可以在后台留言 关于机器学习 深度学习的问题 我们会选择其中的优质问题进行回答 在进行数字图像处理时 我们经常需要对图像进行
  • location.host 与 location.hostname 的区别

    location host 与 location hostname 的区别 location host 包含端口 端口是80的话 就不显示 location hostname 不包含端口 http localhost 8888 locati
  • webgl unity_Unity WebGL中的低级插件

    webgl unity Last year we launched a series of technical blog posts on WebGL starting with a couple of posts on memory No
  • nrm 的安装和使用

    NRM介绍 官方解释 开发的npm registry 管理工具 nrm 能够查看和切换当前使用的registry 换言之nrm的作用就是方便用户切换npm的镜像源地址 npm的原始镜像源地址是在国外 国内网络访问比较慢 因此国内的某些大佬机
  • jupyter生成视频动画video anmation

    本文介绍一个正弦余弦波案例来展示jupyter生成动画过程 首先电脑安装一个叫做ffmpeg的软件 只有40M 是一个关于网页制作动画的软件 安装过程见博客 15条消息 安装ffmpeg并写入jupyter matplotlib 山晨啊8的
  • 目录遍历的三种方法

    1 目录的遍历 递归函数 def visitDir path li os listdir path for p in li pathname os path join path p if not os path isfile pathnam
  • Docker与容器的基本概念

    本文主要对Docker和容器的一些基本概念进行一个总结 一 容器与虚拟机 1 什么是容器 Docker官方对容器的解释 一句话概括 容器 Container 就是将软件打包成标准化单元 以用于开发 交付和部署 容器是打包代码及其所有依赖的软
  • mesa图解

    http www sourcecodebrowser com mesa 7 8 2 state 8c html
  • C - Divisors of the Divisors of An Integer Gym - 102040C

    题目链接 题意 就是求n 中因子的因子的个数 题解 n 中某个因子的个数就是n x的累加 证明 其实就是每次褪一层 即每次除去能除于1个3的 依次两个3的 三个3的个数 最终也就能得到3的个数 这里没必要 整除 因为是阶乘 所以即使不能整除
  • Redis初级命令

    一 常用key命令 查看所有key keys 查看key的类型 type key 返回状态1 0 True False 当传入多个key时返回or的结果 即只要有一个存在就返回True exists key key 将key从当前db移动到
  • 学生成绩管理系统数据库设计--MySQL

    MySQL 数据库设计 学生成绩管理系统 设计大纲 友情链接 1 医疗信息管理系统数据库 MySQL 2 邮件管理数据库设计 MySQL 3 点餐系统数据库设计 SQL Server 4 商品管理系统数据库设计 SQL Server 5 S
  • JavaEE架构之传统三层架构,集群架构,分布式架构,微服务架构

    javaEE架构 1 传统三层架构 all in one项目 传统三层架构大致可以分为表现层 业务层和持久层 数据访问层 其中表现层负责接受请求和转发请求 业务层负责处理请求 注 事务管理 日志记录等AOP类型的操作均封装在这一层 持久层主
  • 将web项目导出到远程服务器的tomcat中

    将web项目导出到远程服务器的tomcat中 前期准备 步骤 前期准备 eclipse2017创建的web项目 阿里云服务器中存在tomcat 远程连接工具 windows自带 步骤 1 在eclipse上将完成好的web项目导出为war文
  • ubuntu linux安装pytorch和torchvision

    1 下载镜像 镜像网址 https download pytorch org whl torch stable html 假设你要下载torch1 4 0版本 cp36代表你的环境是python3 6 cu100代表的是你的cuda是10
  • C语言大作业学生成绩管理系统

    1 设计要求 利用所学的知识 理论和实际结合 利用资源 采用模块化的结构 使用模仿修改自主设计相结合的方法 锻炼学生综合分析解决实际问题的编程能力 通过C语言各个函数功能来实现对学生信息的管理 学生信息包括学生姓名 学号 各科成绩 管理方式
  • c++中的成员访问级别和派生继承方式

    1 一个类中的不同变量和函数的访问属性 总共有三种访问级别 public private protected 在类中定义的成员变量和成员函数的时候 如果不在变量前面加上访问级别修饰符 类中默认为私有成员变量或者私有成员函数 而在结构体中如果
  • OOALV data_changed 與data_changed_finished事件

    data changed在可編輯字段的數據發生變化時才會觸發 可用來檢查輸入數據的正確性 data changed finished在回車時和可編輯字段數據發生變化后 光標移動時觸發 如果可編輯字段數據檢查失敗 則不會觸發此事件 這兩個事件
  • 服务器端hsm芯片,数据加密服务CloudHSM

    数据加密服务 CloudHSM 基于国密局认证的物理加密机 Hardware Security Module HSM 利用虚拟化技术 提供弹性 高可用 高性能的数据加解密 密钥管理等云上数据安全服务 符合国家监管合规要求 满足金融 互联网等
  • 戴尔r410服务器虚拟磁盘,DELL服务器R410原装 SAS 6/IR RAID卡 阵列控制器卡 支持RAID0,1...

    SAS 6 iR 功能 Dell 串行连接 SCSI 6 iR 集成控制器和适配器 用户指南 介绍了 Dell串行连接 SCSI SAS 6 iR 控制器的规格 下表对 SAS 6 iR 适配器和 SAS 6 iR 集成控制器的规格进行了比
  • KITTI数据集之点云地图构建

    本文描述了如何通过KITTI数据集 读取激光雷达点云数据 并通过ground truth 对前后两帧点云进行旋转变换 使得二者统一坐标系 不断叠加点云进行点云建图的过程 使用的是KITTI odometry中的07号数据集 其主要内容包括