PCL 【点云分割2】

一、最小图割(可以用来分割前后景) 

1、最小图割核心代码

#include <pcl/segmentation/min_cut_segmentation.h>//最小图割相关头文件

	pcl::MinCutSegmentation<pcl::PointXYZ> seg;//创建一个PointXYZ类型的最小分割对象
	seg.setInputCloud (cloud);//设置输入点云
	if(Bool_Cuting)seg.setIndices (indices);//如果设置输入点云的索引

	pcl::PointCloud<pcl::PointXYZ>::Ptr foreground_points(new pcl::PointCloud<pcl::PointXYZ> ());//创建一个PointCloud <pcl::PointXYZRGB>共享指针并进行实例化
	pcl::PointXYZ point;//定义中心点并赋值

	point.x =C_x;//中心点坐标
	point.y = C_y;
	point.z = C_z;
	foreground_points->points.push_back(point); //前景中心点
	seg.setForegroundPoints (foreground_points);//输入前景点云(目标物体)的中心点

	seg.setSigma (Sigma);//设置平滑成本的Sigma值
	seg.setRadius (Radius);//设置背景惩罚权重的半径
	seg.setNumberOfNeighbours (NumberOfNeighbours);//设置临近点数目
	seg.setSourceWeight (SourceWeight);//设置前景惩罚权重,设置的越大则分割为前景的概率越大

	std::vector <pcl::PointIndices> clusters;//定义一个点云索引类型的向量,存放分割结果
	seg.extract (clusters);//获取分割的结果,分割结果保存在点云索引的向量中。

	std::cout << "Maximum flow is " << seg.getMaxFlow () << std::endl;//计算并输出分割期间所计算出的流值

	pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = seg.getColoredCloud ();//对前景点赋予红色,对背景点赋予白色。

2、完整代码(注释)

#include <iostream>
#include <vector>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/passthrough.h>
#include <pcl/segmentation/min_cut_segmentation.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
using namespace pcl::console;
int main (int argc, char** argv)
{
	if(argc<2)
	{
		std::cout<<".exe xx.pcd -bc 1 -fc 1.0 -nc 0 -cx 68.97 -cy -18.55 -cz 0.57 -s 0.25 -r 3.0433856 -non 14 -sw 0.5"<<endl;

		return 0;
	}//如果输入参数小于1个,输出提示信息
	time_t start,end,diff[5],option; //计时相关
	start = time(0); //设置起点时刻
	int NumberOfNeighbours=14;//设置默认参数
	bool Bool_Cuting=false;//设置默认参数
	float far_cuting=1,near_cuting=0,C_x=0.071753,C_y= -0.309913,C_z=1.603000,Sigma=0.25,Radius=0.8,SourceWeight=0.5;//设置默认输入参数
	pcl::PointCloud <pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud <pcl::PointXYZ>);// 创建一个PointCloud <pcl::PointXYZ>共享指针并进行实例化,用来读入点云
	if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[1], *cloud) == -1 )// 加载点云数据
	{
		std::cout << "Cloud reading failed." << std::endl;
		return (-1);
	}

	parse_argument (argc, argv, "-bc", Bool_Cuting);//是否使用直通滤波
	parse_argument (argc, argv, "-fc", far_cuting);//直通滤波最大距离
	parse_argument (argc, argv, "-nc", near_cuting);//直通滤波最小距离

	parse_argument (argc, argv, "-cx", C_x);//设置中心点
	parse_argument (argc, argv, "-cy", C_y);
	parse_argument (argc, argv, "-cz", C_z);

	parse_argument (argc, argv, "-s", Sigma);//设置平滑成本的Sigma值
	parse_argument (argc, argv, "-r", Radius);//设置背景惩罚权重的半径
	parse_argument (argc, argv, "-non", NumberOfNeighbours);//算法构照图时需要查找的临近点数目
	parse_argument (argc, argv, "-sw", SourceWeight);//设置输入参数方式

	pcl::IndicesPtr indices (new std::vector <int>);//创建一组索引
	if(Bool_Cuting)//判断是否需要直通滤波
	{
		pcl::PassThrough<pcl::PointXYZ> pass;//设置直通滤波器对象
		pass.setInputCloud (cloud);//设置输入点云
		pass.setFilterFieldName ("z");//设置指定过滤的维度
		pass.setFilterLimits (near_cuting, far_cuting);//设置指定纬度过滤的范围
		pass.filter (*indices);//执行滤波,保存滤波结果在上述索引中

	}
	pcl::MinCutSegmentation<pcl::PointXYZ> seg;//创建一个PointXYZ类型的最小分割对象
	seg.setInputCloud (cloud);//设置输入点云
	if(Bool_Cuting)seg.setIndices (indices);//如果设置输入点云的索引

	pcl::PointCloud<pcl::PointXYZ>::Ptr foreground_points(new pcl::PointCloud<pcl::PointXYZ> ());//创建一个PointCloud <pcl::PointXYZRGB>共享指针并进行实例化
	pcl::PointXYZ point;//定义中心点并赋值

	point.x =C_x;//中心点坐标
	point.y = C_y;
	point.z = C_z;
	foreground_points->points.push_back(point); //前景中心点
	seg.setForegroundPoints (foreground_points);//输入前景点云(目标物体)的中心点

	seg.setSigma (Sigma);//设置平滑成本的Sigma值
	seg.setRadius (Radius);//设置背景惩罚权重的半径
	seg.setNumberOfNeighbours (NumberOfNeighbours);//设置临近点数目
	seg.setSourceWeight (SourceWeight);//设置前景惩罚权重,设置的越大则分割为前景的概率越大

	std::vector <pcl::PointIndices> clusters;//定义一个点云索引类型的向量,存放分割结果
	seg.extract (clusters);//获取分割的结果,分割结果保存在点云索引的向量中。

	std::cout << "Maximum flow is " << seg.getMaxFlow () << std::endl;//计算并输出分割期间所计算出的流值

	pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = seg.getColoredCloud ();//对前景点赋予红色,对背景点赋予白色。
	pcl::visualization::PCLVisualizer viewer ("PCL min_cut_seg");
	viewer.addPointCloud(colored_cloud);
	viewer.addSphere(point,Radius,122,122,0,"sphere");
	viewer.setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,0.2,"sphere");
	viewer.addCoordinateSystem();
	
	while (!viewer.wasStopped ())
	{
		viewer.spin();
	}//进行可视化

	return (0);
}

