PCL知识点汇总

文章目录

  • 1.点云常用处理
    • 1.1点云读写
      • 1.1.1点云存储格式
      • 1.1.2点的类型
      • 1.1.3读写显示
      • 1.1.4点云拼接
    • 1.2搜索方式
      • 1.2.1KDTree
      • 1.2.2Octree
    • 1.3点云滤波
      • 1.3.1直通滤波
      • 1.3.2VoxelGrid滤波
      • 1.3.3均匀采样滤波(下采样)
      • 1.3.4statisticalOutlierRemoval统计滤波
      • 1.3.5RadiusOutlinerRemoval半径滤波
      • 1.3.6ConditionalRemoval条件滤波
      • 1.3.7投影滤波
      • 1.3.8模型滤波
      • 1.3.9高斯滤波
      • 1.3.10双边滤波
      • 1.3.11ExtractIndices索引提取
      • 1.3.12CropHull滤波
    • 1.4点云分割
      • 1.4.1随机采样一致(RANSAC)
      • 1.4.2欧式聚类分割
      • 1.4.3条件欧式聚类分割
      • 1.4.4基于区域生长分割
      • 1.4.5颜色的区域生长分割
      • 1.4.6最小图割的分割
      • 1.4.7基于法线微分分割
      • 1.4.8基于超体素的分割
    • 1.5点云特征点
      • 1.5.1PFH
      • 1.5.2FPFH
      • 1.5.3VFH
      • 1.5.4CVFH
      • 1.5.5RIFT
      • 1.5.6NARF
      • 1.5.7RSD
      • 1.5.8ESF
    • 1.6点云配准
      • 1.6.1ICP迭代最近点算法
      • 1.6.2匹配多幅点云
    • 1.7类型转换
      • 1.6.1Ptr<—>Cloud
      • 1.6.2PCLPointCloud2<—>PointCloud< pcl::PointXYZ >
    • 1.8相关参数
      • 1.8.1模型参数

1.点云常用处理

1.1点云读写

1.1.1点云存储格式

1.pcd
2.ply
3.txt
4.obj
5…

1.1.2点的类型

#include 

1.PointXYZ  
2.PointXYZI强度  
3.PointXYZL标签  
4.PointXYZRGBA 与PointXYZI类似,除了rgba包含打包成无符号32位整数的rgba信息外。由于联合声明,还可以按名称单独访问颜色通道。
5.PointXYZRGB  
6.PointXY  
7.InterestPoint 与PointXYZI类似,除了强度包含关键点强度的度量 
8.Normal 表示给定点处的曲面法向,以及曲率的度量   
9.PointNormal 保存XYZ数据、曲面法线和曲率的点结构
10.PointXYZRGBNormal  保存XYZ数据、RGBA颜色以及曲面法线和曲率的点结构。
11.PointXYZINormal 保存XYZ数据和强度值以及曲面法线和曲率的点结构。

1.1.3读写显示

1.PCD

#include 
#include 
#include 

//1.直接载入 实际上loadPCDFile调用PCDReader实现
pcl::io::loadPCDFile<pcl::PointXYZ>("rabbit.pcd", *cloud);
//2.创建点云对象读取
pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2 ());
pcl::PCDReader reader;
reader.read ("rabbit.pcd", *cloud); 

//1.直接保存
pcl::io::savePCDFile<pcl::PointXYZ>("name.pcd", *cloud);
//以ASCII格式保存
pcl::io::savePCDFileASCII("test_ply.ply", *cloud);
//以二进制格式保存
pcl::io::savePCDFileBinary("Binary.pcd", *cloud);
pcl::io:: savePCDFileBinaryCompressed("xxx.pcd", *cloud);
//2.保存点云 
pcl::PCDWriter writer;
//默认false(保存为ASCII)可以不写
writer.write<pcl::PointXYZ> ("name.pcd, *cloud, false);
//true保存为Binary格式
writer.write("Binary.pcd", *cloud, true);
writer.writeBinary("xxx.pcd", *cloud);
writer.writeASCII("xxx.pcd", *cloud);
writer.writeBinaryCompressed("name.pcd", *cloud);

2.PLY

#include 
#include  
#include 

//1.直接载入
pcl::io::loadPLYFile <pcl::PointXYZ>(str1, *cloud);
//2.创建点云对象读取
pcl::PCLPointCloud2::Ptr cloud_blob(new pcl::PCLPointCloud2);
pcl::PLYReader reader;
reader.read("happy.ply", *cloud);

//1.直接保存
pcl::io::savePLYFile ("name.ply", *cloud);
pcl::io:: savePLYFileASCII("name.ply", *cloud);
pcl::io:: savePLYFileBinary("name.ply", *cloud);
//2.保存点云 
pcl::PLYWriter writer;
writer.write<pcl::PointXYZ> ("name.ply", *cloud);
writer.writeBinary("name.ply", *cloud);
writer.writeASCII("name.ply", *cloud);

3.TXT
获取.txt中点xyz值存储为PointXYZ类型的点,其他格式同理

4.可视化

#include 
#include 
#include 

boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("viewer"));
//设置可视化参数1 此处为所有点设置一个统一的颜色
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 0, 0, 255);
//or设置可视化参数2 选择xyz方向对点云进行渲染显示不同颜色
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> fildColor(cloud, "x");
//添加点进行显示 第二个参数为设置的可视化样式
viewer->addPointCloud<pcl::PointXYZ>(cloud,fildColor, "example");
//设置点云的颜色、大小、等属性;属性,属性值,点云标签id(add中设置的名字,例"example")
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "example");
//viewer->resetCamera();重设视角
//控制相机的位置姿态
viewer->setCameraPosition(-1, 0,0, 0, 0, 0,0,0,1);
//控制相机视角及裁剪平面
result_viewer->setCameraFieldOfView(0.5);
result_viewer->setCameraClipDistances(0.1, 572);
//窗口相关设置 
//设置视窗xy最小最大坐标(0-1间),渲染器
void createViewPort (double xmin, double ymin, double xmax, double ymax, int &viewport);
//双视窗
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3DViewer"));
//添加坐标系
viewer->addCoordinateSystem(); 
viewer->initCameraParameters();
int v1(0),v2(0);
viewer->createViewPort(0.0,0.0,0.5,1.0,v1);
//设置背景颜色
viewer->setBackgroundColor(0,0,0,v1);
//添加视窗名称
viewer->addText("original", 10,10,"v1 text",v1);
//添加点云
viewer->addPointCloud(cloud,"sample cloud1", v1);
//v2同理

  • setPointCloudRenderingProperties属性参数
