PCL点云算法汇总及实战案例汇总的目录地址链接:
PCL点云算法与项目实战案例汇总(长期更新)
一、概述
该代码通过拟合直线模型,将点云投影到该直线上,并输出投影后的点云。
1.1原理
点云投影到直线的过程主要包括以下两步:
- 空间直线拟合:利用随机采样一致性(RANSAC)算法拟合一条空间直线,选择出点云中最符合直线模型的内点。
- 点云投影:通过几何模型的参数,将原始点云中的每个点投影到拟合的直线上。
直线的参数由直线的起点 (x₀, y₀, z₀) 和方向向量 (a, b, c) 共同决定,投影点的位置通过直线的几何公式进行计算。
1.2实现步骤
- 加载点云数据。
- 使用RANSAC算法拟合直线模型,提取符合模型的内点。
- 获取拟合直线的参数。
- 创建滤波器,将点云投影到拟合的直线上。
- 保存并输出投影后的点云数据。
1.3应用场景
- 工业检测:适用于检测长直杆状物体或轨迹的点云数据处理。
- 3D重建:在3D场景中,通过拟合直线和投影来简化建模。
- 自动化装配:直线投影可以用于物体路径规划。
二、代码实现
2.1关键函数
2.1.1 RANSAC直线拟合
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_line.h>
// 使用RANSAC拟合直线
void fitLineWithRANSAC(
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
Eigen::VectorXf& lineCoefs, std::vector<int>& inliers)
{
pcl::SampleConsensusModelLine<pcl::PointXYZ>::Ptr modelLine(
new pcl::SampleConsensusModelLine<pcl::PointXYZ>(cloud)); // 创建直线模型
pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(modelLine); // 创建RANSAC对象
ransac.setDistanceThreshold(0.01); // 设置内点距离阈值
ransac.setMaxIterations(1000); // 设置最大迭代次数
ransac.computeModel(); // 执行RANSAC拟合
ransac.getInliers(inliers); // 获取内点索引
ransac.getModelCoefficients(lineCoefs); // 获取直线模型参数
}
2.1.2 点云投影到拟合直线
#include <pcl/filters/project_inliers.h>
// 投影点云到拟合的直线
void projectPointCloudToLine(
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
Eigen::VectorXf& lineCoefs,
pcl::PointCloud<pcl::PointXYZ>::Ptr projectedCloud)
{
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
coefficients->values.resize(6);
for (int i = 0; i < 6; ++i) {
coefficients->values[i] = lineCoefs[i]; // 获取直线的6个参数
}
pcl::ProjectInliers<pcl::PointXYZ> proj;
proj.setModelType(pcl::SACMODEL_LINE);
proj.setInputCloud(cloud);
proj.setModelCoefficients(coefficients);
proj.filter(*projectedCloud); // 投影点云到直线上
}
2.1.3 可视化原始点云和投影点云
#include <pcl/visualization/pcl_visualizer.h>
// 可视化原始点云和投影点云
void visualizePointClouds(
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
pcl::PointCloud<pcl::PointXYZ>::Ptr projectedCloud)
{
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Point Cloud Visualization"));
int vp1, vp2;
viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp1);
viewer->setBackgroundColor(1.0, 1.0, 1.0, vp1); // 白色背景
viewer->addText("Original Point Cloud", 10, 10, "vp1_text", vp1);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color(cloud, 255, 0, 0); // 红色
viewer->addPointCloud(cloud, cloud_color, "original_cloud", vp1);
viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp2);
viewer->setBackgroundColor(0.98, 0.98, 0.98, vp2); // 浅灰色背景
viewer->addText("Projected Point Cloud", 10, 10, "vp2_text", vp2);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> projected_color(projectedCloud, 0, 255, 0); // 绿色
viewer->addPointCloud(projectedCloud, projected_color, "projected_cloud", vp2);
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
}
2.2完整代码
#include <pcl/io/pcd_io.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_line.h>
#include <pcl/filters/project_inliers.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
using namespace std;
// 使用RANSAC拟合直线
void fitLineWithRANSAC(
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
Eigen::VectorXf& lineCoefs, std::vector<int>& inliers)
{
pcl::SampleConsensusModelLine<pcl::PointXYZ>::Ptr modelLine(
new pcl::SampleConsensusModelLine<pcl::PointXYZ>(cloud)); // 创建直线模型
pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(modelLine); // 创建RANSAC对象
ransac.setDistanceThreshold(0.01); // 设置内点距离阈值
ransac.setMaxIterations(1000); // 设置最大迭代次数
ransac.computeModel(); // 执行RANSAC拟合
ransac.getInliers(inliers); // 获取内点索引
ransac.getModelCoefficients(lineCoefs); // 获取直线模型参数
}
// 投影点云到拟合的直线
void projectPointCloudToLine(
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
Eigen::VectorXf& lineCoefs,
pcl::PointCloud<pcl::PointXYZ>::Ptr projectedCloud)
{
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
coefficients->values.resize(6);
for (int i = 0; i < 6; ++i) {
coefficients->values[i] = lineCoefs[i]; // 获取直线的6个参数
}
pcl::ProjectInliers<pcl::PointXYZ> proj;
proj.setModelType(pcl::SACMODEL_LINE);
proj.setInputCloud(cloud);
proj.setModelCoefficients(coefficients);
proj.filter(*projectedCloud); // 投影点云到直线上
}
// 可视化原始点云和投影点云
void visualizePointClouds(
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
pcl::PointCloud<pcl::PointXYZ>::Ptr projectedCloud)
{
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Point Cloud Visualization"));
int vp1, vp2;
viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp1);
viewer->setBackgroundColor(1.0, 1.0, 1.0, vp1); // 白色背景
viewer->addText("Original Point Cloud", 10, 10, "vp1_text", vp1);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color(cloud, 255, 0, 0); // 红色
viewer->addPointCloud(cloud, cloud_color, "original_cloud", vp1);
viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp2);
viewer->setBackgroundColor(0.98, 0.98, 0.98, vp2); // 浅灰色背景
viewer->addText("Projected Point Cloud", 10, 10, "vp2_text", vp2);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> projected_color(projectedCloud, 0, 255, 0); // 绿色
viewer->addPointCloud(projectedCloud, projected_color, "projected_cloud", vp2);
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
}
int main()
{
// 加载点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile("bunny.pcd", *cloud) < 0)
{
PCL_ERROR("点云文件不存在");
return -1;
}
std::cout << "加载点云个数为:" << cloud->points.size() << std::endl;
// RANSAC直线拟合
Eigen::VectorXf lineCoefs;
std::vector<int> inliers;
fitLineWithRANSAC(cloud, lineCoefs, inliers);
// 投影到拟合直线
pcl::PointCloud<pcl::PointXYZ>::Ptr lineProCloud(new pcl::PointCloud<pcl::PointXYZ>);
projectPointCloudToLine(cloud, lineCoefs, lineProCloud);
// 保存投影点云
//pcl::io::savePCDFileBinary("lineProCloud.pcd", *lineProCloud);
// 可视化原始点云和投影点云
visualizePointClouds(cloud, lineProCloud);
return 0;
}