由前一篇《
方向賦值》,為找到的關鍵點即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...