在獲取點雲數據時 ,由於設備精度,操作者經驗環境因素帶來的影響,以及電磁波的衍射特性,被測物體表面性質變化和數據拼接配准操作過程的影響,點雲數據中講不可避免的出現一些噪聲。在點雲處理流程中濾波處理作為預處理的第一步,對后續的影響比較大,只有在濾波預處理中將噪聲點 ,離群點,孔洞,數據壓縮等按照后續處理定制,才能夠更好的進行配准,特征提取,曲面重建,可視化等后續應用處理,PCL中點雲濾波模塊提供了很多靈活實用的濾波處理算法,例如:雙邊濾波,高斯濾波,條件濾波,直通濾波,基於隨機采樣一致性濾波,
PCL中點雲濾波的方案
PCL中總結了幾種需要進行點雲濾波處理情況,這幾種情況分別如下:
(1) 點雲數據密度不規則需要平滑
(2) 因為遮擋等問題造成離群點需要去除
(3) 大量數據需要下采樣
(4) 噪聲數據需要去除
對應的方案如下:
(1)按照給定的規則限制過濾去除點
(2) 通過常用濾波算法修改點的部分屬性
(3)對數據進行下采樣
雙邊濾波算法是通過取臨近采樣點和加權平均來修正當前采樣點的位置,從而達到濾波效果,同時也會有選擇剔除與當前采樣點“差異”太大的相鄰采樣點,從而保持原特征的目的
| Classes |
|
|
|
pcl::ApproximateVoxelGrid< PointT > 類ApproximateVoxelGrid根據給定的點雲形成三維體素柵格,並利用所有體素的中心點近似體素 |
|
|
中包含的點集,這樣完成下采樣得到濾波結果,該類比較合適對海量點雲數據在處理前進行壓縮,提高算法效率 |
| class |
pcl::BilateralFilter< PointT > 類BilateralFilter是對雙邊濾波算法在點雲上的實現,該類的實現利用的並非XYZ字段的數據進行,而是利用 |
|
|
強度數據進行雙邊濾波算法的實現,所以在使用該類時點雲的類型必須有強度字段,否則無法進行雙邊濾波處理, |
| class |
pcl::BoxClipper3D< PointT >實現用一個原點為中心,XYZ各個方向尺寸為2 經過用戶指定的仿射變換的立方體進行空間裁剪,通過設置一個仿射變換矩陣先對立方體進行變換處理,之后輸出仿射變換后落在該立方體內的點集 |
| class |
pcl::Clipper3D< PointT >是3D空間裁剪對象的基類 |
| class |
pcl::ConditionalRemoval< PointT >實現過濾滿足一定的條件的點雲數據,非常靈活,可以設置濾波條件 |
| class |
pcl::filters::Convolution< PointIn, PointOut > 實現卷積濾波處理 |
| class |
pcl::filters::ConvolvingKernel< PointInT, PointOutT > 是所有卷積核的基類 |
| class |
pcl::filters::GaussianKernel< PointInT, PointOutT > 是基於高斯核的卷積濾波實現 高斯濾波相當於一個具有平滑性能的低通濾波器 |
| class |
pcl::filters::GaussianKernelRGB< PointInT, PointOutT > 是附加RGB通道基於高斯核的卷積濾波實現,不僅考慮空間XYZ而且考慮RGB |
| class |
pcl::CropBox< PointT > 過濾掉在用戶給定立方體內的點雲數據 |
| class |
pcl::CropHull< PointT > 過濾在給定三維封閉曲面或二維封閉多邊形內部或外部的點雲數據 |
| class |
pcl::ExtractIndices< PointT > 從一個點雲中提取索引 |
| class |
pcl::Filter< PointT > 是濾波模塊最重要的類 其他所有的濾波模塊的類都從它繼承。 |
| 。。。。。。。。。。(還有很多) |
|
應用實例
(1)在PCL 中使用直通濾波器對點雲進行濾波處理
代碼解析如下
#include <iostream> #include <pcl/point_types.h> #include <pcl/filters/passthrough.h> int main (int argc, char** argv) { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>); //生成並填充點雲 cloud->width = 5; cloud->height = 1; cloud->points.resize (cloud->width * cloud->height); for (size_t i = 0; i < cloud->points.size (); ++i) //填充數據 { cloud->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f); cloud->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f); cloud->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f); } std::cerr << "Cloud before filtering: " << std::endl; //打印 for (size_t i = 0; i < cloud->points.size (); ++i) std::cerr << " " << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z << std::endl; /************************************************************************************ 創建直通濾波器的對象,設立參數,濾波字段名被設置為Z軸方向,可接受的范圍為(0.0,1.0) 即將點雲中所有點的Z軸坐標不在該范圍內的點過濾掉或保留,這里是過濾掉,由函數setFilterLimitsNegative設定 ***********************************************************************************/ // 設置濾波器對象 pcl::PassThrough<pcl::PointXYZ> pass; pass.setInputCloud (cloud); //設置輸入點雲 pass.setFilterFieldName ("z"); //設置過濾時所需要點雲類型的Z字段 pass.setFilterLimits (0.0, 1.0); //設置在過濾字段的范圍 //pass.setFilterLimitsNegative (true); //設置保留范圍內還是過濾掉范圍內 pass.filter (*cloud_filtered); //執行濾波,保存過濾結果在cloud_filtered std::cerr << "Cloud after filtering: " << std::endl; //打印 for (size_t i = 0; i < cloud_filtered->points.size (); ++i) std::cerr << " " << cloud_filtered->points[i].x << " " << cloud_filtered->points[i].y << " " << cloud_filtered->points[i].z << std::endl; return (0); }
由於隨機生成的點雲,所以每次運行結果不一樣,但是都會將點雲中Z坐標在(0,1)范圍外的點過濾掉

