PCL中点云数据格式之间的转化
首先介绍一下我们使用PCL时会经常用到的两种数据类型
关于pcl::PCLPointCloud2::Ptr和pcl::PointCloud<pcl::PointXYZ>两中数据结构的区别
pcl::PointXYZ::PointXYZ ( float_x, float_y, float_z )
区别:
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
那么要实现它们之间的数据转换,
举个例子
.............其他相关操作
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>),
cloud_p (new pcl::PointCloud<pcl::PointXYZ>),
cloud_f (new pcl::PointCloud<pcl::PointXYZ>);
// 读取PCD文件
pcl::PCDReader reader; reader.read ("table_scene_lms400.pcd", *cloud_blob);
//统计滤波前的点云个数
std::cerr << "PointCloud before filtering: " << cloud_blob->width * cloud_blob->height << " data points." << std::endl;
// 创建体素栅格下采样:下采样的大小为1cm pcl::VoxelGrid<pcl::PCLPointCloud2> sor; //体素栅格下采样对象 sor.setInputCloud (cloud_blob); //原始点云 sor.setLeafSize (0.01f, 0.01f, 0.01f); // 设置采样体素大小 sor.filter (*cloud_filtered_blob); //保存
// 转换为模板点云 pcl::fromPCLPointCloud2 (*cloud_filtered_blob, *cloud_filtered);
std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height << " data points." << std::endl;
// 保存下采样后的点云
pcl::PCDWriter writer; writer.write<pcl::PointXYZ> ("table_scene_lms400_downsampled.pcd", *cloud_filtered, false);
程序中红色部分就是一句实现两者之间的数据转化的我们可以看出
cloud_filtered_blob 声明的数据格式为pcl::PCLPointCloud2::Ptr cloud_filtered_blob (new pcl::PCLPointCloud2);cloud_filtered 申明的数据格式 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>)
那么依照这种的命名风格我们可以查看到更多的关于的数据格式之间的转换的类的成员
(1)
void pcl::fromPCLPointCloud(const pcl:PCLPointCloud2 & msg
pcl::PointCloud<PointT> & cloud
const MsgFieldMap & filed_map
)
函数使用field_map实现将一个pcl::pointcloud2二进制数据blob到PCL::PointCloud<pointT>对象
使用 PCLPointCloud2 (PCLPointCloud2, PointCloud<T>)生成自己的 MsgFieldMap
MsgFieldMap field_map; createMapping<PointT> (msg.fields, field_map);
(2)
void pcl::fromPCLPointCloud2(const pcl::PCLPointCloud & msg
pcl::PointCloud<pointT> &cloud
)
把pcl::PCLPointCloud数据格式的点云转化为pcl::PointCloud<pointT>格式
(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
)
在使用fromROSMsg是一种在ROS 下的一种数据转化的作用,我们举个例子实现订阅使用kinect发布 /camera/depth/points 从程序中我们可以看到如何使用该函数实现数据的转换。并且我在程序中添加了如果使用PCL的库实现在ROS下调用并且可视化,

/************************************************ 关于如何使用PCL在ROS 中,实现简单的数据转化 时间:2017.3.31**/
#include <ros/ros.h>
// PCL specific includes
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/cloud_viewer.h>
ros::Publisher pub;
pcl::visualization::CloudViewer viewer("Cloud Viewer");
void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input) { // 创建一个输出的数据格式 sensor_msgs::PointCloud2 output; //ROS中点云的数据格式
//对数据进行处理
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>); output = *input; pcl::fromROSMsg(output,*cloud);
//blocks until the cloud is actually rendered
viewer.showCloud(cloud); pub.publish (output); }
intmain (int argc, char** argv) { // Initialize ROS ros::init (argc, argv, "my_pcl_tutorial"); ros::NodeHandle nh;
// Create a ROS subscriber for the input point cloud ros::Subscriber sub = nh.subscribe ("input", 1, cloud_cb); ros::Rate loop_rate(100);
// Create a ROS publisher for the output point cloud pub = nh.advertise<sensor_msgs::PointCloud2> ("output", 1); // Spin
ros::spin ();
/*while (!viewer.wasStopped ()) { } */ }
那么对于这一段小程序实现了从发布的节点中转化为可以使用PCL的可视化函数实现可视化,并不一定要用RVIZ来实现,所以我们分析以下其中的步骤,在订阅话题的回调函数中,
void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input)
//这里面设置了一个数据类型为sensor_msgs::PointCloud2ConstPtr& input形参
{
sensor_msgs::PointCloud2 output;
//ROS中点云的数据格式(或者说是发布话题点云的数据类型)
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
//对数据转换后存储的类型
output = *input;
pcl::fromROSMsg(output,*cloud);
//最重要的一步骤实现从ROS到PCL中的数据的转化,同时也可以直接使用PCL库实现可视化
viewer.showCloud(cloud); //PCL库的可视化
pub.publish (output); //那么原来的output的类型仍然是sensor_msgs::PointCloud2,可以通过RVIZ来可视化
}
那么也可以使用
pcl::PCDWriter writer; writer.write<pcl::PointXYZ> ("ros_to_PCL.pcd", *cloud, false);
这一段代码来实现保存的作用。那么见到那看一下可视化的结果

使用pcl_viewer 可视化保存的PCD文件
