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

2021-06-10 13:08:28 字數 3021 閱讀 9422

由前一篇《

方向賦值》,為找到的關鍵點即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

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

cos_t /= hist_width;

sin_t /= hist_width;

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

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

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

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的標準高斯函式。為了除去光照變化影響,還有一步歸一化處理。

//計算梯度直方圖

for( k = 0; k < len; k++ )

// sift關鍵點特徵描述

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

static void calcsiftdescriptor( const mat& img, point2f ptf, float ori, float scl,

int d, int n, 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 < len; k++ )

// finalize histogram, since the orientation histograms are circular

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

for( i = 0; i < d; i++ )

for( j = 0; j < d; 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 < len; k++ )

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

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

for( i = 0, nrm2 = 0; i < k; i++ )

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

for( k = 0; k < len; 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...