属性 默认值
PCLVISUALIZER_COLOR 4
PCLVISUALIZER_FONT_SIZE 3
PCLVISUALIZER_IMMEDIATE_RENDERING 6
PCLVISUALIZER_LINE_WIDTH 2
PCLVISUALIZER_OPACITY透明高 1
PCLVISUALIZER_POINT_SIZE 0
PCLVISUALIZER_REPRESENTATION 5
PCLVISUALIZER_REPRESENTATION_POINTS 0
PCLVISUALIZER_REPRESENTATION_SURFACE 2
PCLVISUALIZER_REPRESENTATION_WIREFRAME 1

  • 相机视角相关参数
void pcl::visualization::PCLVisualizer::setCameraPosition
(double pos_x,double pos_y,double pos_z,
double view_x,double view_y,double view_z,
double up_x,double up_y,double up_z,int viewport = 0 )
参数 含义
pos 相机所在的位置即观察点
view 相机看向的点即焦点
up 相机朝上的方向
viewport 修改相机的视口0修改所有相机

PCL知识点汇总_第1张图片

1.1.4点云拼接

#include  
#include  
#include 

//创建点云对象
pcl::PointCloud<pcl::PointXYZ> cloud;
//设置点云大小 height=1为无序点云 
cloud.points.resize(cloud.width * cloud.height);
//写入点云点坐标,并进行存储
pcl::io::savePCDFileASCII("test_pcd.pcd", cloud);

//两个点云中的点相加,点数为两点云点数和
cloud_c += cloud_b; 
//点云拼接 拼接点和法向量 cloud_b拼接至cloud_a点后方形成cloud_c
pcl::concatenateFields(cloud_a, cloud_b, cloud_c);

1.2搜索方式

  • 提高查找和处理速度 优化系统性能

1.2.1KDTree

#include 
#include 
#include 
#include 

//1.创建KDTree对象,创建点云作为输入,创建搜索点
pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
kdtree.setInputCloud (cloud);
pcl::PointXYZ searchPoint;
//2.执行搜索nearestKSearch/radiusSearch
//执行K近邻搜索
if (kdtree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)  
//执行半径R内近邻搜索方法
if (kdtree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0)  

PCL知识点汇总_第2张图片

1.2.2Octree

#include 
#include 
#include 
#include 

//初始化Octree
pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree(resolution);
//设置输入点云
octree.setInputCloud(cloud);
//构建octree
octree.addPointsFromInputCloud();
//设置searchPoint
pcl::PointXYZ searchPoint;

//体素近邻搜索
//存储体素近邻搜索结果向量
std::vector<int> pointIdxVec;
if (octree.voxelSearch(searchPoint, pointIdxVec))
//K近邻搜索
//结果点的索引的向量
std::vector<int> pointIdxNKNSearch;
//搜索点与近邻之间的距离的平方
std::vector<float> pointNKNSquaredDistance;
if (octree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)

//半径内近邻搜索
std::vector<int> pointIdxRadiusSearch;
std::vector<float> pointRadiusSquaredDistance;
if (octree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0)

//根据key寻找相邻体素的迭代器,可以查找更多相邻的体素
auto it_key = octree.findLeaf(key.x, key.y, key.z);
auto it_key_1 = octree.findLeaf(key.x+1, key.y, key.z);
auto it_key_2 = octree.findLeaf(key.x-1, key.y, key.z);

PCL知识点汇总_第3张图片

1.3点云滤波

  • 数据量大需下采样
  • 平滑 去噪 去除离群点

1.3.1直通滤波

  • 简单高效,适用于消除背景等操作
#include 

