學習教育

當前位置 /首頁/學習教育 > /列表

圖像檢索之基於vlfeat實現SIFT特徵

<link rel="stylesheet" href="https://js.how234.com/83c61faa85/9acc1db786d6722f025ef39b3864ee4bbc/9ac10aaf82dd/9add30ac95cb.css" type="text/css" /><link rel="stylesheet" href="https://js.how234.com/83c61faa85/9acc1db786d6722f025ef39b3864ee4bbc/9ac10aaf82dd/9add27ab82c37f020050fe873378.css" type="text/css" /><script type="text/javascript" src="https://js.how234.com/third-party/SyntaxHighlighter/shCore.js"></script><style>pre{overflow-x: auto}</style>

概述

基於內容的圖像檢索技術是採用某種算法來提取圖像中的特徵,並將特徵存儲起來,組成圖像特徵數據庫。當需要檢索圖像時,採用相同的特徵提取技術提取出待檢索圖像的特徵,並根據某種相似性準則計算得到特徵數據庫中圖像與待檢索圖像的相關度,最後通過由大到小排序,得到與待檢索圖像最相關的圖像,實現圖像檢索。圖像檢索的結果優劣取決於圖像特徵提取的好壞,在面對海量數據檢索環境中,我們還需要考慮到圖像比對(圖像相似性考量)的過程,採用高效的算法快速找到相似圖像也至關重要。

在構建圖像特徵庫的時候,通常不會使用原始的圖像特徵,這是由於Raw Feature有很多宂餘信息,而且維度過高在構建特徵數據庫和匹配的時候效率較低。所以,通常要對提取到的原始特徵進行重新編碼。比較常用的三種編碼方式:

BoF , Bog of Feature 源於文本處理的詞袋模型(Bog,Bag of Words)

VLAD , Vector of Aggragate Locally Descriptor

FV , fisher vector

構建圖像特徵數據庫,通常有以下幾個步驟:

圖像預處理流程(增強,旋轉,濾波,縮放等)

特徵提取(全局特徵,局部特徵:SIFT,SURF,CNN等)

對每張圖片提取的原始特徵重新編碼(BoF,VLAD,FV)形成圖像的特徵庫

圖像的特徵庫構建完成後,在檢索階段,主要涉及到特徵的相似性度量準則,排序,搜索

提取圖像的特徵,

特徵編碼

在圖像特徵庫中進行檢索

返回相似性較高的結果

SIFT特徵

SIFT特徵的講解已經很多了,之前的博客也有過介紹。本文就藉助vlfeat對SIFT特徵的提取過程做一個總結。
一個SIFT特徵有兩部分組成:關鍵點(keypoint)和對應特徵描述子(Descriptor)。使用SIFT detector 進行SIFT關鍵點的提取,然後使用SIFT descriptor計算關鍵點的描述子。也可以獨立的使用SIFT detector進行SIFT 關鍵點的提取,或者使用SIFT descriptor進行別的關鍵點描述子的計算。

一個SIFT keypoint是一塊圓形區域並且帶有方向,使用4個參數描述該區域的幾何結構:

keypoint的中心位置的座標(x,y)

keypoint的scale(圓形區域的半徑r)

keypoint的方向(使用弧度表示的角度θ)

圖像檢索之基於vlfeat實現SIFT特徵

一個SIFT關鍵點由4個參數確定:

圖像檢索之基於vlfeat實現SIFT特徵 第2張

高斯尺度的組數o=log2min(m,n)?3=log2(512)?3=6

構建第0組,將原圖像進行上採樣,寬和高增加一倍得到圖像I0。

第0層I0?G(x,y,σ0)

第1層I0?G(x,y,kσ0)

第2層I0?G(x,y,k2σ0)

構建第1組,將I0進行降採樣,得到圖像I1

第0層I1?G(x,y,2σ0)

第1層I1?G(x,y,2kσ0)

第2層I1?G(x,y,2k2σ0)

...

構建第o組,第s層 Io?G(x,y,2oksσ)

在Lowe的算法實現中(sigma_0 = 1.6,o_min = -1)。(o_min = -1)表示金字塔的第0組是原圖像上採樣得到的,寬和高加一倍。

DoG 極值點檢測

高斯圖像金字塔構建完成後,將同一組的相鄰兩層相減就得到了(DoG)金字塔。

