该文章引用自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中。