点云滤波方法
直通滤波器
pcl::PassThrought<pcl::PointXYZ> pass
//创建滤波器对象
pcl::PassThrough<pcl::PointXYZ> pass;
//设置输入点云
pass.setInputCloud (cloud);
//滤波字段名被设置为z周方向
pass.setFilterFieldName("z");
//可接受的范围(0.0,0.5)
pass.setFilterLimits(0.0, 0.5);
//设置保留范围内还是过滤掉范围内
pass.setFilterLimitsNegative(true);
//执行滤波,保存过滤结果在cloud_filtered
pass.filter(*cloud_filtered);
体素滤波器
pcl::VoxelGrid<pcl::PCLPointCloud2> vox
//创建滤波器对象
pcl::VoxelGrid <pcl::PointXYZ> vox;
//设置输入点云
pcl::setInputCloud (cloud);
//设置滤波时创建的体素体积为1cm的立方体
vox.setLeafSize(0.01f, 0.01f, 0.01f);
//执行滤波,保存过滤波结果在cloud_filtered
vox.filter(*cloud_diltered);
统计滤波器
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sorl;
//创建滤波器对象
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
//设置输入点云
sor.setInputCloud(cloud);
//设置在进行统计时考虑查询点临近点数
sor.setMeanK(50);
//设置判断是否为离群点的阈值
sor.setStddevMulThresh(1.0);
//执行滤波,保存过滤结果在cloud_filtered
sor.filter(*cloud_filtered);
半径滤波器
pcl::RadiusOutlierRemoval<pcl::PointXYZ> rador;
//设置半径为0.8的范围内找临近点
rador.setRadiusSearch(0.8);
//设置查询点的领域点集数小于2的删除
rador.setMinNeighborsInRadius(2);
均匀采样
pcl::UniformSampling<pcl::PointXYZ> unisam;
//设置滤波时创建的体素体积为1cm的立方体
//vox.setLeafSize(0.01f, 0.01f,0.01f);
//设置滤波时创建的半径球体
unisam.setRadiusSearch(0.01f);
条件滤波器
pcl::ConditioalRemoval<pcl::PointXYZ> condr;
//创建条件定义对象
pcl::ConditioanAnd<pcl::PointXYZ>::ptr range_cond (new pcl::ConditionAnd<pcl::PointXYZ>());
//为条件定义对象添加比较算子
range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::GT, 0.0)));
//添加在Z字段上大于(pcl::ComparisonOps::GT great Then) 0的比较算子
//创建条件定义对象 曲率
//pcl::ConditionOr<PointNormal>::Ptr range_cond (new pcl::ConditionOr<PointNormal> ());
range_cond->addComparison (pxl::FieldComparison<PointNormal>::ConstPtr) (new pcl::FieldComparison<PointNormal> ("curvature", pcl::ComparisonOps::GT, threshold));
//创建滤波器并用条件定义对象初始化
pcl::ConditionalRemoval<pcl::PointXYZ> condr;
//并用条件定义对象初始化
condr.setCondition (range_cond);
condr.setInputCloud (cloud);
//设置保持点云的结构
condr.setKeepOrganized(true);
condrem.filter(*cloud_filtered);
索引提取
pcl::ExtractIndices<pcl::PointXYZ> extr;
//创建点云提取对象,设置ExtractIndices的实际参数
pcl::ExtraceIndices::Ptr inliers (new pcl::PointIndices());
//分割点云
//为了处理点云包含的多个模型,在一个循环中执行该过程并在每次模型被提取后,保存剩余的点进行迭代
//seg.setInputCloud(cloud_filtered); //设置源 滤波后的点云
//seg.segment(*inlier, *coefficients); //输入分割系数得到点云 索引inliers
//添加点云索引
inliers.indices.push_back(0);
inliers.indices.push_back(2);
//提取索引 Extract the inliers
extr.setInputCloud (cloud_diltered);
extr.setIndices(inliers);
extr.setNegative(false);
extr.filter(*cloud_p); //按索引提取 点云
投影滤波器
pcl::ProjectInliers<pcl::PointXYZ> proj;
模型滤波器
pcl::ModelOutlierRemoval<pcl::PointXYZ> modr;
空间裁剪滤波
pcl::CropHull<pcl::PointXYZ>
二、八叉树
应用算法
- 搜索操作(邻域、半径、体素搜索)
- 降采样(体素网格/体素质心滤波器)
- 点云压缩
- 空间变化检测
- 空间点密度分析
- 占用检查/占位地图
- 碰撞检测
- 点云合并
2.1 PCL Octree使用
//实例化Octree
float voxelSize = 0.01f; //最小体素分辨率
OctreePointCloud<PointXYZ> octree(voxelSize);
//设置输入点云
octree.setInputCloud(cloud);
//定义Octree边界框
octree.defineBoundingBox();
//手动定义点云的边界框
octree.defineBoundingBox(minX, minY, minZ,maxX,maxY,maxZ);
//输入点云添加到Octree
octree.addPointsFromInputCloud();
//删除Octree数据结构
octree.deleteTree();
//检查给定点坐标的体素是否存在
double X, Y, Z;
bool occuppied;
X = 1.0; Y = 2.0; Z = 3.0;
occuppied = octree.isVoxelOccupiedAtPoint(X, Y, Z);
//获取所有占用体素的中心点(Voxel grid filter/downsampling)
std::vector<PointXYZ> pointGrid;
octree.getOccupiedVoxelCenters(pointGrid);
//查询点所在的体素内的近邻点
std::vector<int> poointIdxVec;
octree.voxelSearch(searchPoint, PointIdxVec);
//删除体素
pcl::PointXYZ point_arg(1.0, 2.0, 3.0);
octree.deleteVoxelAtPoint( point );
//迭代器
OctreePointCloud<PointXYZ>::Iterator it (octreeA); //迭代所有octree节点
OctreePointCloud<PointXYZ>:::eafNodeIterator itL (octreeA); //迭代所有octree叶节点
2.2 PCL Octree 类型
float resolution = 0.01f;
//等于OctreePointCloudPointVector<PointXYZ>
OctreePointCloud<PointXYZ> octreeA (resolution);
//叶节点存储vector的索引
OCtreePointCloudPointVector<PointXYZ> octreeB (resolution);
//叶节点存储单个点的索引
OctreePointCloudSinglePoint<PointXYZ> octreeC (resolution);
//叶节点不存储任何点的信息
OctreePointCloudOccupancy<PointXYZ> octreeD (resolution);
2.3 PCL Octree 领域搜索
- 体素内近邻搜索
- 半径内近邻搜索
- K近邻搜索
/*体素内近邻搜索*/
std::vector<int> pointIdxVec;
octree.voxelSearch(searchPoint, pointIdxVec);
/*半径内近邻搜索*/
//深度优先数搜索
//在每个节点上查询与搜索半径球体重叠的已占用子体素
std::vector<int> pointIdxRadiusSearch;
std::vector<float> pointRadiusSquaredDistance;
float radius = 0.1;
//扫描所有候选体素
if (octree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch,pointRadiusSquaredDistance) > 0)
{......}
//只扫描“搜索点体素”
if (octree.approxNearestSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0)
{......}
/*K近邻搜索*/
//节点与候选点的有限队列(二叉堆)
//只查询已占用的体素(最近体素优先)
//等于半径搜索(半径=到第K个候选点的距离)
int K = 10;
std::vector<int> pointIdxNKNSearch;
std::vector<float> pointNKNSquaredDistance;
if (octree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)
{
for (size_t i = 0; i < pointIdxNKNSearch.size(); ++i)
{
......
}
}
2.4 PCL Octree应用
//光线跟踪/碰撞检测
PointCloud<PointXYZ>::ptr voxelCenters (new PointCloud<PointXYZ>());
Eigen::Vector3f origen (0.0f, 0.0f, 0.0f);
Eigen::vector3f direction (0.1f, 0.2f, 0.3f);
if (octree.getIntersectedVoxelCenters(origin, direction, voxelCenters->points) > )
{......}
//密度估计
OctreePointCloudDensity<PointXYZ>;
//空间变化检测
octree.setInputCloud(cloudA_ptr); //设置输入点云
octree.addPointsFromInputFromInputCloud ();//从输入点云构建八叉树
octree.switchBuffers();//交换八叉树缓存,但是cloudA对应的八叉树结构仍在内存中
octree.setInputCloud(cloudB_ptr);//添加cloudB到八叉树
octree.addPointsFromInputCloud();
std::vector<int> newPontIdxVector();//存储新加点的索引的向量
//获取前一cloudA对应的八叉树 在cloudB 对应八叉树中A内没有的点集
octree.getPointIndicesFromNewVoxels (newPointIdxVector);