EuclideanClusterExtraction这个名字起的很奇怪,欧式距离聚类这个该如何理解?欧式距离只是一种距离测度的方法呀!有了一个Cluster在里面,我以为是某一种聚类算法,层次聚类?k-NN聚类?K-Means?还是模糊聚类?感觉很奇怪,看下代码吧。

找一个实例cluster_extraction.cpp的main入口函数。

找到computer函数,该方法中定义了一个pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;对象,接着就是参数赋值。

具体的算法执行在ec.extract (cluster_indices)中。因此进入EuclideanClusterExtraction查看具体的方法。

 void compute (const pcl::PCLPointCloud2::ConstPtr &input, std::vector<pcl::PCLPointCloud2::Ptr> &output,
int min, int max, double tolerance)
{
// Convert data to PointCloud<T>
PointCloud<pcl::PointXYZ>::Ptr xyz (new PointCloud<pcl::PointXYZ>);
fromPCLPointCloud2 (*input, *xyz); // Estimate
TicToc tt;
tt.tic (); print_highlight (stderr, "Computing "); // Creating the KdTree object for the search method of the extraction
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
tree->setInputCloud (xyz); std::vector<pcl::PointIndices> cluster_indices;
pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;
ec.setClusterTolerance (tolerance);
ec.setMinClusterSize (min);
ec.setMaxClusterSize (max);
ec.setSearchMethod (tree);
ec.setInputCloud (xyz);
ec.extract (cluster_indices); print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", cluster_indices.size ()); print_info (" clusters]\n"); output.reserve (cluster_indices.size ());
for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
{
pcl::ExtractIndices<pcl::PCLPointCloud2> extract;
extract.setInputCloud (input);
extract.setIndices (boost::make_shared<const pcl::PointIndices> (*it));
pcl::PCLPointCloud2::Ptr out (new pcl::PCLPointCloud2);
extract.filter (*out);
output.push_back (out);
}
}

可以在pcl_segmentation项目下的extract_clusters.h文件中查看EuclideanClusterExtraction的定义,可知这是一个模板类。

template <typename PointT> class EuclideanClusterExtraction: public PCLBase<PointT>

实现文件在项目下的extract_clusters.hpp中,(还有一个extract_clusters.cpp文件),查看其中的extract方法:

 template <typename PointT> void pcl::EuclideanClusterExtraction<PointT>::extract (std::vector<PointIndices> &clusters)
{
if (!initCompute () ||
(input_ != && input_->points.empty ()) ||
(indices_ != && indices_->empty ()))
{
clusters.clear ();
return;
} // Initialize the spatial locator
if (!tree_)
{
if (input_->isOrganized ())
tree_.reset (new pcl::search::OrganizedNeighbor<PointT> ());
else
tree_.reset (new pcl::search::KdTree<PointT> (false));
} // Send the input dataset to the spatial locator
tree_->setInputCloud (input_, indices_);
extractEuclideanClusters (*input_, *indices_, tree_, static_cast<float> (cluster_tolerance_), clusters, min_pts_per_cluster_, max_pts_per_cluster_);

//tree_->setInputCloud (input_);
//extractEuclideanClusters (*input_, tree_, cluster_tolerance_, clusters, min_pts_per_cluster_, max_pts_per_cluster_); // Sort the clusters based on their size (largest one first)
std::sort (clusters.rbegin (), clusters.rend (), comparePointClusters); deinitCompute ();
}

注意在extract_clusters.h中定义了四个

  template <typename PointT> void
extractEuclideanClusters (
const PointCloud<PointT> &cloud, const boost::shared_ptr<search::Search<PointT> > &tree,
float tolerance, std::vector<PointIndices> &clusters,
unsigned int min_pts_per_cluster = , unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ());
 template <typename PointT> void
extractEuclideanClusters (
const PointCloud<PointT> &cloud, const std::vector<int> &indices,
const boost::shared_ptr<search::Search<PointT> > &tree, float tolerance, std::vector<PointIndices> &clusters,
unsigned int min_pts_per_cluster = , unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ());
  template <typename PointT, typename Normal> void
extractEuclideanClusters (
const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
float tolerance, const boost::shared_ptr<KdTree<PointT> > &tree,
std::vector<PointIndices> &clusters, double eps_angle,
unsigned int min_pts_per_cluster = ,
unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())
  template <typename PointT, typename Normal>