3、可视化

白色的部分被认为是前景点

 

二、基于法线微分的分割

不太懂

1、分割部分代码

  //创建一个对象存放DoN的结果
  PointCloud<PointNormal>::Ptr doncloud (new pcl::PointCloud<PointNormal>);
  copyPointCloud<PointXYZRGB, PointNormal>(*cloud, *doncloud);

  cout << "Calculating DoN... " << endl;
  // Create DoN operator
  pcl::DifferenceOfNormalsEstimation<PointXYZRGB, PointNormal, PointNormal> don;
  don.setInputCloud (cloud);
  don.setNormalScaleLarge (normals_large_scale);
  don.setNormalScaleSmall (normals_small_scale);

  //检查计算特征向量的要求是否得到满足
  if (!don.initCompute ())
  {
    std::cerr << "Error: Could not intialize DoN feature operator" << std::endl;
    exit (EXIT_FAILURE);
  }

  // Compute DoN 计算DoN特征向量
  don.computeFeature (*doncloud);//对输入点集,计算每一个点的DoN特征向量,并输出。结果保存至doncloud

2、完整代码(注释)

/**
 * @file don_segmentation.cpp
 * Difference of Normals Example for PCL Segmentation Tutorials.
 *
 * @author Yani Ioannou
 * @date 2012-09-24
 * @修改 2015-6-16
 */
#include <string>

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/search/organized.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d_omp.h>//利用多线程计算法向量相关头文件
#include <pcl/filters/conditional_removal.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/segmentation/impl/extract_clusters.hpp>

#include <pcl/features/don.h>
// for visualization
#include <pcl/visualization/pcl_visualizer.h>

using namespace pcl;
using namespace std;


pcl::PointCloud<pcl::PointXYZRGB>::Ptr getColoredCloud (pcl::PointCloud<pcl::PointXYZ>::Ptr input_, std::vector <pcl::PointIndices> clusters_,float r,float g,float b)
{
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr colored_cloud;

  if (!clusters_.empty ())
  {
    colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGB>)->makeShared ();

    srand (static_cast<unsigned int> (time (0)));
    std::vector<unsigned char> colors;
    for (size_t 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));
    }

    colored_cloud->width = input_->width;
    colored_cloud->height = input_->height;
    colored_cloud->is_dense = input_->is_dense;
    for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
    {
      pcl::PointXYZRGB point;
      point.x = *(input_->points[i_point].data);
      point.y = *(input_->points[i_point].data + 1);
      point.z = *(input_->points[i_point].data + 2);
      point.r = r;
      point.g = g;
      point.b = b;
      colored_cloud->points.push_back (point);
    }

    std::vector< pcl::PointIndices >::iterator i_segment;
    int next_color = 0;
    for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
    {
      std::vector<int>::iterator i_point;
      for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
      {
        int index;
        index = *i_point;
        colored_cloud->points[index].r = colors[3 * next_color];
        colored_cloud->points[index].g = colors[3 * next_color + 1];
        colored_cloud->points[index].b = colors[3 * next_color + 2];
      }
      next_color++;
    }
  }

  return (colored_cloud);
}

