SIFT算法實現(xiàn)理解及注釋詳解(基于RobHess源碼)_第1頁
SIFT算法實現(xiàn)理解及注釋詳解(基于RobHess源碼)_第2頁
SIFT算法實現(xiàn)理解及注釋詳解(基于RobHess源碼)_第3頁
SIFT算法實現(xiàn)理解及注釋詳解(基于RobHess源碼)_第4頁
SIFT算法實現(xiàn)理解及注釋詳解(基于RobHess源碼)_第5頁
已閱讀5頁,還剩21頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

RobHess的SIFT算法實現(xiàn)理解及注釋

SIFT算法不用我多解釋了,這是一個很強大的算法,主要用于圖像配準和物體識別等領域,但是其計算量相比也比較大,性價比比較高的算法包括PCA-SIFT和SURF其中OpenCV提供了SURF算法,但是為了方便理解。這里給出了RobHess所實現(xiàn)的SIFT算法的實現(xiàn)以及注釋,結(jié)合我自己的理解,如果,您有關于SIFT算法不理解的地方咱們可以一起交流一下。或者您認為不詳細的地方提出來。

SIFT算法的主要實現(xiàn)在sift.c這個文件,其主要流程為:(1)首先創(chuàng)建初始圖像,即通過將圖像轉(zhuǎn)換為32位的灰度圖,然后將圖像使用三次插值來方大,之后通過高斯模糊處理(2)在此基礎上進行高斯金字塔的構(gòu)建以及高斯差分金字塔的構(gòu)建(3)對圖像進行極值點檢測(4)計算特征向量的尺度(5)調(diào)整圖像大小(6)計算特征的方向(7)計算描述子,其中包括計算二維方向直方圖并轉(zhuǎn)換直方圖為特征描述子首先給出sift算法的整體框架代碼:輸入?yún)?shù):img為輸入圖像;feat為所要提取的特征指針;intvl指的是高斯金字塔和差分金字塔的層數(shù);sigma指的是圖像初始化過程中高斯模糊所使用的參數(shù);

contr_thr是歸一化之后的去除不穩(wěn)定特征的閾值;curv_thr指的是去除邊緣的特征的主曲率閾值;img_dbl是是否將圖像放大為之前的兩倍;descr_with用來計算特征描述子的方向直方圖的寬度;descr_hist_bins是直方圖中的條數(shù)int

_sift_features(

IplImage*

img,

struct

feature**

feat,

int

intvls,

double

sigma,

double

contr_thr,

int

curv_thr,

int

img_dbl,

int

descr_width,

int

descr_hist_bins

)

{

IplImage*

init_img;

IplImage***

gauss_pyr,

***

dog_pyr;

CvMemStorage*

storage;

CvSeq*

features;

int

octvs,

i,

n

=

0;

/*

check

arguments

*/

if(

!

img

)

fatal_error(

"NULL

pointer

error,

%s,

line

%d",

__FILE__,

__LINE__

);

if(

!

feat

)

fatal_error(

"NULL

pointer

error,

%s,

line

%d",

__FILE__,

__LINE__

);

/*

build

scale

space

pyramid;

smallest

dimension

of

top

level

is

~4

pixels

*/

/*

構(gòu)建高斯尺度空間金字塔,頂層最小的為4像素

*/

init_img

=

create_init_img(

img,

img_dbl,

sigma

);

octvs

=

log(

double

MIN(

init_img->width,

init_img->height

)

)

/

log(2.0)

-

2;

//構(gòu)建高斯金字塔和高斯差分金字塔

gauss_pyr

=

build_gauss_pyr(

init_img,

octvs,

intvls,

sigma

);

dog_pyr

=

build_dog_pyr(

gauss_pyr,

octvs,

intvls

);

storage

=

cvCreateMemStorage(

0

);

//尺度空間極值點檢測

features

=

scale_space_extrema(

dog_pyr,

octvs,

intvls,

contr_thr,

curv_thr,

storage

);

//畫出去除低對比度的極值點

//draw_extrempoint(img

,

features);

//計算特征向量的尺度

calc_feature_scales(

features,

sigma,

intvls

);

if(

img_dbl

)

adjust_for_img_dbl(

features

);

//計算特征的方向

calc_feature_oris(

features,

gauss_pyr

);

//計算描述子,包括計算二維方向直方圖和轉(zhuǎn)換其為特征描述子

compute_descriptors(

features,

gauss_pyr,

descr_width,

descr_hist_bins

);

/*

sort

features

by

decreasing

scale

and

move

from

CvSeq

to

array

*/

cvSeqSort(

features,

(CvCmpFunc)feature_cmp,

NULL

);

n

=

features->total;

*feat

=

static_cast<feature

*>(

calloc(

n,

sizeof(struct

feature)

)

);

*feat

=

