点云算法解密-随机采样法

随着三维激光扫描技术的进步,扫描得到的点云数据成海量化。海量点云数据在信息提取与利用中,对计算机的处理、存储、显示能力带来了巨大的考验。在实际应用中需要找到点云精细度和处理效率的平衡点。海量点云导致的问题可以通过减少点云中的冗余数据来解决,也就是使用点云压缩的方法。目前,点云压缩方法较多,效率最高的是随机采样法。

点是点云的基础组成部分,每个点云里都有很多的不同的点,这些点具有不同的坐标。随机采样法的思想是从点云里随机的抽取出一些点,从而减少点云里的点数,达到压缩点云的目的。在抽取时,这些点是等概率,并且不重复的被随机抽取出来的,通常会有个随机数生成函数来实现这些要求。点云是以数组作为其存储的数据结构。使用每个点在数组中的索引值给点做标记,而这个标记称为点的序号。对于给定的点云,当确定压缩率之后,可以知道要保留的点数,然后利用这个随机数生成函数,得到保留点的序号,依据序号提取出对应的点保存,压缩便完成。

PCL里也有随机采样法,其filters模块中,头文件为random_sample.h,不过PCL里的随机算法效果并不好,表现在,点数在几百万以上时,删除的点较为集中,这样对点云里的特征保留并不太好。我以cloudcompare里的随机采样法作为参考,基于PCL写了一个随机采样法,这个改进的随机采样法,采样后,点云的空间分布更为均匀。代码如下:

[code lang=”cpp”]
#include <iostream>
#include <random>

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/filters/random_sample.h>

//本文的随机采样法
void RandomSample(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, float percent,
pcl::PointCloud<pcl::PointXYZ>::Ptr newCloud)
{
int theCloudSize = cloud->size();

std::vector<int> indexs;
indexs.resize(theCloudSize);

for (int i = 0; i < theCloudSize; i++)
{
indexs[i] = i;
}

int newNumberOfPoints = theCloudSize*percent / 100.0;
int pointsToRemove = theCloudSize – newNumberOfPoints;
int lastPointIndexs = theCloudSize – 1;

std::random_device rd;
std::mt19937 gen(rd());

for (int i = 0; i < pointsToRemove; i++)
{
std::uniform_int_distribution<int> dist(0, lastPointIndexs);
int index = dist(gen);
std::swap(indexs[index], indexs[lastPointIndexs]);
–lastPointIndexs;
}

indexs.resize(newNumberOfPoints);

pcl::copyPointCloud(*cloud, indexs, *newCloud);
}

int main()
{
//读取点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

if (pcl::io::loadPCDFile("D:\\bunny.pcd", *cloud))
{
std::cout << "error";
}

//使用本文压缩算法
float percent = 1;
pcl::PointCloud<pcl::PointXYZ>::Ptr myCloud(new pcl::PointCloud<pcl::PointXYZ>);
RandomSample(cloud, percent, myCloud);

//使用PCL的压缩算法
pcl::PointCloud<pcl::PointXYZ>::Ptr pclCloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::RandomSample<pcl::PointXYZ> ran;
ran.setInputCloud(cloud);
ran.setSample(cloud->size()*percent/100.0);
ran.filter(*pclCloud);

//创建显示窗口,分别将原始点云,本文算法和PCL算法压缩后的点云分别显示出来
pcl::visualization::PCLVisualizer viewer("随机采样压缩结果");

int v1 = 1;
viewer.createViewPort(0, 0, 0.33, 1, v1);
viewer.addPointCloud(cloud, "原始点云");

int v2 = 2;
viewer.createViewPort(0.33, 0, 0.66, 1, v2);
viewer.addPointCloud(myCloud, "本文算法压缩后点云");

int v3 = 3;
viewer.createViewPort(0.66, 0, 1, 1, v3);
viewer.addPointCloud(pclCloud, "PCL算法压缩后点云");

while (!viewer.wasStopped())
{
viewer.spinOnce();
}

return (0);
}
[/code]

本文的随机采样法,采用的是不放回抽样,从而保证了每个点抽取的概率相等。

发表评论

电子邮件地址不会被公开。 必填项已用*标注