int
main (int argc, char *argv[])
{
	int VISUAL=1,SAVE=0;//0 indicate shows nothing, 1 indicate shows very step output 2 only shows the final results
  ///The smallest scale to use in the DoN filter.
  double scale1,mean_radius;

  ///The largest scale to use in the DoN filter.
  double scale2;

  ///The minimum DoN magnitude to threshold by
  double threshold;

  ///segment scene into clusters with given distance tolerance using euclidean clustering
  double segradius;//欧几里得聚类分割的阈值

  if (argc < 6)
  {
    cerr << "usage: " << argv[0] << " inputfile smallscale(5) largescale(10) threshold(0.1) segradius(1.5) VISUAL(1) SAVE(0)" << endl;
	cerr << "usage: "<<"smallscale largescale  segradius :multiple with mean radius of point cloud "<< endl;
    exit (EXIT_FAILURE);
  }

  /// the file to read from.
  string infile = argv[1];
  /// small scale
  istringstream (argv[2]) >> scale1;
  /// large scale
  istringstream (argv[3]) >> scale2;
  istringstream (argv[4]) >> threshold;   // threshold for DoN magnitude,条件滤波器的阈值
  istringstream (argv[5]) >> segradius;   // threshold for radius segmentation
  istringstream (argv[6]) >> VISUAL;
   istringstream (argv[7]) >> SAVE;
  // Load cloud in blob format
  pcl::PointCloud<PointXYZRGB>::Ptr cloud (new pcl::PointCloud<PointXYZRGB>);
  pcl::io::loadPCDFile (infile.c_str (), *cloud);
   // Create a search tree, use KDTreee for non-organized data.
   //为无序点云创建一个搜索方式
  pcl::search::Search<PointXYZRGB>::Ptr tree;
  if (cloud->isOrganized ())
  {
    tree.reset (new pcl::search::OrganizedNeighbor<PointXYZRGB> ());
  }
  else
  {
    tree.reset (new pcl::search::KdTree<PointXYZRGB> (false));
  }

  // Set the input pointcloud for the search tree
  tree->setInputCloud (cloud);
 //caculate the mean radius of cloud and mutilply with corresponding input
  {
	  int size_cloud=cloud->size();
	  int step=size_cloud/10;
	  double total_distance=0;
	  int i,j=1;
	  for(i=0;i<size_cloud;i+=step,j++)
	  {
		  std::vector<int> pointIdxNKNSearch(2);
		  std::vector<float> pointNKNSquaredDistance(2);
		  tree->nearestKSearch(cloud->points[i],2,pointIdxNKNSearch,pointNKNSquaredDistance);//搜索最近邻的两个点
		  total_distance+=pointNKNSquaredDistance[1]+pointNKNSquaredDistance[0];//增加第一个点和第二个点与中心点之间的距离
	  }
	  mean_radius=sqrt((total_distance/j));
	  cout<<"mean radius of cloud is: "<<mean_radius<<endl;
	  scale1*=mean_radius;//小尺度辅助半径
	  scale2*=mean_radius;//大尺度辅助半径
	  segradius*=mean_radius;
  }
 

  if (scale1 >= scale2)
  {
    cerr << "Error: Large scale must be > small scale!" << endl;
    exit (EXIT_FAILURE);
  }

  // Compute normals using both small and large scales at each point
  //对每一个点分别使用小尺度和大尺度进行计算法线
  pcl::NormalEstimationOMP<PointXYZRGB, PointNormal> ne;
  ne.setInputCloud (cloud);
  ne.setSearchMethod (tree);

  /**
   * NOTE: setting viewpoint is very important, so that we can ensure
   * normals are all pointed in the same direction!
   */
  ne.setViewPoint (std::numeric_limits<float>::max (), std::numeric_limits<float>::max (), std::numeric_limits<float>::max ());//随机设定视点的坐标

  // calculate normals with the small scale
  cout << "Calculating normals for scale..." << scale1 << endl;
  pcl::PointCloud<PointNormal>::Ptr normals_small_scale (new pcl::PointCloud<PointNormal>);

  ne.setRadiusSearch (scale1);
  ne.compute (*normals_small_scale);//对输入点集利用小尺度计算法向量

  // calculate normals with the large scale
  cout << "Calculating normals for scale..." << scale2 << endl;
  pcl::PointCloud<PointNormal>::Ptr normals_large_scale (new pcl::PointCloud<PointNormal>);

  ne.setRadiusSearch (scale2);
  ne.compute (*normals_large_scale);//对输入点集利用大尺度计算法向量
  //visualize the normals
  if(VISUAL=1)
  {
	  cout << "click q key to quit the visualizer and continue" << endl;
	  boost::shared_ptr<pcl::visualization::PCLVisualizer> MView (new pcl::visualization::PCLVisualizer ("Showing normals with different scale")); 
	  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> green (cloud, 0,255,0); 
	  int v1(0),v2(0); 
	  MView->createViewPort (0.0, 0.0, 0.5, 1.0, v1); 
	  MView->createViewPort (0.5, 0.0, 1.0, 1.0, v2); 
	  MView->setBackgroundColor (1,1,1,v1);
	  MView->setBackgroundColor(255,0,0,v2);
	  MView->addPointCloud (cloud, green, "small_scale", v1);
	  MView->addPointCloud (cloud, green, "large_scale", v2);
	  MView->addPointCloudNormals<pcl::PointXYZRGB,pcl::PointNormal>(cloud,normals_small_scale,100,mean_radius*10,"small_scale_normal");
	  MView->addPointCloudNormals<pcl::PointXYZRGB,pcl::PointNormal>(cloud,normals_large_scale,100,mean_radius*10,"large_scale_normal");
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,8,"small_scale",v1);//设置小尺度点云的大小
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,0,"small_scale",v1);//设置小尺度点云的透明度
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,3,"large_scale",v1);//设置大尺度点云的大小
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,0.5,"large_scale",v1);//设置大尺度点云的透明度
	  MView->spin();

  }
  // Create output cloud for DoN results
  //创建一个对象存放DoN的结果
  PointCloud<PointNormal>::Ptr doncloud (new pcl::PointCloud<PointNormal>);
  copyPointCloud<PointXYZRGB, PointNormal>(*cloud, *doncloud);

  cout << "Calculating DoN... " << endl;
  // Create DoN operator
  pcl::DifferenceOfNormalsEstimation<PointXYZRGB, PointNormal, PointNormal> don;
  don.setInputCloud (cloud);
  don.setNormalScaleLarge (normals_large_scale);
  don.setNormalScaleSmall (normals_small_scale);

  //检查计算特征向量的要求是否得到满足
  if (!don.initCompute ())
  {
    std::cerr << "Error: Could not intialize DoN feature operator" << std::endl;
    exit (EXIT_FAILURE);
  }

  // Compute DoN 计算DoN特征向量
  don.computeFeature (*doncloud);//对输入点集,计算每一个点的DoN特征向量,并输出。结果保存至doncloud
  

  //print some differencense of curvature
  {
	   cout << "You may have some sense about the input threshold (curvature) next time for your data" << endl;
	  int size_cloud=doncloud->size();
	  int step=size_cloud/10;
	  for(int i=0;i<size_cloud;i+=step)
	      cout << " "<<doncloud->points[i].curvature<<" "<< endl;

  }

   //show the differences of curvature with both large and small scale 
  if(VISUAL=1)
  {
	  cout << "click q key to quit the visualizer and continue" << endl;
	  boost::shared_ptr<pcl::visualization::PCLVisualizer> MView (new pcl::visualization::PCLVisualizer ("Showing the difference of curvature of two scale")); 
	  pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointNormal> handler_k(doncloud,"curvature"); 
	  MView->setBackgroundColor (1,1,1); 
	  MView->addPointCloud (doncloud, handler_k); //显示估计出的法线
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,3);
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,0.5);
	  MView->spin();
  }

  
  // Save DoN features
  pcl::PCDWriter writer;
   if(SAVE==1) writer.write<pcl::PointNormal> ("don.pcd", *doncloud, false); 


  // Filter by magnitude
  cout << "Filtering out DoN mag <= " << threshold << "..." << endl;

  // Build the condition for filtering
  //创建条件滤波对象
  pcl::ConditionOr<PointNormal>::Ptr range_cond (
    new pcl::ConditionOr<PointNormal> ()
    );
  range_cond->addComparison (pcl::FieldComparison<PointNormal>::ConstPtr (
                               new pcl::FieldComparison<PointNormal> ("curvature", pcl::ComparisonOps::GT, threshold))
                             );//添加滤波条件,曲率高于阈值滤出
  // Build the filter
  //创建一个条件滤波器

  /*显示说设置条件的方法被抛弃了
  pcl::ConditionalRemoval<PointNormal> condrem (range_cond);//参数为之前创建的条件
   */
  //新的设置条件滤波器初始值的方法
  pcl::ConditionalRemoval<PointNormal> condrem;
  condrem.setCondition(range_cond);

  condrem.setInputCloud (doncloud);//设置输入点云don特征向量

  pcl::PointCloud<PointNormal>::Ptr doncloud_filtered (new pcl::PointCloud<PointNormal>);

  // Apply filter
  condrem.filter (*doncloud_filtered);//滤波之后的数据集保存至doncloud_filtered

  doncloud = doncloud_filtered;//条件滤波之后的点云

  // Save filtered output
  std::cout << "Filtered Pointcloud: " << doncloud->points.size () << " data points." << std::endl;

  if(SAVE==1)writer.write<pcl::PointNormal> ("don_filtered.pcd", *doncloud, false); 


   //show the results of keeping relative small curvature points
   //显示曲率小的点
  if(VISUAL==1)
  {
	  cout << "click q key to quit the visualizer and continue" << endl;
	  boost::shared_ptr<pcl::visualization::PCLVisualizer> MView (new pcl::visualization::PCLVisualizer ("Showing the results of keeping relative small curvature points")); 
	  pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointNormal> handler_k(doncloud,"curvature"); 
	  MView->setBackgroundColor (1,1,1); 
	  MView->addPointCloud (doncloud, handler_k); 
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,3);
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,0.5);
	  MView->spin();
  }

  // Filter by magnitude
  //使用欧几里德聚类将场景分割成具有给定距离容差的聚类
  cout << "Clustering using EuclideanClusterExtraction with tolerance <= " << segradius << "..." << endl;

  pcl::search::KdTree<PointNormal>::Ptr segtree (new pcl::search::KdTree<PointNormal>);//设置无序点云的空间检索方式
  segtree->setInputCloud (doncloud);//输入点云为条件滤波之后的点云

  std::vector<pcl::PointIndices> cluster_indices;//聚类的索引,每一个元素都是一个聚类
  pcl::EuclideanClusterExtraction<PointNormal> ec;//实例化一个欧式聚类分割对象

  ec.setClusterTolerance (segradius);//设置近邻搜索的搜索半径
  ec.setMinClusterSize (50);//一个聚类的最少点数
  ec.setMaxClusterSize (100000);//一个聚类的最多点数
  ec.setSearchMethod (segtree);//设置检索方式
  ec.setInputCloud (doncloud);//设置输入点云
  ec.extract (cluster_indices);//将聚类的点云索引保存至cluster_indices
  if(VISUAL==1)
  {//visualize the clustering results
	  pcl::PointCloud <pcl::PointXYZ>::Ptr tmp_xyz(new pcl::PointCloud<pcl::PointXYZ>);
	  copyPointCloud<pcl::PointNormal,pcl::PointXYZ>(*doncloud,*tmp_xyz);
	  pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = getColoredCloud (tmp_xyz,cluster_indices,0,255,0);//调用开头定义的函数

	  cout << "click q key to quit the visualizer and continue!!" << endl;
	  boost::shared_ptr<pcl::visualization::PCLVisualizer> MView (new pcl::visualization::PCLVisualizer ("visualize the clustering results")); 
	 pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgbps(colored_cloud); 
	  MView->setBackgroundColor (1,1,1); 
	  MView->addPointCloud (colored_cloud, rgbps); 
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,3);
	  MView->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,0.5);
	  MView->spin();

  }
  if(SAVE==1)
  {
      std::cerr<<cluster_indices.size()<<" clusters."<<std::endl;
      std::cout<<"---------------------------------------------------------------------"<<std::endl;
	  int j = 0;
	  for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it, j++)//第一层循环,创建一个迭代器依次访问cluster_indices中的每一个聚类
	  {
		  pcl::PointCloud<PointNormal>::Ptr cloud_cluster_don (new pcl::PointCloud<PointNormal>);
		  for (std::vector<int>::const_iterator pit = it->indices.begin (); pit != it->indices.end (); ++pit)//使用一个迭代器,对每一个聚类中的所有点依次访问,并进行强制类型转换
		  {
			  cloud_cluster_don->points.push_back (doncloud->points[*pit]);
		  }

		  cloud_cluster_don->width = int (cloud_cluster_don->points.size ());
		  cloud_cluster_don->height = 1;
		  cloud_cluster_don->is_dense = true;

		  //Save cluster
		  cout <<" ["<<j<< "] PointCloud representing the Cluster: " << cloud_cluster_don->points.size () << " data points." << std::endl;
		  stringstream ss;
		  ss << "don_cluster_" << j << ".pcd";
		  writer.write<pcl::PointNormal> (ss.str (), *cloud_cluster_don, false);
	  }

  }
  
}

