PCL教程-点云分割之区域生长分割算法

PCL教程-点云分割之区域⽣长分割算法原⽂链接:
本教程使⽤到的点云数据:
在本篇教程中,我们将学习如何使⽤由pcl::RegionGrowing类实现的区域⽣长算法。该算法的⽬的是合并在平滑约束条件下⾜够接近的点。因此,该算法的输出数据结构是由聚类组成的数组,其中每个聚类都是被认为是同⼀光滑表⾯的⼀部分的点的集合。该算法的⼯作原理(光滑度的计算)是基于两点法线之间的⾓度⽐较。
⽬录
基本原理
⾸先,它根据点的曲率值对点进⾏排序。需要这样做是因为区域从曲率最⼩的点开始增长。这样做的原因是曲率最⼩的点位于平坦区域(从最平坦区域⽣长可以减少段的总数)。
我们有了分类过的云。直到云中没有未标记点时,算法选取曲率值最⼩的点,开始区域的增长。这个过程如下所⽰:选中的点被添加到名为种⼦的集合中。
对于每⼀个种⼦点,到它的邻近点:
算出每个相邻点的法线和当前种⼦点的法线之间的⾓度,如果⾓度⼩于阈值,则将当前点添加到当前区域。
然后计算每个邻居点的曲率值,如果曲率⼩于阈值,那么这个点被添加到种⼦中。
将当前的种⼦从种⼦列表中移除。
如果种⼦列表变成空的,这意味着该区域⽣长已完成,继续重复上述过程。
区域⽣长算法: 将具有相似性的点云集合起来构成区域。木纤维袜子
⾸先对每个需要分割的区域出⼀个种⼦点作为⽣长的起点,然后将种⼦点周围邻域中与种⼦有相同或 相似性质的点合并到种⼦像素所在的区域中。⽽新的点继续作为种⼦向四周⽣长,直到再没有满⾜条件 的像素可以包括进来,⼀个区域就⽣长⽽成了。
算法流程:
1. 计算法线normal 和曲率curvatures,依据曲率升序 排序;
2. 选择曲率最低的为初始种⼦点,种⼦周围的临近点和 种⼦点云相⽐较;
3. 法线的⽅向是否⾜够相近(法线夹⾓⾜够 r p y), 法线夹⾓阈值;
4. 曲率是否⾜够⼩(表⾯处在同⼀个弯曲程度),区域 差值阈值;
5. 如果满⾜2,3则该点可⽤做种⼦点;
6. 如果只满⾜2,则归类⽽不做种⼦;
算法伪代码
输⼊
Point cloud =
Point normals =
Points curvatures =
Neighbour finding function
Curvature threshold
Angle threshold
初始化
区域列表置为空: Region list
可⽤的点云列表:Available points list
算法实现
程序代码
#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> #include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
void PrintMemoryInfo( )
{
HANDLE hProcess;
PROCESS_MEMORY_COUNTERS pmc;
hProcess=GetCurrentProcess();
printf( "\nProcess ID: %u\n", hProcess );
/
/ Print information about the memory usage of the process.
//输出进程使⽤的内存信息
if (NULL == hProcess)
return;
if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) )
{
printf( "\tPageFaultCount: 0x%08X\n", pmc.PageFaultCount );
printf( "\tPeakWorkingSetSize: 0x%08X\n",
pmc.PeakWorkingSetSize );
printf( "\tWorkingSetSize: 0x%08X\n", pmc.WorkingSetSize );
printf( "\tQuotaPeakPagedPoolUsage: 0x%08X\n",
pmc.QuotaPeakPagedPoolUsage );
printf( "\tQuotaPagedPoolUsage: 0x%08X\n",
pmc.QuotaPagedPoolUsage );
printf( "\tQuotaPeakNonPagedPoolUsage: 0x%08X\n",
pmc.QuotaPeakNonPagedPoolUsage );
printf( "\tQuotaNonPagedPoolUsage: 0x%08X\n",
pmc.QuotaNonPagedPoolUsage );
printf( "\tPagefileUsage: 0x%08X\n", pmc.PagefileUsage );
printf( "\tPeakPagefileUsage: 0x%08X\n",
pmc.PeakPagefileUsage );
}
CloseHandle( hProcess );
}
using namespace pcl::console;
int
main (int argc, char** argv)
{
if(argc<2)
{
std::cout<<".exe xx.pcd -kn 50 -bc 0 -fc 10.0 -nc 0 -st 30 -ct 0.05"<<endl;
return 0;
}//如果输⼊参数⼩于1个,输出提⽰
time_t start,end,diff[5],option;
start = time(0);
int KN_normal=50; //设置默认输⼊参数
bool Bool_Cuting=false;//设置默认输⼊参数
float far_cuting=10,near_cuting=0,SmoothnessThreshold=30.0,CurvatureThreshold=0.05;//设置默认输⼊参数
交换目录parse_argument (argc, argv, "-kn", KN_normal);
parse_argument (argc, argv, "-bc", Bool_Cuting);
parse_argument (argc, argv, "-fc", far_cuting);
parse_argument (argc, argv, "-nc", near_cuting);
parse_argument (argc, argv, "-st", SmoothnessThreshold);
parse_argument (argc, argv, "-ct", CurvatureThreshold);//设置输⼊参数⽅式
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[1], *cloud) == -1)
{
std::cout << "Cloud reading failed." << std::endl;
return (-1);
}// 加载输⼊点云数据
end = time(0);
diff[0] = difftime (end, start);
PCL_INFO ("\Loading pcd file takes(seconds): %d\n", diff[0]);
//Noraml estimation step(1 parameter)
pcl::search::Search<pcl::PointXYZ>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZ
> > (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 (KN_normal);// 设置⽤于法向量估计的k近邻数⽬
pute (*normals);//计算并输出法向量
end = time(0);
diff[1] = difftime (end, start)-diff[0];
PCL_INFO ("\Estimating normal takes(seconds): %d\n", diff[1]);
//optional step: cutting the part are far from the orignal point in Z direction.2 parameters
pcl::IndicesPtr indices (new std::vector <int>);//创建⼀组索引
if(Bool_Cuting)//判断是否需要直通滤波
{
pcl::PassThrough<pcl::PointXYZ> pass;//设置直通滤波器对象
pass.setInputCloud (cloud);//设置输⼊点云
pass.setFilterFieldName ("z");//设置指定过滤的维度
pass.setFilterLimits (near_cuting, far_cuting);//设置指定纬度过滤的范围
pass.filter (*indices);//执⾏滤波,保存滤波结果在上述索引中
}
// 区域⽣长算法的5个参数
pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;//创建区域⽣长分割对象
reg.setMinClusterSize (50);//设置⼀个聚类需要的最⼩点数
reg.setMaxClusterSize (1000000);//设置⼀个聚类需要的最⼤点数
reg.setSearchMethod (tree);//设置搜索⽅法
reg.setNumberOfNeighbours (30);//设置搜索的临近点数⽬
reg.setInputCloud (cloud);//设置输⼊点云
if(Bool_Cuting)reg.setIndices (indices);//通过输⼊参数设置,确定是否输⼊点云索引
reg.setInputNormals (normals);//设置输⼊点云的法向量
reg.setSmoothnessThreshold (SmoothnessThreshold / 180.0 * M_PI);//设置平滑阈值
reg.setCurvatureThreshold (CurvatureThreshold);//设置曲率阈值
双模具std::vector <pcl::PointIndices> clusters;
end = time(0);
diff[2] = difftime (end, start)-diff[0]-diff[1];
PCL_INFO ("\Region growing takes(seconds): %d\n", diff[2]);
std::cout << "Number of clusters is equal to " << clusters.size () << std::endl;//输出聚类的数量
std::cout << "First cluster has " << clusters[0].indices.size () << " points." << 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;
*/
PrintMemoryInfo();
pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = ColoredCloud ();
pcl::visualization::CloudViewer viewer ("区域增长分割⽅法");
viewer.showCloud(colored_cloud);
while (!viewer.wasStopped ())
{
}//进⾏可视化
return (0);
}
代码分析
然后设置最⼩和最⼤集⼤⼩。这意味着在分割完成后,所有点⼩于最⼩值(或⼤于最⼤值)的聚类将被丢弃。最⼩值和最⼤值的默认值分别为1和“尽可能多”。
算法在内部结构中需要K最近邻搜索,所以这⾥是提供搜索⽅法并设置邻居数量的地⽅。之后,它接收到必须分割的点云、点下标和法线。
pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;
reg.setMinClusterSize (50);
reg.setMaxClusterSize (1000000);
reg.setSearchMethod (tree);
reg.setNumberOfNeighbours (30);
reg.setInputCloud (cloud);
//reg.setIndices (indices);智能定位
reg.setInputNormals (normals);
这两⾏是算法初始化中最重要的部分,因为它们负责上述的平滑约束。第⼀种⽅法以弧度为单位设置⾓度,作为法向偏差的允许范围。如果点之间的法线偏差⼩于平滑阈值,那么建议它们在同⼀簇中(新的点-被测试的点-将被添加到簇中)。第⼆个是曲率阈值。如果两点有⼀个⼩的法向偏差,那么它们之间的曲率差被测试。
reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI);
reg.setCurvatureThreshold (1.0);
RegionGrowing类提供了⼀个返回彩⾊云的⽅法,其中每个集都有⾃⼰的颜⾊。因此,在这部分代码中,实例化
pcl::visualization::CloudViewer以查看分割的结果——相同颜⾊的云
pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = ColoredCloud ();
pcl::visualization::CloudViewer viewer ("Cluster viewer");
viewer.showCloud(colored_cloud);
while (!viewer.wasStopped ())
{
}
return (0);
}
实验结果
原始点云:

本文发布于:2024-09-22 07:19:17,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/1/102780.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:区域   设置   算法
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议