PCL求解规则点云的拟合圆

本文介绍如何使用PCL库中的RANSAC算法提取2D和3D圆形点云模型。通过示例代码展示了如何计算圆心坐标、半径及圆所在平面的法向量等关键参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该文章引用自https://blog.youkuaiyun.com/Asher_zheng/article/details/100019353,https://blog.youkuaiyun.com/baidu_40840693/article/details/103928636
仅作为学习记录

前言

PCL中可通过RANSAC算法来计算一些规则点云的数学模型,并返回模型的参数。
RANSAC算法可用来从点云中提取圆形点云并得到圆形点云的圆心、半径及圆所在平面的法向量
(适合于3D Circle)。
在PCL的RANSAC算法模型中,有2D Circle和3D Circle两种圆形模型,以下分作简要介绍。

2D Circle模型

2D Circle模型是从原点云中提取表达式为 (x-a)²+(y-b)²=r² 的点云圆,因此得到的点云是一个圆柱体的侧面,使用方式如下:
(1) 包含头文件:

#include <pcl/sample_consensus/sac_model_circle.h>

(2) 定义模型:

pcl::SampleConsensusModelCircle2D<pcl::PointXYZ>::Ptr model_circle2D
             (new pcl::SampleConsensusModelCircle2D<pcl::PointXYZ>(cloud));
///cloud为要求解拟合圆的点云        

(3) RANSAC提取2D圆形点云:

pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(model_circle2D);
ransac.setDistanceThreshold(.01);
ransac.computeModel();
ransac.getInliers(inliers);

(4) 得到圆心坐标及半径并输出:

Eigen::VectorXf modelParas;
ransac.getModelCoefficients(modelParas);
std::cout << modelParas<< "\n\n";

演示结果为:

第一个原始点云如最左边图所示,右边两张图为此点云应用RANSAC得出2D Circle模型的不同角度,可以看出是一个圆柱体的侧面:
在这里插入图片描述
所计算出的圆心坐标及半径如下:
在这里插入图片描述

3D Circle模型

3D Circle模型得到的是三维空间的圆形点云,其数学模型可由圆心,半径及圆所在平面的法向量表示,具体计算方式如下:

(1) 包含头文件:

#include <pcl/sample_consensus/sac_model_circle.h>

(2) 定义模型:

pcl::SampleConsensusModelCircle3D<pcl::PointXYZ>::Ptr
		model_circle3D(new pcl::SampleConsensusModelCircle3D<pcl::PointXYZ>(cloud));

(3) RANSAC提取3D圆形点云:

pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(model_circle3D);
ransac.setDistanceThreshold(.01);
ransac.computeModel();
ransac.getInliers(inliers);

(4) 得到模型参数并打印出模型参数:

Eigen::VectorXf modelParas;
ransac.getModelCoefficients(modelParas);
std::cout << modelParas<< "\n\n";

演示结果为:

在这里插入图片描述
所计算出的圆心坐标及半径如下,前三个数值为圆心坐标(x, y, z),第四个数值为计算出的圆形点云的半径,最后三个为圆形点云所在平面的法向量:

在这里插入图片描述

具体实例

    ///定义了final点云,存放最后的结果
    pcl::PointCloud<pcl::PointXYZ>::Ptr final (new pcl::PointCloud<pcl::PointXYZ>);
    ///存放拟合圆
    std::vector<int> inliersCircle3D;
    
    ///oriCloud_inliers:待求解拟合圆的原始点云
    pcl::SampleConsensusModelCircle3D<PointT>::Ptr socCircle3D(new pcl::SampleConsensusModelCircle3D<PointT> (oriCloud_inliers));
    
    ///求解拟合圆
    pcl::RandomSampleConsensus<PointT>::Ptr ransac ( new pcl::RandomSampleConsensus<PointT> (socCircle3D) );
    ransac->setDistanceThreshold(0.1f);
    ransac->computeModel();
    ransac->getInliers(inliersCircle3D);
    
    ///获取拟合圆的参数
    Eigen::VectorXf circle_coeff;
    ransac->getModelCoefficients(circle_coeff);
   
    PointCloud::Ptr finalCircle3D(new PointCloud);
    pcl::copyPointCloud (*oriCloud_inliers, inliersCircle3D, *finalCircle3D);
    std::cout<<"circle_coeff "<<"rows="<<circle_coeff.rows()<<"cols="<<circle_coeff.cols()<<"coefficeints="<<circle_coeff.size()<<std::endl;
    
    ///可视化
    pcl::visualization::PointCloudColorHandlerCustom<PointT> color_handler5(finalCircle3D, 230, 50, 12);//红色
    view->addPointCloud(finalCircle3D, color_handler5, "CH5");

