io获取 pcl_点云数据可视化之PCL滤波学习
PCL濾波概述
在獲取點云數(shù)據(jù)時 ,由于設備精度,操作者經驗環(huán)境因素帶來的影響,以及電磁波的衍射特性,被測物體表面性質變化和數(shù)據(jù)拼接配準操作過程的影響,點云數(shù)據(jù)中將不可避免的出現(xiàn)一些噪聲。在點云處理流程中濾波處理作為預處理的第一步,對后續(xù)的影響比較大,只有在濾波預處理中將噪聲點 ,離群點,孔洞,數(shù)據(jù)壓縮等按照后續(xù)處理定制,才能夠更好的進行配準,特征提取,曲面重建,可視化等后續(xù)應用處理,PCL中點云濾波模塊提供了很多靈活實用的濾波處理算法,例如:PassThrough直通濾波、VoxelGrid過濾、StatisticalOutlierRemoval過濾、點云投影、提取索引等;下面將對幾種常見濾波進行介紹。
PCL中點云濾波的方案
PCL中總結了幾種需要進行點云濾波處理情況,這幾種情況分別如下:
(1) 點云數(shù)據(jù)密度不規(guī)則需要平滑
(2) 因為遮擋等問題造成離群點需要去除
(3) 大量數(shù)據(jù)需要下采樣
(4) 噪聲數(shù)據(jù)需要去除
對應的方案如下:
(1)按照給定的規(guī)則限制過濾去除點
(2) 通過常用濾波算法修改點的部分屬性
(3)對數(shù)據(jù)進行下采樣
常見濾波概述
直通濾波:快速過濾掉用戶自定義區(qū)間范圍內的點云,效果最為明顯并且也最容易理解。
體素濾波:在分割、配準前,如果點云數(shù)量太多會影響后續(xù)時間。此時,需要對點云進行下采樣處理,體素濾波為采用體素網(wǎng)格方法采樣,減少點云數(shù)量。
統(tǒng)計濾波:統(tǒng)計濾波往往去除離群點,利用統(tǒng)計分析技術刪除噪聲異常值等。
投影點云:將點投影到一個參數(shù)化模型上(平面或者球體等)。
提取索引:基于某一分割算法提取點云中的子集。
幾種常見濾波使用實例
對于下面各種濾波的使用并沒有只用文字來闡述,而是主要在代碼的注釋中,我認為這樣會便于理解。
- 直通濾波
直通濾波通俗來講就是設置一個范圍,經該范圍內或者該范圍外的點云數(shù)據(jù)剔除,是一種簡單暴力但效果明顯的方式。
代碼:
#include #include #include #include #include int main (int argc, char** argv){ //點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud(new pcl::PointCloud<:pointxyz>); //處理后點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud_handle(new pcl::PointCloud<:pointxyz>); //處理后點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud_handle2(new pcl::PointCloud<:pointxyz>); //從點云文件中讀取點云數(shù)據(jù) pcl::io::loadPCDFile("d:/2.pcd", *cloud); //目的:通過直通濾波器將某個方向范圍的點云數(shù)據(jù)過濾掉 // 設置濾波器對象 pcl::PassThrough<:pointxyz> pass; //z坐標軸 pass.setInputCloud (cloud); //設置輸入點云 pass.setFilterFieldName ("x"); //設置過濾的坐標軸方向 pass.setFilterLimits (-90, 90); //設置在過濾掉的坐標范圍 pass.setFilterLimitsNegative (false); //設置過濾范圍內還是范圍外,當為false為范圍外 pass.filter (*cloud_handle); //過濾器過濾,過濾后點云數(shù)據(jù)保存在cloud_handle中 // 設置濾波器對象 pcl::PassThrough<:pointxyz> pass2; //z坐標軸 pass.setInputCloud (cloud_handle); //設置輸入點云 pass.setFilterFieldName ("y"); //設置過濾的坐標軸方向 pass.setFilterLimits (-86, 50); //設置在過濾掉的坐標范圍 pass.setFilterLimitsNegative (false); //設置過濾范圍內還是范圍外,當為false為范圍外 pass.filter (*cloud_handle2); //過濾器過濾,過濾后點云數(shù)據(jù)保存在cloud_handle中 //處理后點云顯示 pcl::visualization::CloudViewer viewer("PCL濾波"); viewer.showCloud(cloud_handle2); while (!viewer.wasStopped()){ } return (0);}處理前:
處理后:
這種濾波處理方式效果很明顯,但是它受限于采樣設備的角度,如果角度不佳,僅僅對XYZ軸方向進行過濾就得不到理想的結果。
- 體素濾波
使用體素化網(wǎng)格方法實現(xiàn)下采樣,即減少點的數(shù)量 減少點云數(shù)據(jù),并同時保存點云的形狀特征,在提高后期點云處理速度方面將起到顯著效果。PCL是實現(xiàn)的VoxelGrid類通過輸入的點云數(shù)據(jù)創(chuàng)建一個三維體素柵格,容納后每個體素內用體素中所有點的重心來近似顯示體素中其他點,這樣該體素內所有點都用一個重心點最終表示,對于所有體素處理后得到的過濾后的點云,這種方法比用體素中心逼近的方法更慢,但是對于采樣點對應曲面的表示更為準確。
代碼:
#include #include #include #include #include #include int main (int argc, char** argv){ //點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud(new pcl::PointCloud<:pointxyz>); //處理后點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud_handle(new pcl::PointCloud<:pointxyz>); //從點云文件中讀取點云數(shù)據(jù) pcl::io::loadPCDFile("d:/2.pcd", *cloud); pcl::VoxelGrid<:pointxyz> sor; //創(chuàng)建濾波對象 sor.setInputCloud (cloud); //設置需要過濾的點云給濾波對象 sor.setLeafSize (1, 1, 1); //設置濾波時創(chuàng)建的體素體積,單位m,因為保留點云大體形狀的方式是保留每個體素的中心點,所以體素體積越大那么過濾掉的點云就越多 sor.filter (*cloud_handle); //執(zhí)行濾波處理 //處理后點云顯示 pcl::visualization::CloudViewer viewer("PCL濾波"); viewer.showCloud(cloud_handle); while (!viewer.wasStopped()){ } return (0);}處理前:
處理后:
- 統(tǒng)計濾波
使用統(tǒng)計分析技術,從一個點云數(shù)據(jù)中集中移除測量噪聲點(也就是離群點)比如:激光掃描通常會產生密度不均勻的點云數(shù)據(jù)集,另外測量中的誤差也會產生稀疏的離群點,使效果不好,估計局部點云特征(例如采樣點處法向量或曲率變化率)的運算復雜,這會導致錯誤的數(shù)值,反過來就會導致點云配準等后期的處理失敗。
解決辦法:每個點的鄰域進行一個統(tǒng)計分析,并修剪掉一些不符合一定標準的點,稀疏離群點移除方法基于在輸入數(shù)據(jù)中對點到臨近點的距離分布的計算,對每一個點,計算它到它的所有臨近點的平均距離,,假設得到的結果是一個高斯分布,其形狀是由均值和標準差決定,平均距離在標準范圍之外的點,可以被定義為離群點并可從數(shù)據(jù)中去除。
代碼:
#include #include #include #include #include #include #include int main (int argc, char** argv){ //點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud(new pcl::PointCloud<:pointxyz>); //處理后點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud_handle(new pcl::PointCloud<:pointxyz>); //從點云文件中讀取點云數(shù)據(jù) pcl::io::loadPCDFile("d:/2.pcd", *cloud); pcl::StatisticalOutlierRemoval<:pointxyz> sta; //創(chuàng)建濾波器對象 sta.setInputCloud (cloud); //設置待濾波的點云 sta.setMeanK (1); //設置在進行統(tǒng)計時考慮查詢點臨近點數(shù) sta.setStddevMulThresh (1.0); //設置判斷是否為離群點的閥值,根據(jù)原理來說,閾值越小過濾掉的點就越多 sta.filter (*cloud_handle); //存儲 //處理后點云顯示 pcl::visualization::CloudViewer viewer("PCL濾波"); viewer.showCloud(cloud_handle); while (!viewer.wasStopped()){ } return (0);}處理前:
處理后:
統(tǒng)計濾波我目前的理解是通過算法按照一定閾值將點云中的可能存在干擾的離散點過濾掉。
- 點云投影
點云投影主要是將三維結構投影到二維平面上。
#include #include #include #include #include #include #include #include #include int main (int argc, char** argv){ //點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud(new pcl::PointCloud<:pointxyz>); //處理后點云對象 pcl::PointCloud<:pointxyz>::Ptr cloud_handle(new pcl::PointCloud<:pointxyz>); //從點云文件中讀取點云數(shù)據(jù) pcl::io::loadPCDFile("d:/2.pcd", *cloud); //定義模型系數(shù)對象,并填充對應的數(shù)據(jù),填充ModelCoefficients的值 //使用ax+by+cz+d=0平面模型,其中 a=b=d=0,c=1 也就是X——Z平面 pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ()); coefficients->values.resize (4); coefficients->values[0] = coefficients->values[1] = 1.0; coefficients->values[2] = 0; coefficients->values[3] = 0; pcl::ProjectInliers<:pointxyz> proj; //創(chuàng)建投影濾波對象 proj.setModelType (pcl::SACMODEL_PLANE); //設置對象對應的投影模型 proj.setInputCloud (cloud); //設置輸入點云 proj.setModelCoefficients (coefficients); //設置模型對應的系數(shù) proj.filter (*cloud_handle); //投影結果存儲 //處理后點云顯示 pcl::visualization::CloudViewer viewer("PCL濾波"); viewer.showCloud(cloud_handle); while (!viewer.wasStopped()){ } return (0);}處理前:
處理后:
這里就變成了一個在x-z平面的二維投影。
- 提取索引
代碼:
#include #include #include #include #include #include #include #include #include #include int main (int argc, char** argv){ pcl::PCLPointCloud2::Ptr cloud_blob (new pcl::PCLPointCloud2), cloud_filtered_blob (new pcl::PCLPointCloud2);//聲明濾波前后的點云 pcl::PointCloud<:pointxyz>::Ptr cloud_filtered (new pcl::PointCloud<:pointxyz>), cloud_p (new pcl::PointCloud<:pointxyz>), cloud_f (new pcl::PointCloud<:pointxyz>); // 讀取PCD文件 pcl::PCDReader reader; reader.read ("d:/2.pcd", *cloud_blob); //統(tǒng)計濾波前的點云個數(shù) //從輸入的.PCD 文件載入數(shù)據(jù)后,創(chuàng)建一個VOxelGrid濾波器對數(shù)據(jù)進行下采樣,在這里進行下采樣是為了加速處理過程, //越少的點意味著分割循環(huán)中處理起來越快 // 創(chuàng)建體素柵格下采樣: 下采樣的大小為1cm pcl::VoxelGrid<:pclpointcloud2> sor; //體素柵格下采樣對象 sor.setInputCloud (cloud_blob); //原始點云 sor.setLeafSize (1, 1, 1); // 設置采樣體素大小 sor.filter (*cloud_filtered_blob); //保存 // 轉換為模板點云 pcl::fromPCLPointCloud2 (*cloud_filtered_blob, *cloud_filtered); // 保存下采樣后的點云 pcl::PCDWriter writer; writer.write<:pointxyz> ("table_scene_lms400_downsampled.pcd", *cloud_filtered, false); pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ()); pcl::PointIndices::Ptr inliers (new pcl::PointIndices ()); pcl::SACSegmentation<:pointxyz> seg; //創(chuàng)建分割對象 seg.setOptimizeCoefficients (true); //設置對估計模型參數(shù)進行優(yōu)化處理 seg.setModelType (pcl::SACMODEL_PLANE); //設置分割模型類別 seg.setMethodType (pcl::SAC_RANSAC); //設置用哪個隨機參數(shù)估計方法 seg.setMaxIterations (1000); //設置最大迭代次數(shù) seg.setDistanceThreshold (0.01); //判斷是否為模型內點的距離閥值 // 設置ExtractIndices的實際參數(shù) pcl::ExtractIndices<:pointxyz> extract; //創(chuàng)建點云提取對象 int i = 0, nr_points = (int) cloud_filtered->points.size (); // While 30% of the original cloud is still there while (cloud_filtered->points.size () > 0.3 * nr_points) { // 為了處理點云包含的多個模型,在一個循環(huán)中執(zhí)行該過程并在每次模型被提取后,保存剩余的點進行迭代 seg.setInputCloud (cloud_filtered); seg.segment (*inliers, *coefficients); if (inliers->indices.size () == 0) { break; } // Extract the inliers extract.setInputCloud (cloud_filtered); extract.setIndices (inliers); extract.setNegative (false); extract.filter (*cloud_p); std::stringstream ss; ss << "table_scene_lms400_plane_" << i << ".pcd"; writer.write<:pointxyz> (ss.str (), *cloud_p, false); // Create the filtering object extract.setNegative (true); extract.filter (*cloud_f); cloud_filtered.swap (cloud_f); i++; } //處理后點云顯示 pcl::visualization::CloudViewer viewer("PCL濾波"); viewer.showCloud(cloud_f); while (!viewer.wasStopped()){ } return (0);}處理前:
處理后:
總結
以上是生活随笔為你收集整理的io获取 pcl_点云数据可视化之PCL滤波学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “暑退早凉归”下一句是什么
- 下一篇: npm 安装less插件_2020 VS