(2)使用VoxelGrid濾波器對點雲進行下采樣
使用體素化網格方法實現下采樣,即減少點的數量 減少點雲數據,並同時保存點雲的形狀特征,在提高配准,曲面重建,形狀識別等算法速度中非常實用,PCL是實現的VoxelGrid類通過輸入的點雲數據創建一個三維體素柵格,容納后每個體素內用體素中所有點的重心來近似顯示體素中其他點,這樣該體素內所有點都用一個重心點最終表示,對於所有體素處理后得到的過濾后的點雲,這種方法比用體素中心逼近的方法更慢,但是對於采樣點對應曲面的表示更為准確。
代碼解釋
voxel_grid.cpp
#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/filters/voxel_grid.h> int main (int argc, char** argv) { pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2 ()); pcl::PCLPointCloud2::Ptr cloud_filtered (new pcl::PCLPointCloud2 ()); //點雲對象的讀取 pcl::PCDReader reader; reader.read ("table_400.pcd", *cloud); //讀取點雲到cloud中 std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height << " data points (" << pcl::getFieldsList (*cloud) << ")."; /****************************************************************************** 創建一個葉大小為1cm的pcl::VoxelGrid濾波器, **********************************************************************************/ pcl::VoxelGrid<pcl::PCLPointCloud2> sor; //創建濾波對象 sor.setInputCloud (cloud); //設置需要過濾的點雲給濾波對象 sor.setLeafSize (0.01f, 0.01f, 0.01f); //設置濾波時創建的體素體積為1cm的立方體 sor.filter (*cloud_filtered); //執行濾波處理,存儲輸出 std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height << " data points (" << pcl::getFieldsList (*cloud_filtered) << ")."; pcl::PCDWriter writer; writer.write ("table_scene_lms400_downsampled.pcd", *cloud_filtered, Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), false); return (0); }
從輸出的結果可以看出,過濾后的數據量大大減小了。打印結果如下

顯示的結果圖可以看出對比

原始點雲與濾波后的點雲可視化結果,明顯的可以看出來,點的密度大小與整齊程度不同,雖然處理后的數據量大大減小,但是很明顯所含有的形狀特征和空間結構信息與原始點雲差不多。
微信公眾號號可掃描二維碼一起共同學習交流

未完待續***************************88
