分享

ROS与PCL中点云数据之间的转换

 点云PCL 2021-03-09

标题:ROS与PCL中点云数据之间的转换

作者:particle

欢迎各位加入免费知识星球,获取PDF文档,欢迎转发朋友圈,分享快乐。







应小伙伴们后台留言,想要了解ROS中如何使用PCL,本篇文章就将具体介绍一下。文章中如有错误,欢迎留言指出。也期待大家能够积极分享和讨论。

PCL是随着ROS的而出现的三维点云处理的库,很多做机器人的朋友一定不陌生,这里将首先介绍在PCL库中经常使用的两种点云之间的转换,这里将根据工程中的经验,从代码层面举例分析如何实现程序中定义的各种点云数据之间转换,并且介绍PCL在应用于ROS中应该如何转换数据结构。


pcl::PCLPointCloud2::Ptr 与 pcl::PointCloudpcl::PointXYZ之间的关系

pcl::PointXYZ 是数据结构,pcl::PointCloud 是一个构造函数,比如

pcl::PointCloud<pcl::PointXYZ> cloud;cloud.push_back (pcl::PointXYZ (rand (), rand (), rand ()));cloud.push_back (pcl::PointXYZ (rand (), rand (), rand ()));cloud.push_back (pcl::PointXYZ (rand (), rand (), rand ()));cloud.push_back (pcl::PointXYZ (rand (), rand (), rand ()));

构造函数pcl::PointCloud 还包含了点云的其他属性,比如点云数据的width, height ,is_dense ,sensor_origin_ ,sensor_orientation_。

而pcl::PCLPointCloud2 是一个结构体,同样包含了点云的基本属性,在PCL中的定义为

struct PCLPointCloud2 { PCLPointCloud2 () : header (), height (0), width (0), fields (), is_bigendian (false), point_step (0), row_step (0), data (), is_dense (false) #if defined(BOOST_BIG_ENDIAN) { is_bigendian = true; #elif defined(BOOST_LITTLE_ENDIAN) is_bigendian = false; #else #error "unable to determine system endianness" #endif }::pcl::PCLHeader header; pcl::uint32_t height; pcl::uint32_t width; std::vector< ::pcl::PCLPointField> fields; pcl::uint8_t is_bigendian; pcl::uint32_t point_step; pcl::uint32_t row_step; std::vector<pcl::uint8_t> data; pcl::uint8_t is_dense; public: typedef boost::shared_ptr< ::pcl::PCLPointCloud2> Ptr; typedef boost::shared_ptr< ::pcl::PCLPointCloud2 const> ConstPtr; }; // struct PCLPointCloud2

那么在这个结构体中加上Ptr 

 pcl::PCLPointCloud2::Ptr,就表示智能指针,

下面在程序中实现滤波的功能,并实例说明两者之间的变换

pcl::PCLPointCloud2::Ptr cloud_blob (new pcl::PCLPointCloud2), cloud_filtered_blob (new pcl::PCLPointCloud2);pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>); pcl::PCDReader reader;//在这里读取一个pcl::PCLPointCloud2::Ptr 定义的cloud_blob reader.read ("table_scene_lms400.pcd", *cloud_blob); pcl::VoxelGrid<pcl::PCLPointCloud2> sor; sor.setInputCloud (cloud_blob); sor.setLeafSize (0.01f, 0.01f, 0.01f); //经过体素滤波后输出的点云格式仍然是pcl::PCLPointCloud2::Ptr sor.filter (*cloud_filtered_blob); //重点:这里是为了将pcl::PCLPointCloud2::Ptr 转换到pcl::PointCloud<pcl::PointXYZ>::Ptr pcl::fromPCLPointCloud2 (*cloud_filtered_blob, *cloud_filtered);

pcl::fromPCLPointCloud2 (*cloud_filtered_blob, *cloud_filtered);

这一句实现pcl::PCLPointCloud数据格式的点云转化为pcl::PointCloud格式

智能指针Ptr类型点云数据和非Ptr类型相互转换

pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_Ptr(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ> cloud;cloud=*cloud_Ptr;cloud_Ptr=cloud.makeShared;

比如下面的程序如果我们定义了非智能指针形式的点云表示 cloud,实现一个分割的代码如下,此时我们需要注意在setInputCloud 中需要注意为cloud.makeShared() 将点云表示为指针的形式,因为该函数输入要求是智能指针的点云。

pcl::PointCloud<pcl::PointXYZ> cloud;pcl::SACSegmentation<pcl::PointXYZ>seg;****seg.setInputCloud(cloud.makeShared());

总结一下PCL中提供的点云数据格式之间的转换

(1)

void pcl::fromPCLPointCloud(const pcl:PCLPointCloud2 & msg pcl::PointCloud<PointT> & cloud const MsgFieldMap & filed_map )

(2)

void pcl::fromPCLPointCloud2(const pcl::PCLPointCloud & msg pcl::PointCloud<pointT> &cloud )

(3)

void pcl::fromROSMsg(const pcl:PCLPointCloud2 & msg pcl::PointCloud<PointT> & cloud const MsgFieldMap & filed_map

(4)

void pcl::fromROSMsg(const pcl:PCLPointCloud2 & msg pcl::PointCloud<PointT> & cloud

在ROS中又该如何实现ROS中定义的点云与PCL定义的点云数据转换呢?

首先我们举例在ROS中有以下的两中点云数据格式

sensor_msgs::PointCloud

sensor_msgs::PointCloud2

ROS与PCL中的pcl::PointCloud 点云数据格式转换(使用PCL库里的转换函数):

sensor_msgs::PointCloud2pcl::PointCloud之间的转换

使用pcl::fromROSMsg 和 pcl::toROSMsg

void fromROSMsg(const sensor_msgs::PointCloud2 &, pcl::PointCloud<T>&);  

void toROSMsg(const pcl::PointCloud<T> &, sensor_msgs::PointCloud2 &);   

ROS与PCL中的pcl::PCLPointCloud2点云数据转换(使用ROS中的pcl_conversions函数进行转换):

sensor_msgs::PointCloud2ConstPtr 和 pcl::PCLPointCloud2之间的转换使用

使用pcl_conversions::toPCL和pcl_conversions::fromPCL

void fromPCL(const <PCL Type> &, <ROS Message type> &); 

void toPCL(const <ROS Message type> &, <PCL Type> &);

ROS中两种点云数据格式之间的转换:

sensor_msgs::PointCloudsensor_msgs::PointCloud2之间的转换

使用sensor_msgs::convertPointCloud2ToPointCloud 和 sensor_msgs::convertPointCloudToPointCloud2.

(这里为什么ROS有两种点云的数据格式呢,由于在ROS的迭代,刚开始定义的点云是sensor_msgs::PointCloud 仅仅包含了点云的XYZ以及的多个通道点云,而随着ROS的发展该形式已经不能满足需求,所以出现了 sensor_msgs::PointCloud2 不仅包含了 sensor_msgs::PointCloud2 中的多通道的点云数据,而且还增加了点云的其他属性,比如宽,高,是否稠密等)

这里举个例子比如我们要通过ROS发布一个点云数据的topic,我们该如何写程序呢?

以下功能是实现sensor_msgs::PointCloud2ConstPtr到 sensor_msgs::PointCloud2之间的转换

#include <ros/ros.h>#include <sensor_msgs/PointCloud2.h>#include <pcl_conversions/pcl_conversions.h>#include <pcl/point_cloud.h> #include <pcl/point_types.h> ros::Publisher pub;void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input) { sensor_msgs::PointCloud2 output; output = *input; pub.publish (output); // Publish the data. }

int main (int argc, char** argv) { ros::init (argc, argv, "my_pcl_tutorial"); ros::NodeHandle nh; ros::Subscriber sub = nh.subscribe ("input", 1, cloud_cb); pub = nh.advertise<sensor_msgs::PointCloud2> ("output", 1); ros::spin (); }

以上案例是最为简单的为了实现采集点云通过ROS发布出去的实例,如果我们想在上面的程序中的回调函数cloud_cb中经过一个滤波处理中该如何进行数据转换呢?我们可以分析以下,需要经过以下的转换

sensor_msgs::PointCloud2ConstPtr -->pcl::PCLPointCloud2

(这里我们举例该类型为滤波函数的输入,当然也可以是其他PCL的点云形式)

-->sensor_msgs::PointCloud2

(这是最种需要发布出去的点云的数据形式,为什么要这种形式,因为这种形式在ROS中的RVIZ可视化的时候不会出现警告)

#include <ros/ros.h>#include <sensor_msgs/PointCloud2.h> #include <pcl_conversions/pcl_conversions.h> #include <pcl/point_cloud.h>#include <pcl/point_types.h>//滤波的头文件#include <pcl/filters/voxel_grid.h>ros::Publisher pub; void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input) { pcl::PCLPointCloud2* cloud = new pcl::PCLPointCloud2; pcl::PCLPointCloud2ConstPtr cloudPtr(cloud); pcl::PCLPointCloud2 cloud_filtered; pcl_conversions::toPCL(*input, *cloud); // 进行一个滤波处理 pcl::VoxelGrid<pcl::PCLPointCloud2> sor; sor.setInputCloud (cloudPtr); sor.setLeafSize (0.1, 0.1, 0.1); sor.filter (cloud_filtered); sensor_msgs::PointCloud2 output; //声明的输出的点云的格式 pcl_conversions::fromPCL(cloud_filtered, output); pub.publish (output);} int main (int argc, char** argv) { ros::init (argc, argv, "my_pcl_tutorial"); ros::NodeHandle nh; ros::Subscriber sub = nh.subscribe ("input", 1, cloud_cb); pub = nh.advertise<sensor_msgs::PointCloud2> ("output", 1); ros::spin ();}

解析:上面的函数使用ROS的转换函数,进行了两次点云数据的转换

pcl_conversions::toPCL(*input, *cloud); pcl_conversions::fromPCL(cloud_filtered, output);

以下是一个kinect点云数据在ROS中可视化

sensor_msgs::PointCloud2 与 pcl::PointCloud之间的转换,这里直接以一个回调函数实现平面分割为例,使用PCL提供的接口实现到ROS的转换:

void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input) { pcl::PointCloud<pcl::PointXYZ> cloud; pcl::fromROSMsg (*input, cloud); pcl::ModelCoefficients coefficients; pcl::PointIndices inliers; pcl::SACSegmentation<pcl::PointXYZ> seg; seg.setOptimizeCoefficients (true); seg.setModelType (pcl::SACMODEL_PLANE); //平面模型 seg.setMethodType (pcl::SAC_RANSAC); //分割平面模型所使用的分割方法 seg.setDistanceThreshold (0.01); //设置最小的阀值距离 seg.setInputCloud (cloud.makeShared ()); //设置输入的点云 seg.segment (inliers, coefficients); //cloud.makeShared() 创建一个 boost shared_ptr

pcl_msgs::ModelCoefficients ros_coefficients; pcl_conversions::fromPCL(coefficients, ros_coefficients); pub.publish (ros_coefficients);}

这里不再一一用程序举例,总结一下ROS中提供的pcl_conversions命名空间下点云转换关系

fromPCL (const pcl::PCLPointCloud2 &pcl_pc2, sensor_msgs::PointCloud2 &pc2)toPCL (const sensor_msgs::PointCloud2 &pc2, pcl::PCLPointCloud2 &pcl_pc2)

使用PCL中提供的函数实现到ROS的点云数据转换实例

void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input) { sensor_msgs::PointCloud2 output; pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>); output = *input; pcl::fromROSMsg(output,*cloud); pub.publish (output); }

