1. 程式人生 > >影象特徵描述子之BRIEF

影象特徵描述子之BRIEF

  BRIEF(Binary Robust Independent Elementary Features)是一種對已檢測到的特徵點進行表示和描述的特徵描述方法,和傳統的利用影象區域性鄰域的灰度直方圖或梯度直方圖提取特徵的方式不同,BRIEF是一種二進位制編碼的特徵描述子,既降低了儲存空間的需求,提升了特徵描述子生成的速度,也減少了特徵匹配時所需的時間。

原理概述

  經典的影象特徵描述子SIFT和SURF採用128維(SIFT)或者64維(SURF)特徵向量,每維資料一般佔用4個位元組(Byte),一個特徵點的特徵描述向量需要佔用512或者256個位元組。如果一幅影象中包含有大量的特徵點,那麼特徵描述子將佔用大量的儲存,而且生成描述子的過程也會相當耗時。在SIFT特徵的實際應用中,可以採用PCA、LDA等特徵降維的方法來減少特徵描述子的維度,例如PCA-SIFT;此外還可以採用一些區域性敏感雜湊(Locality-Sensitive Hashing, LSH)的方法將特徵描述子編碼為二進位制串,然後使用漢明距離(Hamming Distance)進行特徵點的匹配,漢明距離計算的是兩個二進位制位元串中同一位置不同值的個數,可通過異或操作快速實現,大大提升了特徵匹配的效率。

  BRIEF正是這樣一種基於二進位制編碼生成特徵描述子,以及利用漢明距離進行特徵匹配的演算法。由於BRIEF只是一種特徵描述子,因此事先得檢測並定位特徵點,可採用Harris、FAST或者是SIFT演算法檢測特徵點,在此基礎上利用BRIEF演算法建立特徵描述符,在特徵點鄰域Patch內隨機選取若干點對(p,q),並比較這些點對的灰度值,若I(p)>I(q),則編碼為1,否則編碼為0。這樣便可得到一個特定長度的二進位制編碼串,即BRIEF特徵描述子。

演算法步驟

  • 利用Harris或者FAST等方法檢測特徵點
  • 確定特徵點的鄰域視窗Patch,並對該鄰域內畫素點進行σ=2、視窗尺寸為9的高斯平滑,以濾除噪聲(也可直接對整幅影象做高斯平滑)
  • 在鄰域視窗內隨機選取n對(n可取128、256等)畫素點,並根據灰度值大小編碼成二進位制串,生成n位(bit)的特徵描述子

取樣方式

  論文原作者Calonder提供了5種在S×S的鄰域Patch內隨機選取點對(X,Y)的方法,如下圖所示,一條線段的兩個端點表示一個隨機點對(xi,yi)
- XY為均勻分佈[S/2,S/2]
- XY均為高斯分佈[0,S2/25],取樣準則服從各向同性的同一高斯分佈
- X服從高斯分佈[0,S2/25]Y服從高斯分佈(xi,S2/100),即取樣分為兩步,首先在原點處為xi進行高斯取樣,然後在中心為xi處為yi進行高斯取樣
- XY在空間量化極座標下的離散位置處進行隨機取樣
- X

固定為(0,0)Y在空間量化極座標下的離散位置處進行隨機從取樣。


sample.jpg

演算法特點

  BRIEF演算法通過檢測隨機響應,並採用二進位制編碼方式建立特徵描述子,減少了特徵的儲存空間需求,並提升了特徵生成的速度;Hamming距離的度量方式便於進行特徵點的快速匹配,而且大量實驗資料表明,不匹配特徵點的Hamming距離為128左右(特徵維數為256),而匹配點的Hamming距離則遠小於128。
  BRIEF演算法的缺點是不具備尺度不變性和旋轉不變性,在影象的旋轉角度超過30時,特徵點匹配的準確率快速下降。

Experiment & Result

OpenCV實現BRIEF特徵檢測與匹配

#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 
#include <opencv2/features2d/features2d.hpp>

using namespace cv;

int main(int argc, char** argv) 
{ 
    Mat img_1 = imread("box.png"); 
    Mat img_2 = imread("box_in_scene.png");

    // -- Step 1: Detect the keypoints using STAR Detector 
    std::vector<KeyPoint> keypoints_1,keypoints_2; 
    StarDetector detector; 
    detector.detect(img_1, keypoints_1); 
    detector.detect(img_2, keypoints_2);

    // -- Stpe 2: Calculate descriptors (feature vectors) 
    BriefDescriptorExtractor brief; 
    Mat descriptors_1, descriptors_2; 
    brief.compute(img_1, keypoints_1, descriptors_1); 
    brief.compute(img_2, keypoints_2, descriptors_2);

    //-- Step 3: Matching descriptor vectors with a brute force matcher 
    BFMatcher matcher(NORM_HAMMING); 
    std::vector<DMatch> mathces; 
    matcher.match(descriptors_1, descriptors_2, mathces); 
    // -- dwaw matches 
    Mat img_mathes; 
    drawMatches(img_1, keypoints_1, img_2, keypoints_2, mathces, img_mathes); 
    // -- show 
    imshow("Mathces", img_mathes);

    waitKey(0); 
    return 0; 
}

match result.jpg

reference