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