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 :
/** rief 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;
...
ply模型数据:
链接: https://pan.baidu.com/s/1i5khc93 密码: s4qu