PCL专栏目录及须知
注意:本方法可按颜色分割点云,适用于具有颜色流通性的点云,看文末结果展示。
1.基于RGB的区域生长分割
将具有颜色或(法线或者曲率【可选】)相似性的点云集合起来构成一簇聚类点。
算法逻辑同区域生长分割相似,只是阈值从法线/曲率变为了颜色。
(1)分割不同颜色点云块。
1)当前种子点P和距离范围在邻域点之间色差小于色差阀值的点簇视为一个聚类。
2)迭代进行步骤1),直到遍历完所有点云。
(2)合并聚类出的点云块,得到结果点云。
1)聚类之间的色差小于色差阀值和并为一个聚类,且当前聚类中点的数量小于聚类点数量的与最近的聚类合并在一起。
源码中所用色差计算公式:
1)点与点的颜色差异值:
diff = (p1.r - p2.r)*(p1.r - p2.r) + (p1.g - p2.g)*(p1.g - p2.g) + (p1.b - p2.b)*(p1.b - p2.b)
2)区域与区域的颜色差异值:
diffArea = 区域中所有点与点的颜色差异值累加和 / 区域中点对个数
2.使用场景
可用于分割具有颜色连通性的点云。如示例中的建筑物等。
3.关键函数
(1)距离阈值,用于聚类相邻点搜索
segmentation.setDistanceThreshold(2.0);
(2)两点颜色阈值
segmentation.setPointColorThreshold(8);
(3)两类区域颜色阈值
segmentation.setRegionColorThreshold(20);
4.完整代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/search/kdtree.h>
#include <pcl/common/angles.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/segmentation/region_growing_rgb.h>
#include <boost/thread/thread.hpp>
#define NorAndCuv
int main()
{
/****************基于颜色的区域生长分割********************/
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>); // 源点云
pcl::io::loadPCDFile("D:/code/csdn/data/unit.pcd", *cloud);
// 区域生长分割
// 法线和表面曲率估计
pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB>);
pcl::PointCloud <pcl::Normal>::Ptr normals(new pcl::PointCloud <pcl::Normal>);
pcl::NormalEstimationOMP<pcl::PointXYZRGB, pcl::Normal> n;
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setNumberOfThreads(6); // 设置线程数
n.setKSearch(20); // k近邻数目
n.compute(*normals);
// 基于颜色的区域生长分割
pcl::RegionGrowingRGB<pcl::PointXYZRGB> segmentation;
segmentation.setInputCloud(cloud);
segmentation.setMinClusterSize(500); // 一簇聚类最小点数
segmentation.setMaxClusterSize(1000000); // 一簇聚类最大点数
segmentation.setSearchMethod(tree);
segmentation.setDistanceThreshold(2.0); // 距离阈值,用于聚类相邻点搜索
segmentation.setPointColorThreshold(8); // 两点颜色阈值
segmentation.setRegionColorThreshold(20); // 两类区域颜色阈值
#ifdef NorAndCuv
segmentation.setSmoothModeFlag(true); // 设置是否使用法向量夹角,设置为true则需提供法线及法线夹角阈值
segmentation.setCurvatureTestFlag(true); // 设置是否使用曲率阈值,设置为true则需提供法线及法线夹角阈值
#else
segmentation.setSmoothModeFlag(false);
segmentation.setCurvatureTestFlag(false);
#endif // NorAndCuv
segmentation.setInputNormals(normals);
segmentation.setSmoothnessThreshold(pcl::deg2rad(3.0)); // 法向量夹角的阈值,超过这个夹角,即认为不在一个平面上
segmentation.setCurvatureThreshold(1.0); // 曲率的阈值,超过这个阈值,即认为不在一个平面上
std::vector <pcl::PointIndices> clustersIndices; // 聚类结果
segmentation.extract(clustersIndices);
// 提取聚类后点云
std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> clustreClouds;
for (size_t i = 0; i < clustersIndices.size(); i++)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTemp(new pcl::PointCloud<pcl::PointXYZ>);
pcl::copyPointCloud(*cloud, clustersIndices[i], *cloudTemp);
clustreClouds.push_back(cloudTemp);
}
/****************展示********************/
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("EuclideanClusterExtraction"));
for (size_t i = 0; i < clustreClouds.size(); i++)
{
pcl::RGB rgb = pcl::getRandomColor(0, 255);
viewer->addPointCloud<pcl::PointXYZ>(clustreClouds.at(i), pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>(clustreClouds.at(i), rgb.r, rgb.g, rgb.b), "clustreClouds" + i);
}
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return (0);
}
5.结果展示
(1)原始RGB点云
(2)分割后点云