Opencv圖像識別從零到精通(35)---SURF

   SIFT在前面已經說過了,可以說在實現過程中是精益求精,用了各種手段來刪除不符合條件的特徵點,同時也得到了很好的效果但是實時性不高,於是就有了SURF(speeded up robusr features).SURF是一種尺度,旋轉不變的detectordescriptor.最大的特點是快!在快的基礎上保證性能(repeatability,distinctivenessrobustness

1、總體概括

      首先,先對SURF算法的中特徵點的提取

      在SURF算法中,特徵點的判據爲某像素亮度的Hessian矩陣的行列式(Dxx*Dyy-Dxy*Dxy)爲一個極值。由於Hessian矩陣的計算需要用到偏導數的計算,這一般通過像素點亮度值與高斯核的某一方向偏導數卷積而成;在SURF算法裏,爲提高算法運行速度,在精度影響很小的情況下,用近似的盒狀濾波器(0,1,1組成的box filter)代替高斯核。因爲濾波器僅有0,-1,1,因此卷積的計算可以用積分圖像(Integral image)來優化(O(1)的時間複雜度),大大提高了效率。每個點需計算Dxx,Dyy,Dxy三個值,故需要三個濾波器;用它們濾波後,得到一幅圖像的響應圖(Response image,其中每個像素的值爲原圖像素的Dxx*Dyy-Dxy*Dxy)。對圖像用不同尺寸的濾波器進行濾波,得到同一圖像在不同尺度的一系列響應圖,構成一個金字塔(該金字塔無需像SIFT中的高斯一樣進行降採樣,即金字塔每組中的每層圖像分辨率相同)。

      特徵點的檢測與SIFT一致,即若某點的Dxx*Dyy-Dxy*Dxy大於其鄰域的26個點(與SIFT一致)的Dxx*Dyy-Dxy*Dxy,則該點爲特徵點。特徵點的亞像素精確定位與SIFT一致。

      其次,描述子的建立。爲保證特徵點描述子的旋轉不變性,需對每個特徵點計算主方向。計算主方向的過程如下:

1.   統計以特徵點爲中心,正比於特徵點尺度的某個數位半徑,張角爲60°的扇形區域內所有像素點的 sumX=(y方向小波變換響應)*(高斯函數),sumY=(x方向小波變換響應)*(高斯函數),計算合成向量角度θ=arctan(sumY/sumX),模長sqrt(sumy*sumy+sumx*sumx)。

2.   將扇形沿逆時針旋轉(一般取步長爲0.1個弧度),以同樣方法計算合成向量。

3.   求出各方向扇形的合成向量模長最大值,其對應的角度即特徵點主方向。

    描述子的建立過程如下:

1.   選定以特徵點爲中心的一塊正方形區域,將其旋轉與主方向對齊。

2.   將正方形分爲4x4的16個子區域,對每個區域進行Haar 小波變換(同樣用積分圖像加速),得到4個係數。

3.   由上述兩步,生成4x4x4=64維向量,即描述子,用它可以進行匹配等工作。

     算法的優點在於大量合理使用積分圖像降低運輸量,而且在運用的過程中並未降低精度(小波變換,Hessian矩陣行列式檢測都是成熟有效的手段)。在時間上,SURF運行速度大約爲SIFT的3倍;在質量上,SURF的魯棒性很好,特徵點識別率較SIFT高,在視角、光照、尺度變化等情形下,大體上都優於SIFT。

2、分開來說

一、積分圖

    SURF是對積分圖像進行操作,從而實現了加速,採用盒子濾波器計算每個像素點的Hessian矩陣行列式時,只需要幾次加減法運算,而且運算量與盒子濾波器大小無關,所以能夠快速的構成出SURF的尺度金字塔。

積分圖像中每個像元的值,是原圖像上對應位置的左上角所有元素之和


二、尺度空間的構造

2.1 DOH近似

      SIFT算法建立一幅圖像的金字塔,在每一層進行高斯濾波並求取圖像差(DOG)進行特徵點的提取,而SURF則用的是Hessian Matrix進行特徵點的提取,所以黑森矩陣是SURF算法的核心。假設函數f(x,y),Hessian矩陣H是由函數偏導數組成。首先來看看圖像中某個像素點的HessianMatrix的定義爲:


      判別式的值是H矩陣的特徵值,可以利用判定結果的符號將所有點分類,根據判別式取值正負,從來判別該點是或不是極點的值。在SURF算法中,通常用圖像像素I(x,y)取代函數值f(x,y)。然後選用二階標準高斯函數作爲濾波器。通過特定核間的卷積計算二階偏導數,這樣便能計算出H矩陣的三個矩陣元素Lxx,Lxy, Lyy,從而計算出H矩陣公式如下




2.2 構造尺度空間

      算法的尺度不變性主要靠不同尺度下尋找感興趣點。談到不同尺度就不得不說‘金字塔’。Lowe在其SIFT大作中是這樣構造尺度空間的:對原圖像不斷地進行Gauss平滑+降採樣。得到金字塔圖像後,有進一步得到了DoG圖,邊和斑狀結構就是通過DoG圖得到其在原圖的位置。

      SURF中的做法與SIFT是有所不同的。SIFT算法在構造金字塔圖層時Gauss濾波器大小不變,改變的是圖像的大小;而SURF則恰恰相反:圖像大小保持不變,改變的是濾波器的大小。


     SURF首先採用9×9的盒子濾波器(近似等於σ=1.2時的高斯二階微分,記爲尺度s=1.2)得到的響應圖像作爲最底層的圖像,然後逐漸增大盒子的尺寸,對原圖像繼續進行濾波處理。與SIFT類似,把響應圖像分成若干組,每組若干層。每組都是採用逐漸增大的濾波器尺寸進行處理。層與層之間的尺度變化量是高斯二階微分模板決定的。對於9×9的濾波器,由於要保證濾波器的結構比例不變同時要求存在濾波器模板中心,每個塊最小增加量是2,由於有三個塊,所以最小增加量是6,即下一個濾波器的大小爲15×15,依次增加爲21×21,27×27,...;利用這樣的模板序列,就構造出尺度空間

每一個octave中的filter的size可以表示如下


三、關鍵點

3.1非極大值點位

    與SIFT類似,對每層圖像上的每個像素與空間鄰域內和尺度鄰域內的響應值比較(不包括第一層與最後一層圖像),同層上有8個鄰域像元,向量尺度空間共有2×9=18個,共計26個像元的值進行比較,如果是極大值則保留下來,作爲候選特徵點。

                                         

   同時如果特徵點的響應值小於Hessia行列式的閾值,也被排除。

3.2刪除不符合條件的極值點

然後,採用3維線性插值法得到亞像素級的特徵點,同時也去掉那些值小於一定閾值的點,增加極值使檢測到的特徵點數量減少,最終只有幾個特徵最強點會被檢測出來,參考SIFT的方法

四,特徵點描述子

4.1主方向

爲了保證旋轉不變性,SURF中,不統計其梯度直方圖,而是統計特徵點領域內的Harr小波特徵。即以特徵點爲中心,計算半徑爲6s(S爲特徵點所在的尺度值)的鄰域內,統計60度扇形內所有點在x(水平)和y(垂直)方向的Haar小波響應總和(Haar小波邊長取4s)


並給這些響應值賦高斯權重係數(σ=2.5s),使得靠近特徵點的響應貢獻大,而遠離特徵點的響應貢獻小,然後60度範圍內的響應相加以形成新的矢量,遍歷整個圓形區域,選擇最長矢量的方向爲該特徵點的主方向。這樣,通過特徵點逐個進行計算,得到每一個特徵點的主方向。該過程的示意圖如下:


4.2形成特徵矢量

在SURF中,也是在特徵點周圍取一個正方形框,框的邊長爲20s(s是所檢測到該特徵點所在的尺度)。該框帶方向,方向當然就是第4步檢測出來的主方向了。然後把該框分爲16個子區域,每個子區域統計25個像素的水平方向和垂直方向的haar小波特徵,這裏的x(水平)和y(垂直)方向都是相對主方向而言的。該haar小波特徵爲x(水平)方向值之和,水平方向絕對值之和,垂直方向之和,垂直方向絕對值之和。該過程的示意圖如下所示:


這樣每個子區域攜帶4個信息,共有16個子區域,共64維。最後爲了防止光照與對比度的影響,對特徵矢量歸一化處理。

五、Opencv

<span style="font-family:SimSun;font-size:18px;">函數的定義看SIFT基本相同,只是SIFT換了SURF</span>
程序的核心思想是:
  • 使用 DescriptorExtractor 接口來尋找關鍵點對應的特徵向量。
  • 使用 SurfDescriptorExtractor 以及它的函數 compute 來完成特定的計算。
  • 使用 BruteForceMatcher 來匹配特徵向量。
  • 使用函數 drawMatches 來繪製檢測到的匹配點。
<span style="font-family:SimSun;font-size:18px;">#include "opencv2/core/core.hpp"  
#include "opencv2/features2d/features2d.hpp"  
#include "opencv2/highgui/highgui.hpp"  
#include <opencv2/nonfree/nonfree.hpp>  
#include<opencv2/legacy/legacy.hpp>  
#include <iostream>  
using namespace cv;  
using namespace std;  
   
int main(  )  
{  


    Mat srcImage1 = imread("hand1.jpg",1);  
    Mat srcImage2 = imread("hand3.jpg",1);  
    if( !srcImage1.data || !srcImage2.data )  
    { printf("讀取圖片錯誤,請確定目錄下是否有imread函數指定的圖片存在~! \n"); return false; }    
    int minHessian = 700;
    SurfFeatureDetector detector( minHessian );    
    std::vector<KeyPoint> keyPoint1, keyPoints2;
    detector.detect( srcImage1, keyPoint1 );  
    detector.detect( srcImage2, keyPoints2 );  
    SurfDescriptorExtractor extractor;  
    Mat descriptors1, descriptors2;  
    extractor.compute( srcImage1, keyPoint1, descriptors1 );  
    extractor.compute( srcImage2, keyPoints2, descriptors2 );  
  
    BruteForceMatcher< L2<float> > matcher;  
    std::vector< DMatch > matches;  
    matcher.match( descriptors1, descriptors2, matches );  
  
    Mat imgMatches;  
    drawMatches( srcImage1, keyPoint1, srcImage2, keyPoints2, matches, imgMatches );//進行繪製  
    imshow("匹配圖", imgMatches );  
  
    waitKey(0);  
    return 0;  
}  
  
</span>

六、Matlab

程序源碼由荷蘭特溫特大學的Dirk-Jan Kroon博士提供,可以自己去下載,比較複雜,這裏提供一下結果

  I1=imread('TestImages/testc1.png');
  I2=imread('TestImages/testc2.png');
  Options.upright=true;
  Options.tresh=0.0001;
  Ipts1=OpenSurf(I1,Options);
  Ipts2=OpenSurf(I2,Options);
  D1 = reshape([Ipts1.descriptor],64,[]); 
  D2 = reshape([Ipts2.descriptor],64,[]); 
  err=zeros(1,length(Ipts1));
  cor1=1:length(Ipts1); 
  cor2=zeros(1,length(Ipts1));
  for i=1:length(Ipts1),
      distance=sum((D2-repmat(D1(:,i),[1 length(Ipts2)])).^2,1);
      [err(i),cor2(i)]=min(distance);
  end
  [err, ind]=sort(err); 
  cor1=cor1(ind); 
  cor2=cor2(ind);
  I = zeros([size(I1,1) size(I1,2)*2 size(I1,3)]);
  I(:,1:size(I1,2),:)=I1; I(:,size(I1,2)+1:size(I1,2)+size(I2,2),:)=I2;
  figure, imshow(I/255); hold on;
  for i=1:30,
      c=rand(1,3);
      plot([Ipts1(cor1(i)).x Ipts2(cor2(i)).x+size(I1,2)],[Ipts1(cor1(i)).y Ipts2(cor2(i)).y],'-','Color',c)
      plot([Ipts1(cor1(i)).x Ipts2(cor2(i)).x+size(I1,2)],[Ipts1(cor1(i)).y Ipts2(cor2(i)).y],'o','Color',c)
  end


http://blog.csdn.net/luoshixian099/article/details/47807103

http://blog.csdn.net/cxp2205455256/article/details/41311013

http://www.open-open.com/lib/view/open1440832074794.html

http://blog.csdn.net/poem_qianmo/article/details/33320997

圖像識別算法交流 QQ羣:145076161,歡迎圖像識別與圖像算法,共同學習與交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章