PCL點雲曲面重建(1)


在測量較小的數據時會產生一些誤差,這些誤差所造成的不規則數據如果直接拿來曲面重建的話,會使得重建的曲面不光滑或者有漏洞,可以采用對數據重采樣來解決這樣問題,通過對周圍的數據點進行高階多項式插值來重建表面缺少的部分,

(1)用最小二乘法對點雲進行平滑處理

新建文件resampling.cpp

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree_flann.h>  //kd-tree搜索對象的類定義的頭文件
#include <pcl/surface/mls.h>        //最小二乘法平滑處理類定義頭文件

int
main (int argc, char** argv)
{
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ> ());
  pcl::io::loadPCDFile ("bun0.pcd", *cloud);

  // 創建 KD-Tree
  pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);

  // Output has the PointNormal type in order to store the normals calculated by MLS
  pcl::PointCloud<pcl::PointNormal> mls_points;

  // 定義最小二乘實現的對象mls
  pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointNormal> mls;
 
  mls.setComputeNormals (true);  //設置在最小二乘計算中需要進行法線估計

  // Set parameters
  mls.setInputCloud (cloud);
  mls.setPolynomialFit (true);
  mls.setSearchMethod (tree);
  mls.setSearchRadius (0.03);

  // Reconstruct
  mls.process (mls_points);

  // Save output
  pcl::io::savePCDFile ("bun0-mls.pcd", mls_points);
}

結果對比

    

(2)在平面模型上提取凸(凹)多邊形

本例子先從點雲中提取平面模型,再通過該估計的平面模型系數從濾波后的點雲投影一組點集形成點雲,最后為投影后的點雲計算其對應的二維凸多邊形

#include <pcl/ModelCoefficients.h>           //采樣一致性模型相關類頭文件
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/project_inliers.h>          //濾波相關類頭文件
#include <pcl/segmentation/sac_segmentation.h>   //基於采樣一致性分割類定義的頭文件
#include <pcl/surface/concave_hull.h>                 //創建凹多邊形類定義頭文件

int
main (int argc, char** argv)
{
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>), 
                                      cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>), 
                                      cloud_projected (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PCDReader reader;

  reader.read ("table_scene_mug_stereo_textured.pcd", *cloud);
  // 建立過濾器消除雜散的NaN
  pcl::PassThrough<pcl::PointXYZ> pass;
  pass.setInputCloud (cloud);                  //設置輸入點雲
  pass.setFilterFieldName ("z");             //設置分割字段為z坐標
  pass.setFilterLimits (0, 1.1);             //設置分割閥值為(0, 1.1)
  pass.filter (*cloud_filtered);              
  std::cerr << "PointCloud after filtering has: "
            << cloud_filtered->points.size () << " data points." << std::endl;

  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);   //inliers存儲分割后的點雲
  // 創建分割對象
  pcl::SACSegmentation<pcl::PointXYZ> seg;
  // 設置優化系數,該參數為可選參數
  seg.setOptimizeCoefficients (true);
  // Mandatory
  seg.setModelType (pcl::SACMODEL_PLANE);
  seg.setMethodType (pcl::SAC_RANSAC);
  seg.setDistanceThreshold (0.01);

  seg.setInputCloud (cloud_filtered);
  seg.segment (*inliers, *coefficients);
  std::cerr << "PointCloud after segmentation has: "
            << inliers->indices.size () << " inliers." << std::endl;

  // Project the model inliers
  pcl::ProjectInliers<pcl::PointXYZ> proj;//點雲投影濾波模型
  proj.setModelType (pcl::SACMODEL_PLANE); //設置投影模型
  proj.setIndices (inliers);             
  proj.setInputCloud (cloud_filtered);
  proj.setModelCoefficients (coefficients);      //將估計得到的平面coefficients參數設置為投影平面模型系數
  proj.filter (*cloud_projected);            //得到投影后的點雲
  std::cerr << "PointCloud after projection has: "
            << cloud_projected->points.size () << " data points." << std::endl;

  // 存儲提取多邊形上的點雲
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::ConcaveHull<pcl::PointXYZ> chull;        //創建多邊形提取對象
  chull.setInputCloud (cloud_projected);       //設置輸入點雲為提取后點雲
  chull.setAlpha (0.1);
  chull.reconstruct (*cloud_hull);   //創建提取創建凹多邊形

  std::cerr << "Concave hull has: " << cloud_hull->points.size ()
            << " data points." << std::endl;

  pcl::PCDWriter writer;
  writer.write ("table_scene_mug_stereo_textured_hull.pcd", *cloud_hull, false);

  return (0);
}