3、可视化

曲率可视化结果

 

对上图基于曲率进行条件滤波 

 对上图又进行欧式聚类提取

 

三、渐进式形态学滤波地面分割(不知什么原因,不能可视化)

 1、渐进式形态学滤波部分

#include <pcl/segmentation/progressive_morphological_filter.h>//渐进式形态学滤波头文件
	//创建一个渐进式形态学滤波器对象
	// Create the filtering object
	pcl::ProgressiveMorphologicalFilter<pcl::PointXYZ> pmf;
	pmf.setInputCloud (cloud);
	pmf.setMaxWindowSize (max_w_s);
	pmf.setSlope (slope);
	pmf.setInitialDistance (initial_d);
	pmf.setMaxDistance (max_d);
	pmf.extract (ground->indices);//滤波结果

	// Create the filtering object
	//创建一个提取对象,将得到的地面的索引点提取出来
	pcl::ExtractIndices<pcl::PointXYZ> extract;
	extract.setInputCloud (cloud);
	extract.setIndices (ground);
	extract.filter (*cloud_ground);

2、完整代码

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/segmentation/progressive_morphological_filter.h>//渐进式形态学滤波头文件
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/parse.h>//命令行解析
int
	main (int argc, char** argv)
{
	int max_w_s (20);//最大窗口大小
	float slope (1.0f);
	float initial_d (0.5f);//初始距离
	float max_d (3.0f);//最大距离
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>),cloud_ground (new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointIndicesPtr ground (new pcl::PointIndices);//实例化一个地面点云的索引
	if(argc<2)
	{
		std::cout << "Usage: " << argv[0] << " filename.pcd [Options]" << std::endl << std::endl;
		std::cout << "Options:" << std::endl;
		std::cout << "     -mw(20):                     Max window size." << std::endl;
		std::cout << "     -s(1.0):                     Slope." << std::endl;
		std::cout << "     -id(0.5):                    initial distance." << std::endl;
		std::cout << "     -md(3.0):                     Max distance" << std::endl;
		exit(1);
	}
	// Fill in the cloud data
	pcl::PCDReader reader;
	// Replace the path below with the path where you saved your file
	reader.read<pcl::PointXYZ> (argv[1], *cloud);
	pcl::console::parse_argument (argc, argv, "-mw", max_w_s);
	pcl::console::parse_argument (argc, argv, "-s", slope);
	pcl::console::parse_argument (argc, argv, "-id", initial_d);
	pcl::console::parse_argument (argc, argv, "-md", max_d);
	std::cerr << "Cloud before filtering: " << std::endl;
	std::cerr << *cloud << std::endl;//运算符重载,输出点云的信息

	//创建一个渐进式形态学滤波器对象
	// Create the filtering object
	pcl::ProgressiveMorphologicalFilter<pcl::PointXYZ> pmf;
	pmf.setInputCloud (cloud);
	pmf.setMaxWindowSize (max_w_s);
	pmf.setSlope (slope);
	pmf.setInitialDistance (initial_d);
	pmf.setMaxDistance (max_d);
	pmf.extract (ground->indices);//滤波结果

	// Create the filtering object
	//创建一个提取对象,将得到的地面的索引点提取出来
	pcl::ExtractIndices<pcl::PointXYZ> extract;
	extract.setInputCloud (cloud);
	extract.setIndices (ground);
	extract.filter (*cloud_ground);

	//输出渐进式形态学滤波之后的点云数据
	std::cerr << "Ground cloud after filtering: " << std::endl;
	std::cerr << *cloud_ground << std::endl;

	//可视化
	int v1(0),v2(0);
	pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("ground extraction"));
	viewer->initCameraParameters();

	viewer->createViewPort(0,0,0.5,1,v1);
	viewer->createViewPort(0.5,0,1,1,v2);
	viewer->setBackgroundColor(255,255,255,v1);
	viewer->setBackgroundColor(255,0,0,v2);
	pcl::PCDWriter writer;
	writer.write<pcl::PointXYZ> ("samp11-utm_ground.pcd", *cloud_ground, false);//保存滤波之后的点云数据
	//viewer->addPointCloud(cloud_ground,pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>(cloud_ground,0,255,0),"cloud_ground",v1);
	viewer->addPointCloud(cloud_ground,"cloud_ground",v1);
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,0,255,0,"cloud_ground",v1);
	// Extract non-ground returns
	//提取除地面之外的物体
	extract.setNegative (true);
	extract.filter (*cloud_filtered);//保存地面以外的点云至cloud_filtered
    writer.write<pcl::PointXYZ> ("samp11-utm_object.pcd", *cloud_filtered, false);//保存地面以外的点云
	viewer->addPointCloud(cloud_filtered,pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>(cloud_filtered,0,0,255),"cloud_filtered",v2);
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,4,"cloud_ground",v1);
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,4,"cloud_filtered",v2);
	std::cerr << "Object cloud after filtering: " << std::endl;
	std::cerr << *cloud_filtered << std::endl;
	viewer->addCoordinateSystem();

	viewer->spin();


	return (0);
}

