PCL 曲面重建 贪婪三角

一、简单原理介绍

       将三维的点通过法向量投影到某一个平面,然后对投影得到的点云做平面内的三角化,从而得到个点的连接关系。

       在平面区域三角化的过程中用到了基于Delauney 的空间区域生长算法,这个方法通过选取一个样本三角片作为初始曲面,不断扩张曲面边界,最后形成一张完整的三角网格曲面,最后根据投影的点云连接关系确定各原始三维点之间的拓补连接,所得到的三角网格就是重建得到的曲面模型。

 该方法使用于 点云密度均匀,不能在算讲话的同时对曲面进行平滑和孔洞的修复。

 

二、步骤

1、求点云的法向量

2、将点云和其1计算的法向量放一起

3、使用法向量做曲面重建

4、显示 

三、显示

PCL 曲面重建 贪婪三角_第1张图片

 


#if 1 //   曲面重建  - 贪婪三角
using namespace std;
int main()
{
    pcl::PointCloud::Ptr cloud(new pcl::PointCloud);			//待滤波点云
    pcl::PointCloud::Ptr cloud_filtered(new pcl::PointCloud);	//滤波后点云

    ///读入点云数据
    cout << "->正在读入点云..." << endl;
    pcl::PCDReader reader;
    reader.read("1.pcd", *cloud);
    cout << "\t\t<读入点云信息>\n" << *cloud << endl;


    //   由于贪婪三角是基于点的法向量的,因此我们需要开始的时候就要进行求法向量的操作
    pcl::NormalEstimation n;
    pcl::PointCloud::Ptr  normals(new  pcl::PointCloud());
    // 我用要使用kd tree 来做法向量
    pcl::search::KdTree::Ptr kdtree(new pcl::search::KdTree());
    kdtree->setInputCloud(cloud);
    n.setInputCloud(cloud);
    n.setSearchMethod(kdtree);  // 在计算法向量的时候使用kdtree 作为方法
    n.setKSearch(20);  // k
    n.compute(*normals);  // 我们计算出了 法向量和曲率

    //我们要把点云和法向量都放到一起,因此我们需要对这个点云添加一个维度,这样才能做曲面重建
    pcl::PointCloud::Ptr cloud_with_normals(new pcl::PointCloud);
    pcl::concatenateFields(*cloud, *normals, *cloud_with_normals);  // concat 就是将xyz和normal 组合到一起


    //   再次创建一个kd tree 用来做曲面重建
    pcl::search::KdTree::Ptr  kdtree_rec(new pcl::search::KdTree());
    // 这里我们需要处理的是xyz +_normal 的点云和上面的点云的是不一样的
    kdtree_rec->setInputCloud(cloud_with_normals);


   // ===========================自此我们三角化的条件已经都准备好了,下面我们开始三角化=====================================
    pcl::GreedyProjectionTriangulation gpt;    //  贪婪三角对象
    pcl::PolygonMesh triangles;  // 存储最终三件化的网格模型,
   
    // 三维曲面重建 ,设置参数
    gpt.setSearchRadius(0.025); // 设置搜索半径,也就是k -临近的球半径
    // 设置样本点到最近邻域距离的乘积系数mu 来获每个样本点的最大搜索距离,这样是的算法自适应点云密度的变化   ,简单理解就是一个系数的问题,也就是说当使用半径来找
    // 周围的点的时候,半径范围里面没有找到点,那么我们会启用radius *  gpt.setMu(2.5);  作为最远距离来找点(一定要看书,网上有的解释是错的这个系数在【2.5,3】
    gpt.setMu(2.5); 

    gpt.setMaximumNearestNeighbors(100);   // 设置样本点最多可以设置搜索的领域数目
    gpt.setMaximumSurfaceAngle(M_PI / 4);     //连接的时候最大的角度,当某点法线相当于采样点的法线偏离角度超过这个最大角度的时候,连接不考虑这个点
    gpt.setMinimumAngle(M_PI /18);  // 设置三角化后三角形的最小角度
    gpt.setMaximumAngle(2*M_PI/3); 

    // 设置法向量的朝向是不是要一致,true 表示一致,false表示不一样
    gpt.setNormalConsistency(false);

    // 开始三维曲面重建
    gpt.setInputCloud(cloud_with_normals);
    gpt.setSearchMethod(kdtree_rec);
    gpt.reconstruct(triangles);



    // std::cout << triangles;
     // Additional vertex information
    std::vector parts = gpt.getPartIDs();                  //获取ID字段
    std::vector states = gpt.getPointStates();             //获取点状态

    boost::shared_ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    ///*-----视口1-----*/
    //int v1(0);
    //viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1); //设置第一个视口在X轴、Y轴的最小值、最大值,取值在0-1之间
    //viewer->setBackgroundColor(0, 0, 0, v1); //设置背景颜色,0-1,默认黑色(0,0,0)
    //viewer->addText("befor_filtered", 10, 10, "v1_text", v1);
    //viewer->addPointCloud(cloud, "befor_filtered_cloud", v1);

    ///*-----视口2-----*/
    //int v2(0);
    //viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);
    //viewer->setBackgroundColor(0.3, 0.3, 0.3, v2);
    //viewer->addText("after_filtered", 10, 10, "v2_text", v2);
    //viewer->addPointCloud(cloud_filtered, "after_filtered_cloud", v2);

    ///*-----设置相关属性-----*/
    //viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "befor_filtered_cloud", v1);
    //viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "befor_filtered_cloud", v1);

    //viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "after_filtered_cloud", v2);
    //viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 1, 0, "after_filtered_cloud", v2);

    可视化
    

    viewer->setBackgroundColor (0, 0, 0);
    viewer->addPolygonMesh(triangles,"mytriangles");

   // viewer->addCoordinateSystem (1.0);
    viewer->initCameraParameters ();
     // 主循环
    while (!viewer->wasStopped ())
    {
      viewer->spinOnce (100);
      boost::this_thread::sleep (boost::posix_time::microseconds (100000));
    }

    // Finish
    return (0);
}

#endif

你可能感兴趣的:(PCL,pcl)