#include //最小图割相关头文件
pcl::MinCutSegmentation seg;//创建一个PointXYZ类型的最小分割对象
seg.setInputCloud (cloud);//设置输入点云
if(Bool_Cuting)seg.setIndices (indices);//如果设置输入点云的索引
pcl::PointCloud::Ptr foreground_points(new pcl::PointCloud ());//创建一个PointCloud 共享指针并进行实例化
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 clusters;//定义一个点云索引类型的向量,存放分割结果
seg.extract (clusters);//获取分割的结果,分割结果保存在点云索引的向量中。
std::cout << "Maximum flow is " << seg.getMaxFlow () << std::endl;//计算并输出分割期间所计算出的流值
pcl::PointCloud ::Ptr colored_cloud = seg.getColoredCloud ();//对前景点赋予红色,对背景点赋予白色。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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"<::Ptr cloud (new pcl::PointCloud );// 创建一个PointCloud 共享指针并进行实例化,用来读入点云
if ( pcl::io::loadPCDFile (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 );//创建一组索引
if(Bool_Cuting)//判断是否需要直通滤波
{
pcl::PassThrough pass;//设置直通滤波器对象
pass.setInputCloud (cloud);//设置输入点云
pass.setFilterFieldName ("z");//设置指定过滤的维度
pass.setFilterLimits (near_cuting, far_cuting);//设置指定纬度过滤的范围
pass.filter (*indices);//执行滤波,保存滤波结果在上述索引中
}
pcl::MinCutSegmentation seg;//创建一个PointXYZ类型的最小分割对象
seg.setInputCloud (cloud);//设置输入点云
if(Bool_Cuting)seg.setIndices (indices);//如果设置输入点云的索引
pcl::PointCloud::Ptr foreground_points(new pcl::PointCloud ());//创建一个PointCloud 共享指针并进行实例化
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 clusters;//定义一个点云索引类型的向量,存放分割结果
seg.extract (clusters);//获取分割的结果,分割结果保存在点云索引的向量中。
std::cout << "Maximum flow is " << seg.getMaxFlow () << std::endl;//计算并输出分割期间所计算出的流值
pcl::PointCloud ::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);
}
白色的部分被认为是前景点
不太懂
//创建一个对象存放DoN的结果
PointCloud::Ptr doncloud (new pcl::PointCloud);
copyPointCloud(*cloud, *doncloud);
cout << "Calculating DoN... " << endl;
// Create DoN operator
pcl::DifferenceOfNormalsEstimation 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
/**
* @file don_segmentation.cpp
* Difference of Normals Example for PCL Segmentation Tutorials.
*
* @author Yani Ioannou
* @date 2012-09-24
* @修改 2015-6-16
*/
#include
#include
#include
#include
#include
#include //利用多线程计算法向量相关头文件
#include
#include
#include
#include
// for visualization
#include
using namespace pcl;
using namespace std;
pcl::PointCloud::Ptr getColoredCloud (pcl::PointCloud::Ptr input_, std::vector clusters_,float r,float g,float b)
{
pcl::PointCloud::Ptr colored_cloud;
if (!clusters_.empty ())
{
colored_cloud = (new pcl::PointCloud)->makeShared ();
srand (static_cast (time (0)));
std::vector colors;
for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
{
colors.push_back (static_cast (rand () % 256));
colors.push_back (static_cast (rand () % 256));
colors.push_back (static_cast (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::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::Ptr cloud (new pcl::PointCloud);
pcl::io::loadPCDFile (infile.c_str (), *cloud);
// Create a search tree, use KDTreee for non-organized data.
//为无序点云创建一个搜索方式
pcl::search::Search::Ptr tree;
if (cloud->isOrganized ())
{
tree.reset (new pcl::search::OrganizedNeighbor ());
}
else
{
tree.reset (new pcl::search::KdTree (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 pointIdxNKNSearch(2);
std::vector 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: "<= 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 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::max (), std::numeric_limits::max (), std::numeric_limits::max ());//随机设定视点的坐标
// calculate normals with the small scale
cout << "Calculating normals for scale..." << scale1 << endl;
pcl::PointCloud::Ptr normals_small_scale (new pcl::PointCloud);
ne.setRadiusSearch (scale1);
ne.compute (*normals_small_scale);//对输入点集利用小尺度计算法向量
// calculate normals with the large scale
cout << "Calculating normals for scale..." << scale2 << endl;
pcl::PointCloud::Ptr normals_large_scale (new pcl::PointCloud);
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 MView (new pcl::visualization::PCLVisualizer ("Showing normals with different scale"));
pcl::visualization::PointCloudColorHandlerCustom 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(cloud,normals_small_scale,100,mean_radius*10,"small_scale_normal");
MView->addPointCloudNormals(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::Ptr doncloud (new pcl::PointCloud);
copyPointCloud(*cloud, *doncloud);
cout << "Calculating DoN... " << endl;
// Create DoN operator
pcl::DifferenceOfNormalsEstimation 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;ipoints[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 MView (new pcl::visualization::PCLVisualizer ("Showing the difference of curvature of two scale"));
pcl::visualization::PointCloudColorHandlerGenericField 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 ("don.pcd", *doncloud, false);
// Filter by magnitude
cout << "Filtering out DoN mag <= " << threshold << "..." << endl;
// Build the condition for filtering
//创建条件滤波对象
pcl::ConditionOr::Ptr range_cond (
new pcl::ConditionOr ()
);
range_cond->addComparison (pcl::FieldComparison::ConstPtr (
new pcl::FieldComparison ("curvature", pcl::ComparisonOps::GT, threshold))
);//添加滤波条件,曲率高于阈值滤出
// Build the filter
//创建一个条件滤波器
/*显示说设置条件的方法被抛弃了
pcl::ConditionalRemoval condrem (range_cond);//参数为之前创建的条件
*/
//新的设置条件滤波器初始值的方法
pcl::ConditionalRemoval condrem;
condrem.setCondition(range_cond);
condrem.setInputCloud (doncloud);//设置输入点云don特征向量
pcl::PointCloud::Ptr doncloud_filtered (new pcl::PointCloud);
// 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 ("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 MView (new pcl::visualization::PCLVisualizer ("Showing the results of keeping relative small curvature points"));
pcl::visualization::PointCloudColorHandlerGenericField 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::Ptr segtree (new pcl::search::KdTree);//设置无序点云的空间检索方式
segtree->setInputCloud (doncloud);//输入点云为条件滤波之后的点云
std::vector cluster_indices;//聚类的索引,每一个元素都是一个聚类
pcl::EuclideanClusterExtraction 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 ::Ptr tmp_xyz(new pcl::PointCloud);
copyPointCloud(*doncloud,*tmp_xyz);
pcl::PointCloud ::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 MView (new pcl::visualization::PCLVisualizer ("visualize the clustering results"));
pcl::visualization::PointCloudColorHandlerRGBField 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<::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it, j++)//第一层循环,创建一个迭代器依次访问cluster_indices中的每一个聚类
{
pcl::PointCloud::Ptr cloud_cluster_don (new pcl::PointCloud);
for (std::vector::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 <<" ["<points.size () << " data points." << std::endl;
stringstream ss;
ss << "don_cluster_" << j << ".pcd";
writer.write (ss.str (), *cloud_cluster_don, false);
}
}
}
曲率可视化结果
对上图基于曲率进行条件滤波
#include //渐进式形态学滤波头文件
//创建一个渐进式形态学滤波器对象
// Create the filtering object
pcl::ProgressiveMorphologicalFilter 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 extract;
extract.setInputCloud (cloud);
extract.setIndices (ground);
extract.filter (*cloud_ground);
#include
#include
#include
#include
#include //渐进式形态学滤波头文件
#include
#include //命令行解析
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::Ptr cloud (new pcl::PointCloud);
pcl::PointCloud::Ptr cloud_filtered (new pcl::PointCloud),cloud_ground (new pcl::PointCloud);
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 (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 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 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 ("samp11-utm_ground.pcd", *cloud_ground, false);//保存滤波之后的点云数据
//viewer->addPointCloud(cloud_ground,pcl::visualization::PointCloudColorHandlerCustom(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 ("samp11-utm_object.pcd", *cloud_filtered, false);//保存地面以外的点云
viewer->addPointCloud(cloud_filtered,pcl::visualization::PointCloudColorHandlerCustom(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);
}
1为原数据,2为地面上的物体,3为地面
该方法的约束条件(如纯欧氏距离、平滑度、RGB颜色)可以由用户自定义,即该方法搜索到一个临近点时,用户可以自定义该近邻点合并到当前聚类的条件。但是该方法同样存在无初始种子、过分割或欠分割等缺陷。另外,该方法从主循环计算中调用条件函数时,时间效率会降低。
该算法基于聚类的点的数量限制还可以自动过滤掉太大或太小的聚类。但这些被过滤掉的聚类仍可以通过设置该类的成员函数使其被查询利用。
#include //条件欧式聚类分割
std::cerr << "Segmenting to clusters...\n", tt.tic ();
pcl::ConditionalEuclideanClustering 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";
#include
#include
#include
#include
#include
#include
#include
#include //条件欧式聚类分割
#include
#include
#include
typedef pcl::PointXYZI PointTypeIO;
typedef pcl::PointXYZINormal PointTypeFull;
typedef pcl::visualization::PointCloudColorHandler 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 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 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"<::Ptr cloud_in (new pcl::PointCloud), cloud_out (new pcl::PointCloud);//创建PointCloud 共享指针并进行实例化
pcl::PointCloud::Ptr cloud_with_normals (new pcl::PointCloud);//创建PointCloud 共享指针并进行实例化
pcl::IndicesClustersPtr clusters (new pcl::IndicesClusters), small_clusters (new pcl::IndicesClusters), large_clusters (new pcl::IndicesClusters);//创建聚类的索引
pcl::search::KdTree::Ptr search_tree (new pcl::search::KdTree);//创建搜索方式
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 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 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 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: "<size()<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: "<size()<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: "<size()<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 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::Ptr color_handler(new pcl::visualization::PointCloudColorHandlerLabelField());
/*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 (cloud,"intensity"));*/
MView->addPointCloud(cloud_in,"input",v1);//设置视口1的输入点云
//MView->addPointCloud(cloud,color_handler,origin, orientation,"output",v2);
MView->addPointCloud(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);
}
由于缺少点云数据,无法运行代码