'Rob'에 해당되는 글 2건

  1. 2009.04.30 Rob Hess의 SIFT [7] 1
  2. 2009.02.23 Rob Hess의 SIFT [3] 2
Computer Vision2009. 4. 30. 00:07


SIFT의 동작은


아래와 같이 호출됩니다.


int sift_features( IplImage* img, struct feature** feat )

{

  return _sift_features( img, feat,

SIFT_INTVLS,

SIFT_SIGMA,

SIFT_CONTR_THR,

                         SIFT_CURV_THR,

SIFT_IMG_DBL,

SIFT_DESCR_WIDTH,

                         SIFT_DESCR_HIST_BINS );

}


영상과 feature는 포인터로 전달되고 나머지는  매크로로 정의되어 있습니다. 이렇게 하면

최상위 함수는 매크로에 따라 파라미터를 줄 수 있고 이하 하위 함수들은 인자들을 기반으로 할 수 있으므로

프로그램 테스트 등이 편리해집니다.


정의된 매크로들은 나중에 코드를 읽어가면서 새로운 그리고 필요한 매크로가 나온다면, 그때마다

하나씩 확인해 가기로 하고 여기서는 건너 뜁니다.


실제 호출은 위의 코드에서 보는 바와 같이 _sift_features를 호출하여 구동합니다.

이 함수는 다음과 같은 순서로 동작합니다.


1. 인자를 검사해서 오류가 있는지 확인을 합니다.

2. 주어진 이미지로 이미지 피라미드를 구축합니다.

3. 구축한 이미지 피라미드에서 DoG를 구축합니다.

4. DoG에서 특징점들을 추출하고

5. 특징점 을 좌표에 매핑하고,

6. 특징점 기술자들을 논문대로 정리한다.


이를 위한 호툴된 함수는 다음과 같습니다.

기계적으로 따라갑니다.


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  

인자를 검사한다. NULL Pointer이면 에러를 출력한다.*/


  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

      이미지 피라미드를 구축한다.

     최상위 피라미드는 그 크기가 4 픽셀 정도이다.

   */


/* 최초의 이미지를 만들어 냅니다.

   이 이미지는 그레이 스케일로 생성됩니다.. */

  init_img = create_init_img( img, img_dbl, sigma );


  octvs = log( MIN( init_img->width, init_img->height ) ) / log(2) - 2;


/* 이미지를  가지고 가우시안 스케일 피라미드를 구성합니다. */

  gauss_pyr = build_gauss_pyr( init_img, octvs, intvls, sigma );


/* DoG 이미지 피라미드를 구성합니다. */

  dog_pyr = build_dog_pyr( gauss_pyr, octvs, intvls );


  storage = cvCreateMemStorage( 0 );


DoG에서 특징점들을 열심히 추출합니다.

  features = scale_space_extrema(

dog_pyr,

octvs,

intvls,

contr_thr,

                            curv_thr,

storage );


/* 추출된 특징들의 특성들을 계산합니다. */

  calc_feature_scales( features, sigma, intvls );


/*  이미지가 2배로 키워서 특징점들을 추출하였을 경우 이를 다시 조절합니다. */

  if( img_dbl )

    adjust_for_img_dbl( features );


/* 정규 좌표를 계산합니다. */

  calc_feature_oris( features, gauss_pyr );


/* Lowe’s Paper 6절에 따라서 특징점 기술자를 만들어냅니다. */

  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 = calloc( n, sizeof(struct feature) );


  *feat = 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;


}


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

SURF Lib  (3) 2010.06.22
Rob Hess의 SIFT [8]  (7) 2009.06.21
OpenCV - Alpha Blending cvAddWeighted , cvFillPoly  (2) 2009.04.25
JPEG2AVI 를 맥에서 빌드하기  (0) 2009.04.24
OpenCV - cvSmooth  (2) 2009.04.22
Posted by GUNDAM_IM
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