//设置滤波器对象
pcl::PassThrough<pcl::PointXYZ> pass;
//设置输入点云
pass.setInputCloud(cloud);
//设置过滤是所需要的点云类型的y字段
pass.setFilterFieldName("y");
//设置在过滤字段上的范围 默认保留范围内的点云
pass.setFilterLimits(4, 555);
//不设置默认为false即保留范围内点云,true则保留范围外的点云
//pass.setFilterLimitsNegative (true); 
//执行滤波,保存过滤结果在cloud_filtered
pass.filter(*cloud_filtered);

PCL知识点汇总_第4张图片

1.3.2VoxelGrid滤波

  • voxelGrid类通过在点云数据中创建三维体素栅格,然后用每个体素的质心来近似表达体素中的其它点。
#include 

//创建滤波对象
pcl::VoxelGrid<pcl::PCLPointCloud2> vox;
//设置需要过滤的点云给滤波对象
vox.setInputCloud (cloud);
//设置滤波时创建的体素体积为1cm的立方体
vox.setLeafSize (0.01f, 0.01f, 0.01f);
//执行滤波处理,存储输出
vox.filter (*cloud_filtered); 

//Approximate 体素格滤波器(以小立方体中心近似立方体若干点)
pcl::ApproximateVoxelGrid<pcl::PointXYZ> appvo_filter;
appvo_filter.setLeafSize (0.2, 0.2, 0.2);
appvo_filter.setInputCloud (input_cloud);
appvo_filter.filter (*filtered_cloud);


1.3.3均匀采样滤波(下采样)

  • 与体素滤波(建立正方体)相似,但不改变点的位置,准确度好于体素滤波
  • 构建指定半径球体对点云进行下采样滤波,将每一个球内距离球体中心最近的点作为下采样之后的点输出。
#include 

// Uniform sampling object.
pcl::UniformSampling<pcl::PointXYZ> filter;
filter.setInputCloud(cloud);
filter.setRadiusSearch(0.01f);
// We need an additional object to store the indices of surviving points.
//pcl::PointCloud keypointIndices;
//filter.compute(keypointIndices);
//pcl::copyPointCloud(*cloud, keypointIndices.points, *outcloud);
filter.filter(*outcloud);

1.3.4statisticalOutlierRemoval统计滤波

  • 滤除稀疏离群点,计算查询点与领域点集的距离判断是否为离群点。
  • 计算点云中每一个点与其临近点的平均距离,假设得到的结果为高斯分布,形状由均值和标准差决定,平均距离在标准范围之外的点定义为离群点并滤除。
#include 

//创建滤波器对象
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
//设置待滤波的点云
sor.setInputCloud (cloud);
//设置用于平均距离估计的 KD-tree最近邻搜索点的个数
sor.setMeanK (50);
//设置判断是否为离群点的阀值;高斯分布标准差的倍数, 也就是 u+1*sigma,u+2*sigma,u+3*sigma 中的倍数1、2、3 
sor.setStddevMulThresh (1.0);
//存储滤波后的点云
sor.filter (*cloud_filtered);
//下面这个参数不设置默认为false,true为取被过滤的点
sor.setNegative (true);

PCL知识点汇总_第5张图片

1.3.5RadiusOutlinerRemoval半径滤波

  • 滤除指定半径范围内点数小于某设定值的点
#include 

//创建滤波器
pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
//输入点云
outrem.setInputCloud(cloud);
//设置半径查找范围为2
outrem.setRadiusSearch(2.0);
//在半径范围内点数小于12的点滤除.
outrem.setMinNeighborsInRadius (12);
//保留存储半径范围内点数大于12的点
outrem.filter (*cloud_filtered);

1.3.6ConditionalRemoval条件滤波

  • 设定滤波条件进行滤波,删除不符合用户指定的一个或者多个条件
#include 
#include 

//创建条件定义对象
pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond (new pcl::ConditionAnd<pcl::PointXYZ> ());
//为条件定义对象添加比较算子
//添加在Z字段上大于0的比较算子
range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::GT, 0.0))); 
//添加在Z字段上小于0.8的比较算子
range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::LT, 0.8)));
//创建滤波器并用条件定义对象初始化
pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
condrem.setCondition (range_cond);               
condrem.setInputCloud (cloud);                   
//设置保持点云的结构
condrem.setKeepOrganized(true);               
// 执行滤波 大于0.0小于0.8这两个条件用于建立滤波器
condrem.filter (*cloud_filtered);
参数 含义
LT less than小于
LE less than or equal 小于等于
EQ 等于
GE 大于等于
GT 大于

1.3.7投影滤波

  • 将三维点云投影至二维平面,用图像处理的方式处理
  • 参数化模型可以是平面,圆球/柱等
#include 
#include         
#include  

//填充ModelCoefficients的值,使用ax+by+cz+d=0平面模型,其中 a=b=d=0,c=1 也就是X0Y平面
//定义模型系数对象,并填充对应的数据
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
coefficients->values.resize(4);
coefficients->values[0] = coefficients->values[1] = 0;
coefficients->values[2] = 1.0;
//创建ProjectInliers对象,使用ModelCoefficients作为投影对象的模型参数
coefficients->values[3] = 0;
//创建投影滤波对象
pcl::ProjectInliers<pcl::PointXYZ> proj; 
//设置对象对应的投影模型
proj.setModelType(pcl::SACMODEL_PLANE); 
proj.setInputCloud(cloud); 
//设置模型对应的系数
proj.setModelCoefficients(coefficients);
//保存投影结果 
proj.filter(*cloud_projected); 

