欢迎点云相关产学研的学者和团体加入我们。
octree是一种用于管理稀疏3D数据的树状数据结构,本小节中我们学习如何利用octree实现用于多个无序点云之间的空间变化检测,这些点云可能在尺寸、分辨率、密度和点顺序等方面有所差异。通过递归地比较octree的树结构,可以鉴定出由octree产生的体素组成之间的区别所代表的空间变化,此外,我们解释了如何使用PCL的octree“双缓冲”技术,以便能实时地探测多个点云之间的空间组成差异。
首先,在PCL(Point Cloud Learning)中国协助发行的书提供光盘的第6章例3文件夹中,打开名为octree_change_detection.cpp的代码文件。
首先实例化OctreePointCloudChangeDetector类,并定义它的体素分辨率。
srand((unsignedint)time(NULL));
float resolution=32.0f;//八叉树分辨率即体素的大小
//初始化空间变化检测对象
pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ> octree(resolution);
然后创建点云实例cloudA,用随机点数据填充,所生成的点数据用于建立八叉树octree对象。
//为cloudA点云填充点数据
cloudA->width =128; //设置点云cloudA点数
cloudA->height =1; //设置点云cloudA为无序点云
cloudA->points.resize (cloudA->width *cloudA->height);
for (size_t i=0; i<cloudA->points.size (); ++i) //循环产生点数据
{
cloudA->points[i].x =64.0f* rand () / (RAND_MAX +1.0f);
cloudA->points[i].y =64.0f* rand () / (RAND_MAX +1.0f);
cloudA->points[i].z =64.0f* rand () / (RAND_MAX +1.0f);
}
//添加点云到八叉树,构建八叉树
octree.setInputCloud (cloudA); //设置输入点云
octree.addPointsFromInputCloud (); //从输入点云构建八叉树
点云cloudA是参考点云,用其建立的八叉树对象描述它的空间分布OctreePointCloudChangeDetector类继承自Octree2BufBase类,Octree2BufBase类允许同时在内存中保存和管理两个octree,另外,它应用了内存池,该机制能够重新利用已经分配了的节点对象,因此减少了在生成多个点云八叉树对象时昂贵的内存分配和释放操作。通过访问“octree.switchBuffers()”,重置了八叉树octree对象的缓冲区,但把之前的octree数据仍保留在内存中。
octree.switchBuffers ();// 交换八叉树缓存,但是cloudA对应的八叉树结构仍在内存中
现在我们实例化第二个点云对象cloudB并用随机点数据填充它,该点云用于建立新的八叉树结构,该新的八叉树与前一个cloudA对应的八叉树共享octree对象,但同时在内存中驻留。
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB (new pcl::PointCloud<pcl::PointXYZ> );
// 为cloudB创建点云
cloudB->width =128;
cloudB->height =1;
cloudB->points.resize (cloudB->width *cloudB->height);
for (size_t i=0; i<cloudB->points.size (); ++i)
{
cloudB->points[i].x =64.0f* rand () / (RAND_MAX +1.0f);
cloudB->points[i].y =64.0f* rand () / (RAND_MAX +1.0f);
cloudB->points[i].z =64.0f* rand () / (RAND_MAX +1.0f);
}
//添加 cloudB到八叉树
octree.setInputCloud (cloudB);
octree.addPointsFromInputCloud ();
为了检索到获取存在于cloudB的点集R,此R并没有cloudA中元素,可以调用getPointIndicesFromNewVoxels方法,通过探测两个八叉树之间体素的不同,它返回cloudB中新加点的索引的向量,通过索引向量可以获取R点集。很明显,这样就探测了cloudB相对于cloudA变化的点集,但是只能探测在cloudA上增加的点集,而不能探测在cloudA上减少的点集。
std::vector<int> newPointIdxVector; //存储新加点的索引的向量
//获取前一cloudA对应的八叉树在cloudB对应八叉树中没有的点集
octree.getPointIndicesFromNewVoxels (newPointIdxVector);
最后,我们把结果输出到std::cout数据流,打印到标准输出设备上。
//打印结果点到标准输出
std::cout<<"Output from getPointIndicesFromNewVoxels:"<<std::endl;
for (size_t i=0; i<newPointIdxVector.size (); ++i) //循环打印所有结果点坐标
std::cout<<i<<"# Index:"<<newPointIdxVector[i]
<<" Point:"<<cloudB->points[newPointIdxVector[i]].x <<" "
<<cloudB->points[newPointIdxVector[i]].y <<" "
<<cloudB->points[newPointIdxVector[i]].z <<std::endl;
利用光盘提供的CMakeLists.txt文件,在cmake中建立工程文件,并生成相应的可执行文件,生成执行文件后,就可以运行了,在cmd中键入命令:
...>octree_change_detection.exe
运行结果如图1所示,打印输出在cloudA上增加的点集。
图1 空间变化检测实例运行结果
敬请关注PCL(Point Cloud Learning)中国更多的点云库PCL(Point Cloud Library)相关官方教程。
参考文献:
1.朱德海、郭浩、苏伟.点云库PCL学习教程(ISBN 978-7-5124-0954-5)北京航空航天出版社 2012-10