SIFT特征匹配與檢索


1.SIFT簡介

  SIFT的英文全稱叫Scale-invariant feature transform,也叫尺度不變特征變換算法,是由David Lowe 先提出的,也是過去十年中最成功的圖像局部描述子之一。SIFT 特征包括興趣點檢測器和描述子。SIFT 描述子具有非常強穩健性,這在很大程度上也是 SIFT 特征能夠成功和流行的主要原因。自從 SIFT 特征的出現,許多其他本質上使用相同描述子的方法也相繼出現。現在,SIFT 描述符經常和許多不同的興趣點檢測器相結合使用(有些情況下是區域檢測器),有時甚至在整幅圖像上密集地使用。SIFT 特征對於尺度、旋轉和亮度都具有不變性,因此,它可以用於三維視角和噪聲的可靠匹配。
 
  SIFT算法的實質是:“不同的尺度空間上查找關鍵點(特征點),並計算出關鍵點的方向” ,SIFT所查找到的關鍵點是一些十分突出,不會因光照,仿射變換和噪音等因素而變化的點,如角點、邊緣點、暗區的亮點及亮區的暗點等。

2.SIFT算法的特點:

1. SIFT特征是圖像的局部特征,其對旋轉、尺度縮放、亮度變化保持不變性,對視角變化、仿射變換、噪聲也保持一定程度的穩定性;

2. 獨特性(Distinctiveness)好,信息量豐富,適用於在海量特征數據庫中進行快速、准確的匹配;

3. 多量性,即使少數的幾個物體也可以產生大量的SIFT特征向量;

4. 高速性,經優化的SIFT匹配算法甚至可以達到實時的要求;

5. 可擴展性,可以很方便的與其他形式的特征向量進行聯合。

3.四步分解SIFT算法

3.1Lowe將SIFT算法分解為如下四步:

① 尺度空間極值檢測:搜索所有尺度上的圖像位置。通過高斯微分函數來識別潛在的對於尺度和旋轉不變的興趣點。

② 關鍵點定位:在每個候選的位置上,通過一個擬合精細的模型來確定位置和尺度。關鍵點的選擇依據於它們的穩定程度。

③ 方向確定:基於圖像局部的梯度方向,分配給每個關鍵點位置一個或多個方向。所有后面的對圖像數據的操作都相對於關鍵點的方向、尺度和位置進行變換,從而提供對於這些變換的不變性。

④ 關鍵點描述:在每個關鍵點周圍的鄰域內,在選定的尺度上測量圖像局部的梯度。這些梯度被變換成一種表示,這種表示允許比較大的局部形狀的變形和光照變化。

3.2尺度空間及作用:

  尺度空間就是在多個尺度下觀察目標,然后加以綜合的分析、理解和應用。尺度空間中各尺度圖像的 模糊程度逐漸變大,能夠模擬人在距離目標由近到遠時目標 在視網膜上的形成過程。 尺度越大圖像越模糊。在未知的場景中,計算機視覺並不能提供物體的尺度大小,其中的一種方法是把物體不同尺度下的圖像都提供給機器,讓機器能夠對物體在不同的尺度下有一個統一的認知。在建立統一認知的過程中,要考慮的就是在圖像在不同的尺度下都存在的特征點。

3.3關鍵點(興趣點)

  SIFT 特征使用高斯差分函數來定位興趣點: D(x,σ)=[Gkσ(x)Gσ(x)]I(x)=[GkσGσ]I=IkσIσ
  其中,Gσ 是上一章中介紹的二維高斯核,Iσ 是使用 Gσ 模糊的灰度圖像,κ 是決定相差尺度的常數。興趣點是在圖像位置和尺度變化下 D(x,σ) 的最大值和最小值點。這些候選位置點通過濾波去除不穩定點。基於一些准則,比如認為低對比度和位於邊上的點不是興趣點,我們可以去除一些候選興趣點。

3.4檢測關鍵點 

  使用開源工具包 VLFeat 提供的二進制文件來計算圖像的 SIFT 特征。VLFeat 庫是用 C 語言來寫的,但是我們可以使用該庫提供的命令行接口。也可以使用 Matlab 接口或者 Python 包裝器來計算圖像的 SIFT 特征,可以從http://github.com/mmmikael/vlfeat/ 下載相應的版本。

 

4.實驗環境

 python+opencv+開源工具包VLFeat0.9.20

5.實驗內容與小結

5.1圖像數據集

  • 本數據集主要以建築物為主體,圖片都來自不同的場景,構成了一個有20張圖片的數據集。

5.2SIFT特征提取

  • 實現對數據集中每張圖片的SIFT特征進行提取,並展示特征點
  •    數據集中1.jpg

       數據集中3.jpg

       數據集中 5.jpg

  •    數據集中6.jpg

  •   數據集中10.jpg

  •  數據集中12.jpg

  • 分析:由上圖可以看出,SIFT可以檢測出較多的特征點。通過兩種算法的比較可以看出,兩種算法所選特征點的位置是不同的,SIFT算法比Harris算法提取圖像的特征點更加准確全面精准,更具有穩健性,效果上比起Harris算法更好。但是SIFT算法的運行速度相對來說慢很多,實時性不高。
  • 代碼展示:
  • # -*- coding: utf-8 -*-
    from PIL import Image
    from pylab import *
    from PCV.localdescriptors import sift
    from PCV.localdescriptors import harris
    
    # 添加中文字體支持
    from matplotlib.font_manager import FontProperties
    font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
    
    imname = 'D:/計算機視覺/SIFT特征匹配圖片庫/12.jpg'
    im = array(Image.open(imname).convert('L'))
    sift.process_image(imname, '12.sift')
    l1, d1 = sift.read_features_from_file('12.sift')
    
    figure()
    gray()
    subplot(131)
    sift.plot_features(im, l1, circle=False)
    title(u'SIFT特征',fontproperties=font)
    subplot(132)
    sift.plot_features(im, l1, circle=True)
    title(u'用圓圈表示SIFT特征尺度',fontproperties=font)
    
    # 檢測harris角點
    harrisim = harris.compute_harris_response(im)
    
    subplot(133)
    filtered_coords = harris.get_harris_points(harrisim, 6, 0.1)
    imshow(im)
    plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*')
    axis('off')
    title(u'Harris角點',fontproperties=font)
    
    show()

5.3SIFT特征匹配

  •  給定兩張圖片,計算其SIFT特征匹配結果
  • 分析:上圖是已經將圖片灰度化,實現過程是在讀取兩張圖片的特征屬性值后,進行雙向匹配,即進行對於第一幅圖像中的每個描述子,選取其在第二幅圖像中的匹配后,再反過來匹配一次。最后將匹配結果用連線的圖片展示出來。當兩幅圖像的SIFT特征向量生成后,用關鍵點特征向量的歐式距離來作為兩幅圖像中關鍵點的相似性判定度量。取圖像1中的某個關鍵點,並找出其與圖像2中歐式距離最近的前兩個關鍵點。由上面匹配結果圖可知,SIFT算法匹配出的特征點更多,這是因為SIFT算法具有尺度和旋轉不變性,具有准確性和穩定性,即使兩張圖大小不一樣、角度不一致也不會影響匹配結果。
  • 代碼展示:

    from PIL import Image
    from pylab import *
    import sys
    from PCV.localdescriptors import sift
    
    
    if len(sys.argv) >= 3:
      im1f, im2f = sys.argv[1], sys.argv[2]
    else:
    #  im1f = '../data/sf_view1.jpg'
    #  im2f = '../data/sf_view2.jpg'
      im1f = 'D:/計算機視覺/SIFT特征匹配圖片庫/19.jpg'
      im2f = 'D:/計算機視覺/SIFT特征匹配圖片庫/20.jpg'
    #  im1f = '../data/climbing_1_small.jpg'
    #  im2f = '../data/climbing_2_small.jpg'
    im1 = array(Image.open(im1f).convert('L'))
    im2 = array(Image.open(im2f).convert('L'))
    
    sift.process_image(im1f, 'out_sift_1.txt')
    l1, d1 = sift.read_features_from_file('out_sift_1.txt')
    figure()
    gray()
    subplot(121)
    sift.plot_features(im1, l1, circle=False)
    
    sift.process_image(im2f, 'out_sift_2.txt')
    l2, d2 = sift.read_features_from_file('out_sift_2.txt')
    subplot(122)
    sift.plot_features(im2, l2, circle=False)
    
    #matches = sift.match(d1, d2)
    matches = sift.match_twosided(d1, d2)
    print ('{} matches'.format(len(matches.nonzero()[0])))
    
    figure()
    gray()
    sift.plot_matches(im1, im2, l1, l2, matches, show_below=True)
    show()

