2025年【PCL-1】RANSAC平面分割

【PCL-1】RANSAC平面分割技术流程 1 点云裁剪 直通滤波 pcl PointCloud pcl pointxyz Ptr cloud PassThrough trim new pcl PointCloud pcl pointxyz 创建 x 轴裁剪对象 pcl PassThrough pcl pointxyz pcl pointxyz

大家好,我是讯享网,很高兴认识大家。

技术流程:

1、点云裁剪(直通滤波)

pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_PassThrough_trim(new pcl::PointCloud<pcl::PointXYZ>); //创建x轴裁剪对象 pcl::PassThrough<pcl::PointXYZ> passX; passX.setInputCloud(cloud); passX.setFilterFieldName("x"); passX.setFilterLimits(-40, 300); //裁剪保留区域 -400m-400m passX.filter(*cloud_PassThrough_trim); //创建y轴裁剪对象 pcl::PassThrough<pcl::PointXYZ> passY; passY.setInputCloud(cloud_PassThrough_trim); passY.setFilterFieldName("y"); passY.setFilterLimits(-200, 300); //裁剪保留区域 -400m-400m passY.filter(*cloud_PassThrough_trim);

讯享网

2、体素滤波(降采样)

原理:根据输入的点云,首先计算一个能够刚好包裹该点云的立方体,然后根据设定的分辨率,将该大立方体分割成不同的小立方体,对于每个小立方体内的点,计算它们的质心,并用该质心的坐标来近似该立方体内的若干点。

讯享网#include <pcl/filters/voxel_grid.h> pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>); //pcl::ApproximateVoxelGrid<pcl::PointXYZ> sor; pcl::VoxelGrid<pcl::PointXYZ> sor; sor.setInputCloud(cloud_PassThrough_trim); sor.setLeafSize(10.0f, 10.0f, 10.0f);//单位为m sor.filter(*cloud_filtered);

3、平面分割(获取地面点)

RANSAC常用于规则点云的分割,如直线、平面、圆球等。

RANSAC原理:从原始点云中随机选取n个点构成平面,当点云距离较近时加入该平面,不断迭代,最终所得平面点的个数达到一个数量即平面拟合完成。

参数:inliers  内点索引,coefficients 模型参数。

#include <pcl/segmentation/sac_segmentation.h> #include <pcl/filters/extract_indices.h> ... pcl::NormalEstimation<PointT, pcl::Normal> ne; pcl::ExtractIndices<PointT> extract; pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>()); pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>); pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg; pcl::PointIndices::Ptr inliers_plane(new pcl::PointIndices), inliers_cylinder(new pcl::PointIndices); pcl::ModelCoefficients::Ptr coefficients_plane(new pcl::ModelCoefficients), coefficients_cylinder(new pcl::ModelCoefficients); // Estimate point normals ne.setSearchMethod(tree); ne.setInputCloud(cloud_filtered); ne.setKSearch(50); ne.compute(*cloud_normals); // Create the segmentation object for the planar model and set all the parameters seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_NORMAL_PLANE); seg.setNormalDistanceWeight(0.1); seg.setMethodType(pcl::SAC_RANSAC); seg.setMaxIterations(100); seg.setDistanceThreshold(12.0); seg.setInputCloud(cloud_filtered); seg.setInputNormals(cloud_normals); // Obtain the plane inliers and coefficients seg.segment(*inliers_plane, *coefficients_plane); std::cerr << "Plane coefficients: " << *coefficients_plane << std::endl; // Extract the planar inliers from the input cloud extract.setInputCloud(cloud_filtered); extract.setIndices(inliers_plane); extract.setNegative(false); // Write the planar inliers to disk pcl::PointCloud<PointT>::Ptr cloud_plane(new pcl::PointCloud<PointT>()); extract.filter(*cloud_plane); std::cerr << "plane: " << cloud_plane->size() << " data points." << std::endl; writer.write("..\\testdata\\plane.pcd", *cloud_plane, false);

注:需调整setDistanceThreshold参数,单位为m,表示离地面多少距离范围内的点会被分到平面上,值越大,越有可能将平面上别的物体错误划分到平面上。

4、获取除地面点以外的点

讯享网pcl::ExtractIndices<PointT> extract; extract.setInputCloud(cloud_filtered); extract.setIndices(inliers_plane); extract.setNegative(false); // Write the planar inliers to disk pcl::PointCloud<PointT>::Ptr cloud_plane(new pcl::PointCloud<PointT>()); extract.filter(*cloud_plane);

完整示例代码:


讯享网

