PCL八叉樹使用說明以及getPointIndicesFromNewVoxels舉例
目錄
原理
八叉樹是一種基於樹的資料結構,用於組織稀疏的三維資料。
八叉樹建立過程,參考1中連結:
虛擬碼:
(1). 設定最大遞迴深度
(2). 找出場景的最大尺寸,並以此尺寸建立第一個立方體
(3). 依序將單位元元素丟入能被包含且沒有子節點的立方體
(4). 若沒有達到最大遞迴深度,就進行細分八等份,再將該立方體所裝的單位元元素全部分擔給八個子立方體
(5). 若發現子立方體所分配到的單位元元素數量不為零且跟父立方體是一樣的,則該子立方體停止細分,因為跟據空間分割理論,細分的空間所得到的分配必定較少,若是一樣數目,則再怎麼切數目還是一樣,會造成無窮切割的情形。
PCL八叉樹用途
根據官方教程
1、八叉樹可以用來點雲壓縮,從而節省記憶體;
2、八叉樹可以查詢某點,某個範圍鄰域中的所有點;PCL
3、八叉樹可以查詢某點,最近鄰的N個元素;
4、根據八叉樹的結構來,找到兩個點雲中結構不同的點,這個比較難理解,在下面例子中說明;
PCL八叉樹用途舉例
八叉樹可以實現來檢測多個無組織點雲之間的空間變化,這些點雲的大小、解析度、密度和點順序可能會有所不同。通過遞迴比較八叉樹的樹結構,可以識別由體素結構差異表示的空間變化,
知識點說明
1、註釋中是如何生成點雲檔案:
2、 octree.switchBuffers() :pcl八叉樹“雙緩衝”技術,使我們能夠隨著時間的推移高效地處理多個點雲。
3、octree.getPointIndicesFromNewVoxels(newPointIdxVector); 是求兩個點雲在八叉樹結構下,在最小體素單位為resolution下,點雲的差異;
4、第一次求octree.getPointIndicesFromNewVoxels(newPointIdxVector);是在cloudB,不在cloudA,第二次求octree.getPointIndicesFromNewVoxels(newPointIdxVector);是求在cloudA,不是cloudB,可見是不一樣的,這個操作不滿足交換律;
5、resolution越小,約束越緊,也就是說如果是想求只要點不相等的點,就是嚴格意義上不相等的情況,修改它為非常小的情況;
程式碼
/*20210104 by 手口一斤*/
#include <pcl/point_cloud.h>
#include <pcl/octree/octree_pointcloud_changedetector.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
#include <vector>
#include <ctime>
int//test_octreeunorgnizedpoint
main(int argc, char** argv)
{
srand((unsigned int)time(NULL));
// Octree resolution - side length of octree voxels
float resolution = 32.0f;//最小體素的邊長
// Instantiate octree-based point cloud change detection class
pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ> octree(resolution);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA(new pcl::PointCloud<pcl::PointXYZ>);
// Generate pointcloud data for cloudA
cloudA->width = 128;
cloudA->height = 1;
cloudA->points.resize(cloudA->width * cloudA->height);
// Generate pointcloud data for cloudB
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB(new pcl::PointCloud<pcl::PointXYZ>);
cloudB->width = 128;
cloudB->height = 1;
cloudB->points.resize(cloudB->width * cloudB->height);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("gendiffa.pcd", *cloudA) == -1)//*開啟點雲檔案
{
PCL_ERROR("Couldn't read file gendiffa.pcd\n");
return(-1);
}
if (pcl::io::loadPCDFile<pcl::PointXYZ>("gendiffb.pcd", *cloudB) == -1)//*開啟點雲檔案
{
PCL_ERROR("Couldn't read file gendiffb.pcd\n");
return(-1);
}
//for (std::size_t i = 0; i < cloudA->size(); ++i)
//{
// (*cloudA)[i].x = 64.0f * rand() / (RAND_MAX + 1.0f);
// (*cloudA)[i].y = 64.0f * rand() / (RAND_MAX + 1.0f);
// (*cloudA)[i].z = 64.0f * rand() / (RAND_MAX + 1.0f);
// (*cloudB)[i].x = 64.0f * rand() / (RAND_MAX + 1.0f);
// (*cloudB)[i].y = 64.0f * rand() / (RAND_MAX + 1.0f);
// (*cloudB)[i].z = 64.0f * rand() / (RAND_MAX + 1.0f);
// std::cout << i << " A:" << (*cloudA)[i].x << " " << (*cloudA)[i].y <<" " <<(*cloudA)[i].z << std::endl;
// std::cout << i << " B:" << (*cloudB)[i].x << " "<<(*cloudB)[i].y << " " <<(*cloudB)[i].z << std::endl;
//}
//pcl::io::savePCDFileASCII("gendiffa.pcd", *cloudA);
//pcl::io::savePCDFileASCII("gendiffb.pcd", *cloudB);
octree.setInputCloud(cloudA);
octree.addPointsFromInputCloud();
octree.switchBuffers();
octree.setInputCloud(cloudB);
octree.addPointsFromInputCloud();
std::vector<int> newPointIdxVector;
octree.getPointIndicesFromNewVoxels(newPointIdxVector);
std::cout << "Output from getPointIndicesFromNewVoxels:" << newPointIdxVector.size() <<std::endl;//在B不在A
for (std::size_t i = 0; i < newPointIdxVector.size(); ++i)
std::cout << i << "# Index:" << newPointIdxVector[i]
<< " Point:" << (*cloudB)[newPointIdxVector[i]].x << " "
<< (*cloudB)[newPointIdxVector[i]].y << " "
<< (*cloudB)[newPointIdxVector[i]].z << std::endl;
octree.switchBuffers();
octree.setInputCloud(cloudA);
octree.addPointsFromInputCloud();
newPointIdxVector.clear();
octree.getPointIndicesFromNewVoxels(newPointIdxVector);
// Output points
std::cout << "Output from getPointIndicesFromNewVoxels:" << newPointIdxVector.size() << std::endl;//在A不在B,可見只是雙快取
for (std::size_t i = 0; i < newPointIdxVector.size(); ++i)
std::cout << i << "# Index:" << newPointIdxVector[i]
<< " Point:" << (*cloudA)[newPointIdxVector[i]].x << " "
<< (*cloudA)[newPointIdxVector[i]].y << " "
<< (*cloudA)[newPointIdxVector[i]].z << std::endl;
}
參考:
1、octree原理:https://blog.csdn.net/jiaojialulu/article/details/69350980
2、程式參考:https://pcl.readthedocs.io/projects/tutorials/en/latest/octree_change.html#octree-change-detection