PCL_点云分割_基于法线微分分割

一、概述

PCL_点云分割_基于法线微分分割_点云法向量微分-CSDN博客

利用不同的半径(大的半径、小半径)来计算同一个点的法向量差值P。判断P的范围,从而进行分割。

PCL_点云分割_基于法线微分分割_第1张图片

看图理解: 

 PCL_点云分割_基于法线微分分割_第2张图片

二、计算流程 

1、计算P点小半径的法向量Ns

2、计算P点大半径的法向量Nl(P 点和1中的P点是同一个点)

3、计算deltN=(Nl-Ns)/2;

4、deltN 和输入的阈值做对比,判断

原始点云:

PCL_点云分割_基于法线微分分割_第3张图片

Code 

重点代码

// 计算法向量查来分割DON
	pcl::DifferenceOfNormalsEstimation don;
	don.setInputCloud(cloud);
	don.setNormalScaleLarge(normals_large_scale);
	don.setNormalScaleSmall(normals_small_scale);
	if (!don.initCompute())
	{
		exit(EXIT_FAILURE);
	}
	don.computeFeature(*doncloud);


	cout << "don.computeFeature(*doncloud);       " << doncloud->size() << "..." << endl;
	pcl::io::savePCDFileBinaryCompressed("DifferenceOfNormalsEstimation.pcd", *doncloud);






  // 生成滤波条件,将法线差和阈值对比
	pcl::ConditionOr::Ptr range_cond(new pcl::ConditionOr());
	range_cond->addComparison(pcl::FieldComparison::ConstPtr(new pcl::FieldComparison("curvature", pcl::ComparisonOps::GT, threshold)));

	// 统计滤波
	pcl::PointCloud::Ptr doncloud_filtered(new pcl::PointCloud);
	pcl::ConditionalRemoval condrem;
	condrem.setCondition(range_cond);
	condrem.setInputCloud(doncloud);
	condrem.filter(*doncloud_filtered);
	doncloud = doncloud_filtered;

全部代码:


int CalcCloudMeanRadius(pcl::PointCloud::Ptr cloud, int  k, double& MeanRadius)
{
	if (cloud->size() < 1)
	{
		cout << "   ==================== ========================== " << endl;
		return -1;
	}

	pcl::search::Search::Ptr tree;
	// 判断点云无序  还是有序
	if (cloud->isOrganized())
	{
		tree.reset(new pcl::search::OrganizedNeighbor());
	}
	else
	{
		tree.reset(new pcl::search::KdTree(false));
	}

	tree->setInputCloud(cloud);
	//计算点云的平均点半径
	{
		int size_cloud = cloud->size();
		int step = size_cloud / 100;
		double total_distance = 0;
		int i, j = 1;
		int K = k;
		for (i = 0; i < size_cloud; i += step, j++)
		{
			std::vector pointIdxNKNSearch(K);
			std::vector pointNKNSquaredDistance(K);
			double distance = 0;
			if (tree->nearestKSearch(cloud->points[i], K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)
			{

				for (size_t m = 0; m < pointIdxNKNSearch.size(); ++m)
				{
					std::cout << j << " 号点 " << cloud->points[pointIdxNKNSearch[m]].x
						<< " " << cloud->points[pointIdxNKNSearch[m]].y
						<< " " << cloud->points[pointIdxNKNSearch[m]].z
						<< " (squared distance: " << pointNKNSquaredDistance[m] << ")" << std::endl;
					distance += pointNKNSquaredDistance[m];
				}
			}
			total_distance += (distance / (K - 1));
		}
		MeanRadius = sqrt((total_distance / j));
	}
}

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

	double scale1 = 5;
	double mean_radius;
	double scale2 = 10;

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

	///segment scene into clusters with given distance tolerance using euclidean clustering
	double segradius = 10;
	pcl::PointCloud::Ptr cloud(new pcl::PointCloud);

	pcl::io::loadPCDFile("D:\\work\\Pointclouds\\clouds\\trees.pcd", *cloud);
	CalcCloudMeanRadius(cloud, 20, mean_radius);

	cerr << "平均半径     :   " << 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);
	}

	// 计算法向量
	pcl::search::Search::Ptr tree;
	pcl::PointCloud::Ptr normals_large_scale(new pcl::PointCloud);
	pcl::PointCloud::Ptr normals_small_scale(new pcl::PointCloud);
	pcl::NormalEstimationOMP ne;
	ne.setInputCloud(cloud);
	ne.setSearchMethod(tree);
	ne.setRadiusSearch(scale1);
	ne.compute(*normals_small_scale);
	ne.setRadiusSearch(scale2);
	ne.compute(*normals_large_scale);

	
	PointCloud::Ptr doncloud(new pcl::PointCloud);
	copyPointCloud(*cloud, *doncloud);

	// 计算法向量查来分割DON
	pcl::DifferenceOfNormalsEstimation don;
	don.setInputCloud(cloud);
	don.setNormalScaleLarge(normals_large_scale);
	don.setNormalScaleSmall(normals_small_scale);
	if (!don.initCompute())
	{
		exit(EXIT_FAILURE);
	}
	don.computeFeature(*doncloud);


	cout << "don.computeFeature(*doncloud);       " << doncloud->size() << "..." << endl;
	pcl::io::savePCDFileBinaryCompressed("DifferenceOfNormalsEstimation.pcd", *doncloud);

  // 生成滤波条件,将法线差和阈值对比
	pcl::ConditionOr::Ptr range_cond(new pcl::ConditionOr());
	range_cond->addComparison(pcl::FieldComparison::ConstPtr(new pcl::FieldComparison("curvature", pcl::ComparisonOps::GT, threshold)));

	// 统计滤波
	pcl::PointCloud::Ptr doncloud_filtered(new pcl::PointCloud);
	pcl::ConditionalRemoval condrem;
	condrem.setCondition(range_cond);
	condrem.setInputCloud(doncloud);
	condrem.filter(*doncloud_filtered);
	doncloud = doncloud_filtered;

	// Save filtered output
	std::cout << "Filtered Pointcloud: " << doncloud->points.size() << " data points." << std::endl;
	pcl::io::savePCDFileBinaryCompressed("don_filtered.pcd", *doncloud);

	

	// 欧氏距离提取
	cout << "Clustering using EuclideanClusterExtraction with tolerance <= " << segradius << "..." << endl;
	pcl::EuclideanClusterExtraction ec;
	pcl::search::KdTree::Ptr segtree(new pcl::search::KdTree);
	segtree->setInputCloud(doncloud);
	std::vector cluster_indices;
	ec.setClusterTolerance(segradius);
	ec.setMinClusterSize(50);
	ec.setMaxClusterSize(100000);
	ec.setSearchMethod(segtree);
	ec.setInputCloud(doncloud);
	ec.extract(cluster_indices);


	  cout << "个数:   " << cluster_indices.size()<::const_iterator it = cluster_indices.begin(); it != cluster_indices.end(); ++it, j++)
		{
			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 << "PointCloud representing the Cluster: " << cloud_cluster_don->points.size() << " data points." << std::endl;
			stringstream ss;
			ss << "don_cluster_" << j << ".pcd";
			pcl::io::savePCDFileBinaryCompressed(ss.str(), *cloud_cluster_don);
		}


}

你可能感兴趣的:(PCL,3D,人工智能,算法)