前言
在PCL中,可以使用pcl::SACSegmentationFromNormals类来实现圆柱体模型的分割。该类可以根据法线信息对点云进行分割,并提取出圆柱体点云。其原理是使用随机采样一致性(RANSAC)算法来估计圆柱体模型的参数,并从点云中提取圆柱体模型。该算法的基本流程如下:
**1、**过滤掉远离感兴趣区域的数据点。
**2、**估计每个点的表面法线。
**3、**使用RANSAC算法从点云中分割出平面模型,并保存。
**4、**使用RANSAC算法从点云中分割出圆柱体模型,并保存。
示例程序
#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>//模型定义头文件
#include <pcl/sample_consensus/model_types.h>//随机参数估计方法头文件
#include <pcl/segmentation/sac_segmentation.h>//基于采样一致性分割的类的头文件
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/features/normal_3d.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/extract_indices.h>
int main()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("./Graphic/yuanzhu.pcd", *cloud_in);
std::vector<pcl::PointIndices> clusters;
int max_iterations = 500;
double threshold = 1;
float keepRatio = 0.2;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZ>);
if (cloud_in->empty())
{
std::cout << "input cloud is empty";
return -1;
}
// 创建圆柱模型的分割对象,并设置所有参数
pcl::PassThrough<pcl::PointXYZ> pass; //直通滤波对象
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; //法线估计对象
pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> seg; //分割对象
pcl::ExtractIndices<pcl::PointXYZ> extract; //点提取对象
pcl::ExtractIndices<pcl::Normal> extract_normals; ///点提取对象
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
pcl::ModelCoefficients::Ptr coefficients_cylinder(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers_cylinder(new pcl::PointIndices);
// Read in the cloud data
std::cerr << "PointCloud has: " << cloud_in->points.size() << " data points." << std::endl;
ne.setSearchMethod(tree);
ne.setInputCloud(cloud_in);
ne.setKSearch(30);
ne.compute(*cloud_normals);
// Create the segmentation object for cylinder segmentation and set all the parameters
seg.setOptimizeCoefficients(true); //设置对估计模型优化
seg.setModelType(pcl::SACMODEL_CYLINDER); //设置分割模型为圆柱形
seg.setMethodType(pcl::SAC_RANSAC); //参数估计方法
seg.setNormalDistanceWeight(0.1); //设置表面法线权重系数
seg.setMaxIterations(1000); //设置迭代的最大次数10000
seg.setDistanceThreshold(0.5); //设置内点到模型的距离允许最大值
seg.setRadiusLimits(49, 51); //设置估计出的圆柱模型的半径的范围
seg.setInputCloud(cloud_in);
seg.setInputNormals(cloud_normals);
// Obtain the cylinder inliers and coefficients
seg.segment(*inliers_cylinder, *coefficients_cylinder);
std::cerr << "Cylinder coefficients: " << *coefficients_cylinder << std::endl;
// Write the cylinder inliers to disk
extract.setInputCloud(cloud_in);
extract.setIndices(inliers_cylinder);
extract.setNegative(false);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cylinder(new pcl::PointCloud<pcl::PointXYZ>());
extract.filter(*cloud_out);
if (cloud_out->points.empty())
std::cerr << "Can't find the cylindrical component." << std::endl;
else
{
std::cerr << "PointCloud representing the cylindrical component: "
<< cloud_out->points.size() << " data points." << std::endl;
}
//可视化
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3d viewer"));
//左边窗口显示输入的点云
int v1(0);
viewer->createViewPort(0, 0, 0.5, 1, v1);
viewer->setBackgroundColor(0, 0, 0, v1);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_in(cloud_in, 255, 255, 255);
viewer->addPointCloud<pcl::PointXYZ>(cloud_in, color_in, "cloud_in", v1);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud_in", v1);
//右边的窗口显示分割后的点云
int v2(0);
viewer->createViewPort(0.5, 0, 1, 1, v2);
viewer->setBackgroundColor(0, 0, 0, v2);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_out(cloud_out, 0, 255, 0);
viewer->addPointCloud<pcl::PointXYZ>(cloud_out,color_out,"cloud_out", v2);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud_out", v2);
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
}
return 0;
}