PCL中點雲數據格式之間的轉化


(1) 關於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);
}



int
main (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文件

於2018年5月5號看到再次更新一點小筆記,比如我們在寫程序的過程中經常會遇到定義點雲的數據格式為

typedef pcl::PointXYZRGB PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
PointCloudT::Ptr cloud_;

但是我們在運行一個簡單的例程比如直通濾波器的內容是一般的點雲的定義為

typedef pcl::PointXYZRGB PointT;
typedef pcl::PointCloud<PointT> PointCloudT

PointCloudT::Ptr cloud (new PointCloudT);
PointCloudT::Ptr cloud_filtered (new PointCloudT)

  pcl::PassThrough<PointT> pass;
  pass.setInputCloud (cloud);            //設置輸入點雲
  pass.setFilterFieldName ("z");         //設置過濾時所需要點雲類型的Z字段
  pass.setFilterLimits (0.0, 1.0);        //設置在過濾字段的范圍
  //pass.setFilterLimitsNegative (true);   //設置保留范圍內還是過濾掉范圍內
  pass.filter (*cloud_filtered);            //執行濾波,保存過濾結果在cloud_filtered

對比我們可以看出

這里兩種定義的方法的不同是不能在直通濾波器直接使用的

PointCloudT::Ptr   cloud_;
PointCloudY::Ptr   cloud_tmp(new PointCloudT)

如何去轉換呢?

如下:

pcl::copyPointCloud (*cloud_tmp, *cloud_);

在構造上的區別:常規變量定義不使用new,定義的對象在定義后就自動可以使用,指針變量定義必須使用new進行對象實例的構造。

使用上的區別:使用new的是一個指針對象,此時對對象成員的訪問需要使用指針操作符“->”,而不使用new的是常規對象,使用普通成員操作符“.”。

 

可能寫的比較亂,但是有用到關於PCL中點雲數據類型的轉換以及可視化等功能可以參考,同時歡迎有興趣者掃描下方二維碼或者QQ群

與我交流並且投稿,大家一起學習,共同進步與分享

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM