PCL点云特征识别-圆孔特征识别

一、引言

个人的blog:sifanのblog

基于点的特征识别算法相对较少,刚好又需要对项目中的圆孔特征进行滤波,故采取点云密度+RANSAC对圆孔特征进行识别和滤波。

  1. 首先,根据采集点云的密度差异提取出包含圆孔特征,边界特征的点云集合;
  2. 然后,利用RANSAC进行圆孔拟合;
  3. 最后,获取拟合的圆孔的半径,圆心利用包围盒进行去除。

二、实现

2.1点云密度差异聚类

计算点云数据的点密度差异,提取出密度差异的特征点云,并进行欧式聚类,具体实现见点云计算点密度特征 | Sifanのblog (liangzhouzz.github.io)

原始图像
在这里插入图片描述


提取后的图像:

在这里插入图片描述

2.2点云聚类

将经过密度提取后的点云进行聚类,代码如下:

pcl::search::KdTree<pcl::PointXYZ>::Ptr kd_tree(new pcl::search::KdTree<pcl::PointXYZ>); //创建kdtree
kd_tree->setInputCloud(cloud);

std::vector<pcl::PointIndices>cluster_indices;//点索引
pcl::EuclideanClusterExtraction<pcl::PointXYZ>ec;//创建欧式聚类
ec.setClusterTolerance(0.2);//聚类容忍度
ec.setMinClusterSize(20);//最小聚类点数量
ec.setMaxClusterSize(cloud->size());//最大聚类点数量
ec.setSearchMethod(kd_tree);//搜索方式
ec.setInputCloud(cloud);
ec.extract(cluster_indices);

2.3RANSAC拟合圆

RANSAC拟合圆,可选择拟合2D圆pcl::SACMODEL_CIRCLE2D或3D圆pcl::SACMODEL_CIRCLE3D,这里选择用3D,RANSAC需传入法向量,对点云进行法向量估计。RANSAC会存在拟合错误的情况,需要对拟合出圆的半径进行限制,限制在其范围内找到目标圆。

//类创建
pcl::SACSegmentationFromNormals<pcl::PointXYZ,pcl::Normal>seg;
pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);//创建索引对象
pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
std::vector<pcl::ModelCoefficients>coeff;

//	估计法向量
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud(cluster);
ne.setSearchMethod(tree);
ne.setRadiusSearch(0.01);
ne.compute(*normals);

//ransac
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_CIRCLE3D);//拟合3D圆
seg.setMethodType(pcl::SAC_RANSAC);//RANSAC
seg.setNormalDistanceWeight(0.9);//设置法向量权重
seg.setMaxIterations(10000);//设置最大迭代次数
seg.setDistanceThreshold(0.1);//eps
seg.setRadiusLimits(1.5,3);//添加拟合圆的半径限制,防止拟合过大或过小的圆
seg.setInputNormals(normals);//输入法向量
seg.setInputCloud(cluster);//传入点集
seg.segment(*inliers,*coefficients);//分割

2.4包围盒分割

根据提取出圆的索引,可以得到其圆心坐标和半径,然后利用最小包围盒进行分割。

拟合出3D圆的参数如下:

  • 圆心坐标x:value[0]
  • 圆心坐标y:value[1]
  • 圆心坐标z:value[2]
  • 半径r:value[3]
  • 法向量nx:value[4]
  • 法向量ny:value[5]
  • 法向量nz:value[6]

设置包围盒的最小点坐标min_pt,和最大点坐标max_pt,然后创建包围盒对象,得到在包围盒内的点云索引。

for (size_t i = 0; i < coeff.size(); i++)
{
    //提取拟合圆环的中心点坐标
    Eigen::Vector3f center(coeff.at(i).values[0],coeff.at(i).values[1],coeff.at(i).values[2]);
    //设置分割的包围盒长宽高,圆环的半径+阈值
    float length0 = fabs(coeff.at(i).values[3])+0.3,width0 = fabs(coeff.at(i).values[3])+0.3, height0 = 5.0;
    Eigen::Vector4f min_pt(center.x()-(length0),center.y()-(width0),center.z()-(height0),0);//半径
    Eigen::Vector4f max_pt(center.x()+(length0),center.y()+(width0),center.z()+(height0),0);
				
    //创建包围盒对象
    pcl::CropBox<pcl::PointXYZ>crop;
    crop.setMin(min_pt);//输入最小坐标
    crop.setMax(max_pt);//最大坐标
    crop.setInputCloud(cloud);
    crop.setKeepOrganized(false);//提取被删除点的索引则为true
    crop.setUserFilterValue(0.1f);//
    pcl::IndicesPtr indexes(new std::vector<int>);
    crop.filter(*indexes);
	//创建分割对象
    pcl::ExtractIndices<pcl::PointXYZ>extract;
    extract.setInputCloud(cloud);
    extract.setIndices(indexes);
    extract.setNegative(true);
    extract.filter(*cloud);//保存点云
}