static_cast<feature

*>(

cvCvtSeqToArray(

features,

*feat,

CV_WHOLE_SEQ

)

);

for(

i

=

0;

i

<

n;

i++

)

{

free(

(*feat)[i].feature_data

);

(*feat)[i].feature_data

=

NULL;

}

cvReleaseMemStorage(

&storage

);

cvReleaseImage(

&init_img

);

release_pyr(

&gauss_pyr,

octvs,

intvls

+

3

);

release_pyr(

&dog_pyr,

octvs,

intvls

+

2

);

return

n;

}

(1)初始化圖像輸入?yún)?shù):這里不需要解釋了該函數(shù)主要用來初始化圖像,轉(zhuǎn)換圖像為32位灰度圖以及進行高斯模糊。static

IplImage*

create_init_img(

IplImage*

img,

int

img_dbl,

double

sigma

)

{

IplImage*

gray,

*

dbl;

float

sig_diff;

gray

=

convert_to_gray32(

img

);

if(

img_dbl

)

{

sig_diff

=

sqrt(

sigma

*

sigma

-

SIFT_INIT_SIGMA

*

SIFT_INIT_SIGMA

*

4

);

dbl

=

cvCreateImage(

cvSize(

img->width*2,

img->height*2

),

IPL_DEPTH_32F,

1

);

cvResize(

gray,

dbl,

CV_INTER_CUBIC

);

cvSmooth(

dbl,

dbl,

CV_GAUSSIAN,

0,

0,

sig_diff,

sig_diff

);

cvReleaseImage(

&gray

);

return

dbl;

}

else

{

sig_diff

=

sqrt(

sigma

*

sigma

-

SIFT_INIT_SIGMA

*

SIFT_INIT_SIGMA

);

cvSmooth(

gray,

gray,

CV_GAUSSIAN,

0,

0,

sig_diff,

sig_diff

);

return

gray;

}

}

(2)構(gòu)建高斯金字塔輸入?yún)?shù):octvs是高斯金字塔的組invls是高斯金字塔的層數(shù)sigma是初始的高斯模糊參數(shù),后續(xù)也通過它計算每一層所使用的sigma<span

style="font-size:13px;">static

IplImage***

build_gauss_pyr(

IplImage*

base,

int

octvs,int

intvls,

double

sigma

)

{

IplImage***

gauss_pyr;

double*

sig

=

static_cast<double

*>(

calloc(

intvls

+

3,

sizeof(double))

);

double

sig_total,

sig_prev,

k;

int

i,

o;

gauss_pyr

=

static_cast<IplImage

***>(

calloc(

octvs,

sizeof(

IplImage**

)

)

);

for(

i

=

0;

i

<

octvs;

i++

)

gauss_pyr[i]

=

static_cast<IplImage

**>(

calloc(

intvls

+

3,

sizeof(

IplImage*

)

)

);

/*

precompute

Gaussian

sigmas

using

the

following

formula:

預計算每次高斯模糊的sigma

\sigma_{total}^2

=

\sigma_{i}^2

+

\sigma_{i-1}^2

*/

sig[0]

=

sigma;

k

=

pow(

2.0,

1.0

/

intvls

);

for(

i

=

1;

i

<

intvls

+

3;

i++

)

{

sig_prev

=

pow(

k,

i

-

1

)

*

sigma;

sig_total

=

sig_prev

*

k;

sig[i]

=

sqrt(

sig_total

*

sig_total

-

sig_prev

*

sig_prev

);

}

for(

o

=

0;

o

<

octvs;

o++

)

for(

i

=

0;

i

<

intvls

+

3;

i++

)

{

//對每一層進行降采樣,形成高斯金字塔的每一層

if(

o

==

0

&&

i

==

0

)

gauss_pyr[o][i]

=

cvCloneImage(base);

/*

base

of

new

octvave

is

halved

image

from

end

of

previous

octave

*/

//每一組的第一層都是通過對前面一組的最上面一層的降采樣實現(xiàn)的

else

if(

i

==

0

)

gauss_pyr[o][i]

=

downsample(

gauss_pyr[o-1][intvls]

);

/*

blur

the

current

octave's

last

image

to

create

the

next

one

*/

//每一組的其他層則使通過使用不同sigma的高斯模糊來進行處理

else

{

gauss_pyr[o][i]

=

cvCreateImage(

cvGetSize(gauss_pyr[o][i-1]),

IPL_DEPTH_32F,

1

);

cvSmooth(

gauss_pyr[o][i-1],

gauss_pyr[o][i],

CV_GAUSSIAN,

0,

0,

sig[i],

sig[i]

);

}

}

free(

sig

);

return

gauss_pyr;

}</span>

降采樣處理輸入?yún)?shù):不解釋這就是降采樣,其實就是將圖像通過最近鄰算法縮小為原來的一半static

