精华内容
下载资源
问答
  • 该程序利用OpenCV中的K均值聚类函数Kmeans2对图像进行颜色聚类,达到分割的目的。 编写此函数的目的是:Kmeans2函数的用法有些难掌握,参考资料少,尤其是对图像进行操作的例子少,我找了很久也找不到, 找到的例子也...
  • 针对Krinidis等人提出的模糊局部C-均值聚类系列算法缺乏合理性的不足,提出一种新的鲁棒模糊局部C-均值聚类分割算法。对鲁棒模糊局部C-均值聚类的目标函数重新分析并建立正确的聚类目标函数,对新的聚类目标函数及其...
  • 采用k均值聚类算法实现对彩色图像分割,将RGB分量转化为三维模式空间进行处理,实现对颜色区域的分割提取
  • 亲测可用!图像模糊C均值聚类分割matlab代码,聚类分割后显示图像。 仅需要自己修改读图路径。
  • 在区域分割阶段, 引入社会粒子群优化模糊C-均值聚类算法对点云数据进行区域聚类, 得到边界清晰的各个分区, 便于后续边界特征的提取; 在特征检测阶段, 对各个分区进行局部径向基函数曲面重构, 以获取各个分区内采样点...
  • 针对核空间模糊局部C-均值聚类分割算法时间复杂性过大而不适合实时场合图像分割需要的问题,提出了一种核空间局部模糊C-均值聚类分割的快速算法。利用像素与其邻域像素之间的空间距离信息和灰度方差信息构造一种加权...
  • 模糊局部均值聚类分割法改进及其应用.pdf
  • 显著特征融合的主颜色聚类分割算法.pdf
  • 基于二次聚类分割与Teager能量谱的滚动轴承微弱故障特征提取.pdf
  • 图像聚类分割

    千次阅读 2020-01-09 13:04:14
    mean shift图像分割 Reference: [1]Mean shift: A robust approach toward feature space analysis, PAMI, 2002 [2]mean shift,非常好的ppt,百度文库链接 [3] Pattern Recognition and Machine Learning, ...

    mean shift 图像分割


    Reference:

    [1] Mean shift: A robust approach toward feature space analysis, PAMI, 2002

    [2] mean shift,非常好的ppt ,百度文库链接

    [3] Pattern Recognition and Machine Learning, Bishop, 2006,Sec 2.5

    [4] Computer Vision Algorithms and Applications, Richard Szeliski, 2010, Sec 5.3

    [5] Kernel smoothing,MP Wand, MC Jones ,1994, Chapter 4


    mean shift 图像分割 (一): 1 总体思想,2 算法步骤

    mean shift 图像分割 (二): 3 算法原理,4 延伸

    mean shift 图像分割 (三): 5 非参数密度估计

    图像分割—mean shift(OpenCV源码注解)

    写在前头的话:这篇笔记看起来公式巨多,实际上只是符号表示,没啥公式推导,不过,多了就难免有差错,欢迎指正。

        Mean shitf的故事说来挺励的,早在1975年就诞生了,接着就是漫长的黑暗岁月,黑暗到几乎淡出了人们的视野,不过,命运总是善良的,95年又重新焕发生机,各种应用喷薄而出,包括目标跟踪,边缘检测,非极大值抑制等。这次就只介绍在图像分割中的应用吧,其它的我也没看。Mean shitf过程也充满正能量,描绘的是如何通过自己的努力,一步一步爬上顶峰的故事。

    1 总体思想

    图 1 特征空间映射:RGB图片 -> L-u特征空间

        首先meanshift是一种特征空间分析方法,要利用此方法来解决特定问题,需要将该问题映射到特征空间。对于图像分割,我们可以映射到颜色特征空间,比如将RGB图片,映射到Luv特征空间,图1是L-u二维可视化的效果。

        图像分割就是求每一个像素点的类标号。类标号取决于它在特征空间所属的cluster。对于每一个cluster,首先得有个类中心,它深深地吸引着一些点,就形成了一个类,即类中心对类中的点构成一个basin of attraction ,好比咱们的太阳系。如此,图像分割问题,就可以看成对每个像素点,找它的类中心问题,因为找到类中心就知道它是属于那一类啦,即类中心一样的点就是一类。

    图2标准化后的概率密度可视化效果 -> 聚类分割结果

        密度估计的思路需要解决两个问题,what:中心是什么?how:怎么找?mean shift认为中心是概率密度(probalility density function )的极大值点,如图2中的红色点,原文称之为mode,我这暂且用模点吧(某篇论文是如此称呼)。对于每个点怎样找到它的类中心呢?只要沿着梯度方向一步一步慢慢爬,就总能爬到极值点,图2中黑色的线,就是爬坡的轨迹。这种迭代搜索的策略在最优化中称之为 multiple restart gradient descent。不过,一般的gradient descent并不能保证收敛到局部极值,但mean shift 可以做到,因为它的步长是自适应调整的,越靠近极值点步长越小。

        也就是说meanshift的核心就两点,密度估计(Density Estimation) 和mode 搜索。对于图像数据,其分布无固定模式可循,所以密度估计必须用非参数估计,选用的是具有平滑效果的核密度估计(Kernel density estimation,KDE)。

    2 算法步骤

    截取这一块可视化

    (a)灰度图可视化à(b)mean shift模点路径à(c)滤波后效果à(d)分割结果

        分三步走:模点搜索/图像平滑、模点聚类/合并相似区域、兼并小区域(可选)。模点搜索是为了找到每个数据点的到类中心,以中心的颜色代替自己的颜色,从而平滑图像。但模点搜索得到的模点太多,并且很多模点挨得很近,若果将每个模点都作为一类的话,类别太多,容易产生过分割,即分割太细,所以要合并掉一些模点,也就是合并相似区域。模点聚类后所得到的分割区域中,有些区域所包含的像素点太少,这些小区域也不是我们想要的,需要再次合并。

    2.1 模点搜索/图像平滑

        建议先看[2]中的演示(P4-12)

        图像中的点包括两类信息:坐标空间(spatial,,),颜色空间(range ,,)。这些就构成了特征空间。

        模点搜索(OpenCV):某一个点,它在联合特征空间中迭代搜索它的mode/模点;

        图像平滑: 将模点的颜色值赋给它自己,即.对应原文中的图像平滑,实质上是通过模点搜索,达到图像平滑的效果, 所以我合并为以一步。

        设点依次爬过的脚印为:

        出发时,它所收敛到的模点为,c代表convergence。

        第一步:如果迭代次数超过最大值(默认最多爬5次),结束搜索跳到第四步,否则,在坐标空间,筛选靠近的数据点进入下一步计算。

        OpenCV是以的坐标 为中心,边长为的方形区域内的数据点。

        其实,本应用为中心,为半径的圆形区域,那样效果更好,但是循环计算时并不方便,所以用方形区域近似。

        第二步:使用第一步幸存下来的点计算重心,并向重心移动。

        写得有点复杂了,下面解释下。是某种核函数,比如高斯分布, 是颜色空间的核平滑尺度。OpenCV使用的是最简单的均匀分布:

    二维可视化效果

        是一个以(第步位置的颜色值)为球心,半径为的球体,球体内部值为1,球体外部值为0。对于经过上一步筛选后幸存的数据点,如果其颜色值满足,也就是颜色值落也在球内,那么求重心时,就要算上,否则落在球外,算重心时,就不带上它。实际上,上一步是依据坐标空间距离筛选数据点,是依据颜色距离进一步筛选数据点,上一步的筛子是矩形,这一步是球体。

        简而言之,设满足的点依次为,那么重心计算公式可以进一步化简为:

        是不是很简单呢,初中知识吧。

        注意:上文中的两个参数,是Mean shift最核心的两个参数(还有一个可选的M),具有直观的意义,分别代表坐标空间和颜色空间的核函数带宽。

        第三步:判断是否到模点了,到了就停止。

        如果,移动后颜色或者位置变化很小,则结束搜索,跳到第四步,否则重返第一步,从继续爬。

    OpenCV停止搜索的条件:

        (1)坐标距离不变

        (2)颜色变化值很小。

        满足一条就可以功成身退,否则继续努力。

        第四步:将模点的颜色赋给出发点/,即。

        注意:原文这一步,不仅将模点的颜色值赋给,顺带把坐标值也赋给了,也就是说。

    2.2 合并相似区域/模点聚类

        合并上一步平滑后的图像。OpenCV采用flood fill函数实现,原理很简单,看下wiki的动画就知道了,模拟洪水浸满峡谷的效果。基本上就是区域生长,从某一点出发,如果和它附近的点(4/8邻域)的颜色值相似就合并,同时再从新合并的点出发继续合并下去,直到碰到不相似的点或者该点已经属于另一类了,此时,就退回来,直到退无可退(所有的4/8邻域搜索空间都已经搜索完毕)。

        虽然很简单,但是不同的方法还是有很多需要注意的细节问题。这里假设滤波后的图像用表示。

        滤波后的两个像素点和,是否合并,可以使用颜色相似度和空间位置相似性判定。

        OpenCV只考虑颜色相似性,而忽略模点的坐标是否相似。而原算法综合了二者的信息。如果像素点,满足或者, 则这两个像素点就合并。不过OpenCV也是有考虑坐标位置的,它是只考虑原空间的4/8邻域,而原文是考虑特征空间模点的 ,相当于说OpenCV的(原空间)。

        此外,floodfill有一个特点,它不能越过已经被分类的区域,再加上没有第三步,使得OpenCV的结果,真的是惨不忍睹。原文的合并算法,具体怎么合并的还得看源代码。不过,应该不是用flood fill。

        《Computer Vision A Modern Approach》中是使用类平均距离判定是否合并。比如,,能否合并成,取决于类平均距离:

        这样做我觉得效果会更好,因为它不是单独依据边界上的两个点来判定是否合并,它是依据两个区域内部所有的点的信息综合判断。所以,它能合并两个区域,而原算法和OpenCV只能是两个点合并成一个区域,该区域又不断地合并点,一旦一个区域已经完成生长,那么它就不会和别的区域合并了。可以反证。假设先形成,区域生长的时候把给合并了,那么必定有两个点满足相似关系,连接了二者,假设这两个点为,相似,那么生长的时候就肯定已经把点合并进来了,接着把所拥有的区域全盘接收,根本不会让区域自成一类。


        当然考虑Outlier,使用中值更好。

        假设合并之后得到m类。对于原文的算法,每个像素点的标号就是其模点所属的模点集合的类标号,比如。不过,OpenCV是所属集合的类标号。

        不过,从原文结果来看,得到的结果并不是类标号,因为类标号一般都是序号,比如1,2,……,然后显示分割结果的时候,就给每一类随机分配一种独有的颜色。但原文的分割结果貌似是这一类的总体颜色值,我猜测原算法可能是用(加权)求平均的方式得到类的颜色值,然后属于这一类的像素点就用这个颜色代替。

        注意:这一步实现的是合并相似区域,但本质上还是而是合并模点,或者说模点聚类,因为每个像素点的值,就是它所属模点的颜色值/模点的联合信息。
    ————————————————
    版权声明:本文为CSDN博主「TTransposition」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/ttransposition/article/details/38514127

    展开全文
  • PCL点云库——欧式聚类分割

    千次阅读 2020-11-16 16:12:41
    PCL欧式聚类分割  pcl::EuclideanClusterExtraction是基于欧式距离提取集群的方法,仅依据距离,将小于距离阈值的点云作为一个集群。  具体的实现方法大致是:  (1) 找到空间中某点p10,有kdTree找到离他最近的n...

    欧式聚类分割


      pcl::EuclideanClusterExtraction是基于欧式距离提取集群的方法,仅依据距离,将小于距离阈值的点云作为一个集群。
      具体的实现方法大致是:
      (1) 找到空间中某点p10,由kdTree找到离他最近的n个点,判断这n个点到p的距离;
      (2) 将距离小于阈值r的点p12、p13、p14…放在类Q里;
      (3) 在 Q\p10 里找到一点p12,重复1;
      (4) 在 Q\p10、p12 找到一点,重复1,找到p22、p23、p24…全部放进Q里;
      (5) 当 Q 再也不能有新点加入了,则完成搜索了。

    //****欧式聚类分割****//
    
    #include <pcl/io/pcd_io.h>
    #include <pcl/segmentation/extract_clusters.h>
    #include <pcl/visualization/cloud_viewer.h>
    #include <string>
    #include <atlstr.h>//CString头文件
    using namespace std;
    
    int 
    main (int argc, char** argv)
    {
      // 读取点云数据
      pcl::PCDReader reader;
      pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
      reader.read ("test.pcd", *cloud);
    
      pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
      tree->setInputCloud(cloud);
    
      std::vector<pcl::PointIndices> cluster_indices;
      pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;//创建欧式聚类分割对象
      ec.setClusterTolerance(3); //设置近邻搜索的搜索半径
      ec.setMinClusterSize(5000); //设置最小聚类尺寸
      ec.setMaxClusterSize(100000);
      ec.setSearchMethod(tree);
      ec.setInputCloud(cloud);
      ec.extract(cluster_indices);
    
      std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> Eucluextra; //用于储存欧式分割后的点云
      for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
      {
    	  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>);
        for (std::vector<int>::const_iterator pit = it->indices.begin (); pit != it->indices.end (); pit++)
    		cloud_cluster->points.push_back(cloud->points[*pit]);
        cloud_cluster->width = cloud_cluster->points.size ();
        cloud_cluster->height = 1;
        cloud_cluster->is_dense = true;
    	Eucluextra.push_back(cloud_cluster);
      }
    
      //可视化
      pcl::visualization::PCLVisualizer viewer("PCLVisualizer");
      viewer.initCameraParameters();
    
      int v1(0);
      viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1);
      viewer.setBackgroundColor(128.0 / 255.0, 138.0 / 255.0, 135.0 / 255.0, v1);
      viewer.addText("Cloud before segmenting", 10, 10, "v1 test", v1);
      viewer.addPointCloud<pcl::PointXYZ>(cloud, "cloud", v1);
    
      int v2(0);
      viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);
      viewer.setBackgroundColor(128.0 / 255.0, 138.0 / 255.0, 135.0 / 255.0, v2);
      viewer.addText("Cloud after segmenting", 10, 10, "v2 test", v2);
      for (int i = 0; i < Eucluextra.size(); i++)
      {
    	  CString cstr;
    	  cstr.Format(_T("cloud_segmented%d"), i);
    	  cstr += _T(".pcd");
    	  string str_filename = CStringA(cstr);
    	  //显示分割得到的各片点云 
    	  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color(Eucluextra[i], 255 * (1 - i)*(2 - i) / 2, 255 * i*(2 - i), 255 * i*(i - 1) / 2);
    	  viewer.addPointCloud(Eucluextra[i], color, str_filename, v2);
      }
    
      while (!viewer.wasStopped())
      { 
    	  viewer.spinOnce(100);
    	  boost::this_thread::sleep(boost::posix_time::microseconds(100000));
      }
      return (0);
    }
    

    在这里插入图片描述

    展开全文
  • 点云分割-PCL点云库欧式聚类分割-基于欧式距离的分割
  • PCL学习:点云分割-欧式聚类分割

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

    http://www.pointclouds.org/documentation/tutorials/cluster_extraction.php#cluster-extraction

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

    (1)欧几里德算法

    具体的实现方法大致是:

    1. 找到空间中某点p10,有kdTree找到离他最近的n个点,判断这n个点到p的距离。将距离小于阈值r的点p12,p13,p14....放在类Q里
    2. 在 Q\p10 里找到一点p12,重复1
    3. 在 Q\p10,p12 找到一点,重复1,找到p22,p23,p24....全部放进Q里
    4. 当 Q 再也不能有新点加入了,则完成搜索了

    因为点云总是连成片的,很少有什么东西会浮在空中来区分。但是如果结合此算法可以应用很多东东。比如

    1. 半径滤波删除离群点
    2. 采样一致找到桌面或者除去滤波

    当然,一旦桌面被剔除,桌上的物体就自然成了一个个的浮空点云团。就能够直接用欧几里德算法进行分割了,这样就可以提取出我们想要识别的东西;在这里我们就可以使用提取平面,平面去掉,利用聚类的方法再显示剩下的所有聚类的结果。

    测试示例:

    1. 加载点云,滤波;

    2. 分割平面模型;

    3. 去除所有平面点云,对余下的点进行聚类分割;

    4. 显示聚类分割结果。

    #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 <pcl/visualization/pcl_visualizer.h>
    
    int color_bar[][3]=
    {
    	{ 255,0,0},
    	{ 0,255,0 },
    	{ 0,0,255 },
    	{ 0,255,255 },
    	{ 255,255,0 },
    	{ 255,255,255 },
    	{ 255,0,255 }
    };
    
    
    int 
    main (int argc, char** argv)
    {
      // Read in the cloud data
      pcl::PCDReader reader;
      pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>), cloud_f (new pcl::PointCloud<pcl::PointXYZ>);
      reader.read ("..\\..\\source\\table_scene_lms400.pcd", *cloud);
      std::cout << "PointCloud before filtering has: " << cloud->points.size () << " data points." << std::endl; //*
    
      // Create the filtering object: downsample the dataset using a leaf size of 1cm
      pcl::VoxelGrid<pcl::PointXYZ> vg;
      pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);
      vg.setInputCloud (cloud);
      vg.setLeafSize (0.01f, 0.01f, 0.01f);
      vg.filter (*cloud_filtered);
      std::cout << "PointCloud after filtering has: " << cloud_filtered->points.size ()  << " data points." << std::endl; //*
    
      // Create the segmentation object for the planar model and set all the parameters
      pcl::SACSegmentation<pcl::PointXYZ> seg;
      pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
      pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
      pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_plane (new pcl::PointCloud<pcl::PointXYZ> ());
      pcl::PCDWriter writer;
      seg.setOptimizeCoefficients (true);
      seg.setModelType (pcl::SACMODEL_PLANE);
      seg.setMethodType (pcl::SAC_RANSAC);
      seg.setMaxIterations (100);
      seg.setDistanceThreshold (0.02);
    
      int i=0, nr_points = (int) cloud_filtered->points.size ();
      while (cloud_filtered->points.size () > 0.3 * nr_points)
      {
        // Segment the largest planar component from the remaining cloud
        seg.setInputCloud (cloud_filtered);
        seg.segment (*inliers, *coefficients);
        if (inliers->indices.size () == 0)
        {
          std::cout << "Could not estimate a planar model for the given dataset." << std::endl;
          break;
        }
    
        // Extract the planar inliers from the input cloud
        pcl::ExtractIndices<pcl::PointXYZ> extract;
        extract.setInputCloud (cloud_filtered);
        extract.setIndices (inliers);
        extract.setNegative (false);
    
        // Write the planar inliers to disk
        extract.filter (*cloud_plane);
        std::cout << "PointCloud representing the planar component: " << cloud_plane->points.size () << " data points." << std::endl;
    
        // Remove the planar inliers, extract the rest
        extract.setNegative (true);
        extract.filter (*cloud_f);
        cloud_filtered = cloud_f;
      }
    
      // 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 (cloud_filtered);
    
      std::vector<pcl::PointIndices> cluster_indices;
      pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;
      ec.setClusterTolerance (0.02); //设置近邻搜索的搜索半径为2cm
      ec.setMinClusterSize (100);    //设置一个聚类需要的最少点数目为100
      ec.setMaxClusterSize (25000);  //设置一个聚类需要的最大点数目为25000
      ec.setSearchMethod (tree);     //设置点云的搜索机制
      ec.setInputCloud (cloud_filtered); //设置原始点云 
      ec.extract (cluster_indices);  //从点云中提取聚类
    
    								 // 可视化部分
      pcl::visualization::PCLVisualizer viewer("segmention");
      // 我们将要使用的颜色
      float bckgr_gray_level = 0.0;  // 黑色
      float txt_gray_lvl = 1.0 - bckgr_gray_level;
      int num = cluster_indices.size();
    
      int j = 0;
      for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
      {
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZ>);
        for (std::vector<int>::const_iterator pit = it->indices.begin (); pit != it->indices.end (); pit++)
          cloud_cluster->points.push_back (cloud_filtered->points[*pit]); //*
        cloud_cluster->width = cloud_cluster->points.size ();
        cloud_cluster->height = 1;
        cloud_cluster->is_dense = true;
    
        std::cout << "PointCloud representing the Cluster: " << cloud_cluster->points.size () << " data points." << std::endl;
        std::stringstream ss;
        ss << "cloud_cluster_" << j << ".pcd";
        writer.write<pcl::PointXYZ> (ss.str (), *cloud_cluster, false); //*
    
    	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_in_color_h(cloud,
    		color_bar[j][0],
    		color_bar[j][1],
    		color_bar[j][2]);//赋予显示点云的颜色
    	viewer.addPointCloud(cloud_cluster, cloud_in_color_h, std::to_string(j));
    
    	j++;
      }
    
      //等待直到可视化窗口关闭。
      while (!viewer.wasStopped())
      {
    	  viewer.spinOnce(100);
    	  boost::this_thread::sleep(boost::posix_time::microseconds(100000));
      }
    
      return (0);
    }

    cmd命令: .\cluster_extraction.exe

    打印信息:分为了5类;

    PointCloud before filtering has: 460400 data points.
    PointCloud after filtering has: 41049 data points.
    PointCloud representing the planar component: 20536 data points.
    PointCloud representing the planar component: 12442 data points.
    PointCloud representing the Cluster: 4857 data points.
    PointCloud representing the Cluster: 1386 data points.
    PointCloud representing the Cluster: 321 data points.
    PointCloud representing the Cluster: 291 data points.
    PointCloud representing the Cluster: 123 data points.

    可视化聚类结果:

    5类,不同的聚类使用不同的颜色表示,同一聚类中的点集使用同一种颜色;

    展开全文
  • pcl聚类----欧式聚类分割方法

    千次阅读 2020-06-01 09:31:41
    欧式聚类分割方法 //为提取点云时使用的搜素对象利用输入点云cloud_filtered创建Kd树对象tree。 pcl::search::KdTree::Ptr tree (new pcl::search::KdTree); tree->setInputCloud (cloud_filtered);//创建点云...

    欧式聚类分割方法

    欧式聚类是一种基于欧氏距离度量的聚类算法

    流程如下:

    欧式聚类流程
    对于欧式聚类来说,距离判断准则为前文提到的欧氏距离。对于空间某点P,通过KD-Tree近邻搜索算法找到k个离p点最近的点,这些点中距离小于设定阈值的便聚类到集合Q中。如果Q中元素的数目不在增加,整个聚类过程便结束;否则须在集合Q中选取p点以外的点,重复上述过程,直到Q中元素的数目不在增加为止

    //为提取点云时使用的搜素对象利用输入点云cloud_filtered创建Kd树对象tree。
    
    pcl::search::KdTree::Ptr tree (new pcl::search::KdTree);
    tree->setInputCloud (cloud_filtered);//创建点云索引向量,用于存储实际的点云信息
    

    使用KD-Tree来加速寻找nearest point

    首先创建一个Kd树对象作为提取点云时所用的搜索方法,再创建一个点云索引向量cluster_indices,用于存储实际的点云索引信息,每个检测到的点云聚类被保存在这里。请注意: cluster_indices是一个向量,对每个检测到的聚类,它都包含一个索引点的实例,如cluster_indices[0]包含点云中第一个聚类包含的点集的所有索引。

    std::vector<pcl::PointIndices> cluster_indices;
    pcl::EuclideanClusterExtraction ec;
    ec.setClusterTolerance (0.02); //设置近邻搜索的搜索半径为2cm
    ec.setMinClusterSize (100);//设置一个聚类需要的最少点数目为100
    ec.setMaxClusterSize (25000); //设置一个聚类需要的最大点数目为25000
    ec.setSearchMethod (tree);//设置点云的搜索机制
    ec.setInputCloud (cloud_filtered);
    ec.extract (cluster_indices);//从点云中提取聚类,并将点云索引保存在cluster_indices中
    

    因为点云是PointXYZ类型的,所以这里用点云类型PointXYZ创建一个欧氏聚类对象,并设置提取的参数和变量。注意:设置一个合适的聚类搜索半径ClusterTolerance,如果搜索半径取一个非常小的值,那么一个实际的对象就会被分割为多个聚类;如果将值设置得太高,那么多个对象就会被分割为一个聚类,所以需要进行测试找出最适合的ClusterTolerance。本例用两个参数来限制找到的聚类:用setMinClusterSize()来限制一个聚类最少需要的点数目,用setMaXClusterSize()来限制最多需要的点数目。接下来我们从点云中提取聚类,并将点云索引保存在cluster_indices中。

    为了从点云索引向量中分割出每个聚类,必须迭代访问点云索引,每次创建一个新的点云数据集,并且将所有当前聚类的点写入到点云数据集中。

    //迭代访问点云索引cluster_indices,直到分割出所有聚类
    
    int j = 0;
    
    for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
        {
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZ>);
        //创建新的点云数据集cloud_cluster,将所有当前聚类写入到点云数据集中
        for (std::vector<int>::const_iterator pit = it->indices.begin (); pit != it->indices.end (); ++pit)
        {
            cloud_cluster->points.push_back (cloud_filtered->points[*pit]);
            cloud_cluster->width = cloud_cluster->points.size ();
            cloud_cluster->height = 1;
            cloud_cluster->is_dense = true; 
        }
        pcl::visualization::CloudViewer viewer("Cloud Viewer");
        viewer.showCloud(cloud_cluster);
        pause();
        }
    保存每个cloud_cluster为单独的.pcd文件,一个文件就是一个聚类
    }
    }
    

    欧几里德算法具体的实现方法大致是:
    1 找到空间中某点p10,有kdTree找到离他最近的n个点,判断这n个点到p的距离。将距离小于阈值r的点p12,p13,p14…放在类Q里
    2 在 Q(p10) 里找到一点p12,重复1

    3 在 Q(p10,p12) 找到一点,重复1,找到p22,p23,p24…全部放进Q里

    4 当 Q 再也不能有新点加入了,则完成搜索了;
    pcl函数原型如下:

     pcl::extractEuclideanClusters (const PointCloud<PointT> &cloud,
                                   const typename search::Search<PointT>::Ptr &tree,
                                   float tolerance, std::vector<PointIndices> &clusters,
                                   unsigned int min_pts_per_cluster,
                                   unsigned int max_pts_per_cluster)
    {
      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;
      }
      // Check if the tree is sorted -- if it is we don't need to check the first element
      int nn_start_idx = tree->getSortedResults () ? 1 : 0;
      // 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 (int i = 0; i < static_cast<int> (cloud.points.size ()); ++i)   //遍历点云中的每一个点
      {
        if (processed[i])   //如果该点已经处理则跳过
          continue;
    
        std::vector<int> seed_queue;   //定义一个种子队列
    
        int sq_idx = 0;
        seed_queue.push_back (i);  //加入一个种子
    
    
        processed[i] = true;
    
        while (sq_idx < static_cast<int> (seed_queue.size ()))    //遍历每一个种子
        {
          // Search for sq_idx  kdtree 树的近邻搜索
          if (!tree->radiusSearch (seed_queue[sq_idx], tolerance, nn_indices, nn_distances))  
          {
            sq_idx++;
            continue;   //没找到近邻点就继续
          }
    
          for (size_t j = nn_start_idx; j < nn_indices.size (); ++j)             // can't assume sorted (default isn't!)
          {
            if (nn_indices[j] == -1 || processed[nn_indices[j]])        // Has this point been processed before ?
              continue;   // 种子点的近邻点中如果已经处理就跳出此次循环继续
    
            // Perform a simple Euclidean clustering
            seed_queue.push_back (nn_indices[j]);   //将此种子点的临近点作为新的种子点。入队操作
            processed[nn_indices[j]] = true;  // 该点已经处理,打标签
          }
    
          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 = 0; 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
        }
      }
    }
    
    展开全文
  • 该课题为基于kmeans的聚类分割,输入一张彩色图像,可以选择需要分割成多少类,就会以不同颜色区分不同的块,带有GUI界面,操作丰富。
  • pcl 条件欧式聚类分割

    2021-10-11 15:03:53
    条件欧式聚类分割(聚类): 使用类pcl::ConditionEuclideanClustering实现点云分割,与其他分割方法不同的是该方法的聚类约束条件(欧式距离、平滑度、RGB颜色等)可以由用户自己定义,即当搜索到一个近邻点时,...
  • Matlab数字图像处理,kmeans聚类分割,带GIUI界面,分割聚类数可以输入。
  • PCL:欧式聚类分割

    2021-04-25 15:09:26
    本文介绍了PCL欧式聚类分割,并将分割结果可视化
  • 针对一般聚类分割算法对于色彩丰富、背景复杂的图像容易造成聚类重叠,引起像素错误分类的缺点,提出一种新的基于自组织特征映射神经网络的彩色图像分割方法.首先利用各像素的RGB 值作为输入样本对网络进行训练;然后...
  • 运行在Matlab2012下,带有GUI,可对彩色图像进行Kmeans和meanshift进行聚类分析,生成最后的聚类图像以及聚类中心的迭代轨迹
  • 本文提出一种基于EnFCM的图像聚类分割模型,直接对图像像素的灰度级进行聚类,能显著提高图像聚类分割的处理速度。为进一步提高处理速度,结合EnFCM图像聚类分割模型特点,设计了三种并行优化策略——纯MPI并行方法...
  • 该课题为基于kmeans的聚类分割,输入一张彩色图像,可以选择需要分割成多少类,就会以不同颜色区分不同的块。
  • Matlab的kmeans聚类分割

    千次阅读 2020-03-18 15:19:28
    Matlab环境下的k-means聚类算法,实现图像分割。(GUI,分割聚类数可以输入) 快速K均值聚类图像分割算法源代码 …\kmeans-image-segmentation.rar …\kmeans.m …\loadFile.do.htm …\loadFile.do_files …\00th....
  • 通过比较几种图像直方图均衡化的应用范围,提出一种基于模糊聚类分割的累计直方图均衡化的方法。实验结果表明:与传统直方图均衡化算法相比,使用该方法处理后的图像不仅使灰度值分布更加均匀,增强了整体对比度,...
  • 具体介绍基于聚类分割算法的思想和原理,并将包含的典型算法的优缺点进行介绍和分析。 经过比较后,归纳了在具体应用中如何对图像分割算法的抉择问题。近年来传统分割算法不断 被科研工作者优化和组合,相信会有更...
  • 完整的ROS工程,针对激光点云数据,可以实现点云降采样处理、基于欧氏距离聚类分割的目标检测和地面拟合分割算法。可以直接使用。
  • 为了提高混凝土表面裂缝的识别效率,提出了一种基于卷积神经网络结合聚类分割的识别方法,实现了对较复杂背景下混凝土表面裂缝图像的准确识别。研究结果显示,该方法不仅能够高效地分类,还能够高精度地对较复杂背景下的...
  • FCM聚类分割算法

    2012-10-30 21:20:22
    FCM算法是一种基于划分的聚类算法,它的思想就是使得被划分到同一簇的对象之间相似度最大,而不同簇之间的相似度最小。模糊C均值算法是普通C均值算法的改进,普通C均值算法对于数据的划分是硬性的,而FCM则是一种...
  • 该课题为基于kmeans的聚类分割,输入一张彩色图像,可以选择需要分割成多少类,就会以不同颜色区分不同的块,带有GUI界面,操作丰富。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,995
精华内容 10,798
关键字:

聚类分割