3、可视化(使用pcl_viewer filename.pcd)

1为原数据,2为地面上的物体,3为地面

 

四、条件欧式聚类点云分割

1、概述

该方法的约束条件(如纯欧氏距离、平滑度、RGB颜色)可以由用户自定义,即该方法搜索到一个临近点时,用户可以自定义该近邻点合并到当前聚类的条件。但是该方法同样存在无初始种子、过分割或欠分割等缺陷。另外,该方法从主循环计算中调用条件函数时,时间效率会降低。

该算法基于聚类的点的数量限制还可以自动过滤掉太大或太小的聚类。但这些被过滤掉的聚类仍可以通过设置该类的成员函数使其被查询利用。

2、条件欧式聚类分割核心代码

#include <pcl/segmentation/conditional_euclidean_clustering.h>//条件欧式聚类分割
	std::cerr << "Segmenting to clusters...\n", tt.tic ();
	pcl::ConditionalEuclideanClustering<PointTypeFull> cec (true);//创建条件聚类分割对象,并进行初始化。
	cec.setInputCloud (cloud_with_normals);//设置输入点集
	//用于选择不同条件函数
	switch(Method)
	{
	case 1:
		cec.setConditionFunction (&enforceIntensitySimilarity);
		break;
	case 2:
		cec.setConditionFunction (&enforceCurvatureOrIntensitySimilarity);
		break;
	case 3:
		cec.setConditionFunction (&customRegionGrowing);
		break;
	default:
		cec.setConditionFunction (&customRegionGrowing);//默认是第三个函数
		break;
	}

	cec.setClusterTolerance (500.0);//设置聚类参考点的搜索距离
	cec.setMinClusterSize (cloud_with_normals->points.size () / 1000);//设置过小聚类的标准
	cec.setMaxClusterSize (cloud_with_normals->points.size () / 5);//设置过大聚类的标准
	cec.segment (*clusters);//获取聚类的结果,分割结果保存在点云索引的向量中
	cec.getRemovedClusters (small_clusters, large_clusters);//获取无效尺寸的聚类
	std::cerr << ">> Done: " << tt.toc () << " ms\n";