IplImage*

downsample(

IplImage*

img

)

{

IplImage*

smaller

=

cvCreateImage(

cvSize(img->width

/

2,

img->height

/

2),

img->depth,

img->nChannels

);

cvResize(

img,

smaller,

CV_INTER_NN

);

return

smaller;

}

(3)構(gòu)建高斯差分金字塔輸入?yún)?shù):不解釋了參見上面的說明即可實際上差分金字塔的構(gòu)成是通過對相鄰層的圖像進行相減獲得的<span

style="font-size:16px;">static

IplImage***

build_dog_pyr(

IplImage***

gauss_pyr,

int

octvs,

int

intvls

)

{

IplImage***

dog_pyr;

int

i,

o;

dog_pyr

=

static_cast<IplImage

***>(

calloc(

octvs,

sizeof(

IplImage**

)

)

);

for(

i

=

0;

i

<

octvs;

i++

)

dog_pyr[i]

=

static_cast<IplImage

**>(

calloc(

intvls

+

2,

sizeof(IplImage*)

)

);

for(

o

=

0;

o

<

octvs;

o++

)

for(

i

=

0;

i

<

intvls

+

2;

i++

)

{

dog_pyr[o][i]

=

cvCreateImage(

cvGetSize(gauss_pyr[o][i]),

IPL_DEPTH_32F,

1

);

cvSub(

gauss_pyr[o][i+1],

gauss_pyr[o][i],

dog_pyr[o][i],

NULL

);

}

return

dog_pyr;

}</span>

(4)極值點檢測輸入?yún)?shù):contr_thr是去除對比度低的點所采用的閾值curv_thr是去除邊緣特征的閾值static

CvSeq*

scale_space_extrema(

IplImage***

dog_pyr,

int

octvs,

int

intvls,

double

contr_thr,

int

curv_thr,

CvMemStorage*

storage

)

{

CvSeq*

features;

double

prelim_contr_thr

=

0.5

*

contr_thr

/

intvls;

struct

feature*

feat;

struct

detection_data*

ddata;

int

o,

i,

r,

c;

features

=

cvCreateSeq(

0,

sizeof(CvSeq),

sizeof(struct

feature),

storage

);

for(

o

=

0;

o

<

octvs;

o++

)

for(

i

=

1;

i

<=

intvls;

i++

)

for(r

=

SIFT_IMG_BORDER;

r

<

dog_pyr[o][0]->height-SIFT_IMG_BORDER;

r++)

for(c

=

SIFT_IMG_BORDER;

c

<

dog_pyr[o][0]->width-SIFT_IMG_BORDER;

c++)

/*

perform

preliminary

check

on

contrast

*/

if(

ABS(

pixval32f(

dog_pyr[o][i],

r,

c

)

)

>

prelim_contr_thr

)

if(

is_extremum(

dog_pyr,

o,

i,

r,

c

)

)

{

feat

=

interp_extremum(dog_pyr,

o,

i,

r,

c,

intvls,

contr_thr);

if(

feat

)

{

ddata

=

feat_detection_data(

feat

);

if(

!

is_too_edge_like(

dog_pyr[ddata->octv][ddata->intvl],

ddata->r,

ddata->c,

curv_thr

)

)

{

cvSeqPush(

features,

feat

);

}

else

free(

ddata

);

free(

feat

);

}

}

return

features;

}

SIFT_IMG_BORDER是預定義的圖像邊緣;通過和對比度閾值比較去掉低對比度的點;而通過is_extremum來判斷是否為極值點,如果是則通過極值點插值的方式獲取亞像素的極值點的位置。然后通過is_too_eage_like和所給的主曲率閾值判斷是否為邊緣點*判斷是否為極值點其原理為:通過和高斯金字塔的上一層的9個像素+本層的除了本像素自己的其他的8個像素和下一層的9個像素進行比較看是否為這26個像素中最小的一個或者是否為最大的一個,如果是則為極值點。static

int

is_extremum(

IplImage***

dog_pyr,

int

octv,

int

intvl,

int

r,

int

c

)

{

float

val

=

pixval32f(

dog_pyr[octv][intvl],

r,

c

);

int

i,

j,

k;

/*

check

for

maximum

*/

if(

val

>

0

)

{

for(

i

=

-1;

i

<=

1;

i++

)

for(

j

=

-1;

j

<=

1;

j++

)

for(

k

=

-1;

k

<=

1;

k++

)

if(

val

<

pixval32f(

dog_pyr[octv][intvl+i],

r

+

j,

c

+

k

)

)

return

0;

}

/*

check

for

minimum

*/

else

{

for(

i

=

-1;

i

<=

1;

i++

)

for(

j

=

-1;

j

<=

1;

j++

)

for(

k

=

-1;

k

<=

1;

k++

)

if(

val

>

pixval32f(

dog_pyr[octv][intvl+i],

r

+

j,

c

+

k

)

)

return

0;

}

return

1;

}