1.3.8模型滤波

  • 根据点到模型的距离,设置距离阈值过滤非模型点,
    基于模型的点分割操作,将模型外的点从点云中剔除
#include 
#include 
#include  
#include 

//x^2 + y^2 + z^2 = 1
//position.x: 0, position.y: 0, position.z:0, radius: 1
pcl::ModelCoefficients sphere_coeff;
sphere_coeff.values.resize (4);
sphere_coeff.values[0] = 0;
sphere_coeff.values[1] = 0;
sphere_coeff.values[2] = 0;
sphere_coeff.values[3] = 1;
pcl::ModelOutlierRemoval<pcl::PointXYZ> sphere_filter;
sphere_filter.setModelCoefficients (sphere_coeff);
sphere_filter.setThreshold (0.05);
//设置滤波模型类型
sphere_filter.setModelType (pcl::SACMODEL_SPHERE);
sphere_filter.setInputCloud (cloud);
sphere_filter.filter (*cloud_sphere_filtered);

PCL知识点汇总_第6张图片

1.3.9高斯滤波

  • 基于高斯核的卷积滤波实现,高斯滤波相当于一个具有平滑性能的低通滤波。
#include 
#include 

//创建高斯核
pcl::filters::GaussianKernel<pcl::PointXYZ, pcl::PointXYZ> kernel;
//高斯函数的标准差
kernel.setSigma(5);
//设置相对于Sigma参数的距离阈值
kernel.setThresholdRelativeToSigma(5);
//设置距离阈值,若点间距离大于阈值则不予考虑
kernel.setThreshold(5);
//创建搜索树
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
//创建3d卷积滤波器
pcl::filters::Convolution3D<pcl::PointXYZ, pcl::PointXYZ, pcl::filters::GaussianKernel<pcl::PointXYZ, pcl::PointXYZ> > convolution;
//设置滤波器参数
convolution.setKernel(kernel);
convolution.setInputCloud(cloud);
convolution.setNumberOfThreads(8);
convolution.setSearchMethod(tree);
convolution.setRadiusSearch(0.1);
convolution.convolve(*cloud_filtered);

1.3.10双边滤波

  • 非线性滤波器,保持边缘,降噪平滑
#include 
#include 
#include   

//设置搜索树KDTree
pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>);
tree->setInputCloud(cloud);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
create_ellipse_pointcloud(cloud);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr outcloud(new pcl::PointCloud<pcl::PointXYZRGB>);

//双边滤波
//利用强度数据进行双边滤波算法的实现
//通过取临近采样点和加权平均来修正当前采样点的位置,从而达到滤波效果,
//同时也会有选择剔除与当前采样点“差异”太大的相邻采样点,从而保持原特征
pcl::BilateralFilter<pcl::PointXYZI> nf;
nf.setInputCloud(cloud);
nf.setSearchMethod(tree);
//高斯滤波器的一半窗口值
nf.setHalfSize(sigma_s);
//标准差
nf.setStdDev(sigma_r);
nf.filter(*outcloud);

//快速双边滤波器
//需要有序点云,不支持PointXYZI点云格式
//时间复杂度高,大的点云不适合
pcl::FastBilateralFilter<pcl::PointXYZRGB> fbf;
fbf.setInputCloud(cloud);
fbf.setSearchMethod(tree)//高斯滤波器的一半窗口值   
fbf.setSigmaS(1);
//标准差  
fbf.setSigmaR(0.01);
fbf.applyFilter(*outcloud);

1.3.11ExtractIndices索引提取

  • 利用索引向量来构建点云索引并提取点云子集
#include 
#include 
#include 
#include 
#include 
#include 

//提取1,3,4位置处点云
std::vector<int> index ={1,3,4};
boost::shared_ptr<std::vector<int>> index_ptr =boost::make_shared<std::vector<int>>(index);
//Create the filtering object
pcl::ExtractIndices<pcl::PointXYZ> extract;
//Extract the inliers
extract.setInputCloud (cloud);
extract.setIndices (index_ptr);
extract.setNegative (false);//如果设为true,可以提取指定index之外的点云
extract.filter (*cloud_p);

//提取子集构成一个新的点云
std::vector<int > indexs = { 1, 2, 5 };//声明索引值
pcl::copyPointCloud(*cloud, indexs, *cloud_p);//将对应索引的点存储

1.3.12CropHull滤波

  • 得到2D封闭多边形内部或外部的点云
//求上面给出的这个边框点集的凸包
pcl::ConvexHull<pcl::PointXYZ> hull;
hull.setInputCloud(boundingbox_ptr);
//设置凸包维度
hull.setDimension(2); 
//polygons保存的是所有凸包多边形的顶点在surface_hull中的下标,用于保存凸包顶点
std::vector<pcl::Vertices> polygons; 
pcl::PointCloud<pcl::PointXYZ>::Ptr
surface_hull (new pcl::PointCloud<pcl::PointXYZ>); 
//凸包点云存放在surface_hull中,polygons中的Vertices存放一组点的索引,索引是surface_hull中的点对应的索引
hull.reconstruct(*surface_hull, polygons);

