欧式聚类算法原理
欧式聚类算法基于点之间的欧式距离来对点云进行聚类。其算法流程如下:
1、初始化两个空集,一个作为备选点的点集,一个作为聚类的结果集。
2、对于每个点,计算其与其他点之间的欧式距离。
3、如果点与其他点的欧式距离小于设定的阈值,则将其加入备选点的点集。
4、从备选点的点集中选择一个点作为种子点,将其加入聚类的结果集。
5、从备选点的点集中移除种子点,并将其与种子点距离小于设定的阈值的点加入聚类的结果集。
6、重复步骤5,直到备选点的点集为空。
7、重复步骤4至步骤6,直到所有点都被聚类。
通过欧式聚类算法,可以将点云数据根据其几何特征进行聚类,从而实现对点云的分割和分析。
示例代码
#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>//模型定义头文件
#include <pcl/sample_consensus/model_types.h>//随机参数估计方法头文件
#include <pcl/segmentation/sac_segmentation.h>//基于采样一致性分割的类的头文件
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/features/normal_3d.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/segmentation/conditional_euclidean_clustering.h>//条件欧式聚类
int main()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("./segmentTest.pcd", *cloud_in);
if (cloud_in->empty())
{
std::cout << "input cloud is empty";
return -1;
}
std::vector<pcl::PointIndices> clusters;
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZRGB>);
//Creating the KdTree object for the search method of the extraction
pcl::console::print_highlight("Segment by Euclidean Cluster Method!\n");
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
tree->setInputCloud(cloud_in);
//set parameters for EuclideanClusterExtraction
pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;
ec.setClusterTolerance(0.2);
ec.setMinClusterSize(500);
ec.setMaxClusterSize(5000);
ec.setSearchMethod(tree);
ec.setInputCloud(cloud_in);
ec.extract(clusters);
std::cout << "Clusters Number :" << clusters.size() << std::endl;
//color cloud for visualization
if (!clusters.empty()) {
srand(static_cast<unsigned int> (time(0)));
std::vector<unsigned char> colors;
for (int i_segment = 0; i_segment < clusters.size(); i_segment++) {
colors.push_back(static_cast<unsigned char> (rand() % 256));
colors.push_back(static_cast<unsigned char> (rand() % 256));
colors.push_back(static_cast<unsigned char> (rand() % 256));
}
cloud_out->width = cloud_in->width;
cloud_out->height = cloud_in->height;
cloud_out->is_dense = cloud_in->is_dense;
for (int i_point = 0; i_point < cloud_in->points.size(); i_point++) {
pcl::PointXYZRGB point;
point.x = *(cloud_in->points[i_point].data);
point.y = *(cloud_in->points[i_point].data + 1);
point.z = *(cloud_in->points[i_point].data + 2);
point.r = 50;
point.g = 50;
point.b = 50;
cloud_out->points.push_back(point);
}
std::vector<pcl::PointIndices>::const_iterator i_segment;
int next_color = 0;
for (i_segment = clusters.begin(); i_segment != clusters.end(); i_segment++) {
std::vector<int>::const_iterator i_point;
for (i_point = i_segment->indices.begin(); i_point != i_segment->indices.end(); i_point++) {
int index = *i_point;
cloud_out->points[index].r = colors[3 * next_color];
cloud_out->points[index].g = colors[3 * next_color + 1];
cloud_out->points[index].b = colors[3 * next_color + 2];
}
next_color++;
}
}
//可视化
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3d viewer"));
//左边窗口显示输入的点云
int v1(0);
viewer->createViewPort(0, 0, 0.5, 1, v1);
viewer->setBackgroundColor(0, 0, 0, v1);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_in(cloud_in, 255, 255, 255);
viewer->addPointCloud<pcl::PointXYZ>(cloud_in, color_in, "cloud_in", v1);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud_in", v1);
//右边的窗口显示分割后的点云
int v2(0);
viewer->createViewPort(0.5, 0, 1, 1, v2);
viewer->setBackgroundColor(0, 0, 0, v2);
viewer->addPointCloud<pcl::PointXYZRGB>(cloud_out, "cloud_out", v2);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud_out", v2);
pcl::io::savePCDFile("./segmentResult.pcd",*cloud_out);
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
}
return 0;
}