實驗結果

 

 (3)無序點雲的快速三角化

使用貪婪投影三角化算法對有向點雲進行三角化,

具體方法是:

(1)先將有向點雲投影到某一局部二維坐標平面內

(2)在坐標平面內進行平面內的三角化

(3)根據平面內三位點的拓撲連接關系獲得一個三角網格曲面模型.

貪婪投影三角化算法原理:

是處理一系列可以使網格“生長擴大”的點(邊緣點)延伸這些點直到所有符合幾何正確性和拓撲正確性的點都被連上,該算法可以用來處理來自一個或者多個掃描儀掃描到得到並且有多個連接處的散亂點雲但是算法也是有很大的局限性,它更適用於采樣點雲來自表面連續光滑的曲面且點雲的密度變化比較均勻的情況

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>      //貪婪投影三角化算法

int
main (int argc, char** argv)
{
  // 將一個XYZ點類型的PCD文件打開並存儲到對象中
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PCLPointCloud2 cloud_blob;
  pcl::io::loadPCDFile ("bun0.pcd", cloud_blob);
  pcl::fromPCLPointCloud2 (cloud_blob, *cloud);
  //* the data should be available in cloud

  // Normal estimation*
  pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;      //法線估計對象
  pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);   //存儲估計的法線
  pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);  //定義kd樹指針
  tree->setInputCloud (cloud);   ///用cloud構建tree對象
  n.setInputCloud (cloud);
  n.setSearchMethod (tree);
  n.setKSearch (20);
  n.compute (*normals);       ////估計法線存儲到其中
  //* normals should not contain the point normals + surface curvatures

  // Concatenate the XYZ and normal fields*
  pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals (new pcl::PointCloud<pcl::PointNormal>);
  pcl::concatenateFields (*cloud, *normals, *cloud_with_normals);    //連接字段
  //* cloud_with_normals = cloud + normals

  //定義搜索樹對象
  pcl::search::KdTree<pcl::PointNormal>::Ptr tree2 (new pcl::search::KdTree<pcl::PointNormal>);
  tree2->setInputCloud (cloud_with_normals);   //點雲構建搜索樹

  // Initialize objects
  pcl::GreedyProjectionTriangulation<pcl::PointNormal> gp3;   //定義三角化對象
  pcl::PolygonMesh triangles;                //存儲最終三角化的網絡模型
 
  // Set the maximum distance between connected points (maximum edge length)
  gp3.setSearchRadius (0.025);  //設置連接點之間的最大距離,(即是三角形最大邊長)

  // 設置各參數值
  gp3.setMu (2.5);  //設置被樣本點搜索其近鄰點的最遠距離為2.5,為了使用點雲密度的變化
  gp3.setMaximumNearestNeighbors (100);    //設置樣本點可搜索的鄰域個數
  gp3.setMaximumSurfaceAngle(M_PI/4); // 設置某點法線方向偏離樣本點法線的最大角度45
  gp3.setMinimumAngle(M_PI/18); // 設置三角化后得到的三角形內角的最小的角度為10
  gp3.setMaximumAngle(2*M_PI/3); // 設置三角化后得到的三角形內角的最大角度為120
  gp3.setNormalConsistency(false);  //設置該參數保證法線朝向一致

  // Get result
  gp3.setInputCloud (cloud_with_normals);     //設置輸入點雲為有向點雲
  gp3.setSearchMethod (tree2);   //設置搜索方式
  gp3.reconstruct (triangles);  //重建提取三角化

  // 附加頂點信息
  std::vector<int> parts = gp3.getPartIDs();
  std::vector<int> states = gp3.getPointStates();

  // Finish
  return (0);
}

 首先看一下原來的PCD可視化文件

對其進行三角化可視化的結果是

效果還是很明顯的阿

 

微信公眾號號可掃描二維碼一起共同學習交流


免責聲明!

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



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