*獲取亞像素的極值點的位置static

struct

feature*

interp_extremum(

IplImage***

dog_pyr,

int

octv,

int

intvl,

int

r,

int

c,

int

intvls,

double

contr_thr

)

{

struct

feature*

feat;

struct

detection_data*

ddata;

double

xi,

xr,

xc,

contr;//分別為亞像素的intval,row,col的偏移offset,和對比度

int

i

=

0;

while(

i

<

SIFT_MAX_INTERP_STEPS

)//重新確定極值點并重新定位的操作只能循環(huán)

5次

{

interp_step(

dog_pyr,

octv,

intvl,

r,

c,

&xi,

&xr,

&xc

);

if(

ABS(

xi

)

<

0.5

&&

ABS(

xr

)

<

0.5

&&

ABS(

xc

)

<

0.5

)//如果滿足條件就停止尋找

break;

//否則繼續(xù)尋找極值點

c

+=

cvRound(

xc

);

r

+=

cvRound(

xr

);

intvl

+=

cvRound(

xi

);

if(

intvl

<

1

||

intvl

>

intvls

||

c

<

SIFT_IMG_BORDER

||

r

<

SIFT_IMG_BORDER

||

c

>=

dog_pyr[octv][0]->width

-

SIFT_IMG_BORDER

||

r

>=

dog_pyr[octv][0]->height

-

SIFT_IMG_BORDER

)

{

return

NULL;

}

i++;

}

//確保極值點是經(jīng)過最大5步找到的

/*

ensure

convergence

of

interpolation

*/

if(

i

>=

SIFT_MAX_INTERP_STEPS

)

return

NULL;

//獲取找到的極值點的對比度

contr

=

interp_contr(

dog_pyr,

octv,

intvl,

r,

c,

xi,

xr,

xc

);

//判斷極值點是否小于某一個閾值

if(

ABS(

contr

)

<

contr_thr

/

intvls

)

return

NULL;

//若小于,則認為是極值點

feat

=

new_feature();

ddata

=

feat_detection_data(

feat

);

feat->img_pt.x

=

feat->x

=

(

c

+

xc

)

*

pow(

2.0,

octv

);

feat->img_pt.y

=

feat->y

=

(

r

+

xr

)

*

pow(

2.0,

octv

);

ddata->r

=

r;

ddata->c

=

c;

ddata->octv

=

octv;

ddata->intvl

=

intvl;

ddata->subintvl

=

xi;

return

feat;

}

*獲取亞像素位置中所用到的函數(shù)static

void

interp_step(

IplImage***

dog_pyr,

int

octv,

int

intvl,

int

r,

int

c,

double*

xi,

double*

xr,

double*

xc

)

{

CvMat*

dD,

*

H,

*

H_inv,

X;

double

x[3]

=

{

0

};

//計算三維偏導數(shù)

dD

=

deriv_3D(

dog_pyr,

octv,

intvl,

r,

c

);

//計算三維海森矩陣

H

=

hessian_3D(

dog_pyr,

octv,

intvl,

r,

c

);

H_inv

=

cvCreateMat(

3,

3,

CV_64FC1

);

cvInvert(

H,

H_inv,

CV_SVD

);

cvInitMatHeader(

&X,

3,

1,

CV_64FC1,

x,

CV_AUTOSTEP

);

cvGEMM(

H_inv,

dD,

-1,

NULL,

0,

&X,

0

);

cvReleaseMat(

&dD

);

cvReleaseMat(

&H

);

cvReleaseMat(

&H_inv

);

*xi

=

x[2];

*xr

=

x[1];

*xc

=

x[0];

}

*計算三維偏導數(shù)計算在x和y方向上的偏導數(shù),高斯差分尺度空間金字塔中像素的尺度實際上在離散數(shù)據(jù)中計算偏導數(shù)是通過相鄰像素的相減來計算的比如說計算x方向的偏導數(shù)dx,則通過該向所的x方向的后一個減去前一個然后除以2即可求的dxstatic

CvMat*

deriv_3D(

IplImage***

dog_pyr,

int

octv,

int

intvl,

int

r,

int

c

)

{

CvMat*

dI;

double

dx,

dy,

ds;

dx

=

(

pixval32f(

dog_pyr[octv][intvl],

r,

c+1

)

-

pixval32f(

dog_pyr[octv][intvl],

r,

c-1

)

)

/

2.0;

dy

=

(

pixval32f(

dog_pyr[octv][intvl],

r+1,

c

)

-

pixval32f(

dog_pyr[octv][intvl],

r-1,

c

)

)

/

2.0;

ds

=

(

pixval32f(

dog_pyr[octv][intvl+1],

r,

c

)

-

pixval32f(

dog_pyr[octv][intvl-1],

r,

c

)

)

/

2.0;

dI

=

cvCreateMat(

3,

1,

CV_64FC1

);

cvmSet(

dI,

0,

0,

dx

);

cvmSet(

dI,

1,

0,

dy

);

cvmSet(

dI,

2,

0,

ds

);

return

dI;

}