2.5代码实现

//头文件
#include<pcl/sample_consensus/sac_model_circle3d.h>
#include<pcl/segmentation/extract_clusters.h>//提取聚类
#include<pcl/filters/crop_box.h>//包围盒
#include<pcl/segmentation/sac_segmentation.h>
#include<pcl/filters/extract_indices.h>


void ExtractCircle(const pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud)
{
        pcl::search::KdTree<pcl::PointXYZ>::Ptr kd_tree(new pcl::search::KdTree<pcl::PointXYZ>);
        kd_tree->setInputCloud(cloud);
        //聚类
        std::vector<pcl::PointIndices>cluster_indices;
        pcl::EuclideanClusterExtraction<pcl::PointXYZ>ec;
        ec.setClusterTolerance(0.2);
        ec.setMinClusterSize(20);
        ec.setMaxClusterSize(cloud->size());
        ec.setSearchMethod(kd_tree);
        ec.setInputCloud(cloud);
        ec.extract(cluster_indices);

        //RANSAC拟合
        pcl::SACSegmentationFromNormals<pcl::PointXYZ,pcl::Normal>seg;
        pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);//创建索引对象
        pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
        std::vector<pcl::ModelCoefficients>coeff;
    
        int counti=0;
        for (const auto & indices : cluster_indices)
        {
                pcl::PointCloud<pcl::PointXYZ>::Ptr cluster(new pcl::PointCloud<pcl::PointXYZ>);
                pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cir(new pcl::PointCloud<pcl::PointXYZ>);
                pcl::copyPointCloud(*cloud,indices.indices,*cluster);
                pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
            	//	估计法向量
                pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
                pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
                ne.setInputCloud(cluster);
                ne.setSearchMethod(tree);
                ne.setRadiusSearch(0.01);
                ne.compute(*normals);
				//RANSAC
                seg.setOptimizeCoefficients(true);
                seg.setModelType(pcl::SACMODEL_CIRCLE3D);//拟合3D圆
                seg.setMethodType(pcl::SAC_RANSAC);//RANSAC
                seg.setNormalDistanceWeight(0.9);//法向量权重
                seg.setMaxIterations(10000);//设置最大迭代次数
                seg.setDistanceThreshold(0.1);//eps
                seg.setRadiusLimits(1.5,3);//添加拟合圆的半径限制,防止拟合过大或过小的圆
                seg.setInputNormals(normals);//输入法向量
                seg.setInputCloud(cluster);//传入点集
                seg.segment(*inliers,*coefficients);//分割
            	//拟合圆的点数限制,因为很容易会拟合半圆,需根据实际的需求调整,防止拟合半圆
                if (inliers->indices.size() < 80)
                {
                        //cerr<<"none"<<endl;
                        continue;
                }
                coeff.push_back(*coefficients);
                counti++;
            	//提取
                pcl::ExtractIndices<pcl::PointXYZ> extract;
                extract.setInputCloud(cluster);
                extract.setIndices(inliers);
                extract.setNegative(false);
                extract.filter(*cloud_cir);
        }
		
        for (size_t i = 0; i < coeff.size(); i++)
        {
            	//提取拟合圆环的中心点坐标
                Eigen::Vector3f center(coeff.at(i).values[0],coeff.at(i).values[1],coeff.at(i).values[2]);
            	//设置分割的包围盒长宽高,圆环的半径+阈值
                float length0 = fabs(coeff.at(i).values[3])+0.3,width0 = fabs(coeff.at(i).values[3])+0.3, height0 = 5.0;
                Eigen::Vector4f min_pt(center.x()-(length0),center.y()-(width0),center.z()-(height0),0);//半径
                Eigen::Vector4f max_pt(center.x()+(length0),center.y()+(width0),center.z()+(height0),0);
				
            	//创建包围盒对象
                pcl::CropBox<pcl::PointXYZ>crop;
                crop.setMin(min_pt);//输入最小坐标
                crop.setMax(max_pt);//最大坐标
                crop.setInputCloud(cloud);
                crop.setKeepOrganized(false);//提取被删除点的索引则为true
                crop.setUserFilterValue(0.1f);//
                pcl::IndicesPtr indexes(new std::vector<int>);
                crop.filter(*indexes);
				//创建分割对象
                pcl::ExtractIndices<pcl::PointXYZ>extract;
                extract.setInputCloud(cloud);
                extract.setIndices(indexes);
                extract.setNegative(true);
                extract.filter(*cloud);//保存点云
        }

}

2.6结果

RANSAC搜索的对象