5.4SIFT數據集匹配

  •  給定一張輸入的圖片,在數據集內部進行檢索,輸出與其匹配最多的三張圖片
  • 原圖:
  •  
  • 檢索結果最高匹配前三張圖:
  • 分析:匹配思路是輸入圖片與數據集中圖片兩兩進行特征匹配后的匹配數保存在數組中,找到與輸入圖片匹配特征點最多的圖,最后將矩陣中數值最大的三個位置輸出。通過測試可知SIFT在大量數據庫中速度也非常快。匹配的結果非常精確,SIFT特征對旋轉、尺度縮放、亮度變化等保持不變性,是一種非常穩定的局部特征。SIFT算法在用於圖片匹配檢索,具有一定的優勢,它不會受圖片大小和拍攝角度的影響,具備較好的穩健性,准確性高。
  • 代碼展示:

    from PIL import Image
    from pylab import *
    from PCV.localdescriptors import sift
    import matplotlib.pyplot as plt


    im1f = 'D:/計算機視覺/SIFT特征匹配圖片庫/3.jpg'
    im1 = array(Image.open(im1f))
    sift.process_image(im1f, 'out_sift_1.txt')
    l1, d1 = sift.read_features_from_file('out_sift_1.txt')

    arr=[]
    arrHash = {}
    for i in range(1, 10):
    im2f = (r'D:/PyCharm Community Edition 2018.2.3/siftpictures/'+'B'+str(i)+'.jpg')
    im2 = array(Image.open(im2f))
    sift.process_image(im2f, 'out_sift_2.txt')
    l2, d2 = sift.read_features_from_file('out_sift_2.txt')
    matches = sift.match_twosided(d1, d2)
    length=len(matches.nonzero()[0])
    length=int(length)
    arr.append(length)
    arrHash[length]=im2f

    arr.sort()
    arr=arr[::-1]
    arr=arr[:3]
    i=0
    plt.figure(figsize=(5,12))
    for item in arr:
    if(arrHash.get(item)!=None):
    img=arrHash.get(item)
    im1 = array(Image.open(img))
    ax=plt.subplot(511 + i)
    ax.set_title('{} matches'.format(item))
    plt.axis('off')
    imshow(im1)
    i = i + 1

    plt.show()

5.5匹配地理標記圖像

  • 本小節實驗內容主要是在數據集中找到並匹配這些圖像對之間的特征,然后使用局部描述子來匹配帶有地理標記的圖像。

      5.5.1提取SIFT特征

  • 先對數據集中的圖像使用SIFT特征提取代碼進行提取SIFT特征,並且將特征保存在和圖像同名的文件路徑下,但文件名是.sift,而不是.jpg。

      

  • 成功結果展示:

    

      5.5.2使用局部描述子匹配

  • 對所有的圖像進行逐個匹配,將每對圖像間的匹配特征數保存在matchscores數組中。

   

      5.5.3可視化連接圖像

      

  •      運行結果圖
  •  

     5.5.4實驗分析與小結

  1. 拍攝的圖像最好先壓縮一下,不然要運行很久。
  2. 左邊起第一類歸類成功;第二類歸類錯誤,前三張圖為一類,后兩張圖為一類;第三類歸類錯誤,前兩張圖為一類,后兩張圖為一類;第四類和第五類以及第六類都歸類成功。可見SIFT算法在用於圖片匹配時,雖然它不會受圖片大小和拍攝角度的影響,准確性高。但不夠穩健,仍然存在錯誤的匹配。
  3. 所拍攝的建築物圖像特征點周圍紋理多且復雜,導致分類效果不佳。
  4. 拍攝的建築物圖像特征點周圍紋理相近並且顏色相近也會導致分類錯誤。
  5. 由實驗結果也可以看出SIFT算法雖然能夠較為准確地匹配出相同場景,但仍然存在錯誤的匹配,某些相同場景的圖片無法匹配到。

