pcl::PolygonMesh简析

PCL利用VTK的IO接口,可以直接读取stl,ply,obj等格式的三维点云数据。pcl的接口方法为

int
pcl::io::loadPolygonFile (const std::string &file_name, pcl::PolygonMesh& mesh);

这里要说明的对象即是PolygonMesh这个类。对于三角网格,其数据构成主要有三维点的坐标、构成三角面的点的索引以及法向量等。下面是类PolygonMesh的定义。

struct PolygonMesh
  {
    PolygonMesh () : header (), cloud (), polygons ()
    {}

    ::pcl::PCLHeader  header;

    ::pcl::PCLPointCloud2 cloud;

    std::vector< ::pcl::Vertices>  polygons;


  public:
    typedef boost::shared_ptr< ::pcl::PolygonMesh> Ptr;
    typedef boost::shared_ptr< ::pcl::PolygonMesh const> ConstPtr;
  }; // struct PolygonMesh

很明显,polygons是顶点的索引,每三个顶点构成一个三角面。根据惯例,可以猜测cloud应该是点云数据了,见PCLPointCloud2 定义。

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

可以发现该类型完全不同于常用的PointCloud< PointT >,这里的std::vector< pcl::uint8_t > data跟点云坐标有没有关系并不能缺定。只能去查看PCL的IO源码部分。

int
pcl::io::vtk2mesh (const vtkSmartPointer<vtkPolyData>& poly_data, pcl::PolygonMesh& mesh)
{
  mesh.polygons.resize (0);
  mesh.cloud.data.clear ();
  mesh.cloud.width = mesh.cloud.height = 0;
  mesh.cloud.is_dense = true;

  vtkSmartPointer<vtkPoints> mesh_points = poly_data->GetPoints ();
  vtkIdType nr_points = mesh_points->GetNumberOfPoints ();
  vtkIdType nr_polygons = poly_data->GetNumberOfPolys ();

  if (nr_points == 0)
    return (0);


  // First get the xyz information
  pcl::PointCloud<pcl::PointXYZ>::Ptr xyz_cloud (new pcl::PointCloud<pcl::PointXYZ> ());
  xyz_cloud->points.resize (nr_points);
  xyz_cloud->width = static_cast<uint32_t> (xyz_cloud->points.size ());
  xyz_cloud->height = 1;
  xyz_cloud->is_dense = true;
  double point_xyz[3];
  for (vtkIdType i = 0; i < mesh_points->GetNumberOfPoints (); i++)
  {
    mesh_points->GetPoint (i, &point_xyz[0]);
    xyz_cloud->points[i].x = static_cast<float> (point_xyz[0]);
    xyz_cloud->points[i].y = static_cast<float> (point_xyz[1]);
    xyz_cloud->points[i].z = static_cast<float> (point_xyz[2]);
  }
  // And put it in the mesh cloud
  pcl::toPCLPointCloud2 (*xyz_cloud, mesh.cloud);

  ...

在vtk2mesh 方法中,xyz_cloud即是点云的xyz坐标信息,其通过toPCLPointCloud2 方法将数据赋值给PCLPointCloud2类型变量cloud,实现了pcl::PointCloud< pcl::PointXYZ >转化为PCLPointCloud2。同时可以发现,PCLPointCloud2不单保存xyz,还可以保存点云颜色以及法线向量

此时,不难发现,同样存在PCLPointCloud2转化为pcl::PointCloud< pcl::PointXYZ >的方法fromPCLPointCloud2 :

 /** \brief Convert a PCLPointCloud2 binary data blob into a pcl::PointCloud<T> object.
  * \param[in] msg the PCLPointCloud2 binary blob
  * \param[out] cloud the resultant pcl::PointCloud<T>
  */
  template<typename PointT> void
  fromPCLPointCloud2 (const pcl::PCLPointCloud2& msg, pcl::PointCloud<PointT>& cloud)

值得注意的是,PCLPointCloud2 在转换成PointCloud< PointT>要确认类型匹配。

示例代码:

...
string infile = "J20170411_L.ply";

pcl::PolygonMesh mesh;
pcl::io::loadPolygonFile(infile, mesh);

std::cout << "Polygon: " << mesh.polygons.size() << std::endl;
std::cout <<"cloud: "<< mesh.cloud.width << std::endl;

pcl::PointCloud<pcl::PointXYZ>::Ptr 
cloud(new pcl::PointCloud<pcl::PointXYZ>);
fromPCLPointCloud2(mesh.cloud, *cloud);

std::cout << cloud->width << " " << cloud->height << std::endl;
std::cout << cloud->points.size() << endl;

int index = rand() % 10000;
std::cout << cloud->points[index].x << " " << 
cloud->points[index].y << " " << cloud->points[index].z << std::endl;
...

out

ply模型数据:
链接: https://pan.baidu.com/s/1i5khc93 密码: s4qu

猜你喜欢

转载自blog.csdn.net/liujiabin076/article/details/70242031