或許網絡上有各位牛人已經對sift算法進行各種的詳解和說明,我(小菜鳥)在翻閱各種資料和對opencv中的代碼進行反推之後,終於理解該算法。並記錄之,供大家一起交流學習!這個博文主要記錄了我的學習歷程,或許對你有幫助,或許可以啓發你,或許你只是一笑而過!沒關係,至少自己總結過。
這篇文章主要是對sift算法的每一個步驟,每一個參數進行說明,並在最後用matlab實現該算法,從理論到代碼實現或許需要考慮方方面面,但是它並不是那麼的難!
1、算法簡介
開始之前要例行一些東西,對sift的簡單介紹。如果不想看直接跳到第二部分,沒問題!
Sift(Scale-invariant feature transform)尺度不變特徵轉換,CV界中赫赫有名的算法,由David Lowe(圖1的老頭)提出,該算法受專利保護,專利權屬於英屬哥倫比亞大學。
圖1 David Lowe
Sift算法可以將一幅圖像映射(變換)爲一個局部特徵向量集;特徵向量具有平移、縮放、旋轉不變性,同時對光照變化、仿射及投影變換也有一定的不變性。
SIFT算法的特點有:(只是理論,所以看看就好)
1.SIFT特徵是圖像的局部特徵,其對旋轉、尺度縮放、亮度變化保持不變性,對視角變化、仿射變換、噪聲也保持一定程度的穩定性;
2.獨特性(Distinctiveness)好,信息量豐富,適用於在海量特徵數據庫中進行快速、準確的匹配;
3.多量性,即使少數的幾個物體也可以產生大量的特徵向量;
4.高速性,經優化的匹配算法甚至可以達到實時的要求;
5.可擴展性,可以很方便的與其他形式的特徵向量進行聯合。
SIFT算法可以解決的問題:
目標的自身狀態、場景所處的環境和成像器材的成像特性等因素影響圖像配準目標識別跟蹤的性能。而算法在一定程度上可解決:
1.目標的旋轉、縮放、平移
2.投影變換
3.光照影響
4.目標遮擋
5.雜物場景
SIFT算法的實質是在不同的尺度空間上查找關鍵點,並計算出關鍵點的方向。所查找到的關鍵點是一些十分突出,不會因光照,仿射變換和噪音等因素而變化的點,如角點、邊緣點、暗區的亮點及亮區的暗點等。
SIFT算法可以分解爲如下四步:
1.高斯差分(DoG)濾波:搜索所有尺度上的圖像位置。通過高斯微分函數來識別潛在的對於尺度和旋轉不變的興趣點。
2.尺度空間的極值檢測和關鍵點位置確定:對DoG金字塔中的每一層,進行尺度空間的極值檢測(極大值和極小值),把每一個極值點作爲候選點,在每個候選的位置上,通過一個擬合精細的模型來確定位置和尺度。關鍵點的選擇依據於它們的穩定程度。
3.關鍵點方向確定:基於圖像局部的梯度方向,分配給每個關鍵點位置一個或多個方向。所有後面的對圖像數據的操作都相對於關鍵點的方向、尺度和位置進行變換,從而提供對於這些變換的不變性。
4.構建關鍵點特徵描述符:在每個關鍵點周圍的內,在選定的尺度上測量圖像局部的梯度。這些梯度被變換成一種表示,這種表示允許比較大的局部形狀的變形和光照變化。
2.高斯差分(DoG)濾波:
在這個部分開始之前,首先要普及一下一些相關的知識點。
2.1圖像尺度空間
在圖像信息處理中引入一個名爲尺度的參數,通過對圖像進行一些變換,獲得在多個尺度空間下的圖像空間序列,對這些序列可以進行一些特徵的提取等操作,可以實現邊緣,角點檢測和不同分辨率上的特徵提取。
對這個尺度空間的理解:它可以模擬人在距離目標由近到遠的過程中,目標在視網膜當中形成的圖像的過程。尺度越大圖像越模糊,相當於我們觀察遠處物體,這時候關注該物體的輪廓。如下圖,我們看到遠方只有兩個人的外形,並不能看到衣服上的花紋。
尺度空間滿足視覺不變性。
- 滿足灰度不變性和對比度不變性:當我們用眼睛觀察物體時,當物體所處背景的光照條件變化時,視網膜感知圖像的亮度水平和對比度是不同的,因此要求尺度空間算子對圖像的分析不受圖像的灰度水平和對比度變化的影響。
- 滿足平移不變性、尺度不變性、歐幾里德不變性以及仿射不變性:相對於某一固定座標系,當觀察者和物體之間的相對位置變化時,視網膜所感知的圖像的位置、大小、角度和形狀是不同的,因此要求尺度空間算子對圖像的分析和圖像的位置、大小、角度以及仿射變換無關。
一個圖像的尺度空間表示在該尺度下,該座標處的值。
2.2二維高斯函數和高斯模糊
下面這些只是一些基礎性的知識,公式並不需要推導,接受就好。
高斯濾波器,使用正態分佈計算的一種卷積模板(基本概念,這不懂的話,需要自己入門),利用高斯濾波器和圖像進行卷積運算,可對圖像進行模糊處理。公式如下(這是一個二維的高斯濾波器):
二維高斯曲面如下:
圖3 高斯二維曲面
其中爲正態分佈的標準差,在高斯模糊中,它越大,圖像越模糊。這裏要定義一個模糊半徑,
表示模板元素到模板中心的距離。
當然上面只是一個連續的曲面,在對圖像進行高斯模糊的過程中需要的是高斯模板,這個模板和圖像卷積便可得到高斯模糊圖像。正態分佈中,在大於3*的範圍之外存在的概率佔僅0.3%,所以在3*的範圍之外,那些像素所起作用基本可以忽略不計了,所以高斯模板只需要計算的大小即可。根據的值計算可以計算出高斯模板。
最後提幾條高斯模糊的特性(後面的理解中會被用到)
- 高斯模糊具有圓對稱性,模板是中心對稱的
- 高斯模糊具有線性可分的性質,這樣在計算卷積的時候就可以利用一行和一列的兩個矩陣和圖像進行卷積,可以大大減小計算量。下面的代碼就是利用這個性質。
- 對同一張圖片進行連續多次高斯模糊與只用一次大的高斯模糊,可以達到一樣的效果。需要滿足的是方和根的關係。如兩次的模糊值分別爲3和4,達到的效果可以只用5就可以。
- 高斯卷積核被證明是尺度變換唯一的變換核,也是唯一的線性核。
下面是高斯模板的生成代碼:
1 function[g,x] = gaussian_filter(sigma,sample) 2 sample = 3.5; 3 if ~exist('sample') 4 sample = 7.0/2.0; 5 end 6 %設置濾波閾值 7 n = 2*round(sample * sigma) + 1; 8 9 x = 1:n; 10 x = x-ceil(n/2); 11 g = exp(-(x.^2)/(2*sigma^2))/(sigma*sqrt(2*pi)); 12 end
這裏產生的是一行的高斯模板,即運用了對模板進行線性分解的這個性質。當時,該模板爲
6.60729028444640e-06 | 0.000426170838253310 | 0.00170911194387669 | 0.000426170838253310 | 6.60729028444640e-06 |
0.000426170838253310 | 0.0274880587288661 | 0.110237879438303 | 0.0274880587288661 | 0.000426170838253310 |
0.00170911194387669 | 0.110237879438303 | 0.442097064144154 | 0.110237879438303 | 0.00170911194387669 |
0.000426170838253310 | 0.0274880587288661 | 0.110237879438303 | 0.0274880587288661 | 0.000426170838253310 |
6.60729028444640e-06 | 0.000426170838253310 | 0.00170911194387669 | 0.000426170838253310 | 0 |
當時,該高斯模糊的效果如圖4
圖4高斯模糊效果
2.3高斯金字塔
先說高斯金字塔要得到啥吧:
高斯金字塔主要是爲了得到不同尺度的圖片,這些圖片的尺度必須是連續的,所以要對圖片進行高斯濾波。高斯金字塔是一個原始圖像,產生幾組(octave)每一組中又包含着幾層(interval)。如圖5:
圖5高斯金字塔示意
當然在構建高斯金字塔之前還需要確定的是我們需要構建該金字塔的階數(o)和每一組的層數(s)。
高斯金字塔的構建主要就是分成兩步走
- 對圖像進行不同尺度的高斯模糊(操作上面已經介紹過了)。
關鍵:模糊尺度的確定
- 對高斯金字塔進行降採樣
關鍵:降採樣的母本圖片的確定
在高斯金字塔的構建中,圖像每一組的大小與相應階數的對應關係爲:(原始圖像以512*512爲例)
階數 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
大小 | 512 | 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 |
2.4高斯差分金字塔(這一部分是結論性的知識)
2002年Mikolajczyk在詳細的實驗比較中發現尺度歸一化的高斯拉普拉斯函數的極大值和極小值同其它的特徵提取函數(如:梯度,Hessian或Harris角特徵)比較,能夠產生最穩定的圖像特徵。
而Lindeberg早在1994年就發現高斯差分函數(Difference of Gaussian 算子)與尺度歸一化的高斯拉普拉斯函數非常近似。其中和的關係可以從如下公式推導得到:
利用差分近似代替微分,則有:
其中k-1是個常數,並不影響極值點位置的求取。而高斯拉普拉斯和高斯差分的比較如圖6:
圖6高斯拉普拉斯和高斯差分
如圖所示,紅色曲線表示的是高斯差分算子,而藍色曲線表示的是高斯拉普拉斯算子。使用更高效的高斯差分算子代替拉普拉斯算子進行極值檢測,如下:
Ok講到這裏,聰明的讀者就應該知道了,學習前面那麼多的知識,只是爲了對sift特徵點的出場做鋪墊。在實際計算時,使用高斯金字塔每組中相鄰上下兩層圖像相減,得到高斯差分圖像,如圖7所示,進行極值檢測。這樣就能得到sift特徵點的候選人,對,只是候選。
圖7高斯差分金字塔生成
2.5高斯金字塔生成的細節
上述所有的知識已經把sift關鍵點候選人的選舉辦法說清楚了,現在該講一講選舉過程中所應該注意的4個問題,這樣就把這一部分結束。
這兩個問題歸根到底還是高斯金字塔構建的過程中的4個問題。
- 金字塔的階數(o)的確定
- 每一組層數(s)的確定
- 每一層的尺度()的確定
- 下一組的圖片降採樣母本的確定
下面一一解答:
1、金字塔的階數(O)一般爲4,也可以根據圖像大小來選擇,但是要滿足下列關係:
分別表示圖像的行數和列數。
2、每一階的層數(S)一般選擇5或者6,一般選擇6的時候效果最好。在這邊就要根據前面的說明,特徵點的選舉是要在相鄰的兩層差分金字塔上面進行檢測的,所以要得到n個尺度的特徵點,就要在層的差分金字塔上檢測,(自己畫個圖就ok了),然而要產生n+2層的差分金字塔,就要有n+3層的高斯金字塔,這樣相鄰的相減,才能產生n+2層差分。注意:這裏的檢測都是同階裏面不同層的操作。所以S = n + 3。記住這個n,有用!
3、尺度因子的選擇,或許這是本節中最讓人頭疼的一件事情了。然而在看完衆多源碼和例程之後我把自己的見解整理如下:
先要理解幾個概念:
高斯金字塔的模糊尺度:這個尺度是我們產生模板的尺度
攝像頭模糊的尺度:這個尺度是圖像被相機鏡頭模糊後的尺度,一般爲固定值,這裏定義0.5。
圖像的尺度:這個尺度是攝像頭模糊尺度和高斯金字塔尺度的合作用,滿足方和根的關係。Lowe定義圖片的尺度爲1.6。
這裏插入解答第4個問題,即下一階的第一層圖像是根據上一階的倒數第三層圖像進行降採樣得到的。見圖8
圖8降採樣示意圖
好了回來繼續解答第三個問題,
在一階的圖像內,每一層之間的高斯模糊的尺度因子的比值爲 ,
於是同一階的第s層高斯模糊尺度就變成了,這裏面是這一階的第一層圖像的高斯模糊尺度。
根據圖7所示,第n+1階的圖像,它的高斯模糊尺度是,這個圖像的高斯模糊帶到了下一階的第一層圖像中去,於是不同階相同層的高斯模糊尺度是2倍關係。如圖9所示
圖9不同層之間的尺度示意
綜上可以概括出階內及階之間的尺度關係了。
i:表示第i階的圖像
s:表示階內第s層的圖像
在理清楚圖像互相之間的關係之後,我們需要的是第一階,第一層的高斯模糊尺度,這樣就能根據上述關係,搞到所有的告示模糊尺度了。還記得兩個數嗎?0.5和1.6,這時候就派上用場了。
在lowe的論文中,他定義圖片的尺度是1.6,被攝像頭模糊的尺度是0.5,於是可以算得高斯模糊是
但是這個1.52對我們來說並沒有啥意思,lowe爲了獲得更多的特徵點(姑且這麼解釋吧)他先對原始圖像進行擴大一倍。然後呢再對它進行高斯平滑作爲第一階第一層,這時候它的高斯模糊尺度爲
於是得到最開始的高斯模糊尺度。這下可以得到所有的高斯模糊尺度了。
到此爲止,我們講完所有理論的工作了,然而在實際實現中,同一階第s+1層的圖片是在第s層圖片的基礎上進行高斯模糊得到的,還記得那個方和根的關係吧。故,第s+1層圖片由第s層圖片用一個尺度的模板進行高斯卷積得到。
最後產生高斯金字塔,相鄰層相減,便得到高斯差分金字塔。附上這一部分的生成代碼:
1 im = imread('gray_testImage1.jpg'); 2 im = im2double(im); 3 % 設定輸入量的默認值 4 if ~exist('octaves') %%最大的階數 5 octaves = 4; 6 end 7 if ~exist('intervals')%%每一階最大的層數 8 intervals = 2; 9 end 10 if ~exist('object_mask')%%計算模板大小 11 object_mask = ones(size(im)); 12 end 13 if size(object_mask) ~= size(im) 14 object_mask = ones(size(im)); 15 end 16 if ~exist('contrast_threshold') 17 contrast_threshold = 0.02;%%設置去除低對比度特徵點閾值大小 18 end 19 if ~exist('curvature_threshold') 20 curvature_threshold = 10.0;%%設置去除邊緣特徵點閾值大小 21 end 22 if ~exist('interactive')%%設置迭代次數 23 interactive = 1; 24 end 25 interactive = 2; 26 27 % 檢驗輸入灰度圖像的像素灰度值是否已歸一化到[0,1] 28 if( (min(im(:)) < 0) | (max(im(:)) > 1) ) 29 fprintf( 2, 'Warning: image not normalized to [0,1].\n' ); 30 31 end 32 33 34 % 將輸入圖像經過高斯平滑處理,採用雙線性差值將其擴大一倍. 35 if interactive >= 1 36 fprintf( 2, 'Doubling image size for first octave...\n' ); 37 end 38 39 40 41 tic; 42 antialias_sigma = 0.5; %%高斯平滑參數 43 if antialias_sigma == 0 %%不進行平滑操作 44 signal = im; 45 else 46 g = gaussian_filter( antialias_sigma ); %%%產生高斯模板 47 if exist('corrsep') == 3 48 signal = corrsep( g, g, im ); 49 else 50 signal = conv2( g, g, im, 'same' ); %%高斯卷積 51 end 52 end 53 signal = im; 54 [X Y] = meshgrid( 1:0.5:size(signal,2), 1:0.5:size(signal,1) ); 55 signal = interp2( signal, X, Y, 'linear' ); %%雙線性插值擴展圖片 56 subsample = [0.5]; % 降採樣率; 57 58 %下一步是生成高斯和差分高斯(DOG)金字塔,這兩個金字塔的數據分別存儲在名爲gauss_pyr{orient,interval} 59 % 和DOG_pyr{orient,interval}的元胞數字中。高斯金字塔含有s+3層,差分高斯金字塔含有s+2層。 60 61 if interactive >= 1 62 fprintf( 2, 'Prebluring image...\n' ); 63 end 64 65 66 preblur_sigma = sqrt(sqrt(2)^2 - (2*antialias_sigma)^2); 67 if preblur_sigma == 0 68 gauss_pyr{1,1} = signal; %%matlab cell數據類型有待考證 69 else 70 g = gaussian_filter( preblur_sigma ); 71 if exist('corrsep') == 3 72 gauss_pyr{1,1} = corrsep( g, g, signal ); 73 else 74 gauss_pyr{1,1} = conv2( g, g, signal, 'same' ); 75 end 76 end 77 clear signal 78 pre_time = toc; 79 if interactive >= 1 80 fprintf( 2, 'Preprocessing time %.2f seconds.\n', pre_time ); 81 end 82 83 84 initial_sigma = sqrt((2 * antialias_sigma)^2 + preblur_sigma^2);%計算第一層第一階模糊金字塔的sigma值 85 86 %%計算不同階層的siama 87 absolute_sigma = zeros(octaves,intervals + 3); 88 absolute_sigma(1,1) = initial_sigma * subsample(1); 89 90 %%對生成的金字塔的濾波核大小和標準差進行跟蹤 91 filter_size = zeros(octaves, intervals+3); 92 filter_sigma = zeros(octaves, intervals+3); 93 94 tic 95 %%計算差分高斯金字塔 96 for octave = 1:octaves 97 sigma = initial_sigma; 98 g = gaussian_filter(sigma); 99 filter_size(octave,1) = length(g); 100 filter_sigma(octave,1) = sigma; 101 DOG_pyr{octave} = zeros(size(gauss_pyr{octave,1},1),size(gauss_pyr{octave,1},2),intervals+2); 102 103 %%從第二層計算差分金字塔 104 for interval = 2:(intervals + 3) 105 sigma_f = sqrt(2^(2/intervals) - 1) * sigma; 106 g = gaussian_filter(sigma_f); 107 sigma = (2^(1/intervals)) *sigma %%得到下一個sigma 108 absolute_sigma(octave,interval) = sigma * subsample(octave); 109 %存儲濾波器的核大小及標準差 110 filter_size(octave,interval) = length(g); 111 filter_sigma(octave,interval) = sigma; 112 if exist('corrsep')==3 113 gauss_pyr{octave,interval} = corrsep(g,g,gauss_pyr{octave,interval - 1}); 114 else 115 gauss_pyr{octave,interval} = conv2(g,g,gauss_pyr{octave,interval - 1},'same'); 116 end 117 DOG_pyr{octave}(:,:,interval - 1) = gauss_pyr{octave,interval} - gauss_pyr{octave,interval -1}; 118 end 119 if octave < octaves 120 sz = size(gauss_pyr{octave,intervals + 1}); 121 [X,Y]= meshgrid(1:2:sz(2),1:2:sz(1)); 122 gauss_pyr{octave + 1,1} = interp2(gauss_pyr{octave,intervals + 1},X,Y,'*nearest'); 123 abslute_sigma(octave+1,1) = absolute_sigma(octave,intervals+1); 124 subsample = [subsample subsample(end)*2]; 125 end 126 end 127 pyr_time = toc; 128 129 130 % 在交互模式下顯示高斯金字塔 131 if interactive >= 2 132 sz = zeros(1,2); 133 sz(2) = (intervals+3)*size(gauss_pyr{1,1},2); 134 for octave = 1:octaves 135 sz(1) = sz(1) + size(gauss_pyr{octave,1},1); 136 end 137 pic = zeros(sz); 138 y = 1; 139 for octave = 1:octaves 140 x = 1; 141 sz = size(gauss_pyr{octave,1}); 142 for interval = 1:(intervals + 3) 143 pic(y:(y+sz(1)-1),x:(x+sz(2)-1)) = gauss_pyr{octave,interval}; 144 x = x + sz(2); 145 end 146 y = y + sz(1); 147 end 148 fig = figure; 149 clf; 150 imshow(pic); 151 % resizeImageFig( fig, size(pic), 0.25 ); 152 % fprintf( 2, 'The gaussian pyramid (0.25 scale).\nPress any key to continue.\n' ); 153 % pause; 154 % close(fig) 155 end 156 157 158 % 在交互模式下顯示差分高斯金字塔 159 if interactive >= 2 160 sz = zeros(1,2); 161 sz(2) = (intervals+2)*size(DOG_pyr{1}(:,:,1),2); 162 for octave = 1:octaves 163 sz(1) = sz(1) + size(DOG_pyr{octave}(:,:,1),1); 164 end 165 pic = zeros(sz); 166 y = 1; 167 for octave = 1:octaves 168 x = 1; 169 sz = size(DOG_pyr{octave}(:,:,1)); 170 for interval = 1:(intervals + 2) 171 pic(y:(y+sz(1)-1),x:(x+sz(2)-1)) = DOG_pyr{octave}(:,:,interval); 172 x = x + sz(2); 173 end 174 y = y + sz(1); 175 end 176 fig = figure; 177 imshow(pic); 178 % clf; 179 % imagesc(pic);%%%這個函數可以調整圖像顯示 180 % resizeImageFig( fig, size(pic), 0.25 ); 181 % fprintf( 2, 'The DOG pyramid (0.25 scale).\nPress any key to continue.\n' ); 182 % pause; 183 % close(fig) 184 end
高斯金字塔:
Ok,至此,我們完成第一部分的高斯濾波和金字塔構建工作。