*計算三維海森矩陣不需要講什么,其實就是計算二次導數(shù),計算方法也和一次導數(shù)的計算如出一轍。然后將結(jié)果放入到一個矩陣中去。static

CvMat*

hessian_3D(

IplImage***

dog_pyr,

int

octv,

int

intvl,

int

r,

int

c

)

{

CvMat*

H;

double

v,

dxx,

dyy,

dss,

dxy,

dxs,

dys;

v

=

pixval32f(

dog_pyr[octv][intvl],

r,

c

);

dxx

=

(

pixval32f(

dog_pyr[octv][intvl],

r,

c+1

)

+

pixval32f(

dog_pyr[octv][intvl],

r,

c-1

)

-

2

*

v

);

dyy

=

(

pixval32f(

dog_pyr[octv][intvl],

r+1,

c

)

+

pixval32f(

dog_pyr[octv][intvl],

r-1,

c

)

-

2

*

v

);

dss

=

(

pixval32f(

dog_pyr[octv][intvl+1],

r,

c

)

+

pixval32f(

dog_pyr[octv][intvl-1],

r,

c

)

-

2

*

v

);

dxy

=

(

pixval32f(

dog_pyr[octv][intvl],

r+1,

c+1

)

-

pixval32f(

dog_pyr[octv][intvl],

r+1,

c-1

)

-

pixval32f(

dog_pyr[octv][intvl],

r-1,

c+1

)

+

pixval32f(

dog_pyr[octv][intvl],

r-1,

c-1

)

)

/

4.0;

dxs

=

(

pixval32f(

dog_pyr[octv][intvl+1],

r,

c+1

)

-

pixval32f(

dog_pyr[octv][intvl+1],

r,

c-1

)

-

pixval32f(

dog_pyr[octv][intvl-1],

r,

c+1

)

+

pixval32f(

dog_pyr[octv][intvl-1],

r,

c-1

)

)

/

4.0;

dys

=

(

pixval32f(

dog_pyr[octv][intvl+1],

r+1,

c

)

-

pixval32f(

dog_pyr[octv][intvl+1],

r-1,

c

)

-

pixval32f(

dog_pyr[octv][intvl-1],

r+1,

c

)

+

pixval32f(

dog_pyr[octv][intvl-1],

r-1,

c

)

)

/

4.0;

H

=

cvCreateMat(

3,

3,

CV_64FC1

);

cvmSet(

H,

0,

0,

dxx

);

cvmSet(

H,

0,

1,

dxy

);

cvmSet(

H,

0,

2,

dxs

);

cvmSet(

H,

1,

0,

dxy

);

cvmSet(

H,

1,

1,

dyy

);

cvmSet(

H,

1,

2,

dys

);

cvmSet(

H,

2,

0,

dxs

);

cvmSet(

H,

2,

1,

dys

);

cvmSet(

H,

2,

2,

dss

);

return

H;

}

*計算插入像素的對比度static

double

interp_contr(

IplImage***

dog_pyr,

int

octv,

int

intvl,

int

r,

int

c,

double

xi,

double

xr,

double

xc

)

{

CvMat*

dD,

X,

T;

double

t[1],

x[3]

=

{

xc,

xr,

xi

};

cvInitMatHeader(

&X,

3,

1,

CV_64FC1,

x,

CV_AUTOSTEP

);

cvInitMatHeader(

&T,

1,

1,

CV_64FC1,

t,

CV_AUTOSTEP

);

dD

=

deriv_3D(

dog_pyr,

octv,

intvl,

r,

c

);

cvGEMM(

dD,

&X,

1,

NULL,

0,

&T,

CV_GEMM_A_T

);

cvReleaseMat(

&dD

);

return

pixval32f(

dog_pyr[octv][intvl],

r,

c

)

+

t[0]

*

0.5;

}

其中cvGEMM是矩陣的通用計算函數(shù),至于CV_GEMM_A_T是計算dD的轉(zhuǎn)置矩陣放入T中*去除邊緣相應

通過計算所在特征向量的主曲率半徑來判斷特征是邊緣的從而導致不穩(wěn)定

即去除邊緣響應static

int

is_too_edge_like(

IplImage*

dog_img,

int

r,

int

c,

int

curv_thr

)

