(1)使用statisticalOutlierRemoval濾波器移除離群點
使用統計分析技術,從一個點雲數據中集中移除測量噪聲點(也就是離群點)比如:激光掃描通常會產生密度不均勻的點雲數據集,另外測量中的誤差也會產生稀疏的離群點,使效果不好,估計局部點雲特征(例如采樣點處法向量或曲率變化率)的運算復雜,這會導致錯誤的數值,反過來就會導致點雲配准等后期的處理失敗。
解決辦法:每個點的鄰域進行一個統計分析,並修剪掉一些不符合一定標准的點,稀疏離群點移除方法基於在輸入數據中對點到臨近點的距離分布的計算,對每一個點,計算它到它的所有臨近點的平均距離,,假設得到的結果是一個高斯分布,其形狀是由均值和標准差決定,平均距離在標准范圍之外的點,可以被定義為離群點並可從數據中去除。
建立文件statistical_removal.cpp
#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/filters/statistical_outlier_removal.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>); // 定義讀取對象 pcl::PCDReader reader; // 讀取點雲文件 reader.read<pcl::PointXYZ> ("table_scene_lms400.pcd", *cloud); std::cerr << "Cloud before filtering: " << std::endl; std::cerr << *cloud << std::endl; // 創建濾波器,對每個點分析的臨近點的個數設置為50 ,並將標准差的倍數設置為1 這意味着如果一 //個點的距離超出了平均距離一個標准差以上,則該點被標記為離群點,並將它移除,存儲起來 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); }
運行結果為:
( 2)使用參數化模型投影點雲
如何將點投影到一個參數化模型上(平面或者球體等),參數化模型通過一組參數來設定,對於平面來說使用其等式形式.在PCL中有特意存儲常見模型系數的數據結構
#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/ModelCoefficients.h> //模型系數頭文件 #include <pcl/filters/project_inliers.h> //投影濾波類頭文件 int main (int argc, char** argv) { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected (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 projection: " << 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; // 填充ModelCoefficients的值,使用ax+by+cz+d=0平面模型,其中 a=b=d=0,c=1 也就是X——Y平面 //定義模型系數對象,並填充對應的數據 pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ()); coefficients->values.resize (4); coefficients->values[0] = coefficients->values[1] = 0; coefficients->values[2] = 1.0; coefficients->values[3] = 0; // 創建ProjectInliers對象,使用ModelCoefficients作為投影對象的模型參數 pcl::ProjectInliers<pcl::PointXYZ> proj; //創建投影濾波對象 proj.setModelType (pcl::SACMODEL_PLANE); //設置對象對應的投影模型 proj.setInputCloud (cloud); //設置輸入點雲 proj.setModelCoefficients (coefficients); //設置模型對應的系數 proj.filter (*cloud_projected); //投影結果存儲 std::cerr << "Cloud after projection: " << std::endl; for (size_t i = 0; i < cloud_projected->points.size (); ++i) std::cerr << " " << cloud_projected->points[i].x << " " << cloud_projected->points[i].y << " " << cloud_projected->points[i].z << std::endl; return (0); }
編譯運行的結果如下
實驗結果可以看出投影前的Z軸都不為0 ,都是隨機產生的值,投影之后,打印的結果表明,xy的值都沒有改變,z都變為0
所以該投影濾波類就是輸入點雲和投影模型,輸出為投影到模型上之后的點雲。
未完待續**************************88888