5.6 RANSAC應用

    5.6.1RANSAC算法簡介

     RANSAC算法是使用盡可能少的初始數據去擬合出一個模型,通過迭代次數,逐漸擴大內點數量,找到一個更好的模型。比如說三個點就足夠定義一個圓,一開始我們可以從數據集中隨機選取三個點,並假設連接它們的構成的圓就是正確的模型。需要注意的是RANSAC算法第一次擬合模型-圓時,用的數據只有n=3個,但是第二次、第三次…..擬合所用的數據會更多n>3。

    5.6.2RANSAC算法講解

      1、容限誤差的確定

           樣本偏差可以通過以下幾個方面確定:噪聲、計算出的模型、測量隱藏誤差。容限誤差=平均偏差+1~2個標准差。

      2、迭代次數k的確定

         E(k)=1/b=wn;  k=[log(1z)/log(1b)] ;其中,k:尋找合適的擬合模型時需要算法的迭代次數; E(k):k的期望值;b:算法迭代中,某一次擬合模型所用的點,所有點(n個點)都是符合容限誤差的概率; ω:從n個點中選出來的一點是符合容限誤差的點的概率( ω 是一個先驗概率,可以實現確定的); a=1-b 表示所有點(n個點)中至少有一個不符合容限誤差的概率; z:算法迭代中,至少有一次擬合模型所用的點都是符合容縣誤差的概率;

      3、閾值t的確定

         閾值t應該足夠大,當內點的數量大於t時,判定擬合出的那個模型合理,否則不合理;(內點就是組成模型參數的數據,相反外點就是不適合模型的數據)。

      4、最小二乘法

         它是一種數學優化技術,原理是通過最小化誤差的平方和尋找數據的最佳模型。使用盡可能多得數據去擬合出一個模型,使得盡可能多的點在模型當中,期望通過“平均”消除偏差,然而在很多實際情況下(數據中帶有重大誤差點),不能夠得到一個好的結果。

    5.6.3RANSAC算法步驟

      1、假設我們要將P個數據點 {x1, x2,… , xn}擬合一個由至少n個點決定的模型(P≥n ,對於圓來說n=2)。

      2、設迭代計數k=1。

      3、從P中隨機選取n個點擬合一個模型,記為M1。

      4、給定容限誤差 ε,計算數據點{x1, x2,… , xn}中相對於模型的殘差在偏差ε內的元素個數,如果內點個數大於閾值t,根據內點集合重新擬合模型(可以利用最小二乘或其變種),算法終止。

       5、設k=k+1,如果k小於預先設定的K,跳至第3步,新的內點集合和模型分別記為S1*和M1*。 否則采用具有當前內點最多的點集的模型,或者算法失敗。

    5.6.4RANSAC算法應用

  • 數據集如下

  

  

     1、針對景深單一的場景(利用SIFT+RANSAC算法進行特征匹配分析,實驗如下:)

  • SIFT特征匹配

  • SIFT+RANSAC特征匹配

  • 全景拼接

     2、針對景深豐富的場景

  • SIFT特征匹配

  • SIFT+RANSAC特征匹配

  • 全景拼接

    3、實驗小結

       通過以上在景深單一和景深豐富兩個不同的場景進行的實驗中,在特征匹配過程中經過RANSAC算法比沒有RANSAC算法匹配得更加准確,對比可以發現RANSAC算法可以去除大部分的錯誤的匹配點,但是仍然存在錯誤匹配點,並且也有刪掉正確匹配點的可能。

另外,通過圖片拼接可以看出圖片拼接得很生硬,分割明顯、照片有所歪斜並且物體也有所變形!

原因分析:

1、建築物相似

2、拍照角度選取不佳

3、圖像光照強度不同

4、沒有得到可信的模型,迭代次數不夠

    4、代碼展示

# -*- coding: utf-8
from pylab import *
from numpy import *
from PIL import Image
from scipy.spatial import Delaunay
# If you have PCV installed, these imports should work
from PCV.geometry import homography, warp
from PCV.localdescriptors import sift


featname = ['D:/計算機視覺/SIFT特征匹配圖片庫/4/' + str(i + 1) + '.sift' for i in range(5)]
imname = ['D:/計算機視覺/SIFT特征匹配圖片庫/4/' + str(i + 1) + '.jpg' for i in range(5)]

# extract features and match
l = {}
d = {}
for i in range(5):
    sift.process_image(imname[i], featname[i])
    l[i], d[i] = sift.read_features_from_file(featname[i])

matches = {}
for i in range(4):
    matches[i] = sift.match(d[i + 1], d[i])

# visualize the matches (Figure 3-11 in the book)

for i in range(4):
    im1 = array(Image.open(imname[i]))
    im2 = array(Image.open(imname[i + 1]))
    figure()
    sift.plot_matches(im2, im1, l[i + 1], l[i], matches[i], show_below=True)


# function to convert the matches to hom. points