void extractEuclideanClusters (
const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
const std::vector<int> &indices, const boost::shared_ptr<KdTree<PointT> > &tree,
float tolerance, std::vector<PointIndices> &clusters, double eps_angle,
unsigned int min_pts_per_cluster = ,
unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())

前两个的方法实现在文件extract_clusters.hpp中,后两个直接在头文件中就以内联函数的形式实现了,两个大同小异。择其中第一个加点注释,发现其实是采用的区域生长算法实现的分割。理解错误了,区域生长需要种子点,这里应该叫层次聚类方法。

  template <typename PointT, typename Normal> void
extractEuclideanClusters (
const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
float tolerance, const boost::shared_ptr<KdTree<PointT> > &tree,
std::vector<PointIndices> &clusters, double eps_angle,
unsigned int min_pts_per_cluster = ,
unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())
{
if (tree->getInputCloud ()->points.size () != cloud.points.size ())
{
PCL_ERROR ("[pcl::extractEuclideanClusters] Tree built for a different point cloud dataset (%lu) than the input cloud (%lu)!\n", tree->getInputCloud ()->points.size (), cloud.points.size ());
return;
}
if (cloud.points.size () != normals.points.size ())
{
PCL_ERROR ("[pcl::extractEuclideanClusters] Number of points in the input point cloud (%lu) different than normals (%lu)!\n", cloud.points.size (), normals.points.size ());
return;
} // Create a bool vector of processed point indices, and initialize it to false
std::vector<bool> processed (cloud.points.size (), false); std::vector<int> nn_indices;
std::vector<float> nn_distances;
// Process all points in the indices vector
for (size_t i = ; i < cloud.points.size (); ++i)//遍历点云中的每一个点
{
if (processed[i])//如果该点已经处理则跳过
continue; std::vector<unsigned int> seed_queue;//定义一个种子队列
int sq_idx = ;
seed_queue.push_back (static_cast<int> (i));//加入一个种子 processed[i] = true; while (sq_idx < static_cast<int> (seed_queue.size ()))//遍历每一个种子
{
// Search for sq_idx
if (!tree->radiusSearch (seed_queue[sq_idx], tolerance, nn_indices, nn_distances))//没找到近邻点就继续
{
sq_idx++;
continue;
} for (size_t j = ; j < nn_indices.size (); ++j) // nn_indices[0] should be sq_idx
{
if (processed[nn_indices[j]]) // Has this point been processed before ?种子点的近邻点中如果已经处理就跳出此次循环继续
continue; //processed[nn_indices[j]] = true;
// [-1;1]
double dot_p = normals.points[i].normal[] * normals.points[nn_indices[j]].normal[] +
normals.points[i].normal[] * normals.points[nn_indices[j]].normal[] +
normals.points[i].normal[] * normals.points[nn_indices[j]].normal[];
if ( fabs (acos (dot_p)) < eps_angle ) //根据内积求夹角,法向量都是单位向量,种子点和近邻点的法向量夹角小于阈值,
{
processed[nn_indices[j]] = true;
seed_queue.push_back (nn_indices[j]);//将此种子点的临近点作为新的种子点。
}
} sq_idx++;
} // If this queue is satisfactory, add to the clusters
if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster)
{
pcl::PointIndices r;
r.indices.resize (seed_queue.size ());
for (size_t j = ; j < seed_queue.size (); ++j)
r.indices[j] = seed_queue[j]; // These two lines should not be needed: (can anyone confirm?) -FF
std::sort (r.indices.begin (), r.indices.end ());
r.indices.erase (std::unique (r.indices.begin (), r.indices.end ()), r.indices.end ()); r.header = cloud.header;
clusters.push_back (r); // We could avoid a copy by working directly in the vector
}
}
}

