PCL點雲分割:Conditional Euclidean Clustering

背景:

pcl官方教程:http://www.pointclouds.org/documentation/tutorials/conditional_euclidean_clustering.php#conditional-euclidean-clustering


1.使用感受

這個算法實際就是region growing segmentation的擴展版。你可以先看看我的另一個文章,關於region growing segmentation的:點擊打開鏈接。Conditional Euclidean Clustering實際就是放開那個蔓延的condition, 你可以寫一個自己的condition函數,而官方教程中提供了以下這幾種condition函數:enforceIntensitySimilarity, enforceCurvatureOrIntensitySimilarity 還有customRegionGrowing。而且一些閾值你需要在你的condition函數裏設置好,你的condition函數變成一個回調函數setConditionFunction的輸入。至於調參的感受和我的那篇region growing segmentation的文章裏說的一樣,調參起來還是相對容易的。主要需要調節蔓延時候用到的閾值。

如果你對你的場景裏的牆壁地板這些物體的點的數目有個先驗的信息,你可以在用戶setMaxClusterSize()來過濾掉他們。再用setMinClusterSize()來過濾一些噪音。還可以調用getRemoveCluster()來獲取這些被過濾掉的點雲。


2. 算法細節

爲了瞭解設置這些參數,讓我們來了解一下如何內部細節。從官方的介紹裏,算法的流程是寫的很仔細的。爲了讓你更直觀的明白,我概括的來說,就是從曲率小的面播種,從種子的位置出發,開始往四周搜索點,然後先對比點與點之間的距離是否小於距離閾值,如果是然後再比對點於點之間的法線/Intensity/Color/Curvature等的差距,如果差距小於閾值就視爲同一個cluster。如果一個cluster無法再蔓延,在剩下的點雲裏再播種,然後繼續重複以上步驟找新的cluster, 直到最後遍歷完畢。


3.調參

略。可以參考我的關於region growing segmentation的文章。

你需要在你自己的condition函數裏設置好閾值。例如:

bool
customRegionGrowing (const PointTypeFull& point_a, const PointTypeFull& point_b, float squared_distance)
{
  Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.getNormalVector3fMap (), point_b_normal = point_b.getNormalVector3fMap ();
  if (squared_distance < 10000)
  {
    if (fabs (point_a.intensity - point_b.intensity) < 8.0f)
      return (true);
    if (fabs (point_a_normal.dot (point_b_normal)) < 0.02)
      return (true);
  }
  else
  {
    if (fabs (point_a.intensity - point_b.intensity) < 3.0f)
      return (true);
  }
  return (false);
}

這裏的法線和intensity閾值8.0f, 0.02和3.0f就需要你根據實際調節。那麼距離閾值在哪調節?是在main函數裏用setClusterTolerance()來設置。那麼官方提供的customRegionGrowing裏面爲什麼還加一個

if (squared_distance < 10000)

經過我的實驗,我發現condition函數是首先經過setClusterTolerance()設置的距離閾值過濾後才運行的。像customRegionGrowing裏那樣再加一個距離閾值,其實是爲了根據距離來自動調節法線和intensity閾值。

可以參考點擊打開鏈接裏面的參數解釋。


4.跑數據集

本來我想跑自己的數據集的,但我發現我的數據集少了一個維度的信息:intensity。Intensity數據在我看看來就是,激光雷達發出激光打到物體後反射回來的激光強度。

那就跑跑他們的數據吧,同時在代碼最底部加了可視化:

#include <pcl/visualization/cloud_viewer.h> 
  pcl::visualization::CloudViewer viewer ("Cluster viewer");
  viewer.showCloud(cloud_out);
  while (!viewer.wasStopped ())
  {
  }

效果:

效果可以說是666了。在大範圍的室外場景裏,小至人,大至樓層,都被分割出來了。

但是,因爲它利用了intensity的信息,我就在想,沒了這一維度的信息,僅僅靠法線變化量做蔓延,效果還能這麼好嗎。所以我就把intensity變化量的閾值調到很大很大,基本多大的相鄰點intensity變化量都小於這個閾值,也就是說intensity不再影響分割了。然後再跑一次,效果如下:

這種情況下呢,效果就不好了。建築與地面融爲一體,建築樓層之間不能分開。只有那些本身與其他點雲不接壤的點雲被分割出來了。可能是法線變化量的閾值卡的不夠小,然後我就調小。最後發現無論調小還是調大都沒有提升效果。


5. 總結

Conditional Euclidean Clustering是一個能讓使用者自己定義condition函數的區域蔓延算法。官方的代碼在官方提供的數據集(<pcl::PointXYZI>格式的數據集)呈現的效果很好,但對於沒有intensity這個維度的數據集表現的不好。

發佈了39 篇原創文章 · 獲贊 34 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章