copyPointCloud()函数

常见的使用方法有两种:

Part 1:完全拷贝到新的点云之中:pcl::copyPointCloud (const pcl::PointCloud &cloud_in,pcl::PointCloud &cloud_out)

pcl::PointCloud<pcl::PointXYZ>::Ptr src(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointNormal>::Ptr src_PN(new pcl::PointCloud<pcl::PointNormal>);

pcl::io::loadPCDFile("src.pcd",*src);//载入原数据
pcl::io::loadPCDFile("src_pn.pcd", *src_PN);//载入原数据

pcl::copyPointCloud(*src, *src_PN);//src中的xyz覆盖掉src_PN中的xyz值

pcl::io::savePCDFile("src_with_normal.pcd", *src_PN);

Part 2:部分索引的使用:pcl::copyPointCloud (const pcl::PointCloud &cloud_in, const std::vector &indices,pcl::PointCloud &cloud_out)

pcl::PointCloud<pcl::PointXYZ>::Ptr src(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("src.pcd",*src);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudout(new pcl::PointCloud<pcl::PointXYZ>);
std::vector<int>indexs = { 0,2,6 };//索引
pcl::copyPointCloud(*src, indexs, *cloudout);
pcl::io::savePCDFile("cloud_out.pcd", *cloudout);//只取src中的第1,第3个,第7个点赋值到新的cloudout中。
### 使用PCL库对平面点云数据进行矩形拟合 为了使用PCL库对平面点云数据进行矩形拟合,通常先通过PCA方法或其他手段找到最佳拟合平面。一旦获得了该平面,则可以在平面上寻找边界框或轮廓以定义矩形区域。 #### 平面拟合过程概述 利用主成分分析(PCA),可以从点云中提取出描述其分布的主要方向,进而确定一个最能代表这些点的最佳拟合平面[^1]。此过程中计算出来的特征向量提供了坐标轴的方向信息,而对应的特征值则反映了沿各个方向上的方差大小;其中最大的两个特征值所对应的方向构成了目标平面内的基底矢量。 对于更精确和平稳的结果,在某些场景下可能还需要调整参数如迭代次数和收敛条件来优化平面拟合的质量[^2]。 #### 实现矩形拟合的具体步骤 完成上述平面拟合之后,下一步就是识别并提取位于同一水平面上的对象边缘以便构建矩形模型: - **分割**:从原始点云中分离出属于特定平面的部分。 - **降维投影**:将三维空间中的点映射至二维平面上,简化后续操作。 - **轮廓检测/聚类**:应用诸如RANSAC等算法查找物体外接多边形或者直接运用形态学运算获取闭合曲线。 - **最小面积包围盒**:基于所得轮廓计算最小旋转矩形作为最终拟合结果的一部分。 以下是Python代码片段展示如何执行这一系列任务: ```cpp #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/features/normal_3d.h> #include <pcl/filters/passthrough.h> #include <pcl/sample_consensus/method_types.h> #include <pcl/sample_consensus/model_types.h> #include <pcl/segmentation/sac_segmentation.h> #include <pcl/filters/project_inliers.h> // ... 初始化 PointCloud 对象 ... pcl::SACSegmentation<pcl::PointXYZ> seg; seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_PLANE); // 设置模型为平面 seg.setMethodType(pcl::SAC_RANSAC); // RANSAC 方法 seg.setMaxIterations(1000); // 迭代上限 seg.setDistanceThreshold(0.01); // 距离阈值 pcl::ModelCoefficients coefficients; pcl::PointIndices inliers; seg.setInputCloud(cloud.makeShared()); seg.segment(inliers, coefficients); if (inliers.indices.size() != 0){ pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected(new pcl::PointCloud<pcl::PointXYZ>); pcl::ProjectInliers<pcl::PointXYZ> proj; proj.setModelType(pcl::SACMODEL_PLANE); proj.setInputCloud(cloud.makeShared()); proj.setModelCoefficients(coefficients); proj.filter(*cloud_projected); // 继续处理 projected_cloud... } ``` 注意这段C++代码主要用于说明目的,并未完全覆盖整个流程特别是最后一步即求解最小外包矩形的过程。这可以通过OpenCV库或者其他几何工具包进一步实现。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值