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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章