1.點雲的頻率
今天在閱讀分割有關的文獻時,驚喜的發現,點雲和圖像一樣,有可能也存在頻率的概念。但這個概念並未在文獻中出現也未被使用,謹在本博文中濫用一下“高頻”一詞。點雲表達的是三維空間中的一種信息,這種信息本身並沒有一一對應的函數值。故點雲本身並沒有在講訴一種變化的信號。但在抽象意義上,點雲必然是在表達某種信號的,雖然沒有明確的時間關系,但應該會存在某種空間關系(例如LiDar點雲)。我們可以人為的指定點雲空間中的一個點(例如Scan的重心或LiDar的“源”),基於此點來討論點雲在各個方向上所謂的頻率。
在傳統的信號處理中,高頻信號一般指信號變化快,低頻信號一般指信號變化緩慢。在圖像處理中,高低頻的概念被引申至不同方向上圖像灰度的變化,傅里葉變換可以用於提取圖像的周期成分濾除布紋噪聲。在點雲處理中,定義:點雲法線向量差為點雲所表達的信號。換言之,如果某處點雲曲率大,則點雲表達的是一個變化的信號。如果點雲曲率小,則其表達的是一個不變的信號。這和我們的直觀感受也是相近的,地面曲率小,它表達的信息量也小;人的五官部分曲率大,其表達了整個Scan中最大的信息量。
2.基於點雲頻率的濾波方法
雖然點雲頻率之前並沒有被討論,但使用頻率信息的思想已經被廣泛的應用在了各個方面,最著名的莫過於DoN算法。DoN算法被作者歸類於點雲分割算法中,但我認為並不准確,本質上DoN只是一種前處理,應該算是一種比較先進的點雲濾波算法。分割本質上還是由歐式分割算法完成的。DoN 是 Difference of Normal 的簡寫。算法的目的是在去除點雲低頻濾波,低頻信息(例如建築物牆面,地面)往往會對分割產生干擾,高頻信息(例如建築物窗框,路面障礙錐)往往尺度上很小,直接采用 基於臨近信息 的濾波器會將此類信息合並至牆面或路面中。所以DoN算法利用了多尺度空間的思想,算法如下:
- 在小尺度上計算點雲法線1
- 在大尺度上計算點雲法線2
- 法線1-法線2
- 濾去3中值較小的點
- 歐式分割
顯然,在小尺度上是可以對高頻信息進行檢測的,此算法可以很好的小尺度高頻信息。其在大規模點雲(如LiDar點雲)中優勢尤其明顯。
3.PCL對該算法的實現
算法運行過程可用圖表示為:
算法實現過程可表示為:
// Create a search tree, use KDTreee for non-organized data. pcl::search::Search<PointXYZRGB>::Ptr tree; if (cloud->isOrganized ()) { tree.reset (new pcl::search::OrganizedNeighbor<PointXYZRGB> ()); } else { tree.reset (new pcl::search::KdTree<PointXYZRGB> (false)); } // Set the input pointcloud for the search tree tree->setInputCloud (cloud); //生成法線估計器(OMP是並行計算,忽略) pcl::NormalEstimationOMP<PointXYZRGB, PointNormal> ne; ne.setInputCloud (cloud); ne.setSearchMethod (tree); //設定法線方向(要做差,同向很重要) ne.setViewPoint (std::numeric_limits<float>::max (), std::numeric_limits<float>::max (), std::numeric_limits<float>::max ()); //計算小尺度法線 pcl::PointCloud<PointNormal>::Ptr normals_large_scale (new pcl::PointCloud<PointNormal>); ne.setRadiusSearch (scale2); ne.compute (*normals_large_scale); //計算大尺度法線 pcl::PointCloud<PointNormal>::Ptr normals_large_scale (new pcl::PointCloud<PointNormal>); ne.setRadiusSearch (scale2); ne.compute (*normals_large_scale); //生成DoN分割器 pcl::DifferenceOfNormalsEstimation<PointXYZRGB, PointNormal, PointNormal> don; don.setInputCloud (cloud); don.setNormalScaleLarge (normals_large_scale); don.setNormalScaleSmall (normals_small_scale); //計算法線差 PointCloud<PointNormal>::Ptr doncloud (new pcl::PointCloud<PointNormal>); copyPointCloud<PointXYZRGB, PointNormal>(*cloud, *doncloud); don.computeFeature (*doncloud); //生成濾波條件:把法線差和閾值比 pcl::ConditionOr<PointNormal>::Ptr range_cond ( new pcl::ConditionOr<PointNormal> () ); range_cond->addComparison (pcl::FieldComparison<PointNormal>::ConstPtr ( new pcl::FieldComparison<PointNormal> ("curvature", pcl::ComparisonOps::GT, threshold)) ); //生成條件濾波器,輸入濾波條件和點雲 pcl::ConditionalRemoval<PointNormal> condrem (range_cond); condrem.setInputCloud (doncloud); //導出濾波結果 pcl::PointCloud<PointNormal>::Ptr doncloud_filtered (new pcl::PointCloud<PointNormal>); condrem.filter (*doncloud_filtered); //歐式聚類~~~(略)