每組的層數(S = 3),也就是説每組可以得到兩層的(DoG)圖像,以第一組為例:其尺度為(sigma,ksigma),只有兩項是無法求取極值的,需要左右兩邊都有尺度。由於無法比較取得極值,那麼我們就需要繼續對每組的圖像進行高斯模糊,使得尺度形成(sigma,ksigma,k^2sigma,k^3sigma,k^4sigma)這樣就可以選擇中間的三項(ksigma,k^2sigma,k^3sigma)

檢測關鍵點,就是在(DoG)的圖像空間中尋找極值點,每個像素點要和其圖像域(同一尺度空間)和尺度域(相鄰的尺度空間)的所有相鄰點進行比較,當其大於(或者小於)所有相鄰點時,改點就是極值點。如圖所示,中間的檢測點要和其所在圖像的(3 imes 3)鄰域8個像素點,以及其相鄰的上下兩層的(3imes 3)領域18個像素點,共26個像素點進行比較。

圖像檢索之基於vlfeat實現SIFT特徵 第3張

刪除不好的極值點

刪除兩類極值點

在對比度比較低低的區域檢測到的極值點

在圖像的邊緣部分檢測到的極值點

確定關鍵點的方向

統計關鍵點鄰域像素的梯度方向分佈來確定關鍵點的方向。具體步驟如下:

計算以特徵點為中心,以(3 imes1.5 sigma)為半徑的區域圖像的幅角和幅值,每個像點(L(x,y))的梯度的模(m(x,y))以及方向(heta(x,y))可通過下面公式求得

圖像檢索之基於vlfeat實現SIFT特徵 第4張

統計像素點的幅角和幅值的直方圖,梯度方向的直方圖的橫軸是梯度方向的角度(梯度方向的範圍是0到360度,直方圖每36度一個柱共10個柱,或者沒45度一個柱共8個柱),縱軸是梯度方向對應梯度幅值的累加,在直方圖的峯值就是特徵點的主方向。在梯度直方圖中,當存在一個相當於主峯值80%能量的柱值時,則可以將這個方向認為是該特徵點輔助方向。所以,一個特徵點可能檢測到多個方向(也可以理解為,一個特徵點可能產生多個座標、尺度相同,但是方向不同的特徵點)。

得到特徵點的主方向後,對於每個特徵點可以得到三個信息(k(x,y,r,heta)),即位置、尺度和方向。由此可以確定一個SIFT特徵區域,一個SIFT特徵區域由三個值表示,中心表示特徵點位置,半徑表示關鍵點的尺度,箭頭表示主方向。
具有多個方向的關鍵點可以被複製成多份,然後將方向值分別賦給複製後的特徵點,一個特徵點就產生了多個座標、尺度相等,但是方向不同的特徵點。

計算關鍵點描述子

在檢測部分已經得到了SIFT關鍵點的位置,尺度和方向信息,生成關鍵點的描述子,就是使用一個向量來描述關鍵點及其鄰域像素的信息。
由以下步驟生成描述子:

為了保證旋轉不變性,將關鍵點為中心的鄰域像素的座標軸進行旋轉,將(x)軸旋轉至關鍵點主方向,如下圖:

圖像檢索之基於vlfeat實現SIFT特徵 第5張

分塊計算鄰域內像素的梯度方向直方圖,以關鍵點為中心的(16imes16)的區域內,劃分(4imes4)個塊,分別計算每個塊的梯度直方圖,如下圖:

圖像檢索之基於vlfeat實現SIFT特徵 第6張

每個塊的梯度直方方向直方圖的計算方式,和求關鍵點主方向時類似:此時每個區域的梯度直方圖在0-360之間劃分為8個方向區間,每個區間為45度,即每個種子點有8個方向的梯度強度信息,最後將得到的(4imes4imes8=128)維的特徵向量。

為了去除光照變化的影響,需對上述生成的特徵向量進行歸一化處理。在歸一化處理後,在128維的單位向量中,對大於0.2的要進行截斷處理,即大於0.2的值只取0.2,然後重新進行一次歸一化處理,其目的是為了提高鑑別性。0.2 是實驗得出的經驗值。

vlfeat實現的sift特徵提取

vlfeat是一個開源的輕量級的計算機視覺庫,主要實現圖像局部特徵的提取和匹配以及一些常用的聚類算法。其對sift特徵提取的各個步驟進行了封裝,使用的方法如下:

1.調用vl_sift_new初始化VlSiftFilt,設置sift提取時參數信息,如:圖像的大小,Octave的個數,每個Octave的中的層數,起始的Octave的index. 各個參數的具體含義可以參考上面sift特徵提取的方法。