总结

无论是ROS还是PCL都相互提供了PCL到ROS,ROS到PCL的点云数据的转换。

资源

三维点云论文及相关应用分享

【点云论文速读】基于激光雷达的里程计及3D点云地图中的定位方法

3D目标检测:MV3D-Net

三维点云分割综述(上)

3D-MiniNet: 从点云中学习2D表示以实现快速有效的3D LIDAR语义分割(2020)

win下使用QT添加VTK插件实现点云可视化GUI

JSNet:3D点云的联合实例和语义分割

大场景三维点云的语义分割综述

PCL中outofcore模块---基于核外八叉树的大规模点云的显示

基于局部凹凸性进行目标分割

基于三维卷积神经网络的点云标记

点云的超体素(SuperVoxel)

基于超点图的大规模点云分割

更多文章可查看:点云学习历史文章大汇总

SLAM及AR相关分享

【开源方案共享】ORB-SLAM3开源啦!

【论文速读】AVP-SLAM:自动泊车系统中的语义SLAM

【点云论文速读】StructSLAM:结构化线特征SLAM

SLAM和AR综述

常用的3D深度相机

AR设备单目视觉惯导SLAM算法综述与评价

SLAM综述(4)激光与视觉融合SLAM

Kimera实时重建的语义SLAM系统

SLAM综述(3)-视觉与惯导,视觉与深度学习SLAM

易扩展的SLAM框架-OpenVSLAM

高翔:非结构化道路激光SLAM中的挑战

SLAM综述之Lidar SLAM

基于鱼眼相机的SLAM方法介绍

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多