3D點雲特征描述與提取是點雲信息處理中最基礎也是最關鍵的一部分,點雲的識別。分割,重采樣,配准曲面重建等處理大部分算法,都嚴重依賴特征描述與提取的結果。從尺度上來分,一般分為局部特征的描述和全局特征的描述,例如局部的法線等幾何形狀特征的描述,全局的拓朴特征的描述,都屬於3D點雲特征描述與提取的范疇,
特征描述與提取相關的概念與算法
1.3D形狀內容描述子(3D shape contexts)
利用描述子建立曲面間的對應點在3D物體識別領域有廣發的應用,采用一個向量描述曲面上指定點及鄰域的形狀特征,通過匹配向量的值來建立不同曲面點的對應關系,此相鄰則則稱為指定點的俄描述子,經典描述子的3D形狀內容描述子結構簡單,辨別力強,且對噪聲不敏感,
2,旋轉圖像(spin iamge)
旋轉圖像最早是由johnson提出的特征描述子,主要用於3D場景中的曲面匹配和模型識別,
3,涉及的算法相關的資料
3D形狀內容描述子
https://en.wikipedia.org/wiki/Shape_context
www.eecs.berkeley.edu/Research/Projects/CS/vision/shape/belongie-pami02.pdf
還有很多中描述子的理論與算法的研究,不再一一列出來
關於理論的部分有待研究,但是暫時我只是學習會用。
關於PCL中特征描述與提取模塊和相關類的介紹
Classes |
|
class | pcl::ShapeContext3DEstimation< PointInT, PointNT, PointOutT > |
實現3D形狀內容描述子算法 | |
class | pcl::BOARDLocalReferenceFrameEstimation< PointInT, PointNT, PointOutT > |
實現局部坐標系估計的方法 特別是處理點雲邊緣或有孔洞有特殊的處理方式 | |
class | pcl::BoundaryEstimation< PointInT, PointNT, PointOutT > |
實現估計一組點集是否處於指定點的投影區域的邊緣位置 | |
class | pcl::CRHEstimation< PointInT, PointNT, PointOutT > |
實現攝像頭旋轉直方圖描述子,利用概算法主要進行剛體對象的位姿估計 | |
class | pcl::CVFHEstimation< PointInT, PointNT, PointOutT > |
實現聚類視點直方圖CVFH描述子的計算 主要是針對解決有殘缺的點雲識別問題 | |
class | pcl::ESFEstimation< PointInT, PointOutT > |
實現ESF描述子,主要用於實時對三維場景中的點雲模型進行分類而提出的 | |
class | pcl::Feature< PointInT, PointOutT > 是所有特征相關模塊中其他類的基類 |
class | pcl::FeatureWithLocalReferenceFrames< PointInT, PointRFT > |
實現FPFH描述子算法主要針對點雲配准過程中對應點而提出的 |
(關於他的類還有很多可以直接去網站自己查看)
PCL中描述三維特征相關基礎
理論基礎
在原始表示形式下,點的定義是用笛卡爾坐標系坐標 x, y, z 相對於一個給定的原點來簡單表示的三維映射系統的概念,假定坐標系的原點不隨着時間而改變,這里有兩個點p1和p2分別在時間t1和t2捕獲,有着相同的坐標,對這兩個點作比較其實是屬於不適定問題(ill—posed problem),因為雖然相對於一些距離測度它們是相等的,但是它們取樣於完全不同的表面,因此當把它們和臨近的其他環境中點放在一起時,它們表達着完全不同的信息,這是因為在t1和t2之間局部環境有可能發生改變。一些獲取設備也許能夠提供取樣點的額外數據,例如強度或表面反射率等,甚至顏色,然而那並不能完全解決問題,單從兩個點之間來 對比仍然是不適定問題。由於各種不同需求需要進行對比以便能夠區分曲面空間的分布情況,應用軟件要求更好的特征度量方式,因此作為一個單一實體的三維點概念和笛卡爾坐標系被淘汰了,出現了一個新的概念取而代之:局部描述子(locl descriptor)。文獻中對這一概念的描述有許多種不同的命名,如:形狀描述子(shape descriptors)或幾何特征(geometric features),文本中剩余部分都統稱為點特征表示。通過包括周圍的領域,特征描述子能夠表征采樣表面的幾何 性質,它有助於解決不適定的對比問題,理想情況下相同或相似表面上的點的特征值將非常相似(相對特定度量准則),而不同表面上的點的特征描述子將有明顯差異。下面幾個條件,通過能否獲得相同的局部表面特征值,可以判定點特征表示方式的優劣:
(1) 剛體變換-----即三維旋轉和三維平移變化 不會影響特征向量F估計,即特征向量具有平移選轉不變性。
(2) 改變采樣密度-----原則上,一個局部表面小塊的采樣密度無論是大還是小,都應該有相同的特征向量值,即特征向量具有抗密度干擾性。
(3) 噪聲---數據中有輕微噪聲的情況下,點特征表示在它的特征向量中必須保持相同或者極其相似的值,即特征向量對點雲噪聲具有穩定性。
通常,PCL中特征向量利用快速kd-tree查詢 ,使用近似法來計算查詢點的最近鄰元素,通常有兩種查詢類型:K鄰域查詢,半徑搜索兩中方法
法線估計實例
一旦確定鄰域以后,查詢點的鄰域點可以用來估計一個局部特征描述子,它用查詢點周圍領域點描述采樣面的幾何特征,描述幾何表面圖形的一個重要屬性,首先是推斷它在坐標系中的方位,也就是估計他的法線,表面法線是表面的一個重要的屬性,在許多領域都有重要的應用,如果用光源來生成符合視覺效果的渲染等,
代碼解析:normal_estimation.cpp
(實現對輸入點雲數據集中的點估計一組表面法線)執行的操作是:對應點雲P中每一個點p得到p點最近鄰元素,計算p點的表面的法線N,檢查N的方向是否指向視點如果不是則翻轉。
視點默認坐標是(0,0,0)可使用setViewPoint(float vpx,float vpy,float vpz)來更換
#include <pcl/io/io.h> #include <pcl/io/pcd_io.h> #include <pcl/features/integral_image_normal.h> //法線估計類頭文件 #include <pcl/visualization/cloud_viewer.h> #include <pcl/point_types.h> #include <pcl/features/normal_3d.h> int main () { //打開點雲代碼 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile ("table_scene_lms400.pcd", *cloud); //創建法線估計估計向量 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; ne.setInputCloud (cloud); //創建一個空的KdTree對象,並把它傳遞給法線估計向量 //基於給出的輸入數據集,KdTree將被建立 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ()); ne.setSearchMethod (tree); //存儲輸出數據 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>); //使用半徑在查詢點周圍3厘米范圍內的所有臨近元素 ne.setRadiusSearch (0.03); //計算特征值 ne.compute (*cloud_normals); // cloud_normals->points.size ()應該與input cloud_downsampled->points.size ()有相同的尺寸 //可視化 pcl::visualization::PCLVisualizer viewer("PCL Viewer"); viewer.setBackgroundColor (0.0, 0.0, 0.0); viewer.addPointCloudNormals<pcl::PointXYZ,pcl::Normal>(cloud, cloud_normals); while (!viewer.wasStopped ()) { viewer.spinOnce (); } return 0; }
運行結果並執行:
(2)估計一個點雲的表面法線
表面法線是幾何體表面一個十分重要的屬性,例如:在進行光照渲染時產生符合可視習慣的效果時需要表面法線的信息才能正常進行,對於一個已經已經知道的幾何體表面,根據垂直於點表面的的矢量,因此推推處表面某一點的法線方向比較容易,然而由於我們獲取的點雲的數據集在真實的物體的表面表現為一組定點的樣本,這樣就會有兩種方法解決:
1 . 使用曲面重建技術,從獲取的點雲數據中得到采樣點對應的曲面,然后從曲面模型中計算出表面法線
2. 直接從點雲數據中近似推斷表面法線
在確定表面一點法線的問題近似於估計表面的一個相切面法線的問題,因此轉換過來就是求一個最小二乘法平面擬合的問題
(3)使用積分圖進行法線估計
使用積分圖計算一個有序的點雲的法線,注意此方法只適用有序點雲
代碼解析normal_estimation_using_integral_images.cpp
#include <pcl/io/io.h> #include <pcl/io/pcd_io.h> #include <pcl/features/integral_image_normal.h> #include <pcl/visualization/cloud_viewer.h> int main () { //打開點雲 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile ("table_scene_mug_stereo_textured.pcd", *cloud); //創建法線估計向量 pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>); pcl::IntegralImageNormalEstimation<pcl::PointXYZ, pcl::Normal> ne; /**************************************************************************************** 三種法線估計方法 COVARIANCE_MATRIX 模式從具體某個點的局部鄰域的協方差矩陣創建9個積分,來計算這個點的法線 AVERAGE_3D_GRADIENT 模式創建6個積分圖來計算水平方向和垂直方向的平滑后的三維梯度並使用兩個梯度間的向量 積計算法線 AVERAGE_DEPTH——CHANGE 模式只創建了一個單一的積分圖,從而平局深度變化計算法線 ********************************************************************************************/ ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT); //設置法線估計的方式AVERAGE_3D_GRADIENT ne.setMaxDepthChangeFactor(0.02f); //設置深度變化系數 ne.setNormalSmoothingSize(10.0f); //設置法線優化時考慮的鄰域的大小 ne.setInputCloud(cloud); //輸入的點雲 ne.compute(*normals); //計算法線 //可視化 pcl::visualization::PCLVisualizer viewer("PCL Viewer"); //視口的名稱 viewer.setBackgroundColor (0.0, 0.0, 0.5); //背景顏色的設置 viewer.addPointCloudNormals<pcl::PointXYZ,pcl::Normal>(cloud, normals); //將法線加入到點雲中 while (!viewer.wasStopped ()) { viewer.spinOnce (); } return 0; }
運行結果為:
微信公眾號號可掃描二維碼一起共同學習交流
未完待續*********************8