在这里插入图片描述

包围盒分割图像

在这里插入图片描述

### 回答1: PCL(Point Cloud Library)是一个开源的点云处理库,可以用于点云数据的各种操作,包括点云拟合、配准、分割、重建等。 要拟合一个圆孔并提取圆心坐标,可以使用PCL中的圆拟合(Circle Fitting)模块。具体步骤如下: 1. 读取点云数据,例如从一个.pcd文件中读取: ``` pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile<pcl::PointXYZ>("cloud.pcd", *cloud); ``` 2. 对点云进行预处理,例如去除离群点: ``` pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setInputCloud(cloud); sor.setMeanK(50); sor.setStddevMulThresh(1.0); sor.filter(*cloud_filtered); ``` 3. 对点云进行圆拟合: ``` pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients); pcl::PointIndices::Ptr inliers(new pcl::PointIndices); pcl::SACSegmentation<pcl::PointXYZ> seg; seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_CIRCLE2D); seg.setMethodType(pcl::SAC_RANSAC); seg.setDistanceThreshold(0.01); seg.setInputCloud(cloud_filtered); seg.segment(*inliers, *coefficients); ``` 4. 提取圆心坐标: ``` float x = coefficients->values[0]; float y = coefficients->values[1]; ``` 其中,x和y即为圆心坐标。 完整代码示例: ``` pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile<pcl::PointXYZ>("cloud.pcd", *cloud); pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setInputCloud(cloud); sor.setMeanK(50); sor.setStddevMulThresh(1.0); sor.filter(*cloud_filtered); pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients); pcl::PointIndices::Ptr inliers(new pcl::PointIndices); pcl::SACSegmentation<pcl::PointXYZ> seg; seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_CIRCLE2D); seg.setMethodType(pcl::SAC_RANSAC); seg.setDistanceThreshold(0.01); seg.setInputCloud(cloud_filtered); seg.segment(*inliers, *coefficients); float x = coefficients->values[0]; float y = coefficients->values[1]; ``` ### 回答2: PCL(点云库)是一个用于点云处理的开源库,可以在三维点云数据中进行各种操作,包括拟合圆孔和提取圆心坐标。 在点云中拟合圆孔并提取圆心坐标的过程主要分为以下几个步骤: 1. 数据准备:将点云数据加载到PCL中,并进行预处理,例如去除离群点、滤波和降采样等。 2. 圆形检测:使用PCL中的圆形检测算法对处理后的点云进行圆形检测。该算法基于RANSAC(随机样本一致性)方法,通过对圆形模型的样本进行采样和测试,找到最佳拟合圆形的参数。 3. 提取圆心坐标:通过拟合得到的圆形参数,可以得到圆形的中心坐标。这些参数通常包括圆心坐标和半径。 4. 圆孔筛选:根据所需圆孔的尺寸范围和其他条件,对检测到的圆形进行筛选和过滤。 5. 输出结果:将筛选后的圆孔结果输出,包括圆心坐标和其他额外信息。 总结起来,使用PCL拟合圆孔并提取圆心坐标的过程包括数据准备、圆形检测、提取圆心坐标、圆孔筛选和输出结果等步骤。这些步骤可以借助PCL中提供的函数和算法来完成,并且可以根据具体需求进行参数调整和处理优化。 ### 回答3: PCL(Point Cloud Library)是一个非常强大的开源点云处理库,可以用于处理、分析和可视化点云数据。在PCL中,可以使用一些滤波器和拟合方法来对点云数据中的圆孔进行拟合,并提取圆心坐标。 首先,我们需要进行离散点云数据的预处理,可以使用滤波器(如体素格滤波器)来降低噪声。然后,我们可以使用RANSAC(Random Sample Consensus)算法进行圆形拟合。RANSAC算法是一种迭代的拟合算法,通过随机选择一定数量的点,拟合出一个圆形模型,并计算其他点与该模型的拟合误差。然后,选择与模型拟合误差较小的一组点,继续迭代拟合过程,直到满足收敛条件为止。 在PCL中,可以使用pcl::SampleConsensusModelCircle类进行圆形拟合。该类提供了一些函数来设置拟合参数和获取拟合结果,包括圆心坐标等信息。在拟合完成后,可以利用这些信息提取圆心坐标。 具体步骤如下: 1. 加载点云数据并进行滤波处理(如体素格滤波器)。 2. 创建pcl::SampleConsensusModelCircle对象,并设置拟合参数。 3. 调用该对象的estimate函数,进行圆形拟合。 4. 获取拟合结果,包括圆心坐标等信息。 需要注意的是,拟合的效果受点云数据质量和拟合参数设置的影响。根据实际情况,可以调整拟合参数以获得更好的拟合效果。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值