#include <pcl/ModelCoefficients.h> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/filters/extract_indices.h> #include <pcl/filters/passthrough.h> #include <pcl/features/normal_3d.h> #include <pcl/sample_consensus/method_types.h> #include <pcl/sample_consensus/model_types.h> #include <pcl/segmentation/sac_segmentation.h> #include <pcl/filters/voxel_grid.h> typedef pcl::PointXYZ PointT; int main() { // All the objects needed pcl::PCDReader reader; pcl::PassThrough<PointT> pass; pcl::NormalEstimation<PointT, pcl::Normal> ne; pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg; pcl::PCDWriter writer; pcl::ExtractIndices<PointT> extract; pcl::ExtractIndices<pcl::Normal> extract_normals; pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>()); // Datasets pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>); pcl::PointCloud<PointT>::Ptr cloud_filtered(new pcl::PointCloud<PointT>); pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>); pcl::PointCloud<PointT>::Ptr cloud_filtered2(new pcl::PointCloud<PointT>); pcl::PointCloud<pcl::Normal>::Ptr cloud_normals2(new pcl::PointCloud<pcl::Normal>); 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); // Read in the cloud data reader.read("E://TY//camport3-master//test-Cloud.pcd", *cloud); std::cerr << "PointCloud has: " << cloud->size() << " data points." << std::endl; // Build a passthrough filter to remove spurious NaNs and scene background /*pass.setInputCloud(cloud); pass.setFilterFieldName("z"); pass.setFilterLimits(0, 1.5); pass.filter(*cloud_filtered); std::cerr << "PointCloud after filtering has: " << cloud_filtered->size() << " data points." << std::endl;*/ pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_PassThrough_trim(new pcl::PointCloud<pcl::PointXYZ>); //创建x轴裁剪对象 pcl::PassThrough<pcl::PointXYZ> passX; passX.setInputCloud(cloud); passX.setFilterFieldName("x"); passX.setFilterLimits(-40, 300); //裁剪保留区域 -400m-400m passX.filter(*cloud_PassThrough_trim); //创建y轴裁剪对象 pcl::PassThrough<pcl::PointXYZ> passY; passY.setInputCloud(cloud_PassThrough_trim); passY.setFilterFieldName("y"); passY.setFilterLimits(-200, 300); //裁剪保留区域 -400m-400m passY.filter(*cloud_PassThrough_trim); //采用体素滤波器来实现降采样,去除噪点 //pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>); //pcl::ApproximateVoxelGrid<pcl::PointXYZ> sor; pcl::VoxelGrid<pcl::PointXYZ> sor; sor.setInputCloud(cloud_PassThrough_trim); sor.setLeafSize(10.0f, 10.0f, 10.0f);//单位为m sor.filter(*cloud_filtered); // Estimate point normals ne.setSearchMethod(tree); ne.setInputCloud(cloud_filtered); ne.setKSearch(50); ne.compute(*cloud_normals); // Create the segmentation object for the planar model and set all the parameters seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_NORMAL_PLANE); seg.setNormalDistanceWeight(0.1); seg.setMethodType(pcl::SAC_RANSAC); seg.setMaxIterations(100); seg.setDistanceThreshold(12.0); seg.setInputCloud(cloud_filtered); seg.setInputNormals(cloud_normals); // Obtain the plane inliers and coefficients seg.segment(*inliers_plane, *coefficients_plane); std::cerr << "Plane coefficients: " << *coefficients_plane << std::endl; // Extract the planar inliers from the input cloud extract.setInputCloud(cloud_filtered); extract.setIndices(inliers_plane); extract.setNegative(false); // Write the planar inliers to disk pcl::PointCloud<PointT>::Ptr cloud_plane(new pcl::PointCloud<PointT>()); extract.filter(*cloud_plane); std::cerr << "PointCloud representing the planar component: " << cloud_plane->size() << " data points." << std::endl; writer.write("E://TY//camport3-master//table_scene_mug_stereo_textured_plane.pcd", *cloud_plane, false); // Remove the planar inliers, extract the rest 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); writer.write("E://TY//camport3-master//table_scene_mug_stereo_textured_cylinder.pcd", *cloud_filtered2, false); // 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(10000); //seg.setDistanceThreshold(0.05); //seg.setRadiusLimits(0, 0.1); //seg.setInputCloud(cloud_filtered2); //seg.setInputNormals(cloud_normals2); 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_filtered2); //extract.setIndices(inliers_cylinder); //extract.setNegative(false); //pcl::PointCloud<PointT>::Ptr cloud_cylinder(new pcl::PointCloud<PointT>()); //extract.filter(*cloud_cylinder); //if (cloud_cylinder->points.empty()) //std::cerr << "Can't find the cylindrical component." << std::endl; //else //{ // std::cerr << "PointCloud representing the cylindrical component: " << cloud_cylinder->size() << " data points." << std::endl; // writer.write("E://TY//camport3-master//table_scene_mug_stereo_textured_cylinder.pcd", *cloud_cylinder, false); //} return (0); }

结果图:

原始点云

分割地面点云

目标点云

参考链接 【只谈干货】利用pcl库三步提取点云中的目标_点云目标提取_Open钢蛋的博客-CSDN博客

Cylinder model segmentation — Point Cloud Library 0.0 documentation

PCL学习笔记(二):PCL官方教程学习_pcl教程_Sakurazzy的博客-CSDN博客

小讯
上一篇 2025-01-29 20:55
下一篇 2025-01-25 21:59

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/21322.html