1. 程式人生 > 其它 >OpenCV-Python系列之ORB演算法

OpenCV-Python系列之ORB演算法

ORB是2011年ICCV上作者Rublee所提出,主要針對目前主流的SIFT或者SURF等演算法的實時性進行改進。當然在實時性大為提升的基礎上,匹配效能也在一定程度較SIFT與SURF演算法降低。但是,在影象Two Views匹配對之間變換關係較小時,能夠匹配效能逼近SIFT演算法,同時計算耗時極大降低。ORB演算法實時性在移動端裝置上提供很好的應用,當下比較流行SLAM中採用較多的ORB-SLAM演算法主要就是青睞於ORB演算法實時性同時匹配精度並不差。

論文對ORB演算法主要貢獻如下:

1、 在FAST角點運算元快速提取角點基礎上,新增主方向資訊。

2 、通過方向BRIEF描述運算元高效計算FAST角點提取的特徵點描述符。

3 、分析方向BRIEF描述符的方差與相關性。

4 、提出一種在旋轉不變情況下去除相關性的BRIEF描述子的學習方式,在最近鄰應用中獲得更好的效果。

ORB特徵通過增加了FAST檢測子所沒有的方向性,利用計算速度特快的描述子BRIEF,這就使得提取影象特徵時速度加快了很多。在以往提取一幀影象特徵點的實驗中,在提取相同數量的特徵點情況下,提取SURF點耗時時間大約是提取ORB特徵點的14倍,而提取SIFT點耗時更大,大概比提取ORB特徵點多三百多倍。由此可知提取ORB特徵點比提取SIFT, SURF特徵點所需要的計算量小得多。所以對於需要實時執行視覺SLAM演算法的系統,其前端提取ORB特徵點比較合適,且ORB特徵點具有兩個特性:一是尺度不變,二是旋轉不變性。

下面幾種特徵點檢測的效果圖:

現在我們來進行原理解讀。

原理

ORB 是 Oriented Fast and Rotated Brief 的簡稱,可以用來對影象中的關鍵點快速建立特徵向量,這些特徵向量可以用來識別影象中的物件。
其中,Fast 和 Brief 分別是特徵檢測演算法和向量建立演算法。ORB 首先會從影象中查詢特殊區域,稱為關鍵點。關鍵點即影象中突出的小區域,比如角點,比如它們具有畫素值急劇的從淺色變為深色的特徵。然後 ORB 會為每個關鍵點計算相應的特徵向量。ORB 演算法建立的特徵向量只包含 1 和 0,稱為二元特徵向量。1 和 0 的順序會根據特定關鍵點和其周圍的畫素區域而變化。該向量表示關鍵點周圍的強度模式,因此多個特徵向量可以用來識別更大的區域,甚至影象中的特定物件。
ORB 的特點是速度超快,而且在一定程度上不受噪點和影象變換的影響,例如旋轉和縮放變換等。

FAST 演算法

ORB 特徵檢測的第一步是查詢影象中的關鍵點,而關鍵點檢測演算法即使用 FAST 演算法。

FAST 是 Features from Accelerated Segments Test 的簡稱,可以快速選擇關鍵點,演算法步驟如下:

給與一個畫素點 p,FAST 比較目標 p 圓圈範圍中的 16 個畫素,每個畫素按高於 p,小於 p,或者與 p 相似,分為三類。

注意這裡的比較是帶有閾值 h 的。對於給定的閾值 h,更亮的畫素將是亮度超過 Ip+h 的畫素,更暗的畫素將是亮度低於 Ip-h 的畫素,相似畫素將是亮度在這兩個值之間的畫素。在對畫素分類後, 如果圈圈上有 8 個以上的相連畫素,暗於或亮於 p 則將畫素 p 選作關鍵點。

而 FAST 如此高效的原因是,僅將 p 與圓圈中的 4 個等距畫素相比。這種方法已經證明和比較 16 個周圍畫素的效果相同。如果至少有一對連續畫素的亮度高於或低於 p,則將 p 選作關鍵點。這種優化使得在整個影象中搜索關鍵點的時間縮短了四倍。

但是,這些關鍵點可以像我們提供什麼樣的資訊?對比鄰近畫素的亮度有何意義?首先觀察一下 FAST 演算法標記關鍵點的影象:

可以看出關鍵點位於亮度有變化的區域,此類區域通常確定了某種邊緣,例如貓的爪子。邊緣定義了貓的界限,以及臉部區域的界限,因此這些關鍵點使我們能夠識別這隻貓,而不是影象中的任何其他物件或背景。

第二個則為BRIEF演算法,我們在上一節已經講過,這裡就不在贅述了。

縮放不變性和旋轉不變性

ORB 使用 FAST 檢測影象中的關鍵點,並且通過額外的幾個步驟確保無論物件的大小或位置如何都能檢測到影象中的物件。

給定一個影象 ORB 演算法首先開始構建影象金字塔。

影象金字塔是單個影象的多尺度表示法,由一系列原始影象的不同解析度版本組成。金字塔的每個級別都由上個級別的影象下采樣版本組成。下采樣是指影象解析度被降低,比如影象按照 1/2 比例下采樣。因此一開始的 4x4 正方形區域現在變成 2x2 正方形。影象的下采樣包含更少的畫素,並且以 1/2 的比例降低大小。

