3D点云系列——pcl:点云平滑及法线估计
生活随笔
收集整理的這篇文章主要介紹了
3D点云系列——pcl:点云平滑及法线估计
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
通過重采樣實現點云平滑
需要平滑的情況:
-
用RGB-D激光掃描儀等設備掃描物體,尤其是比較小的物體時,往往會有測量誤差。這些誤差所造成的不規則數據如果直接拿來曲面重建的話,會使得重建的曲面不光滑或者有漏洞,而且這種不規則數據很難用前面我們提到過的統計分析等濾波方法消除;
-
后處理過程中,對同一個物體從不同方向進行了多次掃描,然后把掃描結果進行配準,最后得到一個完整的模型,但是你配準的結果不一定準,比如,同一面墻壁由于配準誤差變成了“兩面墻”,并不能完全重疊。
點云重采樣,我們實際上是通過一種叫做“移動最小二乘”(MLS, Moving Least Squares )法來實現的,對應的類名叫做:pcl::MovingLeastSquares(官網)
// 對點云重采樣 pcl::search::KdTree<PointT>::Ptr treeSampling (new pcl::search::KdTree<PointT>); // 創建用于最近鄰搜索的KD-Tree pcl::PointCloud<PointT> mls_points; //輸出MLS pcl::MovingLeastSquares<PointT, PointT> mls; // 定義最小二乘實現的對象mls mls.setComputeNormals (false); //設置在最小二乘計算中是否需要存儲計算的法線 mls.setInputCloud (cloud_filtered); //設置待處理點云 mls.setPolynomialOrder(2); // 擬合2階多項式擬合 mls.setPolynomialFit (false); // 設置為false可以 加速 smooth mls.setSearchMethod (treeSampling); // 設置KD-Tree作為搜索方法 mls.setSearchRadius (0.05); // 單位m.設置用于擬合的K近鄰半徑 mls.process (mls_points); //輸出Kd-Tree是一種數據結構,是空間二分樹的一種特殊情況,可以很方便的用于進行范圍搜索。在這里用KD-Tree就是為了便于管理、搜索點云,這種結構來可以很方便的找到最近鄰點。
估計點云的表面法線
點云的法線計算一般有兩種方法:
- 使用曲面重建方法,從點云數據中得到采樣點對應的曲面,然后再用曲面模型計算其表面的法線
- 直接使用近似值直接從點云數據集推斷出曲面法線
用第2種方法來近似估計點云中每個點的表面法線。
// 法線估計 pcl::NormalEstimation<PointT, pcl::Normal> normalEstimation; //創建法線估計的對象 normalEstimation.setInputCloud(cloud_smoothed); //輸入點云 pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>); // 創建用于最近鄰搜索的KD-Tree normalEstimation.setSearchMethod(tree); pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>); // 定義輸出的點云法線 // K近鄰確定方法,使用k個最近點,或者確定一個以r為半徑的圓內的點集來確定都可以,兩者選1即可 normalEstimation.setKSearch(10); // 使用當前點周圍最近的10個點 //normalEstimation.setRadiusSearch(0.03); //對于每一個點都用半徑為3cm的近鄰搜索方式 normalEstimation.compute(*normals); //計算法線實踐
/***************************** 給定一個融合后的點云,對其進行下采樣和濾波。* 再進行平滑(輸出結果),然后計算法線,并講法線顯示在平滑后的點云上。 ****************************/#include <pcl/point_types.h> #include <pcl/io/io.h> #include <pcl/io/pcd_io.h> #include <pcl/visualization/cloud_viewer.h> #include <pcl/filters/radius_outlier_removal.h> #include <pcl/filters/voxel_grid.h> #include <pcl/filters/statistical_outlier_removal.h> #include <pcl/surface/mls.h> #include <pcl/features/normal_3d.h>typedef pcl::PointXYZRGB PointT;int main(int argc, char** argv) {// Load input filepcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);pcl::PointCloud<PointT>::Ptr cloud_downSampled(new pcl::PointCloud<PointT>);pcl::PointCloud<PointT>::Ptr cloud_filtered(new pcl::PointCloud<PointT>);pcl::PointCloud<PointT>::Ptr cloud_smoothed(new pcl::PointCloud<PointT>);if (pcl::io::loadPCDFile("/home/xiaohu/learn_SLAM/zuoye15/作業15-點云平滑及法線估計及顯示/data/fusedCloud.pcd", *cloud) == -1){cout << "點云數據讀取失敗!" << endl;}std::cout << "Orginal points number: " << cloud->points.size() << std::endl;// 下采樣,同時保持點云形狀特征pcl::VoxelGrid<PointT> downSampled; //創建濾波對象downSampled.setInputCloud (cloud); //設置需要過濾的點云給濾波對象downSampled.setLeafSize (0.01f, 0.01f, 0.01f); //設置濾波時創建的體素體積為1cm的立方體downSampled.filter (*cloud_downSampled); //執行濾波處理,存儲輸出pcl::io::savePCDFile ("/home/xiaohu/learn_SLAM/zuoye15/作業15-點云平滑及法線估計及顯示/data/downsampledPC.pcd", *cloud_downSampled);// 統計濾波pcl::StatisticalOutlierRemoval<PointT> statisOutlierRemoval; //創建濾波器對象statisOutlierRemoval.setInputCloud (cloud_downSampled); //設置待濾波的點云statisOutlierRemoval.setMeanK (50); //設置在進行統計時考慮查詢點臨近點數statisOutlierRemoval.setStddevMulThresh (3.0); //設置判斷是否為離群點的閥值:均值+1.0*標準差statisOutlierRemoval.filter (*cloud_filtered); //濾波結果存儲到cloud_filteredpcl::io::savePCDFile ("/home/xiaohu/learn_SLAM/zuoye15/作業15-點云平滑及法線估計及顯示/data/filteredPC.pcd", *cloud_filtered);// ----------------------開始你的代碼--------------------------//// 請參考PCL官網實現以下功能// 對點云重采樣pcl::search::KdTree<PointT>::Ptr treeSampling (new pcl::search::KdTree<PointT>);// 創建用于最近鄰搜索的KD-Treepcl::PointCloud<PointT> mls_point; //輸出MLSpcl::MovingLeastSquares<PointT,PointT> mls; // 定義最小二乘實現的對象mlsmls.setComputeNormals(false); //設置在最小二乘計算中是否需要存儲計算的法線mls.setInputCloud(cloud_filtered); //設置待處理點云mls.setPolynomialOrder(2); // 擬合2階多項式擬合mls.setPolynomialFit(false); // 設置為false可以 加速 smoothmls.setSearchMethod(treeSampling); // 設置KD-Tree作為搜索方法mls.setSearchRadius(0.05); // 單位m.設置用于擬合的K近鄰半徑mls.process(mls_point); //輸出// 輸出重采樣結果cloud_smoothed = mls_point.makeShared();std::cout<<"cloud_smoothed: "<<cloud_smoothed->size() <<std::endl;//save cloud_smoothedpcl::io::savePCDFileASCII("/home/xiaohu/learn_SLAM/zuoye15/作業15-點云平滑及法線估計及顯示/data/cloud_smoothed.pcd",*cloud_smoothed);// 法線估計pcl::NormalEstimation<PointT,pcl::Normal> normalEstimation; //創建法線估計的對象normalEstimation.setInputCloud(cloud_smoothed); //輸入點云pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>);// 創建用于最近鄰搜索的KD-TreenormalEstimation.setSearchMethod(tree);pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>); // 定義輸出的點云法線// K近鄰確定方法,使用k個最近點,或者確定一個以r為半徑的圓內的點集來確定都可以,兩者選1即可normalEstimation.setKSearch(10);// 使用當前點周圍最近的10個點//normalEstimation.setRadiusSearch(0.03); //對于每一個點都用半徑為3cm的近鄰搜索方式normalEstimation.compute(*normals); //計算法線std::cout<<"normals: "<<normals->size()<<", "<<"normals fields: "<<pcl::getFieldsList(*normals)<<std::endl;pcl::io::savePCDFileASCII("/home/xiaohu/learn_SLAM/zuoye15/作業15-點云平滑及法線估計及顯示/data/normals.pcd",*normals);// 顯示結果boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("PCL Viewer"));viewer->setBackgroundColor (0, 0, 0);pcl::visualization::PointCloudColorHandlerRGBField<PointT> rgb(cloud_smoothed);viewer->addPointCloud<PointT> (cloud_smoothed, rgb, "smooth cloud");viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "smooth cloud");viewer->addPointCloudNormals<PointT, pcl::Normal> (cloud_smoothed, normals, 20, 0.05, "normals");viewer->initCameraParameters ();while (!viewer->wasStopped ()){viewer->spinOnce (100);boost::this_thread::sleep (boost::posix_time::microseconds (100000));}return 1; }平滑后:
平滑及法線估計:
參考:https://mp.weixin.qq.com/s/GFDWOudJ08In6jFyrZ7hhg
總結
以上是生活随笔為你收集整理的3D点云系列——pcl:点云平滑及法线估计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于浏览器中使用百度定位
- 下一篇: 华为无线wifi设备连接到服务器,wif