3、完整代码

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/console/time.h>
#include <iostream>
#include <ostream>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/segmentation/conditional_euclidean_clustering.h>//条件欧式聚类分割
#include <pcl/console/parse.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/visualization/point_cloud_color_handlers.h>
typedef pcl::PointXYZI PointTypeIO;
typedef pcl::PointXYZINormal PointTypeFull;
typedef pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2> ColorHandler;
typedef ColorHandler::Ptr ColorHandlerPtr;
typedef ColorHandler::ConstPtr ColorHandlerConstPtr;
using namespace pcl::console;
//设置条件函数1,合并具有相似强度数值的点
bool
	enforceIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float squared_distance)
{
	if (fabs ((float)point_a.intensity - (float)point_b.intensity) < 5.0f)
		return (true);
	else
		return (false);
}
//设置条件函数2,合并具有相似法线方向或者相似的强度数值的点,比如纹理相似的大楼
bool
	enforceCurvatureOrIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float squared_distance)
{
	Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.getNormalVector3fMap(), point_b_normal = point_b.getVector3fMap();
	if (fabs ((float)point_a.intensity - (float)point_b.intensity) < 5.0f)
		return (true);
	if (fabs (point_a_normal.dot (point_b_normal)) < 0.05)
		return (true);
	return (false);
}
//设置条件函数3,1000以内合并相似法线方向或相似强度数值的点;1000以外只合并具有相似强度数值的点
bool
	customRegionGrowing (const PointTypeFull& point_a, const PointTypeFull& point_b, float squared_distance)
{
	Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.getNormalVector3fMap(), point_b_normal = point_b.getVector3fMap();
	if (squared_distance < 10000)
	{
		if (fabs ((float)point_a.intensity - (float)point_b.intensity) < 8.0f)
			return (true);
		if (fabs (point_a_normal.dot (point_b_normal)) < 0.06)
			return (true);
	}
	else
	{
		if (fabs ((float)point_a.intensity - (float)point_b.intensity) < 3.0f)
			return (true);
	}
	return (false);
}