pcl::PointCloud<pcl::PointXYZ>::Ptr objects (new pcl::PointCloud<pcl::PointXYZ>);
pcl::CropHull<pcl::PointXYZ> bb_filter;
//设置维度
bb_filter.setDim(2);
bb_filter.setInputCloud(cloud);
//封闭多边形顶点
bb_filter.setHullIndices(polygons); 
//封闭多边形形状
bb_filter.setHullCloud(surface_hull); 
bb_filter.filter(*objects); 
std::cout << objects->size() << std::endl;

1.4点云分割

1.4.1随机采样一致(RANSAC)

  • 随机取两个点计算直线模型方程
  • 将所有数据点套到模型中计算误差
  • 找到所有满足误差阈值的点
  • 重复上述步骤,直到达到一定迭代次数K,选出被支持最多的模型作为解
#include 
#include 
#include //模型系数相关头文件
#include //模型定义头文件
#include //随机参数估计方法头文件
#include //基于采样一致性分割的类的头文件


//创建一个模型参数对象,用于记录结果
pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
//inliers表示误差能容忍的点 记录的是点云的序号
pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
// 创建一个分割器
pcl::SACSegmentation<pcl::PointXYZ> seg;
// Optional设置对估计的模型做优化处理
seg.setOptimizeCoefficients (true);
// Mandatory-设置目标几何形状
seg.setModelType (pcl::SACMODEL_PLANE);
//分割方法:随机采样法
seg.setMethodType (pcl::SAC_RANSAC);
//迭代次数
seg.setMaxIterations(1000);
//设置误差容忍范围
seg.setDistanceThreshold (0.01);
//输入点云
seg.setInputCloud (cloud);
//分割点云,得到参数
seg.segment (*inliers, *coefficients);

PCL知识点汇总_第7张图片

1.4.2欧式聚类分割

  • 空间中一点P利用KDTree找离其最近n个点P1P2P3…,距离小于阈值r则归入类Q中
  • 在类中另取一点P1,重复上述步骤,将找到的P22P23P24放入类Q中
  • 当类Q中没有新的点加入,搜索完成
#include 
#include 

//Creating the KdTree object for the search method of the extraction
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
tree->setInputCloud (cloud_filtered);//将无法提取平面的点云作为cloud_filtered
std::vector<pcl::PointIndices> cluster_indices;//保存每一种聚类,每一种聚类下还有具体的聚类的点
pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;//实例化一个欧式聚类提取对象
ec.setClusterTolerance (0.02); // 近邻搜索的搜索半径为2cm,重要参数
ec.setMinClusterSize (100);//设置一个聚类需要的最少点数目为100
ec.setMaxClusterSize (25000);//一个聚类最大点数目为25000
ec.setSearchMethod (tree);//设置点云的搜索机制
ec.setInputCloud (cloud_filtered);//设置输入点云
ec.extract (cluster_indices);//将聚类结果保存至cluster_indices中
//迭代访问点云索引cluster_indices,直到分割出所有聚类,一个循环提取出一类点云
int j = 0;
for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
  {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZ>);
    //创建新的点云数据集cloud_cluster,直到分割出所有聚类
    for (std::vector<int>::const_iterator pit = it->indices.begin (); pit != it->indices.end (); pit++)
    {
        cloud_cluster->points.push_back (cloud_filtered->points[*pit]); //*
    }
    cloud_cluster->width = cloud_cluster->points.size ();
    cloud_cluster->height = 1;
    cloud_cluster->is_dense = true;
    std::cout << "PointCloud representing the Cluster: " << cloud_cluster->points.size () << " data points." << std::endl;
    std::stringstream ss;
    ss << "cloud_cluster_" << j << ".pcd";
    writer.write<pcl::PointXYZ> (ss.str (), *cloud_cluster, false); //*
    j++;
  }

PCL知识点汇总_第8张图片

1.4.3条件欧式聚类分割

  • 聚类约束条件(欧式距离、平滑度、RGB颜色等)可以由用户自己定义,即当搜索到一个近邻点时,用户可以自定义该邻域点是否合并到当前聚类的条件
  • 以第一个点为标准作为种子点,候选其周边的点作为它的对比或者比较的对象,
    如果满足条件就加入到聚类的对象中
#include //条件欧式聚类

pcl::ConditionalEuclideanClustering<pcl::PointXYZINormal> cec (true);//创建条件聚类分割对象,并进行初始化。
cec.setInputCloud (cloud_with_normals);//设置输入点集
//用于选择不同条件函数
switch(Method)
{
case 1:
 cec.setConditionFunction (&enforceIntensitySimilarity);
 break;
case 2:
 cec.setConditionFunction (&enforceCurvatureOrIntensitySimilarity);
 break;
case 3:
 cec.setConditionFunction (&customRegionGrowing);
 break;
default:
 cec.setConditionFunction (&customRegionGrowing);
 break; 
}
//设置聚类参考点的搜索距离
cec.setClusterTolerance (500.0);
//设置过小聚类的标准
cec.setMinClusterSize (cloud_with_normals->points.size () / 1000);
//设置过大聚类的标准
cec.setMaxClusterSize (cloud_with_normals->points.size () / 5);
//获取聚类的结果,分割结果保存在点云索引的向量中
cec.segment (*clusters);
//获取无效尺寸的聚类
cec.getRemovedClusters (small_clusters, large_clusters);

//如果此函数返回true,则将添加候选点到种子点的簇类中。
bool customCondition(const pcl::PointXYZ& seedPoint, const pcl::PointXYZ& candidatePoint, float squaredDistance) 
{
    //自定义条件
    return false;
    return true;
} 


1.4.4基于区域生长分割

  • 将具有相似性的点云集合起来构成区域。
  • 计算法线曲率,依据曲率升序排序;
    选曲率最低为初始种子点,种子周围的临近点和
    种子点云相比较;法线的方向是否足够相近(法线夹角足够 r p y),法线夹角阈值; 曲率是否足够小(表面处在同一个弯曲程度),区域差值阈值;如果满足2,3则该点可用做种子点;如果只满足2,则归类而不做种子;
#include 

//区域增长聚类分割对象 <点,法线>
pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;
//最小的聚类的点数
reg.setMinClusterSize (50); 
//最大的聚类的点数
reg.setMaxClusterSize (1000000);
reg.setSearchMethod (tree); 
//设置搜索的邻域点的个数
reg.setNumberOfNeighbours (30); 
reg.setInputCloud (cloud); 
//reg.setIndices (indices);
//输入的法线
reg.setInputNormals (normals); 
//设置平滑度 法线差值阈值
reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI);
//设置曲率的阀值
reg.setCurvatureThreshold (1.0); 

PCL知识点汇总_第9张图片

1.4.5颜色的区域生长分割

  • 分割,当前种子点和领域点之间色差小于色差阀值的视为一个聚类;合并,聚类之间的色差小于色差阀值和并为一个聚类,且当前聚类中点的数量小于聚类点数量的与最近的聚类合并在一起
#include 

//基于颜色的区域生成的对象
pcl::RegionGrowingRGB<pcl::PointXYZRGB> reg;
reg.setInputCloud (cloud);
//点云的索引,可处理存储直通滤波后的点云
reg.setIndices (indices); 
reg.setSearchMethod (tree);
//距离的阀值
reg.setDistanceThreshold (10);
//点与点之间颜色容差
reg.setPointColorThreshold (6);
//区域之间容差
reg.setRegionColorThreshold (5);
//设置聚类的大小
reg.setMinClusterSize (600); 
std::vector <pcl::PointIndices> clusters;
reg.extract (clusters);//
pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud ();


1.4.6最小图割的分割

  • 建图;为边缘分配权重;设置数据成本;对前背景点进行划分。
#include 

// 申明一个Min-cut的聚类对象
pcl::MinCutSegmentation<pcl::PointXYZ> clustering;
clustering.setInputCloud(cloud); //设置输入
//创建一个点云,列出所知道的所有属于对象的点
//(前景点)在这里设置聚类对象的中心点
pcl::PointCloud<pcl::PointXYZ>::Ptr foregroundPoints(new pcl::PointCloud<pcl::PointXYZ>());
pcl::PointXYZ point;
point.x = 100.0;
point.y = 100.0;
point.z = 100.0;
foregroundPoints->points.push_back(point);
clustering.setForegroundPoints(foregroundPoints);//设置聚类对象的前景点
//设置sigma,它影响计算平滑度的成本。它的设置取决于点云之间的间隔(分辨率)
clustering.setSigma(0.02);// cet cost = exp(-(dist/cet)^2)
// 设置聚类对象的半径.
clustering.setRadius(0.01);// dist2Center / radius
//设置需要搜索的临近点的个数,增加这个也就是要增加边界处图的个数
clustering.setNumberOfNeighbours(20);
//设置前景点的权重(也就是排除在聚类对象中的点,它是点云之间线的权重,)
clustering.setSourceWeight(0.6);
std::vector <pcl::PointIndices> clusters;
clustering.extract(clusters);

1.4.7基于法线微分分割

  • 对于输入点云数据中的每一点,利用较大的支撑半径计算法向量;对于输入点云数据中的每一点,单位化每一点的法向量差异;过滤所得的向量域(DoN特征向量),分割出目标尺寸对应的点云。
#include 
#include 

//Create output cloud for DoN results
PointCloud<PointNormal>::Ptr doncloud (new pcl::PointCloud<PointNormal>);
copyPointCloud<PointXYZRGB, PointNormal>(*cloud, *doncloud);
pcl::DifferenceOfNormalsEstimation<PointXYZRGB, PointNormal, PointNormal> don;
don.setInputCloud (cloud);
don.setNormalScaleLarge (normals_large_scale);
don.setNormalScaleSmall (normals_small_scale);
don.initCompute ();
//Compute DoN
don.computeFeature (*doncloud);

1.4.8基于超体素的分割

  • 以八叉树对点云进行划分,获得不同点团之间的邻接关系