{

double

d,

dxx,

dyy,

dxy,

tr,

det;

/*

principal

curvatures

are

computed

using

the

trace

and

det

of

Hessian

*/

d

=

pixval32f(dog_img,

r,

c);

dxx

=

pixval32f(

dog_img,

r,

c+1

)

+

pixval32f(

dog_img,

r,

c-1

)

-

2

*

d;

dyy

=

pixval32f(

dog_img,

r+1,

c

)

+

pixval32f(

dog_img,

r-1,

c

)

-

2

*

d;

dxy

=

(

pixval32f(dog_img,

r+1,

c+1)

-

pixval32f(dog_img,

r+1,

c-1)

-

pixval32f(dog_img,

r-1,

c+1)

+

pixval32f(dog_img,

r-1,

c-1)

)

/

4.0;

tr

=

dxx

+

dyy;

det

=

dxx

*

dyy

-

dxy

*

dxy;

/*

negative

determinant

->

curvatures

have

different

signs;

reject

feature

*/

if(

det

<=

0

)

return

1;

if(

tr

*

tr

/

det

<

(

curv_thr

+

1.0

)*(

curv_thr

+

1.0

)

/

curv_thr

)

return

0;

return

1;

}

(4)計算特征向量的尺度實際上是通過最初的sigma來獲得每一層每一組的尺度static

void

calc_feature_scales(

CvSeq*

features,

double

sigma,

int

intvls

)

{

struct

feature*

feat;

struct

detection_data*

ddata;

double

intvl;

int

i,

n;

n

=

features->total;

for(

i

=

0;

i

<

n;

i++

)

{

feat

=

CV_GET_SEQ_ELEM(

struct

feature,

features,

i

);

ddata

=

feat_detection_data(

feat

);

intvl

=

ddata->intvl

+

ddata->subintvl;

feat->scl

=

sigma

*

pow(

2.0,

ddata->octv

+

intvl

/

intvls

);

ddata->scl_octv

=

sigma

*

pow(

2.0,

intvl

/

intvls

);

}

}

(5)調(diào)整圖像特征坐標、尺度、點的坐標大小為原來的一半static

void

adjust_for_img_dbl(

CvSeq*

features

)

{

struct

feature*

feat;

int

i,

n;

n

=

features->total;

for(

i

=

0;

i

<

n;

i++

)

{

feat

=

CV_GET_SEQ_ELEM(

struct

feature,

features,

i

);

feat->x

/=

2.0;

feat->y

/=

2.0;

feat->scl

/=

2.0;

feat->img_pt.x

/=

2.0;

feat->img_pt.y

/=

2.0;

}

}

(6)給每一個圖像特征向量計算規(guī)范化的方向static

void

calc_feature_oris(

CvSeq*

features,

IplImage***

gauss_pyr

)

{

struct

feature*

feat;

struct

detection_data*

ddata;

double*

hist;

double

omax;

int

i,

j,

n

=

features->total;

//遍歷整個檢測出來的特征點,計算每個特征點的直方圖,然后平滑直方圖去除突變,然后找到每一個特征點的主方向,并加入到好的方向特征數(shù)組中去

for(

i

=

0;

i

<

n;

i++

)

{

feat

=

static_cast<feature

*>(

malloc(

sizeof(

struct

feature

)

)

);

cvSeqPopFront(

features,

feat

);

ddata

=

feat_detection_data(

feat

);

//計算給定的某個像素的灰度方向直方圖

hist

=

ori_hist(

gauss_pyr[ddata->octv][ddata->intvl],

ddata->r,

ddata->c,

SIFT_ORI_HIST_BINS,

cvRound(

SIFT_ORI_RADIUS

*

ddata->scl_octv

),

SIFT_ORI_SIG_FCTR

*

ddata->scl_octv

);

for(

j

=

0;

j

<

SIFT_ORI_SMOOTH_PASSES;

j++

)

smooth_ori_hist(

hist,

SIFT_ORI_HIST_BINS

);

omax

=

dominant_ori(

hist,

SIFT_ORI_HIST_BINS

);

//描述子向量元素門限化

add_good_ori_features(

features,

hist,

SIFT_ORI_HIST_BINS,

omax

*

SIFT_ORI_PEAK_RATIO,

feat

);

free(

ddata

);

free(

feat

);

free(

hist

);

}

}

*對所給像素計算灰度方向直方圖

以關鍵點為中心的鄰域窗口內(nèi)采樣,并用直方圖統(tǒng)計鄰域像素的梯度

方向。梯度直方圖的范圍是0~360度,其中每10度一個柱,總共36個柱static

double*

ori_hist(

IplImage*

img,

int

r,

int

c,

int

n,

int

rad,

double

sigma)