int
	main (int argc, char** argv)
{

	if(argc<2)
	{
		std::cout<<".exe xx.pcd -l 40 -r 300.0 -v 1 -m 1/2/3"<<std::endl;

		return 0;
	}//如果输入参数小于2个,输出提示
	bool Visual=true;
	//设置默认输入参数
	float Leaf=0.2,Radius=300;
	int Method=1;
	//设置输入参数方式
	parse_argument (argc, argv, "-l", Leaf);//下采样的分辨率
	parse_argument (argc, argv, "-r", Radius);//设置搜索半径
	parse_argument (argc, argv, "-v", Visual);//----------------------没找到干嘛的------------------
	parse_argument (argc, argv, "-m", Method);//用来选择条件欧式聚类时所用的条件函数
	// Data containers used
	pcl::PointCloud<PointTypeIO>::Ptr cloud_in (new pcl::PointCloud<PointTypeIO>), cloud_out (new pcl::PointCloud<PointTypeIO>);//创建PointCloud <pcl::PointXYZI>共享指针并进行实例化
	pcl::PointCloud<PointTypeFull>::Ptr cloud_with_normals (new pcl::PointCloud<PointTypeFull>);//创建PointCloud <pcl::PointXYZINormal>共享指针并进行实例化
	pcl::IndicesClustersPtr clusters (new pcl::IndicesClusters), small_clusters (new pcl::IndicesClusters), large_clusters (new pcl::IndicesClusters);//创建聚类的索引
	pcl::search::KdTree<PointTypeIO>::Ptr search_tree (new pcl::search::KdTree<PointTypeIO>);//创建搜索方式
	pcl::console::TicToc tt;//计时相关

	// Load the input point cloud
	std::cerr << "Loading...\n", tt.tic ();
	pcl::io::loadPCDFile (argv[1], *cloud_in);//打开输入点云文件
	std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_in->points.size () << " points\n";

	// Downsample the cloud using a Voxel Grid class
	//下采样
	std::cerr << "Downsampling...\n", tt.tic ();
	pcl::VoxelGrid<PointTypeIO> vg;//设置滤波对象
	vg.setInputCloud (cloud_in);//设置需要过滤的点云给滤波对象
	vg.setLeafSize (Leaf,Leaf,Leaf);//设置滤波时创建的栅格边长
	vg.setDownsampleAllData (true);//设置所有的数值域需要被下采样
	vg.filter (*cloud_out);//执行滤波处理,存储输出cloud_out
	std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_out->points.size () << " points\n";

	// Set up a Normal Estimation class and merge data in cloud_with_normals
	//创建一个法线估计对象
	std::cerr << "Computing normals...\n", tt.tic ();
	pcl::copyPointCloud (*cloud_out, *cloud_with_normals);//复制点云到cloud_with_normals
	pcl::NormalEstimation<PointTypeIO, PointTypeFull> ne;//创建法线估计对象
	ne.setInputCloud (cloud_out);//设置法线估计对象输入点集
	ne.setSearchMethod (search_tree);//设置搜索方法
	ne.setRadiusSearch (Radius);// 设置搜索半径
	ne.compute (*cloud_with_normals);//计算并输出法向量
	std::cerr << ">> Done: " << tt.toc () << " ms\n";

	// Set up a Conditional Euclidean Clustering class
	//创建一个条件欧式聚类分割对象
	std::cerr << "Segmenting to clusters...\n", tt.tic ();
	pcl::ConditionalEuclideanClustering<PointTypeFull> cec (true);//创建条件聚类分割对象,并进行初始化。
	cec.setInputCloud (cloud_with_normals);//设置输入点集
	//用于选择不同条件函数
	switch(Method)
	{
	case 1:
		cec.setConditionFunction (&enforceIntensitySimilarity);
		break;
	case 2:
		cec.setConditionFunction (&enforceCurvatureOrIntensitySimilarity);
		break;
	case 3:
		cec.setConditionFunction (&customRegionGrowing);
		break;
	default:
		cec.setConditionFunction (&customRegionGrowing);//默认是第三个函数
		break;
	}

	cec.setClusterTolerance (500.0);//设置聚类参考点的搜索距离
	cec.setMinClusterSize (cloud_with_normals->points.size () / 1000);//设置过小聚类的标准
	cec.setMaxClusterSize (cloud_with_normals->points.size () / 5);//设置过大聚类的标准
	cec.segment (*clusters);//获取聚类的结果,分割结果保存在点云索引的向量中
	cec.getRemovedClusters (small_clusters, large_clusters);//获取无效尺寸的聚类
	std::cerr << ">> Done: " << tt.toc () << " ms\n";

	std::cout<<"small_clusters->size: "<<small_clusters->size()<<std::endl;
	for (int i = 0; i < small_clusters->size (); ++i)//遍历每一个过小的聚类
		for (int j = 0; j < (*small_clusters)[i].indices.size (); ++j)//任意一个聚类的所有点的强度设置为-2.0
			cloud_out->points[(*small_clusters)[i].indices[j]].intensity = -2.0;

    std::cout<<"large_clusters->size: "<<large_clusters->size()<<std::endl;
	for (int i = 0; i < large_clusters->size (); ++i)
		for (int j = 0; j < (*large_clusters)[i].indices.size (); ++j)
			cloud_out->points[(*large_clusters)[i].indices[j]].intensity = +10.0;//过大聚类的点的强度设置为+10.0

    std::cout<<"clusters->size: "<<clusters->size()<<std::endl;
	for (int i = 0; i < clusters->size (); ++i)
	{
		int label = rand () % 8;
		for (int j = 0; j < (*clusters)[i].indices.size (); ++j)
			cloud_out->points[(*clusters)[i].indices[j]].intensity = label;//cluster的强度
	}
	// Save the output point cloud
	if(0)
	{//可视化部分包含有错误。待修改!
		
		boost::shared_ptr<pcl::visualization::PCLVisualizer> MView (new pcl::visualization::PCLVisualizer ("点云库PCL学习教程第二版-条件分割方法")); 
		//View-Port1 
		int v1(0); 
		MView->createViewPort (0.0, 0.0, 0.5, 1.0, v1); //设置视口1的几何参数
		MView->setBackgroundColor (1, 0.2, 1); //设置视口1的背景
		MView->addText ("Before segmentation", 10, 10, "Before segmentation", v1); //为视口1添加标签
		int v2(0); 
		MView->createViewPort (0.5, 0.0, 1.0, 1.0, v2); 
		MView->setBackgroundColor (0.5, 0.5,0.5, v2); 
		MView->addText ("After segmentation", 10, 10, "After segmentation", v2); 
		//pcl::visualization::PointCloudColorHandlerLabelField<pcl::PointXYZI>::Ptr color_handler(new pcl::visualization::PointCloudColorHandlerLabelField<pcl::PointXYZI>());
		/*pcl::PCLPointCloud2::Ptr cloud;
		ColorHandlerPtr color_handler;
		pcl::fromPCLPointCloud2 (*cloud, *cloud_out);
		Eigen::Vector4f origin=Eigen::Vector4f::Identity();
		Eigen::Quaternionf orientation=Eigen::Quaternionf::Identity();

		color_handler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (cloud,"intensity"));*/
		MView->addPointCloud<pcl::PointXYZI>(cloud_in,"input",v1);//设置视口1的输入点云
		//MView->addPointCloud(cloud,color_handler,origin, orientation,"output",v2);
		MView->addPointCloud<pcl::PointXYZI>(cloud_out,"output",v2);
		MView->spin();
	}
	else
	{
		std::cerr << "Saving...\n", tt.tic ();
		pcl::io::savePCDFile ("output.pcd", *cloud_out);
		std::cerr << ">> Done: " << tt.toc () << " ms\n";
	}


	return (0);
}