//体素大小,空间八叉树的分辨率,类kinect或xtion获取的数据0.008左右合适
float voxel_resolution = 0.008f;
//种子的分辨率,一般可设置为体素分辨率的50倍以上
float seed_resolution = 0.1f;
//针对分割场景,如果分割场景中各个物体之间的颜色特征差异明显,可以设置较大
float color_importance = 0.2f;
//设置较大且其他影响较小时,基本按照空间分辨率来决定体素分割
float spatial_importance = 0.4f;
//针对分割场景,如果分割场景中各个物体连通处的法线特征差异明显,可以设置较大,但在实际使用中,需要针对数据的结构适当考虑,发现估计的准确性等因素
float normal_importance = 1.0f;
//生成结晶器
pcl::SupervoxelClustering<PointT> super(voxel_resolution, seed_resolution);
//和点云形式有关
if(disable_transform)
super.setUseSingleCameraTransform(false);
//输入点云及结晶参数
super.setInputCloud(cloud);
super.setColorImportance(color_importance);
super.setSpatialImportance(spatial_importance);
super.setNormalImportance(normal_importance);
//输出结晶分割结果:结果是一个映射表
std::map <uint32_t, pcl::Supervoxel<PointT>::Ptr > supervoxel_clusters;
//获得晶体中心
super.extract(supervoxel_clusters);
//获得晶体
PointCloudT::Ptr voxel_centroid_cloud = super.getVoxelCentroidCloud(); 
PointLCloudT::Ptr labeled_voxel_cloud = super.getLabeledVoxelCloud();

PCL知识点汇总_第10张图片

1.5点云特征点

Feature Name Supports Texture / Color Local / Global / Regional Best Use Case
PFH No L
FPFH No L 2.5D Scans (Pseudo single position range images)
VFH No G Object detection with basic pose estimation
CVFH No R Object detection with basic pose estimation, detection of partial objects
RIFT Yes L Real world 3D-Scans with no mirror effects. RIFT is vulnerable against flipping.
RSD No L
NARF No L 2.5D (Range Images)

1.5.1PFH

  • 局部特征点
  • (1)计算P中点云法线;估计P中的点Pi的特征。
    (2)获取围绕点Pi(Pik)的半径r中的k个邻居的集合。在两点之间计算四个特征。相应的bin增加1.生成点特征直方图(PFH)。
    (3)将得到的直方图组与其他点云的组进行比较,以便找到对应关系。

1.5.2FPFH

  • (1)计算P中点法线;获取围绕点Pi(Pik)的半径r中的k个邻居的集合。在两点之间计算三个特征(仅在Pi与其邻居之间!)。相应的bin增加1.生成简单的点特征直方图(SPFH)
    (2)为了达到更多的点和连接(最多2次r),邻居的SPFH根据它们的空间距离加以加权作为最后一步
    (3)可以将得到的直方图组与其他点云的组进行比较,以便找到对应关系。

1.5.3VFH

  • 全局特征点
  • (1)估算点云中的质心及其法线。计算视点和视点之间的归一化矢量vc。
    (2)对于所有点,计算它们的法线和vc之间的角度。
    (3)估算质心的FPFH,将所有剩余点设置为邻居。

1.5.4CVFH

  • 基于区域描述
  • (1)将点云细分为具有相似法线的相邻点的聚类(稳定区域)。
    (2)计算每个群集的VFH。
    (3)将形状分布组件(SDC)添加到每个直方图。

1.5.5RIFT

  • 局部特征描述法,输入点须有纹理
  • (1)对于P样本中的每个点Pi,Pi周围的所有k个邻居。
    (2)根据距离d和它们的梯度角θ将所有邻居分配给直方图。
    (3)可以将得到的直方图组与其他点云的组进行比较,以便找到对应关系。

1.5.6NARF

  • 局部特征点,输入深度图像
  • (1)对于深度图像RI中的每个关键点Pi,对Pi周围的所有邻居进行采样,并将它们转换为局部坐标系,其中Pi为O.
    (2)在图像块上投射星形图案并计算每个光束下的强度变化以获得光束的分数。 在计算中,更靠近中心的光束具有更大的权重。 分数归一化为[-0.5,0.5]。
    (3)迭代所有光束并找到图像块的主要方向。

1.5.7RSD

  • 局部特征点
  • (1)对于P样本中的每个点Pi,Pi周围的所有k个邻居。
    (2)根据距离d和无向法线的角度将所有邻居分配到直方图。
    (3)假设与每个邻居的Pi对描述一个圆(见图)。 找到Pi描述的所有球体的最小和最大半径及其邻域。
    (4)得到的直方图和半径组可以与其他点云的组合进行比较,以便找到对应关系。

1.5.8ESF

  • (1)开始一个从点云P中随机抽样20,000点的循环。每轮样本三点Pri,Prj,Prk。
    (2)对于两个点对,计算彼此之间的距离,并检查两者之间的线是否位于表面上,外部或与物体相交(IN,OUT或MIXED)。在D2的三个子图表中的一个中增加与计算的距离对应的bin。
    (3)对于前一行,找到位于表面或外部的那条线的部分之间的比率。结果应该是0表示完全在外面,1表示完全在表面上,并且来自MIXED线的所有值都在它们之间分布。增加D2比率直方图的对应bin。
    (4)对于三元组,建立一个三角形并计算两侧之间的角度,并将角度的一侧分为三角形(IN,OUT,MIXED)。增加A3的IN,OUT或MIXED子组合图中的相应角度箱。
    (5)对于前一个三角形,计算区域的平方根,并将区域分为IN,OUT或MIXED。增加D3的IN,OUT或MIXED子组合图中的相应区域bin。