def convert_points(j):
    ndx = matches[j].nonzero()[0]
    fp = homography.make_homog(l[j + 1][ndx, :2].T)
    ndx2 = [int(matches[j][i]) for i in ndx]
    tp = homography.make_homog(l[j][ndx2, :2].T)

    # switch x and y - TODO this should move elsewhere
    fp = vstack([fp[1], fp[0], fp[2]])
    tp = vstack([tp[1], tp[0], tp[2]])
    return fp, tp


# estimate the homographies

model = homography.RansacModel()

fp, tp = convert_points(1)
H_12 = homography.H_from_ransac(fp, tp, model)[0]  # im 1 to 2  # im1 到 im2 的單應性矩陣


fp, tp = convert_points(0)
H_01 = homography.H_from_ransac(fp, tp, model)[0]  # im 0 to 1

tp, fp = convert_points(2)  # NB: reverse order
H_32 = homography.H_from_ransac(fp, tp, model)[0]  # im 3 to 2

tp, fp = convert_points(3)  # NB: reverse order
H_43 = homography.H_from_ransac(fp, tp, model)[0]  # im 4 to 3

# warp the images
# 扭曲圖像

delta = 2000  # for padding and translation 用於填充和平移

im1 = array(Image.open(imname[1]), "uint8")
im2 = array(Image.open(imname[2]), "uint8")
im_12 = warp.panorama(H_12, im1, im2, delta, delta)

im1 = array(Image.open(imname[0]), "f")
im_02 = warp.panorama(dot(H_12, H_01), im1, im_12, delta, delta)

im1 = array(Image.open(imname[3]), "f")
im_32 = warp.panorama(H_32, im1, im_02, delta, delta)

im1 = array(Image.open(imname[4]), "f")
im_42 = warp.panorama(dot(H_32, H_43), im1, im_32, delta, 2 * delta)
imsave('jmu2.jpg', array(im_42, "uint8"))
figure()
imshow(array(im_42, "uint8"))
axis('off')
show()

6.實驗中遇到的問題與解決方案

  1. 運行過程中提示print錯誤!!原因是3.5的python的print用法需要加括號,必須修改print語法。根據提示的路徑找到最終文件打開進行改正后就可以運行了。

             

             根據提示的路徑找到最終文件打開進行改正后就可以運行了。

         

       2. SIFT特征進行Harris角點檢測時出現empire.sift not found!! 解決方案是下載開源工具包VLFeat。

       3. 圖片像素過大時,容易發生報錯;可調整圖片的大小或者將圖片的jpg格式改為png格式,這樣程序的運行速度可加快。缺點是會降低匹配值!!

       4.匹配地理標記圖像時出現import pydot的錯誤

           解決方案:4.1 在Anaconda Prompt中先使用安裝pydot:pip install pydot
                             4.2然后再下載Graphviz:graphviz-2.38.msi ,進入官網下載https://graphviz.gitlab.io/_pages/Download/Download_windows.html 下載graphviz的時候,一定要選擇后綴是.msi的文件。

                            4.3下載后一直安裝即可

                            4.4 然后根據安裝的路徑配置環境變量即可

      5.出現"dot" not found in path.的錯誤

        解決方案:修改self.prog = 'dot’為self.prog = ‘dot.exe’ 即可

7.實驗總結

  • SIFT算法與Harris算法相比,提取圖像的特征點更加准確全面精准,更具有穩健性,效果上比起Harris算法更好。但是SIFT算法的運行速度相對來說慢很多。
  • SIFT特征是圖像的局部特征,其對旋轉、尺度縮放、亮度變化保持不變性。對視角變化、仿射變換、噪聲也保持一定程度的穩定性。信息量豐富,適用於在海量特征數據庫中進行快速、准確的匹配。匹配速度快。
  • 圖片像素過大時,容易發生報錯;可調整圖片的大小或者將圖片的jpg格式改為png格式,這樣程序的運行速度可加快,但會降低匹配值。
  • SIFT所查找到的關鍵點是一些十分突出,不會因光照,仿射變換和噪音等因素而變化的點,如角點、邊緣點、暗區的亮點及亮區的暗點等。
  • SIFT算法匹配出的特征點多,即使兩張圖大小不一樣、角度不一致也不會影響匹配結果,具有准確性和穩定性。SIFT在提取方面擁有一定的優勢,但是並不完美。存在實時性不高及對邊緣光滑的目標無法准確提取特征點等缺點。
  • 網絡不好的時候千萬別暴躁,也別太自責,冷靜!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM