日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

基于octree的空间划分及搜索操作

發布時間:2023/11/27 生活经验 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于octree的空间划分及搜索操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
(1)? octree是一種用于管理稀疏3D數據的樹形數據結構,每個內部節點都正好有八個子節點,介紹如何用octree在點云數據中進行空間劃分及近鄰搜索,實現“體素內近鄰搜索(Neighbors within VOxel Search)”,"K近鄰搜索(K Nearest Neighbor Search)","半徑內近鄰搜索"(Neighbors within Radius Search)

K近鄰搜索(K Nearest Neighbor Search)

所謂K近鄰算法,即是給定一個訓練數據集,對新的輸入實例,在訓練數據集中找到與該實例最鄰近的K個實例(也就是上面所說的K個鄰居), 這K個實例的多數屬于某個類,就把該輸入實例分類到這個類中。

如果,有兩類不同的樣本數據,分別用藍色的小正方形和紅色的小三角形表示,而圖正中間的那個綠色的圓所標示的數據則是待分類的數據。也就是說,現在, 我們不知道中間那個綠色的數據是從屬于哪一類(藍色小正方形or紅色小三角形),下面,我們就要解決這個問題:給這個綠色的圓分類。
  我們常說,物以類聚,人以群分,判別一個人是一個什么樣品質特征的人,常常可以從他/她身邊的朋友入手,所謂觀其友,而識其人。我們不是要判別上圖中那個綠色的圓是屬于哪一類數據么,好說,從它的鄰居下手。但一次性看多少個鄰居呢?從上圖中,你還能看到:
  • 如果K=3,綠色圓點的最近的3個鄰居是2個紅色小三角形和1個藍色小正方形,少數從屬于多數,基于統計的方法,判定綠色的這個待分類點屬于紅色的三角形一類。
  • 如果K=5,綠色圓點的最近的5個鄰居是2個紅色三角形和3個藍色的正方形,還是少數從屬于多數,基于統計的方法,判定綠色的這個待分類點屬于藍色的正方形一類。
于此我們看到,當無法判定當前待分類點是從屬于已知分類中的哪一類時,我們可以依據統計學的理論看它所處的位置特征,衡量它周圍鄰居的權重,而把它歸為(或分配)到權重更大的那一類。這就是K近鄰算法的核心思想。 KNN算法中,所選擇的鄰居都是已經正確分類的對象。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。 KNN 算法本身簡單有效,它是一種 lazy-learning 算法,分類器不需要使用訓練集進行訓練,訓練時間復雜度為0。KNN 分類的計算復雜度和訓練集中的文檔數目成正比,也就是說,如果訓練集中文檔總數為 n,那么 KNN 的分類時間復雜度為O(n)。 KNN方法雖然從原理上也依賴于極限定理,但在類別決策時,只與極少量的相鄰樣本有關。由于KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對于類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更為適合。 K 近鄰算法使用的模型實際上對應于對特征空間的劃分。K 值的選擇,距離度量和分類決策規則是該算法的三個基本要素:
  1. K 值的選擇會對算法的結果產生重大影響。K值較小意味著只有與輸入實例較近的訓練實例才會對預測結果起作用,但容易發生過擬合;如果 K 值較大,優點是可以減少學習的估計誤差,但缺點是學習的近似誤差增大,這時與輸入實例較遠的訓練實例也會對預測起作用,使預測發生錯誤。在實際應用中,K 值一般選擇一個較小的數值,通常采用交叉驗證的方法來選擇最優的 K 值。隨著訓練實例數目趨向于無窮和 K=1 時,誤差率不會超過貝葉斯誤差率的2倍,如果K也趨向于無窮,則誤差率趨向于貝葉斯誤差率。
  2. 該算法中的分類決策規則往往是多數表決,即由輸入實例的 K 個最臨近的訓練實例中的多數類決定輸入實例的類別
  3. 距離度量一般采用 Lp 距離,當p=2時,即為歐氏距離,在度量之前,應該將每個屬性的值規范化,這樣有助于防止具有較大初始值域的屬性比具有較小初始值域的屬性的權重過大。

半徑內近鄰搜索"(Neighbors within Radius Search)


代碼解析,新建工程文件ch3_3,及文件octree_search.cpp

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));   //用系統時間初始化隨機種子與 srand (time (NULL))的區別
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);}/****************************************************************************創建一個octree實例,用設置分辨率進行初始化,該octree用它的頁節點存放點索引向量,分辨率參數描述最低一級octree的最小體素的尺寸,因此octree的深度是分辨率和點云空間維度的函數,如果知道點云的邊界框,應該用defineBoundingbox方法把它分配給octree然后通過點云指針把所有點增加到ctree中。*****************************************************************************/float resolution = 128.0f;pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree (resolution);   //初始化Octree
octree.setInputCloud (cloud);         //設置輸入點云    這兩句是最關鍵的建立PointCloud和octree之間的聯系octree.addPointsFromInputCloud ();   //構建octree
pcl::PointXYZ searchPoint;   //設置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);/*************************************************************************************一旦PointCloud和octree聯系一起,就能進行搜索操作,這里使用的是“體素近鄰搜索”,把查詢點所在體素中其他點的索引作為查詢結果返回,結果以點索引向量的形式保存,因此搜索點和搜索結果之間的距離取決于octree的分辨率參數
*****************************************************************************************/std::vector<int> pointIdxVec;            //存儲體素近鄰搜索結果向量if (octree.voxelSearch (searchPoint, pointIdxVec))    //執行搜索,返回結果到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 被設置為10 ,K近鄰搜索  方法把搜索結果寫到兩個分開的向量,第一個pointIdxNKNSearch包含搜索結果(結果點的索引的向量)  第二個向量pointNKNSquaredDistance存儲搜索點與近鄰之間的距離的平方。
*************************************************************************************///K 近鄰搜索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;}// 半徑內近鄰搜索
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;}}

建立八叉樹,根據不同的搜索形式搜索體素周圍的點云。

結果如下:

Octree類關鍵點的說明
?? PCL octree組件提供了幾個octree類型,它們各自的葉節點特征基本上是不同的,

OctreePointCloudVector(等于OctreePointCloud):該octree能夠保存每一個節點上的點索引列。

OctreePointCloudSinglePoint: 該octree類僅僅保存每一個節點上的單個點的索引,僅僅保存最后分配給葉節點的點索引

OctreePointCloudOccupancy: 該octree類不存儲它的葉節點上的任何信息,它能用于空間填充情況檢查

OctreePointCloudDensity:存儲每一個葉節點體素中點的數目,它可以進行空間點集密集程度的查詢

?

(2)? 無序點云數據集的空間變化檢測

octree是一種管理稀疏3D數據的樹狀結構,利用octree實現多個無序點云之間的空間變化檢測,這些點云可能在尺寸。分辨率 密度,和點順序等方面有所差異,通過遞歸的比較octree的樹結構,可以鑒定出由octree產生的體素組成的區別所代表的空間變化,還要學習關于octree的“雙緩沖”技術,以便實時的探測多個點云之間的空間組成的差異。

代碼分析

octree_change_detection.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));  //用系統時間初始化隨機種子// 八叉樹的分辨率,即體素的大小float resolution = 32.0f;// 初始化空間變化檢測對象pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ> octree (resolution);pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA (new pcl::PointCloud<pcl::PointXYZ> );  //創建點云實例cloudA生成的點云數據用于建立八叉樹octree對象// 為cloudA點云填充點數據cloudA->width = 128;                      //設置點云cloudA的點數cloudA->height = 1;                          //無序點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類繼承自Octree2BufBae類,Octree2BufBae類允許同時在內存中保存和管理兩個octree,另外它應用了內存池該機制能夠重新利用已經分配了的節點對象,因此減少了在生成點云八叉樹對象時昂貴的內存分配和釋放操作通過訪問 octree.switchBuffers ()重置八叉樹 octree對象的緩沖區,但把之前的octree數據仍然保留在內存中************************************************************************************/// 交換八叉樹的緩沖,但是CloudA對應的八叉樹結構仍然在內存中
  octree.switchBuffers ();//cloudB點云用于建立新的八叉樹結構,與前一個cloudA對應的八叉樹共享octree對象,同時在內存中駐留pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB (new pcl::PointCloud<pcl::PointXYZ> );   //實例化點云對象cloudB// 為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 ();/**************************************************************************************************************為了檢索獲取存在于couodB的點集R,此R并沒有cloudA中的元素,可以調用getPointIndicesFromNewVoxels方法,通過探測兩個八叉樹之間體素的不同,它返回cloudB 中新加點的索引的向量,通過索引向量可以獲取R點集  很明顯這樣就探測了cloudB相對于cloudA變化的點集,但是只能探測到在cloudA上增加的點集,二不能探測減少的
****************************************************************************************************************/std::vector<int> newPointIdxVector;  //存儲新添加的索引的向量// 獲取前一cloudA對應八叉樹在cloudB對應在八叉樹中沒有的點集
  octree.getPointIndicesFromNewVoxels (newPointIdxVector);// 打印點集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;}
本實驗是為了檢索獲取存在于couodB的點集R,此R并沒有cloudA中的元素,可以調用getPointIndicesFromNewVoxels方法,通過探測兩個八叉樹之間體素的不同,它返回cloudB 中新加點的索引的向量,通過索引向量可以獲取R點集  很明顯這樣就探測了cloudB相對于cloudA變化的點集,但是只能探測到在cloudA上增加的點集,二不能探測減少的

編譯運行的結果如下(因為生成的隨機點云,所以運行的結果每次都會不一樣的):

微信公眾號號可掃描二維碼一起共同學習交流

未完待續*******************************************8888

?

總結

以上是生活随笔為你收集整理的基于octree的空间划分及搜索操作的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。