您当前的位置: 首页 > 

暂无认证

  • 0浏览

    0关注

    101061博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

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

发布时间:2020-09-06 00:00:00 ,浏览量:0

本文转载于公众号@点云PCL,原文链接:https://mp.weixin.qq.com/s/akqAAKQIWe6ua6NRkRSW4Q

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

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

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

pcl::PointCloud 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::vectordata;
  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::Ptr  cloud_filtered (new pcl::PointCloud);
  pcl::PCDReader reader;
//在这里读取一个pcl::PCLPointCloud2::Ptr 定义的cloud_blob 
  reader.read ("table_scene_lms400.pcd", *cloud_blob);  
  pcl::VoxelGridsor;  
  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::Ptr
  pcl::fromPCLPointCloud2 (*cloud_filtered_blob, *cloud_filtered);

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

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

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

pcl::PointCloud::Ptr cloud_Ptr(new pcl::PointCloud);
pcl::PointCloudcloud;
cloud=*cloud_Ptr;
cloud_Ptr=cloud.makeShared;

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

pcl::PointCloudcloud;pcl::SACSegmentationseg;****seg.setInputCloud(cloud.makeShared());

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

(1)

void pcl::fromPCLPointCloud(const pcl:PCLPointCloud2 & msg                          pcl::PointCloud& cloudconst MsgFieldMap & filed_map                         )

(2)

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

(3)

void pcl::fromROSMsg(const pcl:PCLPointCloud2 & msg                    pcl::PointCloud& cloudconst MsgFieldMap & filed_map                      )

(4)

void pcl::fromROSMsg(const pcl:PCLPointCloud2 & msg                     pcl::PointCloud& cloud                     )

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

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

sensor_msgs::PointCloud

sensor_msgs::PointCloud2

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

sensor_msgs::PointCloud2 和 pcl::PointCloud之间的转换

使用pcl::fromROSMsg 和 pcl::toROSMsg

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

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

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

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

使用pcl_conversions::toPCL和pcl_conversions::fromPCL

void fromPCL(const&,&); 

void toPCL(const&,&);

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

sensor_msgs::PointCloud 和 sensor_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 #include #include #include  #include  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("output", 1);   ros::spin (); }

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

sensor_msgs::PointCloud2ConstPtr -->pcl::PCLPointCloud2

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

-->sensor_msgs::PointCloud2

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

#include #include  #include  #include #include //滤波的头文件#include 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::VoxelGridsor;    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("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::PointCloudcloud;    pcl::fromROSMsg (*input, cloud);    pcl::ModelCoefficients coefficients;   pcl::PointIndices inliers;           pcl::SACSegmentationseg;    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::Ptr cloud (new pcl::PointCloud);   output = *input;  pcl::fromROSMsg(output,*cloud);     pub.publish (output); }

总结

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

本文仅做学术分享,如有侵权,请联系删文。

下载1

在「3D视觉工坊」公众号后台回复:3D视觉,即可下载 3D视觉相关资料干货,涉及相机标定、三维重建、立体视觉、SLAM、深度学习、点云后处理、多视图几何等方向。

下载2

在「3D视觉工坊」公众号后台回复:3D视觉github资源汇总,即可下载包括结构光、标定源码、缺陷检测源码、深度估计与深度补全源码、点云处理相关源码、立体匹配源码、单目、双目3D检测、基于点云的3D检测、6D姿态估计源码汇总等。

下载3

在「3D视觉工坊」公众号后台回复:相机标定,即可下载独家相机标定学习课件与视频网址;后台回复:立体匹配,即可下载独家立体匹配学习课件与视频网址。

汇总|国内最全的3D视觉学习资源,涉及计算机视觉、SLAM、三维重建、点云处理、姿态估计、深度估计、3D检测、自动驾驶、深度学习(2D+3D)、图像处理、立体视觉、结构光等方向:https://mp.weixin.qq.com/s/xyGndcupuK1Zzmv1AJA5CQ

关注
打赏
1655516835
查看更多评论
立即登录/注册

微信扫码登录

0.0496s