作者:迅卓科技
简介:本人从事过多项点云项目,并且负责的项目均已得到好评!
公众号:迅卓科技,一个可以让您可以学习点云的好地方
目录
1.前言
我们团队注重每一个细节,确保代码的可读性、可维护性和可扩展性达到最高标准。我们严格遵循行业最佳实践,采用模块化和面向对象的设计原则,使得我们的代码结构清晰且易于理解。
我们的点云服务更是引以为傲。我们的技术团队拥有深厚的专业知识和丰富的经验,能够提供高度准确和高效的点云处理服务。无论是点云的获取、存储还是分析,我们都能够满足客户的需求,并提供出色的解决方案。
我们的技术实力也是无与伦比的,拥有广泛的技术背景和深入的专业知识。无论是算法优化、性能调优还是技术创新,我们都能够应对自如,并为客户提供最佳的技术支持。
2.开发环境
下载源代码并解压缩。
在Visual Studio中打开项目。
根据需要配置PCL库。
编译和运行项目。
3.示例(效果图)及说明
PGetMaxPlaneCoe函数:
使用RANSAC算法从点云中提取最大平面的系数和内点索引。该函数能够鲁棒地识别点云中主要平面的特征,通过RANSAC迭代,计算最适合的平面模型,并返回其法向量和内点索引,从而实现对点云的平面分割。
PExtracting函数:
根据给定的内点索引,从点云中提取或排除点,生成提取后的点云。这个功能强大的函数使用户能够根据特定需求,从原始点云中提取感兴趣的区域,或者排除掉一些干扰点,为后续处理提供了定制化的数据准备。
PGetPlaneCoe函数:
使用RANSAC算法从点云中提取与给定法线方向垂直的平面,并将剩余的点云分割成多个平面。通过指定法线方向,该函数能够提取垂直于该方向的平面,从而在点云中捕捉到更多的几何信息,同时将剩余点云按照平面分割,实现对点云的多平面分析。
PAshape函数:
使用凹壳算法对点云进行凹壳重构,生成凹壳点云。凹壳算法通过迭代过程,逐渐构建出点云的凹壳,形成具有几何形状信息的点云模型。该函数有助于提取点云中的整体形状特征,为形状分析和识别提供了基础。
PMultipleLines函数:
使用RANSAC算法从点云中提取多条直线,并将直线分割成多个段。通过RANSAC算法,该函数能够有效地识别点云中的多条直线,同时将每条直线分割成不同的段,为点云的分段处理提供了可靠的工具。
Spherical_Search函数:
在点云中进行球形搜索,找到给定球半径内的邻域点,并返回其索引。这个函数实现了基于球形搜索的点云分析,可以用于提取点云中局部区域的邻域点,为局部几何特征的计算提供了灵活而高效的方法。
getWall函数:
根据点云中点的强度值,提取出墙面的点,并返回其索引。通过对点云的强度值进行筛选,该函数实现了对墙面点的提取,可应用于建筑结构的分析,为特定应用场景提供了有效的数据过滤工具。
4.源码如下
main.cpp
#include "File.h"
#include "Fliter.h"
#include <iostream>
#include <algorithm>
#include <pcl/io/pcd_io.h>
#include <pcl/console/time.h>
int main()
{
//Initialize data to prevent data from not being empty
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr input_cloud(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_Boundary(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_Boundary_RGB(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_socket(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_socket_all(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_end(new pcl::PointCloud<pcl::PointXYZI>);
pcl::ModelCoefficients::Ptr coefficients_underside(new pcl::ModelCoefficients);
pcl::ModelCoefficients::Ptr coefficients_side(new pcl::ModelCoefficients);
pcl::ModelCoefficients::Ptr coefficients_Line(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
pcl::console::TicToc tt;
tt.tic();
//Load pointcloud from the inputPath
//pcl::io::loadPCDFile("input/Cloud.pcd", *input_cloud);
ReadFileToCloud("input/Cloud.txt", input_cloud);
//here we creat a vector to put into the point cloud we will use next
std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr> cloud_CutVector;
//Using the PGetMaxPlaneCoe and PExtracting to get underside and the remain pointcloud
PGetPlaneCoe(input_cloud, cloud_CutVector);
for (int i = 0; i < cloud_CutVector.size(); ++i)
{
inliers->indices.clear();
getWall(inliers, cloud_CutVector[i]);
PExtracting(inliers, cloud_CutVector[i], cloud_socket, false);
*cloud_socket_all += *cloud_socket;
}
pcl::io::savePCDFileBinary("output/cloud_socket_all.pcd", *cloud_socket_all);
//Get the boundary of the underside
for (int i = 0; i < cloud_CutVector.size(); ++i)
{
PAshape(cloud_CutVector[i], cloud_Boundary);
std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr> cloud_Cut;
PMultipleLines(cloud_Boundary, cloud_Cut, 2);
cloud_Boundary->clear();
for (int i = 0; i < cloud_Cut.size(); ++i)
{
*cloud_Boundary += *cloud_Cut[i];
}
uint8_t R = rand() % 255 + 1;
uint8_t G = rand() % 255 + 1;
uint8_t B = rand() % 255 + 1;
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_RGB(new pcl::PointCloud<pcl::PointXYZI>);
*cloud_Boundary_RGB += *cloud_Boundary;
}
//For getting a good quality pointCloud,we will move forward a single step
inliers->indices.clear();
Spherical_Search(inliers, input_cloud, cloud_Boundary_RGB);
cloud_Boundary_RGB->clear();
PExtracting(inliers, input_cloud, cloud_Boundary_RGB, true);
//For getting a good quality pointCloud,we will move forward a single step
inliers->indices.clear();
Spherical_Search(inliers, cloud_Boundary_RGB, cloud_socket_all);
PExtracting(inliers, cloud_Boundary_RGB, cloud_end, true);
//here you can load the point cloud to look wrong or right
pcl::io::savePCDFileBinary("output/cloud_end.pcd", *cloud_end);
std::cout << "Ok ! The progress is finished,and the time of this progress is :" << tt.toc() / 1000 << "s!" << std::endl;
}
Fliter.h
#pragma once
#include <Eigen/Core>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/common/angles.h>
#include <pcl/common/transforms.h>
#include <pcl/features/boundary.h> //边界提取
#include <pcl/common/transforms.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/passthrough.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/surface/concave_hull.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/project_inliers.h>
#include <pcl/segmentation/region_growing.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>
void PGetMaxPlaneCoe(pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, pcl::ModelCoefficients::Ptr& coefficients, pcl::PointIndices::Ptr& inliers, double Threshold);
void PExtracting(pcl::PointIndices::Ptr& inliers, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud_extracted, bool negative);
void PGetPlaneCoe(pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr>& cloud_Plane);
void PAshape(pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud_hull);
void PMultipleLines(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr>& cloud_Cut, int n);
void Spherical_Search(pcl::PointIndices::Ptr& inliers, pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_search);
void getWall(pcl::PointIndices::Ptr& inliers, pcl::PointCloud<pcl::PointXYZI>::Ptr cloud);
Fliter.cpp
#include "Fliter.h"
#include <pcl/io/pcd_io.h>
void PGetMaxPlaneCoe(pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, pcl::ModelCoefficients::Ptr& coefficients, pcl::PointIndices::Ptr& inliers, double Threshold)
{
pcl::SACSegmentation<pcl::PointXYZI> seg;
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_PLANE); //分割模型
seg.setMethodType(pcl::SAC_RANSAC); //随机参数估计方法
seg.setMaxIterations(1000); //最大的迭代的次数
seg.setDistanceThreshold(Threshold); //设置阀值
seg.setInputCloud(cloud);
seg.segment(*inliers, *coefficients);
}
void PExtracting(pcl::PointIndices::Ptr& inliers, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud_extracted, bool negative)
{
//cloud_extracted->clear();
pcl::ExtractIndices<pcl::PointXYZI> extract;
extract.setInputCloud(cloud);
extract.setIndices(inliers);
extract.setNegative(negative);//如果设为true,可以提取指定index之外的点云
extract.filter(*cloud_extracted);
}
void PGetPlaneCoe(pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr>& cloud_Plane)
{
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
pcl::SACSegmentation<pcl::PointXYZI> seg;
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_PERPENDICULAR_PLANE);
seg.setMethodType(pcl::SAC_RANSAC);
seg.setDistanceThreshold(0.04);
float angle = 5;
float EpsAngle = pcl::deg2rad(angle);
Eigen::Vector3f Axis(0.0, 1.0, 0.0);
seg.setAxis(Axis);
seg.setEpsAngle(EpsAngle);
seg.setInputCloud(cloud);
seg.segment(*inliers, *coefficients);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_E(new pcl::PointCloud<pcl::PointXYZI>);
PExtracting(inliers, cloud, cloud_E, true);
//pcl::io::savePCDFileBinary("output/cloud_E.pcd", *cloud_E);
int n_size = cloud_E->points.size();
while (cloud_E->points.size() > 0.01 * n_size)
{
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
pcl::ModelCoefficients::Ptr coefficients_underside(new pcl::ModelCoefficients);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_plane(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_else(new pcl::PointCloud<pcl::PointXYZI>);
//Using the PGetMaxPlaneCoe and PExtracting to get underside and the remain pointcloud
PGetMaxPlaneCoe(cloud_E, coefficients_underside, inliers, 0.02);
PExtracting(inliers, cloud_E, cloud_plane, false);
PExtracting(inliers, cloud_E, cloud_else, true);
//pcl::io::savePCDFileBinary("output/cloud_plane.pcd", *cloud_plane);
cloud_Plane.push_back(cloud_plane);
*cloud_E = *cloud_else;
}
}
void PAshape(pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud_hull)
{
pcl::ConcaveHull<pcl::PointXYZI> chull;
chull.setInputCloud(cloud); // 输入点云为投影后的点云
chull.setAlpha(0.1); // 设置alpha值为0.1
chull.reconstruct(*cloud_hull);
}
void PMultipleLines(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr>& cloud_Cut, int n)
{
pcl::PointIndices::Ptr inliers(new pcl::PointIndices());
pcl::SACSegmentation<pcl::PointXYZI> seg;
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_LINE);
seg.setMethodType(pcl::SAC_RANSAC);
seg.setMaxIterations(1000);
seg.setDistanceThreshold(0.01);
int nr_point = cloud->points.size();
while (cloud->points.size() > 0.1 * nr_point)// 从0循环到5执行6次,并且每次cloud的点数必须要大于原始总点数的0.1倍
{
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_line(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr outside(new pcl::PointCloud<pcl::PointXYZI>);
pcl::ModelCoefficients coefficients;
seg.setInputCloud(cloud);
seg.segment(*inliers, coefficients);
pcl::ExtractIndices<pcl::PointXYZI> extract;
extract.setInputCloud(cloud);
extract.setIndices(inliers);
extract.setNegative(false);
extract.filter(*cloud_line);
if (cloud_line->points.size() > 50)
{
cloud_Cut.push_back(cloud_line);
}
extract.setNegative(true);
extract.filter(*outside);
cloud.swap(outside);
}
}
void Spherical_Search(pcl::PointIndices::Ptr& inliers, pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_search)
{
double spherical_radius = 0.05;
pcl::KdTreeFLANN<pcl::PointXYZI> kdtree; //创建KdTreeFLANN 对象 注意<>这里的点云类型要保持一致
kdtree.setInputCloud(cloud);//添加点云
std::vector<int> pointIdxRadiusSearch;
std::vector<float> pointRadiusSquaredDistance;//邻域点的待搜索点距离的平方
std::vector<float> pointIndex;
pcl::PointXYZI point_source;
for (int i = 0; i < cloud_search->points.size(); ++i)
{
if (kdtree.radiusSearch(cloud_search->points[i], spherical_radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0)
{
for (size_t j = 0; j < pointIdxRadiusSearch.size(); ++j)
{
auto it = find(pointIndex.begin(), pointIndex.end(), pointIdxRadiusSearch[j]);
if (it == pointIndex.end())//防止重复点云
{
pointIndex.push_back(pointIdxRadiusSearch[j]);
inliers->indices.push_back(pointIdxRadiusSearch[j]);
}
}
}
}
}
void getWall(pcl::PointIndices::Ptr& inliers, pcl::PointCloud<pcl::PointXYZI>::Ptr cloud)
{
std::vector<double>iden;
for (int i = 0; i < cloud->points.size(); ++i)
{
iden.push_back(cloud->points[i].intensity);
}
std::sort(iden.begin(), iden.end());
double bigIden = iden.at(iden.size() - 1);
double range = 0.003;
for (int i = 0; i < cloud->points.size(); ++i)
{
if (bigIden - cloud->points[i].intensity < range)
inliers->indices.push_back(i);
}
}
File.h
//格式文件读取
#include <string>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
int ReadFileToCloud(const std::string& pointCloudPath, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud);
File.cpp
#include "File.h"
int ReadFileToCloud(const std::string& pointCloudPath, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud)
{
#if true
std::ifstream m_filestream;
m_filestream.open(pointCloudPath.c_str(), std::ios_base::in);
if (m_filestream.is_open())
{
while (m_filestream.peek() != EOF)
{
char buf[128] = { 0 };
m_filestream.getline(buf, 128);
///
std::string strPt = buf;
pcl::PointXYZI pt;
try
{
int b = 0; int e = 0;
e = strPt.find(' ', b);
if (-1 == e) continue;
pt.x = atof(strPt.substr(0, e - b).c_str());
b = e + 1;
e = strPt.find(' ', b);
if (-1 == e) continue;
pt.y = atof(strPt.substr(b, e - b).c_str());
b = e + 1;
e = strPt.find(' ', b);
if (-1 == e) continue;
pt.z = atof(strPt.substr(b, e - b).c_str());
b = e + 1;
e = strPt.find(' ', b);
pt.intensity = atof(strPt.substr(b, e - b).c_str());
}
catch (const std::exception&)
{
continue;
}
///
cloud->push_back(pt);
}
m_filestream.close();
}
#endif
if (cloud->size() == 0)
{
return 0;
}
return cloud->size();
}