PCL区域生长分割算法

10 篇文章 0 订阅
8 篇文章 0 订阅

1.介绍

本项目使用ubuntu16.04,ubuntu的其他版本应该也是可以的;

点云库PCL某某这本书其实是以官方的英文手册翻译成的,英文链接见以下地址:

https://pcl.readthedocs.io/projects/tutorials/en/latest/region_growing_segmentation.html#region-growing-segmentation

但是想做相关的算法开发,只看书中的内容还是不够明白,只能找来官方文档读了,以下基本是翻译再加一些我自己的理解,如果有不清楚的还是建议自己去啃英文说明。

使用pcl:: regiong类实现区域增长算法。该算法的目的是在光滑性约束条件下合并相近的点,实现区域的分割,适用于不同平/曲面的分割。该算法的输出是不同曲面单元的集合,其中每个单元可以认为是一个光滑表面的点的总成。该算法基于点之间的法线角度比较完成划分。

2.算法实现

因为生长点是根据曲率进行寻找的,选择曲率最小的点,所以首先根据曲率将点进行分类。由于选择的曲率是最小的点,所以生长点附近一般均为平面或者相对较平坦的面。

将生长点添加进种子的集合。然后对种子里的每个生长点进行生长运算。

种子点的运算过程如下:

  1. 测试每个临近点与种子点法向量的夹角,如果角度小于临界值,则添加进当前的种子区域;
  2. 测试每个临近点的曲率,如果曲率小于临界值,则将该点添加进当前区域的种子列表;
  3. 第三步的意思其实是在找到曲率小于临界值的点后添加进种子列表,原来的种子点就要删除了,但是这一个地方有一个问题,是否需要原有的种子周围临近点全部搜索完毕,这个应该是要搜索完毕的;但是如果发现多个曲率小于临界值的点,是否需要都添加?我的理解是都需要添加;

注:曲面的一阶微分的分量包括法向量,曲面的二阶微分的分量包括曲率;从某种意义上说法向量的夹角是类似与曲率的。但是为什么区域增长算法通过夹角生成区域,而通过曲率生成种子列表?这个后面会有描述。

待种子列表中为空时,说明该区域生长完毕;

这里贴出算法伪代码:

 

 

关于伪代码这里就不解释了,只要花时间认真去看,相信是可以理解的。其中的\是去除的意思。

代码如下:

#include <iostream>
#include <vector>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/search/search.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/passthrough.h>
#include <pcl/segmentation/region_growing.h>

int
main (int argc, char** argv)
{
//加载pcd文件
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  if ( pcl::io::loadPCDFile <pcl::PointXYZ> ("region_growing_tutorial.pcd", *cloud) == -1)
  {
    std::cout << "Cloud reading failed." << std::endl;
    return (-1);
  }
//通过NormalEstimation类计算法线
  pcl::search::Search<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
  pcl::PointCloud <pcl::Normal>::Ptr normals (new pcl::PointCloud <pcl::Normal>);
  pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator;
  normal_estimator.setSearchMethod (tree);
  normal_estimator.setInputCloud (cloud);
  normal_estimator.setKSearch (50);
  normal_estimator.compute (*normals);
//在z轴方向滤波,剔除0~1.0范围之外的点
// PassThrough是滤波类,得到的indices是各点的索引值
  pcl::IndicesPtr indices (new std::vector <int>);
  pcl::PassThrough<pcl::PointXYZ> pass;
  pass.setInputCloud (cloud);
  pass.setFilterFieldName ("z");
  pass.setFilterLimits (0.0, 1.0);
  pass.filter (*indices);
//设置一个簇中包含点的最大值门限与最小值门限,通过区域生长算法生成的所有的簇,小于50个点或者大//于1000000个点都被丢弃,不包含在簇内
  pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;
  reg.setMinClusterSize (50);
  reg.setMaxClusterSize (1000000);
//算法需要k近邻搜索,搜索近邻点的数量限制为30
  reg.setSearchMethod (tree);
  reg.setNumberOfNeighbours (30);
  reg.setInputCloud (cloud);
  //reg.setIndices (indices);
  reg.setInputNormals (normals);
//此处两个初始化的值是最关键的,直接影响分割结果的好坏;
// setSmoothnessThreshold是法线的夹角门限
// setCurvatureThreshold是曲率门限,对于满足发现夹角的点,如果也满足曲率门限
//则将会被添加进种子列表内;
  reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI);
  reg.setCurvatureThreshold (1.0);
//下面执行区域生长算法,返回一个簇的数组
  std::vector <pcl::PointIndices> clusters;
  reg.extract (clusters);
//显示一些信息
  std::cout << "Number of clusters is equal to " << clusters.size () << std::endl;
  std::cout << "First cluster has " << clusters[0].indices.size () << " points." << std::endl;
  std::cout << "These are the indices of the points of the initial" <<
    std::endl << "cloud that belong to the first cluster:" << std::endl;
  int counter = 0;
  while (counter < clusters[0].indices.size ())
  {
    std::cout << clusters[0].indices[counter] << ", ";
    counter++;
    if (counter % 10 == 0)
      std::cout << std::endl;
  }
  std::cout << std::endl;
//显示分割后的图像
  pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud ();
  pcl::visualization::CloudViewer viewer ("Cluster viewer");
  viewer.showCloud(colored_cloud);
  while (!viewer.wasStopped ())
  {
  }
//
  return (0);
}

需要将region_growing_tutorial.pcd替换成你想分析的pcd文件,或者自己去网站下载相应的pcd文件;

3.编译与执行

CMakeList.txt内容如下:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(region_growing_segmentation)

find_package(PCL 1.5 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (region_growing_segmentation region_growing_segmentation.cpp)
target_link_libraries (region_growing_segmentation ${PCL_LIBRARIES})

将CMakeList.txt与cpp文件放在同一个文件夹,然后依次执行

cmake CMakeList.txt

make

./region_growing_segmentation

执行之后就显示出了分割后的图,不同区域通过不同颜色分割,其中的红色点是为分区的点,

  reg.setMinClusterSize (50);

  reg.setMaxClusterSize (1000000);

红色点区域上述规划的小于50或者大于1000000的情况

4.问题总结

关于依据曲率选择种子的问题

根据官方的文档可以看出,是在通过法线夹角筛选后的点中选择满足曲率要求的种子点的。同时,种子点也是加进种子列表的,其原来的点并没有删除,只有当原来的点的规定半径区域的点运算完毕后才会将其删除,这一点官方文档描述的不是很清楚,但是伪代码写的是对的。

关于初始种子的选取问题

另一篇文章有描述,是将所有点按照曲率值进行排序,找到最小曲率点,将其添加到种子点集,链接如下:

https://cloud.tencent.com/developer/article/1475904

 

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值