@[TOC]PCL中点云分割模块的学习
学习背景
参考书籍:《点云库PCL从入门到精通》以及官方代码PCL官方代码链接,,PCL版本为1.10.0,CMake版本为3.16
学习内容
用一组点云做平面、圆柱分割
源代码及所用函数
源代码
//实现圆柱体模型的分割
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char** argv)
{
pcl::PCDReader reader;//PCD读取
pcl::PassThrough
pcl::NormalEstimation
pcl::SACSegmentationFromNormals
pcl::PCDWriter writer;//PCD文件写入对象
pcl::ExtractIndices
pcl::ExtractIndices
pcl::search::KdTree
/*****************************数据集*************************************************/
pcl::PointCloud
pcl::PointCloud
pcl::PointCloud
pcl::PointCloud
pcl::PointCloud
pcl::ModelCoefficients::Ptr coeffcients_plane(new pcl::ModelCoefficients),coeffcients_cylinder(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers_plane(new pcl::PointIndices),inliers_cylinder(new pcl::PointIndices);
/*****************************读取点云*************************************************/
reader.read("/home/jojo/PointCloud/table_scene_mug_stereo_textured.pcd",*cloud);
std::cout << "点云中有:" << cloud->points.size() << "个点" << std::endl;
/*****************************直通滤波,将Z轴不在(0,1.5)范围的点过滤掉,将剩余的点存储到cloud_filtered对象中***************/
pass.setInputCloud(cloud);
pass.setFilterFieldName("z");
pass.setFilterLimits(0,1.5);
pass.filter(*cloud_filtered);
std::cout << "滤波后点云还有:" << cloud_filtered->points.size() << "个数据点" < /******************过滤后的点云进行法线估计,为后续进行基于法线的分割准备数据****************************/ ne.setSearchMethod(tree); ne.setInputCloud(cloud_filtered); ne.setKSearch(50);//设置法向量估计时使用的K近邻搜索方法,并将K的值设置为50。这意味着对于每个查询点,将在其50个最近邻域内搜索用于估计法向量的邻域点。 ne.compute(*cloud_normals); /***********************************************为平面模型创建分割对象并设置所有参数**********************************/ seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_NORMAL_PLANE); seg.setNormalDistanceWeight(0.1);//设置法向量距离权重系数为0.1 seg.setMaxIterations(100);//设置随机采样一致性(RANSAC)算法的最大迭代次数为100。 seg.setDistanceThreshold(0.03);//这行代码设置了点到模型的距离阈值为0.03 seg.setInputCloud(cloud_filtered); seg.setInputNormals(cloud_normals); //获取平面模型的系数和处在平面内的点 seg.segment(*inliers_plane,*coeffcients_plane); std::cout << "平面系数" << *coeffcients_plane << std::endl; /**********************************************从点云中提取分割出处于平面上的点云****************************************/ extract.setInputCloud(cloud_filtered); extract.setIndices(inliers_plane); extract.setNegative(false); //将点云保存 pcl::PointCloud extract.filter(*cloud_plane); std::cout << "代表平面组件的点云有" < writer.write("table_scene_mug_stereo_textured_plane.pcd",*cloud_plane,false); /**************************************************************移除离群点*******************************************/ extract.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); /***************************************************************创建圆柱体分割对象并设置所有参数**********************/ seg.setOptimizeCoefficients(true);//设置对估计模型优化 seg.setModelType(pcl::SACMODEL_CYLINDER);//设置分割模型为圆柱形 seg.setNormalDistanceWeight(0.1);//设置表面法线权重系数 seg.setMaxIterations(10000);//设置迭代的最大次数10000 seg.setDistanceThreshold(0.05);//设置内点到模型的距离允许最大值 seg.setRadiusLimits(0,0.1);//设置估计出的圆柱模型的半径的范围 seg.setInputCloud(cloud_filtered2); seg.setInputNormals(cloud_normals2); /*************************************************获取圆柱体离群值和系数*****************************************/ seg.segment(*inliers_cylinder,*coeffcients_cylinder); std::cout << "圆柱系数" << *coeffcients_cylinder << std::endl; //将圆柱体离群值写入磁盘 extract.setInputCloud(cloud_filtered2); extract.setIndices(inliers_cylinder); extract.setNegative(false); pcl::PointCloud extract.filter(*cloud_cylinder); if (cloud_cylinder->points.empty()) { std::cerr << "找不到圆柱." << std::endl; } else { std::cerr << "代表圆柱形分量的点云: " << cloud_cylinder->points.size () << std::endl; writer.write ("table_scene_mug_stereo_textured_cylinder.pcd", *cloud_cylinder, false); } return 0; } CMakeLists.txt cmake_minimum_required(VERSION 3.16 FATAL_ERROR)#指定CMake的最低版本要求为3.16 project(project)#设置项目名称 find_package(PCL 1.10 REQUIRED)#查找PCL库,要求版本为1.10或更高。 include_directories(${PCL_INCLUDE_DIRS})#将PCL库的头文件目录添加到包含路径中 link_directories(${PCL_LIBRARY_DIRS})#将PCL库的库文件目录添加到链接器搜索路径中。 add_definitions(${PCL_DEFINITIONS})#添加PCL库的编译器定义 add_executable (cylinder_segmentation cylinder_segmentation.cpp) target_link_libraries (cylinder_segmentation ${PCL_LIBRARIES})#将PCL库链接到可执行文件目标。 运行结果 原始点云 获得的平面点云 获得的圆柱点云 函数 #include 补充内容 pcl::io::loadPCDFile和pcl::PCDReader的区别: pcl::io::loadPCDFile用于直接从文件路径加载点云数据到pcl::PointCloud对象中。示例如下 pcl::PointCloud pcl::io::loadPCDFile("path/to/file.pcd", cloud); pcl::PCDReader提供了更多的功能和控制选项。它需要先创建一个pcl::PCDReader对象,然后调用相应的成员函数来读取PCD文件。 pcl::PointCloud pcl::PCDReader reader; // 设置读取选项(可选) reader.setKeepOrganized(true); // 从文件路径读取点云数据 reader.read("path/to/file.pcd", cloud); 参考文章
发表评论