通过八叉树进行空间分割和搜索
一個octree是一個以樹基礎為的管理稀疏3-D數據的數據結構。每個中間的節點有8個子節點。在這次,我們將學習怎么使用octree進行稀疏分割和近鄰搜索。尤其,我們將解釋如何操作"體元近鄰搜索",和"最近鄰搜索"和"半徑近鄰搜索".
我們將創建一個octree_search.cpp這個文件
#include <pcl/point_cloud.h>
#include <pcl/octree/octree.h>
#include <iostream>
#include <vector>
#include <ctime>
int
main (int argc, char** argv)
{
? srand ((unsigned int) time (NULL));
? pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
? // Generate pointcloud data
? cloud->width = 1000;
? cloud->height = 1;
? cloud->points.resize (cloud->width * cloud->height);
? for (size_t i = 0; i < cloud->points.size (); ++i)
? {
??? cloud->points[i].x = 1024.0f * rand () / (RAND_MAX + 1.0f);
??? cloud->points[i].y = 1024.0f * rand () / (RAND_MAX + 1.0f);
??? cloud->points[i].z = 1024.0f * rand () / (RAND_MAX + 1.0f);
? }
? float resolution = 128.0f;
? pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree (resolution);
? octree.setInputCloud (cloud);
? octree.addPointsFromInputCloud ();
? pcl::PointXYZ searchPoint;
? searchPoint.x = 1024.0f * rand () / (RAND_MAX + 1.0f);
? searchPoint.y = 1024.0f * rand () / (RAND_MAX + 1.0f);
? searchPoint.z = 1024.0f * rand () / (RAND_MAX + 1.0f);
? // Neighbors within voxel search
? std::vector<int> pointIdxVec;
? if (octree.voxelSearch (searchPoint, pointIdxVec))
? {
??? std::cout << "Neighbors within voxel search at (" << searchPoint.x
???? << " " << searchPoint.y
???? << " " << searchPoint.z << ")"
???? << std::endl;
?????????????
??? for (size_t i = 0; i < pointIdxVec.size (); ++i)
?? std::cout << "??? " << cloud->points[pointIdxVec[i]].x
?????? << " " << cloud->points[pointIdxVec[i]].y
?????? << " " << cloud->points[pointIdxVec[i]].z << std::endl;
? }
? // K nearest neighbor search
? int K = 10;
? std::vector<int> pointIdxNKNSearch;
? std::vector<float> pointNKNSquaredDistance;
? std::cout << "K nearest neighbor search at (" << searchPoint.x
??????????? << " " << searchPoint.y
??????????? << " " << searchPoint.z
??????????? << ") with K=" << K << std::endl;
? if (octree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)
? {
??? for (size_t i = 0; i < pointIdxNKNSearch.size (); ++i)
????? std::cout << "??? "? <<?? cloud->points[ pointIdxNKNSearch[i] ].x
??????????????? << " " << cloud->points[ pointIdxNKNSearch[i] ].y
??????????????? << " " << cloud->points[ pointIdxNKNSearch[i] ].z
??????????????? << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;
? }
? // Neighbors within radius search
? std::vector<int> pointIdxRadiusSearch;
? std::vector<float> pointRadiusSquaredDistance;
? float radius = 256.0f * rand () / (RAND_MAX + 1.0f);
? std::cout << "Neighbors within radius search at (" << searchPoint.x
????? << " " << searchPoint.y
????? << " " << searchPoint.z
????? << ") with radius=" << radius << std::endl;
? if (octree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0)
? {
??? for (size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)
????? std::cout << "??? "? <<?? cloud->points[ pointIdxRadiusSearch[i] ].x
??????????????? << " " << cloud->points[ pointIdxRadiusSearch[i] ].y
??????????????? << " " << cloud->points[ pointIdxRadiusSearch[i] ].z
??????????????? << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
? }
}
代碼解釋
定義和實例化了一個PointCloud這個數據結構,并生成隨機點云。
? pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
? // Generate pointcloud data
? cloud->width = 1000;
? cloud->height = 1;
? cloud->points.resize (cloud->width * cloud->height);
? for (size_t i = 0; i < cloud->points.size (); ++i)
? {
??? cloud->points[i].x = 1024.0f * rand () / (RAND_MAX + 1.0f);
??? cloud->points[i].y = 1024.0f * rand () / (RAND_MAX + 1.0f);
??? cloud->points[i].z = 1024.0f * rand () / (RAND_MAX + 1.0f);
? }
接下去我們創造了一個用下面的這個分辨率為初始化的octree實例。octree保持了它的葉子節點的點下標。分辨率參數描述了小體元的長度。octree的深度因此是一個分辨率的函數和點云的空間維度一樣。如果一個點云的邊框盒子已知,它通過使用defineBoundingBox這個方法分配給octree。然后我們把一個指針分配給點云并把所有的點加入到octree里面。
? float resolution = 128.0f;
? pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree (resolution);
? octree.setInputCloud (cloud);
? octree.addPointsFromInputCloud ();
一旦點云與octree相聯系上,我們就能使用搜索的操作。我們第一個搜索方法"Neighbors within Voxel Search"。它將被分配給相應葉子節點的體元的搜索點并返回一個點下標的向量。這個下標和進入同一個體元里面的點有關系。搜索點與搜索結果距離依賴于octree的分辨率。
? std::vector<int> pointIdxVec;
? if (octree.voxelSearch (searchPoint, pointIdxVec))
? {
??? std::cout << "Neighbors within voxel search at (" << searchPoint.x
???? << " " << searchPoint.y
???? << " " << searchPoint.z << ")"
???? << std::endl;
?????????????
??? for (size_t i = 0; i < pointIdxVec.size (); ++i)
?? std::cout << "??? " << cloud->points[pointIdxVec[i]].x
?????? << " " << cloud->points[pointIdxVec[i]].y
?????? << " " << cloud->points[pointIdxVec[i]].z << std::endl;
? }
接下去,顯示了一個K最近鄰搜索。在這個例子里面,K被設置為10,"K最近鄰搜索"的方法的搜索結果被寫入兩個獨立的向量里面。第一個,pointIdxNKNSearch,將會包含搜索結果(與相鄰點云數據集相關的下標)。第二個下標向量保持相應的搜索得到節點和最近鄰之間的平方距離。
? int K = 10;
? std::vector<int> pointIdxNKNSearch;
? std::vector<float> pointNKNSquaredDistance;
? std::cout << "K nearest neighbor search at (" << searchPoint.x
??????????? << " " << searchPoint.y
??????????? << " " << searchPoint.z
??????????? << ") with K=" << K << std::endl;
? if (octree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)
? {
??? for (size_t i = 0; i < pointIdxNKNSearch.size (); ++i)
????? std::cout << "??? "? <<?? cloud->points[ pointIdxNKNSearch[i] ].x
??????????????? << " " << cloud->points[ pointIdxNKNSearch[i] ].y
??????????????? << " " << cloud->points[ pointIdxNKNSearch[i] ].z
??????????????? << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;
? }
指定半徑內的鄰居搜索和"最近鄰搜索"相似。它的搜索結果被寫成2個獨立的向量,描述了下標點和搜索點的平方距離。
?std::vector<int> pointIdxRadiusSearch;
? std::vector<float> pointRadiusSquaredDistance;
? float radius = 256.0f * rand () / (RAND_MAX + 1.0f);
? std::cout << "Neighbors within radius search at (" << searchPoint.x
????? << " " << searchPoint.y
????? << " " << searchPoint.z
????? << ") with radius=" << radius << std::endl;
? if (octree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0)
? {
??? for (size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)
????? std::cout << "??? "? <<?? cloud->points[ pointIdxRadiusSearch[i] ].x
??????????????? << " " << cloud->points[ pointIdxRadiusSearch[i] ].y
??????????????? << " " << cloud->points[ pointIdxRadiusSearch[i] ].z
??????????????? << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
? }
下面是運行結果
Neighbors within voxel search at (974.82 188.793 138.779)
??? 903.656 82.8158 162.392
??? 1007.34 191.035 61.7727
??? 896.88 155.711 58.1942
K nearest neighbor search at (974.82 188.793 138.779) with K=10
??? 903.656 82.8158 162.392 (squared distance: 16853.1)
??? 903.18 247.058 54.3528 (squared distance: 15655)
??? 861.595 149.96 135.199 (squared distance: 14340.7)
??? 896.88 155.711 58.1942 (squared distance: 13663)
??? 995.889 116.224 219.077 (squared distance: 12157.9)
??? 885.852 238.41 160.966 (squared distance: 10869.5)
??? 900.807 220.317 77.1432 (squared distance: 10270.7)
??? 1002.46 117.236 184.594 (squared distance: 7983.59)
??? 1007.34 191.035 61.7727 (squared distance: 6992.54)
??? 930.13 223.335 174.763 (squared distance: 4485.15)
Neighbors within radius search at (974.82 188.793 138.779) with radius=109.783
??? 1007.34 191.035 61.7727 (squared distance: 6992.54)
??? 900.807 220.317 77.1432 (squared distance: 10270.7)
??? 885.852 238.41 160.966 (squared distance: 10869.5)
??? 1002.46 117.236 184.594 (squared distance: 7983.59)
??? 930.13 223.335 174.763 (squared distance: 4485.15)
一些額外的細節
PCL八叉樹組件里面提供了幾種八叉樹的類型。他們通過他們的獨特的葉子節點特征來區別。
OctreePointCloudPointVector(等于OctreePointCloud):這個octree可以包含每個葉子節點的一系列的點的下標。
OctreePointCloudSinglePoint:這個八叉樹類在每一個葉子節點里面包含一個點的下標。只有被分配到葉子節點里面最多的下標將會被存儲。
OctreePointCloudOccupancy:這個八叉樹沒有存儲任何點的信息在它的葉子節點上。
OctreePointCloudDensity:這個octree計算每個葉子節點體元的數量。它允許特殊的空間密度查詢。
如果八叉樹需要經常被創建,請看一下八叉樹的double buffering implementation(Octree2BufBase這個類)。這個類同時保持兩個并行的八叉樹結構在內存里面。除了每個搜索操作,它也使得空間改變檢測成為可能。更多,一個先進的內存管理減少了內存分配和回收操作在octree構建的時候。
總結:
PCL里面的octree是一個進行空間分割和搜索的有力的工具。
總結
以上是生活随笔為你收集整理的通过八叉树进行空间分割和搜索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python中利用LSTM模型进行时间序
- 下一篇: 我的Go+语言初体验——(2)IDE 详