[PCL]3 欧式距离分类EuclideanClusterExtraction的更多相关文章

  1. 剑指Offer——网易笔试之不要二——欧式距离的典型应用

    剑指Offer--网易笔试之不要二--欧式距离的典型应用 前言 欧几里得度量(euclidean metric)(也称欧氏距离)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的 ...

  2. 机器学习进阶-疲劳检测(眨眼检测) 1.dist.eculidean(计算两个点的欧式距离) 2.dlib.get_frontal_face_detector(脸部位置检测器) 3.dlib.shape_predictor(脸部特征位置检测器) 4.Orderdict(构造有序的字典)

    1.dist.eculidean(A, B) # 求出A和B点的欧式距离 参数说明:A,B表示位置信息 2.dlib.get_frontal_face_detector()表示脸部位置检测器 3.dl ...

  3. l2-loss,l2正则化,l2范数,欧式距离

    欧式距离: l2范数: l2正则化: l2-loss(也叫平方损失函数): http://openaccess.thecvf.com/content_cvpr_2017/papers/Li_Mimic ...

  4. PIE SDK 距离分类和最大似然分类

       1.算法功能简介 监督分类,也叫训练场地法.训练分类法,是遥感图像分类的一种,用被确认类别的样本像元去识别其他未知类别像元的过程.监督分类算法有平行算法.平行六面体法.最小距离法.最大似然法.马 ...

  5. cos距离与欧式距离

    1. 欧氏距离(EuclideanDistance) 欧氏距离是最易于理解的一种距离计算方法,源自欧氏空间中两点间的距离公式. (1)二维平面上两点a(x1,y1)与b(x2,y2)间的欧氏距离: ( ...

  6. Acwing 社交距离 分类讨论+贪心

    一种新型疾病,COWVID-19,开始在全世界的奶牛之间传播. Farmer John 正在采取尽可能多的预防措施来防止他的牛群被感染. Farmer John 的牛棚是一个狭长的建筑物,有一排共 N ...

  7. 两个向量之间的欧式距离及radial-basis-functions(RBF)

    template <class DataType1, class DataType2>double EuclideanDistance(std::vector<DataType1&g ...

  8. PCL中分割_欧式分割(1)

    基于欧式距离的分割和基于区域生长的分割本质上都是用区分邻里关系远近来完成的.由于点云数据提供了更高维度的数据,故有很多信息可以提取获得.欧几里得算法使用邻居之间距离作为判定标准,而区域生长算法则利用了 ...

  9. PCL—低层次视觉—点云分割(邻近信息)

    分割给人最直观的影响大概就是邻居和我不一样.比如某条界线这边是中华文明,界线那边是西方文,最简单的分割方式就是在边界上找些居民问:"小伙子,你到底能不能上油管啊?”.然后把能上油管的居民坐标 ...

随机推荐

  1. yii2 debug工具条不出现

    UrlManger美化后,debug工具条不出现,禁用UrlManager出现

  2. C#安全API

    Bouncycastle库C#版 官网地址为:http://www.bouncycastle.org/csharp/. http://blog.csdn.net/popozhu/article/det ...

  3. Linux 计划任务 Crontab 笔记与总结(2)Crontab 的基本组成与配置

    [Crontab 的基本组成] ① 系统服务 CROND:每分钟都会从配置文件刷新定时任务 ② 配置文件 :文件方式设置定时任务 ③ 配置工具 crontab:用途调整定时任务 [配置文件的配置文件格 ...

  4. 浏览器 user-agent 字符串的故事

    你是否好奇标识浏览器身份的User-Agent,为什么每个浏览器都有Mozilla字样? 故事还得从头说起,最初的主角叫NCSA Mosaic,简称Mosaic(马赛克),是1992年末位于伊利诺伊大 ...

  5. 修改linux系统时间的方法(date命令)

    修改linux系统时间的方法(date命令) 来源:互联网 作者:佚名 时间:11-18 23:22:27 [大 中 小] date命令不仅可以显示系统当前时间,还可以用它来修改系统时间,下面简单的介 ...

  6. 设计模式学习系列9 外观模式Facade

    1.概述 自己卖了一辆越野自行车,但毕竟不是自己定制的,买回来之后可能需要更改一下脚蹬,座皮,里程计数器或者刹车系统,假如将自行车看做一个整体系统,对我们而言使用的是自行车,然后我们对自己车构件的修改 ...

  7. 从 github 执行 git clone 一个大的项目时提示 error: RPC failed

    目前克隆一个比较大的项目,出现RPC failed的错误 Cloning into 'bigfiles'... remote: Counting objects: 190, done. remote: ...

  8. C#读取shapefile文件(不用AE)

    1.创建工程文件,选窗体应用程序,命名为:EsriShpReader 2.添加SplitContainer控件到窗体 3.在SplitContainer.panel1中添加两个按钮Button,tex ...

  9. Docker Device Mapper 使用 direct-lvm

      一.Device Mapper: loop-lvm 默认 CentOS7 下 Docker 使用的 Device Mapper 设备默认使用 loopback 设备,后端为自动生成的稀疏文件,如下 ...

  10. fseek的使用

    一:概述 在官方文档里,对于fseek的描述是 Move to specified position in file,移到文件的某一个特殊位置 二:语法 status = fseek(fileID, ...