{

double*

hist;

double

mag,

ori,

w,

exp_denom,

PI2

=

CV_PI

*

2.0;

int

bin,

i,

j;

hist

=

static_cast<double

*>(

calloc(

n,

sizeof(

double

)

)

);

exp_denom

=

2.0

*

sigma

*

sigma;

for(

i

=

-rad;

i

<=

rad;

i++

)

for(

j

=

-rad;

j

<=

rad;

j++

)

if(

calc_grad_mag_ori(

img,

r

+

i,

c

+

j,

&mag,

&ori

)

)

{

w

=

exp(

-(

i*i

+

j*j

)

/

exp_denom

);

bin

=

cvRound(

n

*

(

ori

+

CV_PI

)

/

PI2

);

bin

=

(

bin

<

n

)?

bin

:

0;

hist[bin]

+=

w

*

mag;

}

return

hist;

}

*計算所給像素的梯度大小和方向

每一個小格都代表了特征點鄰域所在的尺度空間的一個像素,箭頭方向代表了像素梯

度方向,箭頭長度代表該像素的幅值也就是梯度的值static

int

calc_grad_mag_ori(

IplImage*

img,

int

r,

int

c,

double*

mag,

double*

ori

)

{

double

dx,

dy;

if(

r

>

0

&&

r

<

img->height

-

1

&&

c

>

0

&&

c

<

img->width

-

1

)

{

dx

=

pixval32f(

img,

r,

c+1

)

-

pixval32f(

img,

r,

c-1

);

dy

=

pixval32f(

img,

r-1,

c

)

-

pixval32f(

img,

r+1,

c

);

*mag

=

sqrt(

dx*dx

+

dy*dy

);

*ori

=

atan2(

dy,

dx

);

return

1;

}

else

return

0;

}

*對方向直方圖進行高斯模糊

使用高斯函數(shù)對直方圖進行平滑,減少突變的影響。static

void

smooth_ori_hist(

double*

hist,

int

n

)

{

double

prev,

tmp,

h0

=

hist[0];

int

i;

prev

=

hist[n-1];

for(

i

=

0;

i

<

n;

i++

)

{

tmp

=

hist[i];

hist[i]

=

0.25

*

prev

+

0.5

*

hist[i]

+

0.25

*

(

(

i+1

==

n

)?

h0

:

hist[i+1]

);

prev

=

tmp;

}

}

*在直方圖中找到主方向的梯度

利用關鍵點鄰域像素的梯度方向分布特性為每個關鍵點指定方向參數(shù),使算子具備

旋轉(zhuǎn)不變性。static

double

dominant_ori(

double*

hist,

int

n

)

{

double

omax;

int

maxbin,

i;

omax

=

hist[0];

maxbin

=

0;

for(

i

=

1;

i

<

n;

i++

)

if(

hist[i]

>

omax

)

{

omax

=

hist[i];

maxbin

=

i;

}

return

omax;

}

*將大于某一個梯度大小閾值的特征向量加入到直方圖中去n為方向的個數(shù)<span

style="font-size:18px;">mag_thr描述子向量門限一般取0.2</span>

static

void

add_good_ori_features(

CvSeq*

features,

double*

hist,

int

n,

double

mag_thr,

struct

feature*

feat

)

{

struct

feature*

new_feat;

double

bin,

PI2

=

CV_PI

*

2.0;

int

l,

r,

i;

for(

i

=

0;

i

<

n;

i++

)

{

l

=

(

i

==

0

)?

n

-

1

:

i-1;

r

=

(

i

+

1

)

%

n;

//描述子向量門限化,一般門限取0.2

if(

hist[i]

>

hist[l]

&&

hist[i]

>

hist[r]

&&

hist[i]

>=

mag_thr

)

{

bin

=

i

+

interp_hist_peak(

hist[l],

hist[i],

hist[r]

);

bin

=

(

bin

<

0

)?

n

+

bin

:

(

bin

>=

n

)?

bin

-

n

:

bin;

new_feat

=

clone_feature(

feat

);

new_feat->ori

=

(

(

PI2

*

bin

)

/

n

)

-

CV_PI;

cvSeqPush(

features,

new_feat

);

free(

new_feat

);

}

}

}

(7)計算特征描述子static

void

compute_descriptors(

CvSeq*

features,

IplImage***

gauss_pyr,

int

d,

int

n)

{

struct

feature*

feat;

struct

detection_data*

ddata;

double***

hist;

int

i,

k

=

features->total;

for(

i

=

0;

i

<

k;

i++

)

{

feat

=

CV_GET_SEQ_ELEM(

struct

feature,

features,

i

);

ddata

=

feat_detection_data(

feat

);

//計算二維方向直方圖

hist

=

descr_hist(

gauss_pyr[ddata->octv][ddata->intvl],

ddata->r,

ddata->c,

feat->ori,

ddata->scl_octv,

d,

n

);

//將二維方向直方圖轉(zhuǎn)換為特征描述子

hist_to_descr(

hist,

d,

n,

feat

);

release_descr_hist(

&hist,

d

);

}

}

