Computer Vision2009. 2. 23. 08:23

Rob Hess의 SIFT


앞서 두번에 걸쳐서 Rob의 코드를 컴파일해서 정상적으로 움직이는 것을 확인하였습니다.

이제 코드 내부가 어떻게 동작하는지 확인을 해보겠습니다.

SIFT자체는 나중에 따로 정리하기로 하고 전체 맥락을 한번 따라가는 형식으로 정리하였습니다.



이번에는 전체 코드를 한번 찬찬히 따라가면서 정리하였습니다.

그냥 코드를 읽는 수준이므로 큰 무리 없이 따라가면 됩니다.

OpenCV에 기반하므로, 그냥 이런 함수가 있다고 보고 읽어 가면 됩니다.


1. dspFeat의 분석


dspFeat를 먼저 코드를 보곘습니다.

이 프로그램은 그냥 SIFT를 대상 이미지에 올리는 그림입니다.

별다른 어려운 부분이 없읍니다.


시작 부분에서 두개의 파일을 먼저 설정하고 있습니다.


char* feat_file = "..\\beaver.sift";

char* img_file = "..\\beaver.png";


앞서의 것은 beaver.sift 의 결과물입니다. 텍스트 파일로 되어 있네요

두번째 것은 png format 으로 되어 있는 이미지 파일입니다.



int main( int argc, char** argv )

{

IplImage* img;

struct feature* feat;

char* name;

int n;


img = cvLoadImage( img_file, 1 );  // 먼저 이미지 파일을 로딩한다.


if( ! img )

fatal_error( "unable to load image from %s", img_file );


n = import_features( feat_file, feat_type, &feat ); // 피쳐 파일을 로딩한다.

if( n == -1 )

fatal_error( "unable to import features from %s", feat_file );


name = feat_file;


draw_features( img, feat, n );  // SIFT를 그린다.

cvNamedWindow( name, 1 );  // 창을 열고~~~

cvShowImage( name, img );   // 그림을 그린다. 이때 그림은  draw_feature로 그린것이다.

cvWaitKey( 0 );   // 글고 키 값을 기다린다. 

return 0;

}


이다. 큰 문제점은... 은 없네요~ 


draw_feature()함수를 나중에 따로 정리하여야 하겠습니다.

이것은 SIFT를 정리하면서 하면 되므로 여기서는  SKIP...



2. match의 코드 따라가기


그럼 이제 두번째로 match를 한번 따라가 보겠습니다.



/******************************** Globals ************************************/


char img1_file[] = "..\\beaver.png"; // 찾고자 하는 이미지  파일이다.

char img2_file[] = "..\\beaver_xform.png"; // 비교 대상 파일이다.


/********************************** Main *************************************/



int main( int argc, char** argv )

{

IplImage* img1, * img2, * stacked;

struct feature* feat1, * feat2, * feat;

struct feature** nbrs;

struct kd_node* kd_root;

CvPoint pt1, pt2;

double d0, d1;

int n1, n2, k, i, m = 0;


img1 = cvLoadImage( img1_file, 1 ); // 찾는 이미지를 먼저 로딩한다.

if( ! img1 )

fatal_error( "unable to load image from %s", img1_file );


img2 = cvLoadImage( img2_file, 1 ); // 대상 이미지를 로딩한다.

if( ! img2 )

fatal_error( "unable to load image from %s", img2_file );


stacked = stack_imgs( img1, img2 ); // 두개의 이미지를 합쳐서 하나의 이미지로 만든다.

    // 그렇다고 이미지를 겹치는 것이 아니라 상하로 포개는 것이다.


fprintf( stderr, "Finding features in %s...\n", img1_file );

n1 = sift_features( img1, &feat1 ); // 이제 FEATURE를 찾기...


fprintf( stderr, "Finding features in %s...\n", img2_file );

n2 = sift_features( img2, &feat2 ); // 피쳐를 더 찾기...


kd_root = kdtree_build( feat2, n2 ); // 키포인트 배열에서 원하는 kd tree로 구성한다.


for( i = 0; i < n1; i++ ) // 찾고자 하는 이미지 1의 특징점을 대상으로 반복한다.

{

feat = feat1 + i;

k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );

// 특징점에서 NN방식으로 하여 찾아낸다.

if( k == 2 ) // k가 2라면.. 찾아낸 것이므로.. 

{

d0 = descr_dist_sq( feat, nbrs[0] ); // nn과 두번째 nn사이의 

      // 유클리드 제곱 거리를 구한다.

d1 = descr_dist_sq( feat, nbrs[1] );

if( d0 < d1 * NN_SQ_DIST_RATIO_THR ) // 임계치보다 크다면.. 

{

// 두개의 포인트로 선을 그린다. 

pt1 = cvPoint( cvRound( feat->x ), cvRound( feat->y ) );

pt2 = cvPoint( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );

pt2.y += img1->height;

cvLine( stacked, pt1, pt2, CV_RGB(255,0,255), 1, 8, 0 );

m++;

feat1[i].fwd_match = nbrs[0];

}

}

free( nbrs );

}


// 다 찾았으면 이미지를 그린다.

fprintf( stderr, "Found %d total matches\n", m );

cvNamedWindow( "Matches", 1 );

cvShowImage( "Matches", stacked );

cvWaitKey( 0 );



/*  

       이 것은 RANSAC함수가 어떻게 움직이는지 보기 위해서 만든 것입니다.

       아래 주석 처리가 된 블럭을 풀면 됩니다.

UNCOMMENT BELOW TO SEE HOW RANSAC FUNCTION WORKS


Note that this line above:


feat1[i].fwd_match = nbrs[0];


is important for the RANSAC function to work.

*/

/*

{

CvMat* H;

H = ransac_xform( feat1, n1, FEATURE_FWD_MATCH, lsq_homog, 4, 0.01,

homog_xfer_err, 3.0, NULL, NULL );

if( H )

{

IplImage* xformed;

xformed = cvCreateImage( cvGetSize( img2 ), IPL_DEPTH_8U, 3 );

cvWarpPerspective( img1, xformed, H, 

CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS,

cvScalarAll( 0 ) );

cvNamedWindow( "Xformed", 1 );

cvShowImage( "Xformed", xformed );

cvWaitKey( 0 );

cvReleaseImage( &xformed );

cvReleaseMat( &H );

}

}

*/


//모두 해제합니다.

cvReleaseImage( &stacked );

cvReleaseImage( &img1 );

cvReleaseImage( &img2 );

kdtree_release( kd_root );

free( feat1 );

free( feat2 );

return 0;


여기서는 KDTree를 이용해서 공간상에서 dB를 구축하였음을 알수 있습니다.

다음에는 이것을 좀더 자세하게 따라가 보겠습니다.


'Computer Vision' 카테고리의 다른 글

Rob Hess의 SIFT [5]  (2) 2009.03.02
Rob Hess의 SIFT [4]  (0) 2009.02.25
Rob Hess의 SIFT [2]  (0) 2009.02.18
Rob Hess의 SIFT [1]  (1) 2009.02.16
MAC에서 OpenCV를 컴파일 하기  (0) 2009.01.06
Posted by GUNDAM_IM