4、可视化

由于缺少点云数据,无法运行代码

  • 0
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
PCL(Point Cloud Library)是一个开源的点云处理库用于处理和分析三维点云数据。在点云分割任务中,评价指标用于衡量算法的性能和准确度。以下是几个常用的PCL点云分割评价指标: 1. 点云分割准确率(Segmentation Accuracy):该指标用于评估算法对点云数据进行正确分割的能力。准确率可以通过计算正确分割的点数与总点数之比来得到。 2. 点云分割召回率(Segmentation Recall):该指标用于评估算法对点云数据进行完整分割的能力。召回率可以通过计算正确分割的点数与真实分割点数之比来得到。 3. 平均欠分割误差(Under-segmentation Error):该指标用于评估算法对点云数据进行过度分割的程度。欠分割误差可以通过计算未正确分割的点数与总点数之比来得到。 4. 平均过分割误差(Over-segmentation Error):该指标用于评估算法对点云数据进行不足分割的程度。过分割误差可以通过计算错误分割的点数与总点数之比来得到。 5. 边界正确率(Boundary Precision):该指标用于评估算法对点云数据中物体边界的准确度。边界正确率可以通过计算正确分割的边界点数与总边界点数之比来得到。 6. 边界召回率(Boundary Recall):该指标用于评估算法对点云数据中物体边界的完整性。边界召回率可以通过计算正确分割的边界点数与真实边界点数之比来得到。 以上是一些常见的PCL点云分割评价指标,可以根据具体任务和需求选择适合的指标进行评估。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tech沉思录

点赞加投币,感谢您的资瓷~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值