*計算二維方向直方圖static

double***

descr_hist(

IplImage*

img,

int

r,

int

c,

double

ori,

double

scl,

int

d,

int

n

)

{

double***

hist;

double

cos_t,

sin_t,

hist_width,

exp_denom,

r_rot,

c_rot,

grad_mag,

grad_ori,

w,

rbin,

cbin,

obin,

bins_per_rad,

PI2

=

2.0

*

CV_PI;

int

radius,

i,

j;

hist

=

static_cast<double

***>(

calloc(

d,

sizeof(

double**

)

)

);

for(

i

=

0;

i

<

d;

i++

)

{

hist[i]

=static_cast<double

**>(

calloc(

d,

sizeof(

double*

)

)

);

for(

j

=

0;

j

<

d;

j++

)

hist[i][j]

=

static_cast<double

*>(

calloc(

n,

sizeof(

double

)

)

);

}

cos_t

=

cos(

ori

);

sin_t

=

sin(

ori

);

bins_per_rad

=

n

/

PI2;

exp_denom

=

d

*

d

*

0.5;

hist_width

=

SIFT_DESCR_SCL_FCTR

*

scl;

radius

=

hist_width

*

sqrt(2.0)

*

(

d

+

1.0

)

*

0.5

+

0.5;

for(

i

=

-radius;

i

<=

radius;

i++

)

for(

j

=

-radius;

j

<=

radius;

j++

)

{

/*

即將坐標移至關鍵點主方向

計算采用的直方圖數(shù)組中相對于方向旋轉(zhuǎn)的坐標

Calculate

sample's

histogram

array

coords

rotated

relative

to

ori.

Subtract

0.5

so

samples

that

fall

e.g.

in

the

center

of

row

1

(i.e.

r_rot

=

1.5)

have

full

weight

placed

in

row

1

after

interpolation.

*/

c_rot

=

(

j

*

cos_t

-

i

*

sin_t

)

/

hist_width;

r_rot

=

(

j

*

sin_t

+

i

*

cos_t

)

/

hist_width;

rbin

=

r_rot

+

d

/

2

-

0.5;

cbin

=

c_rot

+

d

/

2

-

0.5;

if(

rbin

>

-1.0

&&

rbin

<

d

&&

cbin

>

-1.0

&&

cbin

<

d

)

if(

calc_grad_mag_ori(

img,

r

+

i,

c

+

j,

&grad_mag,

&grad_ori

))

{

grad_ori

-=

ori;

while(

grad_ori

<

0.0

)

grad_ori

+=

PI2;

while(

grad_ori

>=

PI2

)

grad_ori

-=

PI2;

obin

=

grad_ori

*

bins_per_rad;

w

=

exp(

-(c_rot

*

c_rot

+

r_rot

*

r_rot)

/

exp_denom

);

interp_hist_entry(

hist,

rbin,

cbin,

obin,

grad_mag

*

w,

d,

n

);

}

}

return

hist;

}

*插入一個entry進入到方向直方圖中從而形成特征描述子這個,我也不怎么明白。。。static

void

interp_hist_entry(

double***

hist,

double

rbin,

double

cbin,

double

obin,

double

mag,

int

d,

int

n

)

{

double

d_r,

d_c,

d_o,

v_r,

v_c,

v_o;

double**

row,

*

h;

int

r0,

c0,

o0,

rb,

cb,

ob,

r,

c,

o;

r0

=

cvFloor(

rbin

);

c0

=

cvFloor(

cbin

);

o0

=

cvFloor(

obin

);

d_r

=

rbin

-

r0;

d_c

=

cbin

-

c0;

d_o

=

obin

-

o0;

/*

The

entry

is

distributed

into

up

to

8

bins.

Each

entry

into

a

bin

is

multiplied

by

a

weight

of

1

-

d

for

each

dimension,

where

d

is

the

distance

from

the

center

value

of

the

bin

measured

in

bin

units.

*/

for(

r

=

0;

r

<=

1;

r++

)

{

rb

=

r0

+

r;

if(

rb

>=

0

&&

rb

<

d

)

{

v_r

=

mag

*

(

(

r

==

0

)?

1.0

-

d_r

:

d_r

);

row

=

hist[rb];

for(

c

=

0;

c

<=

1;

c++

)

{

cb

=

c0

+

c;

if(

cb

>=

0

&&

cb

<

d

)

{

v_c

=

v_r

*

(

(

c

==

0

)?

1.0

-

d_c

:

d_c

);

h

=

row[cb];

for(

o

=

0;

o

<=

1;

o++

)

{

ob

=

(

o0

+

o

)

%

n;

v_o

=

v_c

*

(

(

o

==

0

)?

1.0

-

d_o

:

d_o

);

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論