這是一個包含 5 個級別的圖形金字塔示例,在每個級別影象都以 1/2 的比例下采樣。到了第四級別影象的解析度是原始影象的 1/16。ORB 建立好影象金字塔後,它會使用 FAST 演算法從每個級別不同大小的影象中快速找到關鍵點。因為金字塔的每個級別由原始影象的更小版本組成,因此原始影象中的任何物件在金字塔的每個級別也會降低大小。
通過確定每個級別的關鍵點 ORB 能夠有效發現不同尺寸的物件的關鍵點,這樣的話 ORB 實現了部分縮放不變性。這一點很重要,因為物件不太可能在每個影象中的大小都完全一樣,尤其是像貓這樣的物件某個時刻可能靠近相機,在另一個時刻離相機很遠。

例如朝左或朝右,取決於該關鍵點周圍的強度是如何變化的。
我們詳細瞭解下背後原理。ORB 首先選擇金字塔Level 0 中的影象,對於該影象 ORB 將計算關鍵點的方向。

方法是首先計算以該關鍵點為中心的方框中的強度形心。強度形心可以看做給定 patch 中的平均畫素強度的位置。計算強度形心後,通過畫一條從關鍵點到強度形心的向量,獲得該關鍵點的方向,如上圖所示。這個關鍵點的方向是向下並朝左,因為這個區域的亮度朝著這個方向增強。
為金字塔級別 0 的影象中的每個關鍵點分配方向後,ORB 現在為所有其他金字塔級別的影象重複相同流程。需要注意的是,在每個影象金字塔級別,Patch 大小並沒有縮減,因此相同 Patch 在每個金字塔級別覆蓋的影象區域將更大,導致關鍵點的大小各不相同。

可以從此處看出這一點。在此圖中,圓圈表示每個關鍵點的大小,更高的金字塔級別中的關鍵點大小更大。
找到關鍵點併為其分配方向後,ORB 現在使用修改後的 BRIEF 版本建立特徵向量,這個修改後的 BRIEF 版本稱為 rBRIEF,即 Rotation-Aware BRIEF。無論物件的方向如何,它都可以為關鍵點建立相同的向量,使得 ORB 演算法具有旋轉不變性,意味著它可以在朝著任何角度旋轉的影象中檢測到相同的關鍵點。和 BRIEF 一樣 rBRIEF 首先在給定關鍵點周圍的已界定 patch 中隨機選擇 256 個畫素對,以構建 256 位向量。然後根據關鍵點的方向角度旋轉這些隨機畫素對,使隨機點的方向與關鍵點的一致。最後, rBRIEF 對比隨機畫素對的亮度並相應地分配 1 和 0 建立對應的特徵向量,為影象中的所有關鍵點建立的所有特徵向量集合稱之為 ORB 描述符。

OpenCV中的ORB演算法

ORB演算法的第一步是定位訓練影象中的所有關鍵點。找到關鍵點後,ORB會建立相應的二進位制特徵向量,並在ORB描述符中將它們組合在一起。

我們將使用OpenCV的ORB類來定位關鍵點並建立它們相應的ORB描述符。使用ORB_create()函式設定ORB演算法的引數。 ORB_create()函式的引數及其預設值如下:

cv2.ORB_create(nfeatures = 500,

scaleFactor = 1.2,

nlevels = 8,

edgeThreshold = 31,

firstLevel = 0,

WTA_K = 2,

scoreType = HARRIS_SCORE,

patchSize = 31,

fastThreshold = 20)

引數:

·nfeatures - int

確定要查詢的最大要素(關鍵點)數。

·scaleFactor - float

金字塔抽取率,必須大於1。ORB使用影象金字塔來查詢要素,因此必須提供金字塔中每個圖層與金字塔所具有的級別數之間的比例因子。scaleFactor = 2表示經典金字塔,其中每個下一級別的畫素比前一級低4倍。大比例因子將減少發現的功能數量。

·nlevels - int

金字塔等級的數量。最小級別的線性大小等於input_image_linear_size / pow(scaleFactor,nlevels)。

·edgeThreshold - - int

未檢測到要素的邊框大小。由於關鍵點具有特定的畫素大小,因此必須從搜尋中排除影象的邊緣。 edgeThreshold的大小應該等於或大於patchSize引數。

·firstLevel - int

此引數允許您確定應將哪個級別視為金字塔中的第一級別。它在當前實現中應為0。通常,具有統一標度的金字塔等級被認為是第一級。

·WTA_K - int

用於生成定向的BRIEF描述符的每個元素的隨機畫素的數量。可能的值為2,3和4,其中2為預設值。例如,值3意味著一次選擇三個隨機畫素來比較它們的亮度。返回最亮畫素的索引。由於有3個畫素,因此返回的索引將為0,1或2。

·scoreType - int

此引數可以設定為HARRIS_SCORE或FAST_SCORE。預設的HARRIS_SCORE表示Harris角演算法用於對要素進行排名。該分數僅用於保留最佳功能。 FAST_SCORE生成的關鍵點稍差,但計算起來要快一些。

·patchSize - int

面向簡要描述符使用的補丁的大小。當然,在較小的金字塔層上,由特徵覆蓋的感知影象區域將更大。

我們可以看到,cv2.ORB_create()函式支援多種引數。前兩個引數(nfeatures和scaleFactor)可能是最有可能改變的引數。其他引數可以安全地保留其預設值,將獲得良好的結果。

我們仍然使用這張圖片:

來看程式碼:

def ORB(img):
     # Initiate ORB detector
     orb = cv2.ORB_create()
 
     # find the keypoints with ORB
     kp = orb.detect(img, None)
 
     # compute the descriptors with ORB
     kp, des = orb.compute(img, kp)
 
     # draw only keypoints location,not size and orientation
     img2 = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)
     plt.imshow(img2), plt.show()

結果:

我們會在之後講述使用各大演算法如何對兩幅影象進行特徵匹配。

天道酬勤 循序漸進 技壓群雄