1.6点云配准

  • 点云不完整,旋转错位,平移错位
  • 确定一个合适的坐标系,将从各个视角得到的点集合并到统一的坐标系下形成一个完整的点云。关键:得到坐标变换的参数R(旋转矩阵)和T(平移向量),使得两视角下测得的三维数据经坐标变换后的距离最小
  • 实质:把不同的坐标系中测得到的数据点云进行坐标系的变换,以得到整体的数据模型。
提取关键点->计算特征描述子->估算对应关系及点对->除去噪声点对->用剩余的正确的对应关系来估算刚体变换完成配准

1.6.1ICP迭代最近点算法

  • 程序随机生成一个点与作为源点云,并将其沿x轴平移后作为目标点云,然后利用ICP估计源到目标的刚体变换矩阵
#include 

//创建IterativeClosestPoint的对象
pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;   
//设置点云源点
icp.setInputCloud(cloud_in);
//cloud_out设置为与cloud_in对应的匹配目标                 
icp.setInputTarget(cloud_out); 
//存储经过配准变换点云后的点云            
pcl::PointCloud<pcl::PointXYZ> Final; 
//打印配准相关输入信息        
icp.align(Final);                             

1.6.2匹配多幅点云

#include            //ICP类相关头文件
#include         //非线性ICP 相关头文件
#include       //变换矩阵类头文件

//配准对象
pcl::IterativeClosestPointNonLinear<PointNormalT, PointNormalT> reg; 
//设置收敛判断条件,越小精度越大,收敛也越慢 
reg.setTransformationEpsilon (1e-6);   
//Set the maximum distance between two correspondences (src<->tgt) to 10cm大于此值的点对不考虑
//Note: adjust this based on the size of your datasets
reg.setMaxCorrespondenceDistance (0.1);  
//设置点表示
reg.setPointRepresentation (boost::make_shared<const MyPointRepresentation> (point_representation));
//设置源点云
reg.setInputSource (points_with_normals_src);   
//设置目标点云
reg.setInputTarget (points_with_normals_tgt);    
//Run the same optimization in a loop and visualize the results
Eigen::Matrix4f Ti = Eigen::Matrix4f::Identity (), prev,targetToSource;
PointCloudWithNormals::Ptr reg_result = points_with_normals_src;
//设置最大的迭代次数,即每迭代两次就认为收敛,停止内部迭代
reg.setMaximumIterations (2);

1.7类型转换

1.6.1Ptr<—>Cloud

//ptr->cloud
pcl::PointCloud<pcl::PointXYZ> cloud;
pcl::PointCloud < pcl::PointXYZ >::ptr cloud_ptr(new pcl::PointCloud<pcl::PointXYZ>);
cloud=*cloud_ptr;

//cloud->ptr
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ> cloud;
cloud_ptr=cloud.makeShared();

1.6.2PCLPointCloud2<—>PointCloud< pcl::PointXYZ >

//PCLPointCloud2—>PointCloud< pcl::PointXYZ >
pcl::fromPCLPointCloud2(*cloud_blob, *cloud);

//PointCloud< pcl::PointXYZ >—>PCLPointCloud2
pcl::toPCLPointCloud2(*cloud, *cloud_blob);

1.8相关参数

1.8.1模型参数

  • setModelType
参数 含义
SACMODEL_PLANE 平面模型,4个参数ax+by+cz+d=0
SACMODEL_LINE 线模型,直线的六个系数由直线上的一个点和直线的方向给出
SACMODEL_CIRCLE2D 确定平面中的2D圆,圆的三个系数由其中心和半径给出
SACMODEL_CIRCLE3D 平面中的3D圆,圆的七个系数由其中心、半径和法线给出
SACMODEL_SPHERE 球体模型,球体的四个系数由其3D中心和半径给出。
SACMODEL_CYLINDER 气缸模型,圆柱体的七个系数由其轴上的点、轴方向和半径给出
SACMODEL_CONE 锥模型,锥体的七个系数由其顶点、轴方向和张角给出。
SACMODEL_PARALLEL_LINE 在最大指定角度偏差内确定与给定轴平行的线的模型
SACMODEL_PERPENDICULAR_PLANE 在最大指定角度偏差内确定垂直于用户指定轴的平面的模型
SACMODEL_NORMAL_PLANE 使用附加约束确定平面模型的模型:每个内点的表面法线必须平行于输出平面的表面法线,在指定的最大角度偏差内。平面系数类似于SACMODEL_PLANE
SACMODEL_NORMAL_SPHERE 类似于SACMODEL_SPHERE,但具有额外的表面法线约束。
SACMODEL_PARALLEL_PLANE 在最大指定角度偏差内确定平行于用户指定轴的平面的模型。平面系数类似于SACMODEL_PLANE
SACMODEL_NORMAL_PARALLEL_PLANE 使用附加表面法线约束定义 3D 平面分割模型。平面法线必须平行于用户指定的轴。因此SACMODEL_NORMAL_PARALLEL_PLANE 等效于SACMODEL_NORMAL_PLANE + SACMODEL_PERPENDICULAR_PLANE。平面系数类似于SACMODEL_PLANE
SACMODEL_STICK 3D 棒分割模型。一根棍子是一条给定用户最小/最大宽度的线

你可能感兴趣的:(点云,c++)