首先在获取的大场景范围下,点云中不可避免地存在大量的噪声信息,为了防止这些噪声点在对点云数据进行特征提取时造成干扰,对点云数据进行预处理排除噪声干扰。噪声通常是个数较少且散乱分布的离群点,以前尝试过先对点云进行半径滤波,直通滤波之类的噪声以及非目标点的提出,再使用聚类的方法进行目标物体分割。但是本次想直接尝试一下在有点云数据的基础上直接进行聚类。根据激光扫描的特点,激光扫描数据的聚类算法的整体思路为:如果当前扫描点与前一个扫描点的距离在预设阈值范围内,则当前点被聚到前一个扫描点的类中;否则,把当前扫描点设置为新的聚类种子,根据预设阈值判断下一个扫描点是否与该种子属于同一类。重复以上步骤,直到所有的点都被聚到不同的类中。通过聚类,可以减少物体边界点对特征点检测的影响,同时,对于点云中不规则的离散点,往往其所在类的尺寸较小,很容易将其滤掉。由于特征提取中常使用的搜索算法在小范围内的计算效率也远高于整体范围,因此点云聚类也有助于加速特征提取。
//欧式距离聚类,实现点云分割
#include "pch.h"
#include <pcl/ModelCoefficients.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>
#include <iostream>
using namespace std;
int
main(int argc, char** argv)
{
// 申明存储点云的对象.
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
//读取Pcd文件
if (pcl::io::loadPCDFile<pcl::PointXYZ>("C://Users//HEHE//Desktop//flange_filter3_Radius_filter2.pcd", *cloud) == -1)
{
PCL_ERROR("Cloudn't read file!");
return -1;
} cout << "there are " << cloud->points.size()<<" points before filtering." << endl;
// 建立kd-tree对象用来搜索 .
pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
kdtree->setInputCloud(cloud);
// Euclidean 聚类对象.
pcl::EuclideanClusterExtraction<pcl::PointXYZ> clustering;//类EuclideanClusterExtraction是基于欧式距离进行聚类分割的类
clustering.setClusterTolerance(4.0);//设置在欧氏空间中所使用的搜索半径设置的过小可能导致聚类被划分到几个集群,设置的过大可能将聚类进行联通
clustering.setMinClusterSize(100);// 设置聚类包含的的最小点数目
clustering.setMaxClusterSize(25000); //设置聚类包含的的最大点数目
clustering.setSearchMethod(kdtree);//类的关键成员函数
clustering.setInputCloud(cloud);//指定输入的点云进行聚类分割
std::vector<pcl::PointIndices> clusters;// cluster存储点云聚类分割的结果。PointIndices存储对应点集的索引
clustering.extract(clusters);
// For every cluster...
int currentClusterNum = 1;
for (std::vector<pcl::PointIndices>::const_iterator i = clusters.begin(); i != clusters.end(); ++i)
{
//添加所有的点云到一个新的点云中
pcl::PointCloud<pcl::PointXYZ>::Ptr cluster(new pcl::PointCloud<pcl::PointXYZ>);
for (std::vector<int>::const_iterator point = i->indices.begin(); point != i->indices.end(); point++)
cluster->points.push_back(cloud->points[*point]);
cluster->width = cluster->points.size();
cluster->height = 1;
cluster->is_dense = true;
// 保存
if (cluster->points.size() <= 0)
break;
std::cout << "Cluster " << currentClusterNum << " has " << cluster->points.size() << " points." << std::endl;
std::string fileName = "C://Users//HEHE//Desktop//cluster" + boost::to_string(currentClusterNum) + ".pcd";
pcl::io::savePCDFileASCII(fileName, *cluster);
currentClusterNum++;
}
}