原文链接:Cylinder model segmentation — Point Cloud Library 0.0 documentation
目录
处理流程
圆柱分割
程序代码
实验结果
打印结果
原始点云
过滤杂点
平面分割
将平面去除
分割圆柱
CMakeLists.txt
本教程演示了如何运行圆柱形模型的Sample Consensus分割。为了使示例更实用一些,将以下操作应用于输入数据集(按顺序):
本次使用的数据集:table_scene_mug_stereo_textured.pcd
由于数据中存在噪声,圆柱模型并不完美。
平面分割可以参考博文:PCL教程-点云分割之平面模型分割
seg.setOptimizeCoefficients(true);seg.setModelType(pcl::SACMODEL_NORMAL_PLANE);seg.setNormalDistanceWeight(0.1);seg.setMethodType(pcl::SAC_RANSAC);seg.setMaxIterations(100);seg.setDistanceThreshold(0.03);seg.setInputCloud(cloud_filtered);seg.setInputNormals(cloud_normals);
- Using a model of type: SACMODEL_NORMAL_PLANE
- Setting normal distance weight to 0.100000
- Using a method of type: SAC_RANSAC with a model threshold of 0.030000
- Setting the maximum number of iterations to 100
下面重点介绍圆柱分割:
// Create the segmentation object for cylinder segmentation and set all the parametersseg.setOptimizeCoefficients (true);seg.setModelType (pcl::SACMODEL_CYLINDER);seg.setMethodType (pcl::SAC_RANSAC);seg.setNormalDistanceWeight (0.1);seg.setMaxIterations (10000);seg.setDistanceThreshold (0.05);seg.setRadiusLimits (0, 0.1);
- 这里同样使用了RANSAC鲁棒估计来获取圆柱的系数因子。
- 还设置了距离阈值为0.05m(5cm):小于这个阈值的点将标记为圆柱内部点。
- 此外还设置了表面法线的距离权重为0.1
- 限制了圆柱模型的半径为0~0.1m(10cm)
- 最大的迭代次数为10000
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// All the objects needed
pcl::PCDReader reader;
pcl::PassThrough
pcl::NormalEstimation
pcl::SACSegmentationFromNormals
pcl::PCDWriter writer;
pcl::ExtractIndices
pcl::ExtractIndices
pcl::search::KdTree
pcl::PointCloud
pcl::PointCloud
pcl::PointCloud
pcl::PointCloud
pcl::PointCloud
pcl::ModelCoefficients::Ptr coefficients_plane(new pcl::ModelCoefficients), coefficients_cylinder(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers_plane(new pcl::PointIndices), inliers_cylinder(new pcl::PointIndices);pcl::PointCloud
pcl::PointCloud
//PCLVisualizer
pcl::visualization::PCLVisualizer viewer("Cylinder Segmentation");int step_count;void pass_through_filter()
{// Build a passthrough filter to remove spurious NaNspass.setInputCloud(cloud);pass.setFilterFieldName("z");pass.setFilterLimits(0, 1.5);pass.filter(*cloud_filtered);std::cerr <<"PointCloud after filtering has: " <
}void plane_seg()
{// Create the segmentation object for the planar model and set all the parametersseg.setOptimizeCoefficients(true);seg.setModelType(pcl::SACMODEL_NORMAL_PLANE);seg.setNormalDistanceWeight(0.1);seg.setMethodType(pcl::SAC_RANSAC);seg.setMaxIterations(100);seg.setDistanceThreshold(0.03);seg.setInputCloud(cloud_filtered);seg.setInputNormals(cloud_normals);// Obtain the plane inliers and coefficientsseg.segment(*inliers_plane, *coefficients_plane);std::cerr <<"Plane coefficients: " <<*coefficients_plane <
{// Extract the planar inliers from the input cloudextract.setInputCloud(cloud_filtered);extract.setIndices(inliers_plane);extract.setNegative(false);// Write the planar inliers to diskextract.filter(*cloud_plane);std::cerr <<"PointCloud representing the planar component: " <
{// Remove the planar inliers, extract the restextract.setNegative(true);extract.filter(*cloud_filtered2);extract_normals.setNegative(true);extract_normals.setInputCloud(cloud_normals);extract_normals.setIndices(inliers_plane);extract_normals.filter(*cloud_normals2);
}void cylinder_seg()
{// Create the segmentation object for cylinder segmentation and set all the parametersseg.setOptimizeCoefficients(true);seg.setModelType(pcl::SACMODEL_CYLINDER);seg.setMethodType(pcl::SAC_RANSAC);seg.setNormalDistanceWeight(0.1);seg.setMaxIterations(10000);seg.setDistanceThreshold(0.05);seg.setRadiusLimits(0, 0.1);seg.setInputCloud(cloud_filtered2);seg.setInputNormals(cloud_normals2);// Obtain the cylinder inliers and coefficientsseg.segment(*inliers_cylinder, *coefficients_cylinder);std::cerr <<"Cylinder coefficients: " <<*coefficients_cylinder <
void get_cylinder()
{extract.setInputCloud(cloud_filtered2);extract.setIndices(inliers_cylinder);extract.setNegative(false);extract.filter(*cloud_cylinder);if (cloud_cylinder->points.empty())std::cerr <<"Can&#39;t find the cylindrical component." <
{if (event.getKeySym() &#61;&#61; "space" && event.keyDown()){&#43;&#43;step_count;}
}
int
main(int argc, char** argv)
{step_count &#61; 1;std::string str &#61; "STEP";//初始化PCLVisualizer//viewer.addCoordinateSystem(1);//viewer.setBackgroundColor(0, 0, 255);viewer.addText(str&#43; std::to_string(step_count), 10, 10,16, 200,200,100,"text");viewer.registerKeyboardCallback(&keyboard_event_occurred, (void*)NULL);// Read in the cloud datareader.read("table_scene_mug_stereo_textured.pcd", *cloud);std::cerr <<"PointCloud has: " <
}
PointCloud has: 307200 data points.
PointCloud after filtering has: 139897 data points.
Plane coefficients: header:
seq: 0 stamp: 0 frame_id:
values[]
values[0]: 0.0161902
values[1]: -0.837667
values[2]: -0.545941
values[3]: 0.528862PointCloud representing the planar component: 116300 data points.
Cylinder coefficients: header:
seq: 0 stamp: 0 frame_id:
values[]
values[0]: 0.0543319
values[1]: 0.100139
values[2]: 0.787577
values[3]: -0.0135876
values[4]: 0.834831
values[5]: 0.550338
values[6]: 0.0387446PointCloud representing the cylindrical component: 11462 data points.
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)project(cylinder_segmentation)find_package(PCL 1.2 REQUIRED)include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})add_executable (cylinder_segmentation cylinder_segmentation.cpp)
target_link_libraries (cylinder_segmentation ${PCL_LIBRARIES})