在本文中,我们将学习如何使用pcl:: regiongrow类中实现的区域增长算法。所述算法的目的是将在平滑性约束方面足够接近的点分类。因此,该算法的输出是聚类的集合,其中每个聚类都是一组点,被认为是同一光滑曲面的一部分。该算法的工作是基于点法线之间角度的比较。
让我们来看看该算法是如何工作的。
1.首先,它根据它们的曲率值对点进行分类。之所以要这样做是因为这个区域从曲率最小的点开始增长。这是因为曲率最小的点位于平坦的区域(从最平坦的区域增长可以减少分割总数)。
2.选中的点被添加到名为seeds(增长种子集合)的集合中。
3.对于每个种子点,算法找到它的邻近点。
a.每个邻居都被计算它的法线和当前种子点的法线之间的角度。如果角度小于阈值,则将当前点添加到当前种子所在区域。
b.然后对每个邻域进行曲率值测试。如果曲率小于阈值,则将此点添加到种子集合中作为新种子。
c.从种子集合中删除当前的种子。
4.如果种子集变成空的,这意味着算法扩大了区域,这个过程从头开始重复迭代,直到种子集合为空。
#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/filter_indices.h> // for pcl::removeNaNFromPointCloud
#include <pcl/segmentation/region_growing.h>
int
main ()
{
// 读取点云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);
}
// 建立搜索KD树
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); // 搜索方法为kd树走索
normal_estimator.setInputCloud (cloud); // 填入点云
normal_estimator.setKSearch (50); // 设置搜索范围
normal_estimator.compute (*normals); // 将法相保存在normals
pcl::IndicesPtr indices (new std::vector <int>);
pcl::removeNaNFromPointCloud(*cloud, *indices); // 对点云建立索引
pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg; // 区域增长类
reg.setMinClusterSize (50); // 设置最小的集合点数
reg.setMaxClusterSize (1000000); // 设置最大集合点数
reg.setSearchMethod (tree); // 设置kd树搜索方法
reg.setNumberOfNeighbours (30); // 设置每次邻域搜索数(影响计算速度)
reg.setInputCloud (cloud); // 设置输入点云
reg.setIndices (indices); // 设置输入的索引
reg.setInputNormals (normals); // 设置输入法向
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;
std::size_t 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);
}
运行效果如下:
【博主简介】
斯坦福的兔子,男,天津大学工学硕士。毕业至今从事光学三维成像及点云处理相关工作。因工作中使用的三维处理库为公司内部库,不具有普遍适用性,遂自学开源PCL库及其相关数学知识以备使用。谨此将自学过程与君共享。
博主才疏学浅,尚不具有指导能力,如有问题还请各位在评论处留言供大家共同讨论。’