OpenCV SIFT原理與原始碼分析 關鍵點描述

2021-06-18 10:08:11 字數 3319 閱讀 3875

由前一篇《

方向賦值》,為找到的關鍵點即sift特徵點賦了值,包含位置、尺度和方向的資訊。接下來的步驟是關鍵點描述,即用用一組向量將這個關鍵點描述出來,這個描述子不但包括關鍵點,也包括關鍵點周圍對其有貢獻的畫素點。用來作為目標匹配的依據(所以描述子應該有較高的獨特性,以保證匹配率),也可使關鍵點具有更多的不變特性,如光照變化、3d視點變化等。

sift描述子h(x,y,θ)是對關鍵點附近鄰域內高斯影象梯度統計的結果,是乙個三維矩陣,但通常用乙個向量來表示。向量通過對三維矩陣按一定規律排列得到。

特徵描述子與關鍵點所在尺度有關,因此對梯度的求取應在特徵點對應的高斯影象上進行。將關鍵點附近劃分成d×d個子區域,每個子區域尺寸為mσ個像元(d=4,m=3,σ為尺特徵點的尺度值)。考慮到實際計算時需要雙線性插值,故計算的影象區域為mσ(d+1),再考慮旋轉,則實際計算的影象區域為

//計算余弦,正弦,cv_pi/180:將角度值轉化為幅度值

float

cos_t = cosf(ori*(

float

)(cv_pi/180));  

float

sin_t = sinf(ori*(

float

)(cv_pi/180));  

float

bins_per_rad = n / 360.f;  

float

exp_scale = -1.f/(d * d * 0.5f); 

//d:sift_descr_width 4    

float

hist_width = sift_descr_scl_fctr * scl;  

// sift_descr_scl_fctr: 3 

// scl: size*0.5f

// 計算影象區域半徑mσ(d+1)/2*sqrt(2)

// 1.4142135623730951f 為根號2

intradius = cvround(hist_width * 1.4142135623730951f * (d + 1) * 0.5f);  

cos_t /= hist_width;  

sin_t /= hist_width;  

為了保證特徵向量具有旋轉不變性,要以特徵點為中心,在附近鄰域內旋轉θ角,即旋轉為特徵點的方向。

旋轉後區域內取樣點新的座標為:

[cpp]view plain

copy

//計算取樣區域點座標旋轉

for( i = -radius, k = 0; i <= radius; i++ )  

for( j = -radius; j <= radius; j++ )  

}  

將旋轉後區域劃分為d×d個子區域(每個區域間隔為mσ像元),在子區域內計算8個方向的梯度直方圖,繪製每個方向梯度方向的累加值,形成乙個種子點。

與求主方向不同的是,此時,每個子區域梯度方向直方圖將0°~360°劃分為8個方向區間,每個區間為45°。即每個種子點有8個方向區間的梯度強度資訊。由於存在d×d,即4×4個子區域,所以最終共有4×4×8=128個資料,形成128維sift特徵向量。

對特徵向量需要加權處理,加權採用mσd/2的標準高斯函式。為了除去光照變化影響,還有一步歸一化處理。

[cpp]view plain

copy

//計算梯度直方圖

for( k = 0; k 

[cpp]view plain

copy

// sift關鍵點特徵描述

// sift描述子是關鍵點領域高斯影象提取統計結果的一種表示

static

void

calcsiftdescriptor( 

const

mat& img, point2f ptf, 

float

ori, 

float

scl,  

intd, 

intn, 

float

* dst )  

//計算取樣區域點座標旋轉

for( i = -radius, k = 0; i <= radius; i++ )  

for( j = -radius; j <= radius; j++ )  

}  len = k;  

fastatan2(y, x, ori, len, true

);  

magnitude(x, y, mag, len);  

exp(w, w, len);  

//計算梯度直方圖

for( k = 0; k 

// finalize histogram, since the orientation histograms are circular

// 最後確定直方圖,目標方向直方圖是圓的

for( i = 0; i 

for( j = 0; j 

// copy histogram to the descriptor,

// and scale the result, so that it can be easily converted

// to byte array

float

nrm2 = 0;  

len = d*d*n;  

for( k = 0; k 

nrm2 += dst[k]*dst[k];  

float

thr = std::sqrt(nrm2)*sift_descr_mag_thr;  

for( i = 0, nrm2 = 0; i 

nrm2 = sift_int_descr_fctr/std::max(std::sqrt(nrm2), flt_epsilon);  

for( k = 0; k 

}  

至此sift描述子生成,sift演算法也基本完成了~參見《

sift原理與原始碼分析》

OpenCV SIFT原理與原始碼分析 關鍵點描述

由前一篇 方向賦值 為找到的關鍵點即sift特徵點賦了值,包含位置 尺度和方向的資訊。接下來的步驟是關鍵點描述,即用用一組向量將這個關鍵點描述出來,這個描述子不但包括關鍵點,也包括關鍵點周圍對其有貢獻的畫素點。用來作為目標匹配的依據 所以描述子應該有較高的獨特性,以保證匹配率 也可使關鍵點具有更多的...

Redis LFU與LRU內部實現原理原始碼分析

1 lru模式有效控制記憶體的大小,將冷資料從記憶體中淘汰出去,在redis裡引入乙個新的淘汰形式lfu 1 lfu全稱是least frequently used 表示按最近的訪問頻率進行淘汰,更加準確的判斷乙個key別訪問的熱度 2 redis物件的熱度 redis中所有物件結構頭中都有乙個24...

AbstractCollection原始碼分析

abstractcollection抽象類提供了collection的骨架實現,collection分析請看 這裡直接看它的 是如何實現的.public abstract iterator iterator 該方法沒有實現.public abstract int size 該方法沒有實現.publi...