PCL 将点云投影到圆柱(Ransac拟合)
目录
一、概述
1.1原理
1.2实现步骤
1.3应用场景
二、代码实现
2.1关键函数
2.1.1 法线估计
2.1.2 圆柱拟合
2.1.3 投影滤波
2.1.4 可视化
2.2完整代码
三、实现效果
PCL点云算法汇总及实战案例汇总的目录地址链接:
PCL点云算法与项目实战案例汇总(长期更新)
一、概述
点云投影到圆柱模型 是通过拟合点云数据中的圆柱形特征,将原始点云投影到圆柱体表面。通过拟合圆柱体的模型,可以将点云数据与该圆柱体匹配,并将其投影到圆柱表面。该过程常用于几何建模、特征提取和3D重建中。
1.1原理
- 法线估计:通过计算点云的法向量,帮助拟合几何模型。
- 圆柱拟合:使用RANSAC算法对点云进行圆柱模型拟合,获得圆柱模型系数(包括轴线方向、圆柱半径等)。
- 投影滤波:将原始点云投影到拟合得到的圆柱模型上,使点云数据与圆柱模型相匹配。
1.2实现步骤
- 读取点云数据并计算其法向量。
- 使用RANSAC算法拟合圆柱模型,获取模型系数。
- 将原始点云投影到圆柱体表面。
- 可视化原始点云和投影后的点云
1.3应用场景
- 管道检测:在工业或建筑领域,圆柱形的物体如管道、柱子等,常见于各种检测任务,通过将点云投影到圆柱模型,可以检测和分析这些物体的几何特征。
- 3D重建:在3D重建过程中,圆柱形物体(如杆、柱等)需要精确拟合,以确保重建模型的准确性。
- 医学成像:圆柱模型在骨骼、血管等医学影像处理中也有应用,点云投影可以辅助分析器官或骨骼的形态。
- 机器人导航:在复杂环境中,圆柱形障碍物的检测有助于机器人避障和路径规划。
二、代码实现
2.1关键函数
2.1.1 法线估计
#include <pcl/features/normal_3d.h> // 引入法线估计相关的头文件// 计算点云法线
void computeNormals(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::Normal>::Ptr normals)
{pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());ne.setSearchMethod(tree); // 设置搜索方式ne.setInputCloud(cloud); // 输入点云ne.setKSearch(20); // 设置K近邻搜索点的个数ne.compute(*normals); // 计算法线
}
2.1.2 圆柱拟合
#include <pcl/segmentation/sac_segmentation.h> // 引入分割模块// 圆柱拟合
void segmentCylinder(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,pcl::PointCloud<pcl::Normal>::Ptr normals,pcl::PointIndices::Ptr inliers_cylinder,pcl::ModelCoefficients::Ptr coefficients_cylinder)
{pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> seg;seg.setInputCloud(cloud); // 输入点云seg.setInputNormals(normals); // 输入法向量seg.setOptimizeCoefficients(true); // 对估计的模型系数进行优化seg.setModelType(pcl::SACMODEL_CYLINDER); // 设置模型类型为圆柱seg.setMethodType(pcl::SAC_RANSAC); // 使用RANSAC算法seg.setNormalDistanceWeight(0.3); // 设置表面法线的权重seg.setMaxIterations(10000); // 最大迭代次数seg.setDistanceThreshold(0.1); // 内点到模型的最大距离seg.setRadiusLimits(2.0, 3.0); // 圆柱半径范围seg.segment(*inliers_cylinder, *coefficients_cylinder); // 执行分割,获取模型系数
}
2.1.3 投影滤波
#include <pcl/filters/project_inliers.h> // 引入投影滤波器头文件// 将点云投影到圆柱
void projectPointCloudToCylinder(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,pcl::ModelCoefficients::Ptr coefficients_cylinder,pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected)
{pcl::ProjectInliers<pcl::PointXYZ> proj;proj.setModelType(pcl::SACMODEL_CYLINDER); // 设置模型类型为圆柱proj.setInputCloud(cloud); // 输入点云proj.setModelCoefficients(coefficients_cylinder); // 输入圆柱模型系数proj.filter(*cloud_projected); // 执行投影滤波
}
2.1.4 可视化
#include <pcl/visualization/pcl_visualizer.h> // 引入可视化库// 可视化原始点云和投影后的点云
void visualizePointClouds(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,pcl::PointCloud<pcl::PointXYZ>::Ptr projected_cloud)
{pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Cylinder Projection Visualization"));// 设置视口1,显示原始点云int vp_1;viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp_1);viewer->setBackgroundColor(1.0, 1.0, 1.0, vp_1); // 白色背景viewer->addText("Original PointCloud", 10, 10, "vp1_text", vp_1);pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color(cloud, 0, 255, 0); // 绿色显示原始点云viewer->addPointCloud(cloud, cloud_color, "original_cloud", vp_1);// 设置视口2,显示投影后的点云int vp_2;viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp_2);viewer->setBackgroundColor(0.98, 0.98, 0.98, vp_2); // 浅灰色背景viewer->addText("Projected PointCloud", 10, 10, "vp2_text", vp_2);pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> projected_color(projected_cloud, 0, 0, 255); // 蓝色显示投影后的点云viewer->addPointCloud(projected_cloud, projected_color, "projected_cloud", vp_2);while (!viewer->wasStopped()){viewer->spinOnce(100);}
}
2.2完整代码
#include <iostream>
#include <pcl/io/pcd_io.h> // PCD文件读取
#include <pcl/point_types.h> // 点云类型
#include <pcl/ModelCoefficients.h> // 模型系数
#include <pcl/features/normal_3d.h> // 法线估计
#include <pcl/segmentation/sac_segmentation.h> // 分割
#include <pcl/filters/project_inliers.h> // 投影滤波
#include <pcl/visualization/pcl_visualizer.h> // 可视化库
#include <boost/thread/thread.hpp> // 线程库// 计算点云法线
void computeNormals(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::Normal>::Ptr normals)
{pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());ne.setSearchMethod(tree); // 设置搜索方式ne.setInputCloud(cloud); // 输入点云ne.setKSearch(20); // 设置K近邻搜索点的个数ne.compute(*normals); // 计算法线
}// 圆柱拟合
void segmentCylinder(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,pcl::PointCloud<pcl::Normal>::Ptr normals,pcl::PointIndices::Ptr inliers_cylinder,pcl::ModelCoefficients::Ptr coefficients_cylinder)
{pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> seg;seg.setInputCloud(cloud); // 输入点云seg.setInputNormals(normals); // 输入法向量seg.setOptimizeCoefficients(true); // 对估计的模型系数进行优化seg.setModelType(pcl::SACMODEL_CYLINDER); // 设置模型类型为圆柱seg.setMethodType(pcl::SAC_RANSAC); // 使用RANSAC算法seg.setNormalDistanceWeight(0.3); // 设置表面法线的权重seg.setMaxIterations(10000); // 最大迭代次数seg.setDistanceThreshold(0.1); // 内点到模型的最大距离seg.setRadiusLimits(2.0, 3.0); // 圆柱半径范围seg.segment(*inliers_cylinder, *coefficients_cylinder); // 执行分割,获取模型系数
}// 将点云投影到圆柱
void projectPointCloudToCylinder(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,pcl::ModelCoefficients::Ptr coefficients_cylinder,pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected)
{pcl::ProjectInliers<pcl::PointXYZ> proj;proj.setModelType(pcl::SACMODEL_CYLINDER); // 设置模型类型为圆柱proj.setInputCloud(cloud); // 输入点云proj.setModelCoefficients(coefficients_cylinder); // 输入圆柱模型系数proj.filter(*cloud_projected); // 执行投影滤波
}// 可视化函数
void visualizePointClouds(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,pcl::PointCloud<pcl::PointXYZ>::Ptr projected_cloud)
{pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Cylinder Projection Visualization"));// 设置视口1,显示原始点云int vp_1;viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp_1);viewer->setBackgroundColor(1.0, 1.0, 1.0, vp_1); // 白色背景viewer->addText("Original PointCloud", 10, 10, "vp1_text", vp_1);pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color(cloud, 0, 255, 0); // 绿色显示原始点云viewer->addPointCloud(cloud, cloud_color, "original_cloud", vp_1);// 设置视口2,显示投影后的点云int vp_2;viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp_2);viewer->setBackgroundColor(0.98, 0.98, 0.98, vp_2); // 浅灰色背景viewer->addText("Projected PointCloud", 10, 10, "vp2_text", vp_2);pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> projected_color(projected_cloud, 0, 0, 255); // 蓝色显示投影后的点云viewer->addPointCloud(projected_cloud, projected_color, "projected_cloud", vp_2);while (!viewer->wasStopped()){viewer->spinOnce(100);}
}// main函数
int main(int argc, char** argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);pcl::io::loadPCDFile<pcl::PointXYZ>("侍女.pcd", *cloud);pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);computeNormals(cloud, normals); // 计算法向量pcl::PointIndices::Ptr inliers_cylinder(new pcl::PointIndices);pcl::ModelCoefficients::Ptr coefficients_cylinder(new pcl::ModelCoefficients);segmentCylinder(cloud, normals, inliers_cylinder, coefficients_cylinder); // 圆柱拟合pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected(new pcl::PointCloud<pcl::PointXYZ>);projectPointCloudToCylinder(cloud, coefficients_cylinder, cloud_projected); // 点云投影visualizePointClouds(cloud, cloud_projected); // 可视化结果return 0;
}