(小技巧記錄:博客園編輯的網頁界面變小了使用Ctrl ++來變大網頁字體)
通過雷達,激光掃描,立體攝像機等三維測量設備獲取的點雲數據,具有數據量大,分布不均勻等特點,作為三維領域中一個重要的數據來源,點雲主要是表征目標表面的海量點的集合,並不具備傳統網格數據的幾何拓撲信息,所以點雲數據處理中最為核心的問題就是建立離散點間的拓撲關系,實現基於鄰域關系的快速查找。
k-d樹 (k-dimensional樹的簡稱),是一種分割k維數據空間的數據結構。主要應用於多維空間關鍵數據的搜索(如:范圍搜索和最近鄰搜索)。K-D樹是二進制空間分割樹的特殊的情況。用來組織表示K維空間中點的幾何,是一種帶有其他約束的二分查找樹,為了達到目的,通常只在三個維度中進行處理因此所有的kd_tree都將是三維的kd_tree,kd_tree的每一維在指定維度上分開所有的字節點,在樹 的根部所有子節點是以第一個指定的維度上被分開。
k-d樹算法可以分為兩大部分,一部分是有關k-d樹本身這種數據結構建立的算法,另一部分是在建立的k-d樹上如何進行最鄰近查找的算法。
構建算法
k-d樹是一個二叉樹,每個節點表示一個空間范圍。表1給出的是k-d樹每個節點中主要包含的數據結構。
域名
|
數據類型
|
描述
|
Node-data
|
數據矢量
|
數據集中某個數據點,是n維矢量(這里也就是k維)
|
Range
|
空間矢量
|
該節點所代表的空間范圍
|
split
|
整數
|
垂直於分割超平面的方向軸序號
|
Left
|
k-d樹
|
由位於該節點分割超平面左子空間內所有數據點所構成的k-d樹
|
Right
|
k-d樹
|
由位於該節點分割超平面右子空間內所有數據點所構成的k-d樹
|
parent
|
k-d樹
|
父節點
|
先以一個簡單直觀的實例來介紹k-d樹算法。假設有6個二維數據點{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},數據點 位於二維空間內(如圖1中黑點所示)。k-d樹算法就是要確定圖1中這些分割空間的分割線(多維空間即為分割平面,一般為超平面)。下面就要通過一步步展 示k-d樹是如何確定這些分割線的。
virtual void pcl::KdTree< PointT >::setInputCloud | ( | const PointCloudConstPtr & | cloud, |
const IndicesConstPtr & | indices = IndicesConstPtr () |
||
) |
virtual int pcl::KdTree< PointT >::nearestKSearch | ( | int | index, |
int | k, | ||
std::vector< int > & | k_indices, | ||
std::vector< float > & | k_sqr_distances | ||
) | const |
#include <pcl/point_cloud.h> //點類型定義頭文件 #include <pcl/kdtree/kdtree_flann.h> //kdtree類定義頭文件 #include <iostream> #include <vector> #include <ctime> int main (int argc, char** argv) { srand (time (NULL)); //用系統時間初始化隨機種子 //創建一個PointCloud<pcl::PointXYZ> pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); // 隨機點雲生成 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); } //創建KdTreeFLANN對象,並把創建的點雲設置為輸入,創建一個searchPoint變量作為查詢點 pcl::KdTreeFLANN<pcl::PointXYZ> kdtree; //設置搜索空間 kdtree.setInputCloud (cloud); //設置查詢點並賦隨機值 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); // K 臨近搜索 //創建一個整數(設置為10)和兩個向量來存儲搜索到的K近鄰,兩個向量中,一個存儲搜索到查詢點近鄰的索引,另一個存儲對應近鄰的距離平方 int K = 10; std::vector<int> pointIdxNKNSearch(K); //存儲查詢點近鄰索引 std::vector<float> pointNKNSquaredDistance(K); //存儲近鄰點對應距離平方 //打印相關信息 std::cout << "K nearest neighbor search at (" << searchPoint.x << " " << searchPoint.y << " " << searchPoint.z << ") with K=" << K << std::endl; if ( kdtree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0 ) //執行K近鄰搜索 { //打印所有近鄰坐標 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; } /********************************************************************************** 下面的代碼展示查找到給定的searchPoint的某一半徑(隨機產生)內所有近鄰,重新定義兩個向量 pointIdxRadiusSearch pointRadiusSquaredDistance來存儲關於近鄰的信息 ********************************************************************************/ // 半徑 R內近鄰搜索方法 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 ( kdtree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0 ) //執行半徑R內近鄰搜索方法 { 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; } return 0; }