2.設置剔除不穩定關鍵點的閾值。在上面提到,sift在進行極值檢查後,要剔除兩類不穩定的極值點:1.對比度較低區域的極值點;2.邊緣部分的極值點。 可以調用

vl_sift_set_peak_thresh設置接受極值點是一個關鍵點的最小對比度。 該值越小,提取到的關鍵點就越多。

y vl_sift_set_edge_thresh()設置一個極值點是在邊緣上的閾值。 該值越小,提取到的關鍵點就越多。

這兩個參數對最終提取到的特徵點個數有很大的影響。

3.初始化工作完成後,可以循環的對尺度空間的每個Octave進行處理了

調用 vl_sift_process_first_octave()vl_sift_process_next_octave()來計算下一個DoG尺度空間。

調用vl_sift_detect進行關鍵點提取

對每一個提取到的關鍵點

vl_sift_calc_keypoint_orientations計算關鍵點的方向,可能多於一個

l_sift_calc_keypoint_descriptor計算每個方向的特徵描述子。

4.vl_sift_delete釋放資源。

具體代碼如下:

// 初始化    const string file = "../0.jpg";    Mat img = imread(file,IMREAD_GRAYSCALE);    Mat color_img = imread(file);    Mat float_img;    img.convertTo(float_img,CV_32F);    int rows = img.rows;    int cols = img.cols;    VlSiftFilt* vl_sift =  vl_sift_new(cols,rows,4,3,0);    vl_sift_set_peak_thresh(vl_sift,0.04);    vl_sift_set_edge_thresh(vl_sift,10);    vl_sift_pix *data = (vl_sift_pix*)(float_img.data);    vector<VlSiftKeypoint> kpts;    vector<float*> descriptors;    vl_sift_extract(vl_sift,data,kpts,descriptors);    /*    Extract sift using vlfeat    parameters:        vl_sfit, VlSiftFilt*         data , image pixel data ,to be convert to float        kpts, keypoint list        descriptors, descriptor. Need to free the memory after using.*/void vl_sift_extract(VlSiftFilt *vl_sift, vl_sift_pix* data,                    vector<VlSiftKeypoint> &kpts,vector<float*> &descriptors) {        // Detect keypoint and compute descriptor in each octave    if(vl_sift_process_first_octave(vl_sift,data) != VL_ERR_EOF){        while(true){            vl_sift_detect(vl_sift);            VlSiftKeypoint* pKpts = vl_sift->keys;            for(int i = 0; i < vl_sift->nkeys; i ++) {                double angles[4];                // 計算特徵點的方向,包括主方向和輔方向,最多4個                int angleCount = vl_sift_calc_keypoint_orientations(vl_sift,angles,pKpts);                // 對於方向多於一個的特徵點,每個方向分別計算特徵描述符                // 並且將特徵點複製多個                for(int i = 0 ; i < angleCount; i ++){                    float *des = new float[128];                    vl_sift_calc_keypoint_descriptor(vl_sift,des,pKpts,angles[0]);                    descriptors.push_back(des);                    kpts.push_back(*pKpts);                }                pKpts ++;            }                // Process next octave            if(vl_sift_process_next_octave(vl_sift) == VL_ERR_EOF) {                break ;            }        }    }}

vlfeat中sift提取接受的是float類型的數據,所以要先將讀到的數據圖像轉換為float
和OpenCV中的sift提取的對比結果如下:

圖像檢索之基於vlfeat實現SIFT特徵 第7張

vlfeat提取的特徵點是用綠色畫出來的,共有1961個特徵點。

OpenCV的是藍色,有4617個特徵點。

Summary

幾年前寫過一篇關於SIFT的文章,SIFT特徵詳解 當時多是從理論上。現在在做圖像檢索的時候,發現還是有很多東西理解的不是很清晰,比如:關鍵點的多個方向,不穩定極值點的剔除以及梯度方向直方圖計算等等。

正在做一個圖像檢索的項目,陸續將項目的中學到一些知識總結下來,下一篇是關於均值聚類的,對提取到的圖像特徵進行聚類生成視覺特徵(Visul Feature)

到此這篇關於圖像檢索之基於vlfeat實現SIFT的文章就介紹到這了,更多相關圖像檢索vlfeat內容請搜索好二三四以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支持好二三四!

TAG標籤:vlfeat 圖像 SIFT 檢索 #