標籤:技術 輸入 div 對象 show return style include 錯誤
雷射掃描通常會產生密度不均勻的點雲資料集。另外,測量中的誤差會產生稀疏的離群點,使效果更糟。估計局部點雲特徵(例如採樣點處法向量或曲率變動率)的運算很複雜,這會導致錯誤的數值,反過來有可能導致點雲的配准等後期處理失敗。
以下方法可以解決其中部分問題:對每個點的鄰域進行一個統計分析,並修剪掉那些不符合一定標準的點。我們的稀疏離群點移除方法基於在輸入資料中對點到臨近點的距離分布的計算。對每個點,我們計算它到它的所有臨近點的平均距離。假設得到的結果是一個高斯分布,其形狀由均值和標準差決定,平均距離在標準範圍(由全域距離平均值和方差定義)之外的點,可被定義為離群點並可從資料集中去除掉。
使用StatisticalOutlierRemoval濾波器移除離群點
圖1展示了稀疏離群點分析和移除的效果:左圖為未經處理資料集,右圖為處理結果。該圖展示了處理前和處理後,一個點鄰域範圍內的k近鄰鄰域平均距離。
圖1 稀疏離群點分析和移除的效果對比圖
代碼
首先,在PCL(Point Cloud Learning)中國協助發行的書[1]提供光碟片的第8章例3檔案夾中,開啟名為statistical_removal.cpp的代碼檔案,
同檔案夾下可以找到相關的測試點雲檔案table_scene_lms400.pcd
下面來解析上面開啟原始碼的關鍵語句。下列代碼將從磁碟中讀取點雲資料。
pcl::PCDReaderreader;//定義讀取對象
reader.read<pcl::PointXYZ>("table_scene_lms400.pcd",*cloud);//讀取點雲檔案
然後,建立了一個pcl::StatisticalOutlierRemoval濾波器,將對每個點分析的臨近點個數設為50,並將標準差倍數設為1,這意味著如果一個點的距離超出平均距離一個標準差以上,則該點被標記為離群點,並將被移除。計算後的輸出結果儲存在cloud_filtered中。
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;// 建立濾波器對象
sor.setInputCloud(cloud); //設定呆濾波的點雲
sor.setMeanK(50); //設定在進行統計時考慮查詢點鄰近點數
sor.setStddevMulThresh(1.0); //設定判斷是否為離群點的閾值
sor.filter(*cloud_filtered); //執行濾波處理儲存內點到cloud_filtered
剩下的資料(內部點)將被存入磁碟,以供其他使用,例如可視化等。
pcl::PCDWriterwriter;
writer.write<pcl::PointXYZ>("table_scene_lms400_inliers.pcd",*cloud_filtered,false);
然後,使用同樣的參數再次調用該濾波器,但是利用函數setNegative設定使輸出取外點,以擷取離群點資料(也就是原本濾除掉的點)。
sor.setNegative(true);
sor.filter(*cloud_filtered);
並將資料寫回到磁碟。
writer.write<pcl::PointXYZ>("table_scene_lms400_outliers.pcd",*cloud_filtered,false);
#include <iostream>#include <pcl/io/pcd_io.h>#include <pcl/point_types.h>#include <pcl/filters/statistical_outlier_removal.h>intmain (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>); // 填入點雲資料 pcl::PCDReader reader; // 把路徑改為自己存放檔案的路徑 reader.read<pcl::PointXYZ> ("table_scene_lms400.pcd", *cloud); std::cerr << "Cloud before filtering: " << std::endl; std::cerr << *cloud << std::endl; // 建立濾波器對象 pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setInputCloud (cloud); sor.setMeanK (50); sor.setStddevMulThresh (1.0); sor.filter (*cloud_filtered); std::cerr << "Cloud after filtering: " << std::endl; std::cerr << *cloud_filtered << std::endl; pcl::PCDWriter writer; writer.write<pcl::PointXYZ> ("table_scene_lms400_inliers.pcd", *cloud_filtered, false); sor.setNegative (true); sor.filter (*cloud_filtered); writer.write<pcl::PointXYZ> ("table_scene_lms400_outliers.pcd", *cloud_filtered, false); return (0);}
可以直接在VS中執行控制台會輸出點雲濾波的資訊,並得到兩個pcb分別儲存內點和外點:
table_scene_lms400_inliers.pcd
table_scene_lms400_outliers.pcd
原點雲可視化結果:
濾波處理後:
參考:http://www.pclcn.org/study/shownews.php?lang=cn&id=68
點雲的濾波