Windows下 Robhess SIFT源碼配置


Robhess OpenSIFT 源碼下載:傳送門

為了進一步學習SIFT,選擇論文就着代碼看,在VS2013、OpenCV2.4.13下新建項目,跑一跑經典之作。由於將代碼和Opencv配置好后還會有些錯誤提示,所以下面是代碼的一些改動之處。(試了下其實還是ubuntu下更方便,因為有許多參數或者命令是linux下的,當然windows下可以進行一些修改后利用)。

大前提:opencv配置好。剩下的都可以通過修改來搞定。

首先看看解壓后的文件,我們只需要頭文件和源文件:

                                              頭文件:6個                                                                                                                          源文件:10個

注意直接運行肯定不行,因為有幾個文件比較特殊,下面對所有頭、源文件進行解釋:

1)imgfeatures.c 和 imgfeatures.h:

有SIFT特征點結構struct feature的定義,除此之外還有一些特征點的導入導出以及特征點繪制函數的聲明,對應的imgfeatures.c文件中是特征點的導入導出以及特征點繪制函數的實現。

2)utils.c 和 utils.h:

這兩個文件中是一些圖像基本操作的函數,包括:獲取某位置的像素點,設置某位置的像素點(8位,32位和64位),計算兩點之間的距離的平方,在圖片某一點畫一個“X”,將兩張圖片合成為一個(在特征匹配中用到),高是二者之和,寬是二者的較大者。

3)minpq.c 和 minpq.h

這兩個文件中實現了最小優先級隊列(Minimizing Priority Queue),也就是小頂堆,在k-d樹的建立和搜索過程中要用到。

4)kdtree.c 和 kdtree.h

這兩個文件中實現了k-d樹的建立以及用BBF(Best Bin First)算法搜索匹配點的函數。如果需要對兩個圖片中的特征點進行匹配,就要用到這兩個文件。

5)xform.c 和 xform.h:

這兩個文件中實現了RANSAC算法(RANdom SAmple Consensus 隨機抽樣一致)。RANSAC算法可用來篩選兩個圖像間的SIFT特征匹配並計算變換矩陣。可以單利用RANSAC算法篩選兩個圖像間的SIFT特征匹配,以得到更好的匹配結果,很經典的算法,值得學習。

6)sift.c 和 sift.h:   

論文里最主要的內容在此,里面的內容就是兩個特征點檢測函數sift_features()和 _sift_features(),sift_features()是用默認參數進行特征點檢測, _sift_features()允許用戶輸入各種檢測參數,其實sift_features()中也是再次調用_sift_features()函數。所以只需提供原圖像和存儲特征點的數組以及其他一些檢測參數,然后調用sift_features()或 _sift_features()就可完成SIFT特征點檢測。

7)siftfeat.c :含有main函數,用來實現特征點的檢測,返回特征點數目和標記特征點的圖像。(主要用到)

8)match.c 含有main函數, 檢測兩張圖中的sift特征點,然后找到特征點的匹配對。(主要用到)

9)match_num.c 含有main函數,檢測sift特征點,但是用到了linux下的多線程編程,所以這里暫時不做討論。

10)dspfeat.c : 含有main函數,可以從預先保存的特征點文件中讀取特征點並顯示在圖片上。

 

 

一. 修改代碼

第一步:將代碼中所有頭文件源文件中的聲明改一下:

修改前:

#include <cv.h>
#include <cxcore.h>
#include <highgui.h>

修改后:

#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>

修改原因:因為直接利用找不到opencv路徑,所以調整路徑。

 

第二步:修改源文件代碼:

1. sift.c:

將函數   static IplImage*** build_gauss_pyr( IplImage* base, int octvs, int intvls, double sigma ) 中的代碼進行改動:

修改前:

  const int _intvls = intvls;
  double sig[_intvls+3], sig_total, sig_prev, k;

修改后:

  const int _intvls = intvls;
  double *sig = (double*)malloc(sizeof(double)*(_intvls+3)); 
  double sig_total, sig_prev, k;
...
free(sig); //子函數返回前釋放內存

修改原因:

源代碼中用變量_intvls+3作為數組的長度,但是VC的編譯器不是GCC,它不允許這樣做。DEV-C++使用的編譯器是GCC,它允許使用變量作為數組的長度定義數組。

當然利用C++中的 new或者vector也可以。參考 new、delete與malloc、free區別

 

2. utils.c

首先刪除這兩行:

#include <gdk/gdk.h>
#include <gtk/gtk.h>

為啥刪掉?

gtk是一個功能強大、設計靈活的一個通用圖形庫,是GNU/Linux下開發圖形界面的應用程序的主流開發工具之一,GTK+也有Windows版本和Mac OS X版。在作者的源碼中gtk用來調整窗口來顯示圖像,因為我懶於裝gtk,所以直接利用opencv進行顯示,所以這里需要修改一些opencv的東西。

將函數進行改動:

修改前:

 1 void display_big_img( IplImage* img, char* title )
 2 {
 3   IplImage* small;
 4   GdkScreen* scr;
 5   int scr_width, scr_height;
 6   double img_aspect, scr_aspect, scale;
 7 
 8   /* determine screen size to see if image fits on screen */
 9   gdk_init( NULL, NULL );
10   scr = gdk_screen_get_default();
11   scr_width = gdk_screen_get_width( scr );
12   scr_height = gdk_screen_get_height( scr );
13 
14   if( img->width >= 0.90 * scr_width  ||  img->height >= 0.90 * scr_height )
15     {
16       img_aspect = (double)(img->width) / img->height;
17       scr_aspect = (double)(scr_width) / scr_height;
18       
19       if( img_aspect > scr_aspect )
20     scale = 0.90 * scr_width / img->width;
21       else
22     scale = 0.90 * scr_height / img->height;
23 
24       small = cvCreateImage( cvSize( img->width * scale, img->height * scale ),
25                  img->depth, img->nChannels );
26       cvResize( img, small, CV_INTER_AREA );
27     }
28   else
29     small = cvCloneImage( img );
30   
31   cvNamedWindow( title, 1 );
32   cvShowImage( title, small );
33   cvReleaseImage( &small );
34 }
View Code

修改后:

void display_big_img(IplImage* img, char* title)
{
    cvNamedWindow(title, 0);   //參數0表示生成的窗口大小可調整,參數1表示窗口自適應圖像而用戶不可調整,所以我選擇參數0
    cvShowImage(title, img);
    cvReleaseImage(&img);
}

 

3. siftfeat.c

注釋掉下面一行:

#include <unistd.h>

原因:顧名思義,unistd.h是unix std的意思,是POSIX標准定義的unix類系統定義符號常量的頭文件,所以在windows下先注釋掉。

然后注釋掉下面這兩個函數:static void arg_parse( int argc, char** argv ) 和 static void usage( char* name )

  1 static void arg_parse( int argc, char** argv )
  2 {
  3   //extract program name from command line (remove path, if present)
  4   pname = basename( argv[0] );
  5 
  6   //parse commandline options
  7   while( 1 )
  8     {
  9       char* arg_check;
 10       int arg = getopt( argc, argv, OPTIONS );
 11       if( arg == -1 )
 12     break;
 13 
 14       switch( arg )
 15     {
 16       // catch unsupplied required arguments and exit
 17     case ':':
 18       fatal_error( "-%c option requires an argument\n"        \
 19                "Try '%s -h' for help.", optopt, pname );
 20       break;
 21 
 22       // read out_file_name
 23     case 'o':
 24       if( ! optarg )
 25         fatal_error( "error parsing arguments at -%c\n"    \
 26              "Try '%s -h' for help.", arg, pname );
 27       out_file_name = optarg;
 28       break;
 29 
 30       // read out_img_name
 31     case 'm':
 32       if( ! optarg )
 33         fatal_error( "error parsing arguments at -%c\n"    \
 34              "Try '%s -h' for help.", arg, pname );
 35       out_img_name = optarg;
 36       break;
 37       
 38       // read intervals
 39     case 'i':
 40       // ensure argument provided
 41       if( ! optarg )
 42         fatal_error( "error parsing arguments at -%c\n"    \
 43              "Try '%s -h' for help.", arg, pname );
 44       
 45       // parse argument and ensure it is an integer
 46       intvls = strtol( optarg, &arg_check, 10 );
 47       if( arg_check == optarg  ||  *arg_check != '\0' )
 48         fatal_error( "-%c option requires an integer argument\n"    \
 49              "Try '%s -h' for help.", arg, pname );
 50       break;
 51       
 52       // read sigma
 53     case 's' :
 54       // ensure argument provided
 55       if( ! optarg )
 56         fatal_error( "error parsing arguments at -%c\n"    \
 57              "Try '%s -h' for help.", arg, pname );
 58       
 59       // parse argument and ensure it is a floating point number
 60       sigma = strtod( optarg, &arg_check );
 61       if( arg_check == optarg  ||  *arg_check != '\0' )
 62         fatal_error( "-%c option requires a floating point argument\n" \
 63              "Try '%s -h' for help.", arg, pname );
 64       break;
 65       
 66       // read contrast_thresh
 67     case 'c' :
 68       // ensure argument provided
 69       if( ! optarg )
 70         fatal_error( "error parsing arguments at -%c\n"    \
 71              "Try '%s -h' for help.", arg, pname );
 72       
 73       // parse argument and ensure it is a floating point number
 74       contr_thr = strtod( optarg, &arg_check );
 75       if( arg_check == optarg  ||  *arg_check != '\0' )
 76         fatal_error( "-%c option requires a floating point argument\n" \
 77              "Try '%s -h' for help.", arg, pname );
 78       break;
 79       
 80       // read curvature_thresh
 81     case 'r' :
 82       // ensure argument provided
 83       if( ! optarg )
 84         fatal_error( "error parsing arguments at -%c\n"    \
 85              "Try '%s -h' for help.", arg, pname );
 86       
 87       // parse argument and ensure it is a floating point number
 88       curv_thr = strtol( optarg, &arg_check, 10 );
 89       if( arg_check == optarg  ||  *arg_check != '\0' )
 90         fatal_error( "-%c option requires an integer argument\n"    \
 91              "Try '%s -h' for help.", arg, pname );
 92       break;
 93       
 94       // read descr_width
 95     case 'n' :
 96       // ensure argument provided
 97       if( ! optarg )
 98         fatal_error( "error parsing arguments at -%c\n"    \
 99              "Try '%s -h' for help.", arg, pname );
100       
101       // parse argument and ensure it is a floating point number
102       descr_width = strtol( optarg, &arg_check, 10 );
103       if( arg_check == optarg  ||  *arg_check != '\0' )
104         fatal_error( "-%c option requires an integer argument\n"    \
105              "Try '%s -h' for help.", arg, pname );
106       break;
107       
108       // read descr_histo_bins
109     case 'b' :
110       // ensure argument provided
111       if( ! optarg )
112         fatal_error( "error parsing arguments at -%c\n"    \
113              "Try '%s -h' for help.", arg, pname );
114       
115       // parse argument and ensure it is a floating point number
116       descr_hist_bins = strtol( optarg, &arg_check, 10 );
117       if( arg_check == optarg  ||  *arg_check != '\0' )
118         fatal_error( "-%c option requires an integer argument\n"    \
119              "Try '%s -h' for help.", arg, pname );
120       break;
121       
122       // read double_image
123     case 'd' :
124       img_dbl = ( img_dbl == 1 )? 0 : 1;
125       break;
126 
127       // read display
128     case 'x' :
129       display = 0;
130       break;
131 
132       // user asked for help
133     case 'h':
134       usage( pname );
135       exit(0);
136       break;
137 
138       // catch invalid arguments
139     default:
140       fatal_error( "-%c: invalid option.\nTry '%s -h' for help.",
141                optopt, pname );
142     }
143     }
144 
145   // make sure an input file is specified
146   if( argc - optind < 1 )
147     fatal_error( "no input file specified.\nTry '%s -h' for help.", pname );
148 
149   // make sure there aren't too many arguments
150   if( argc - optind > 1 )
151     fatal_error( "too many arguments.\nTry '%s -h' for help.", pname );
152 
153   // copy image file name from command line argument
154   img_file_name = argv[optind];
155 }
View Code
 1 static void usage( char* name )
 2 {
 3   fprintf(stderr, "%s: detect SIFT keypoints in an image\n\n", name);
 4   fprintf(stderr, "Usage: %s [options] <img_file>\n", name);
 5   fprintf(stderr, "Options:\n");
 6   fprintf(stderr, "  -h               Display this message and exit\n");
 7   fprintf(stderr, "  -o <out_file>    Output keypoints to text file\n");
 8   fprintf(stderr, "  -m <out_img>     Output keypoint image file (format" \
 9       " determined by extension)\n");
10   fprintf(stderr, "  -i <intervals>   Set number of sampled intervals per" \
11       " octave in scale space\n");
12   fprintf(stderr, "                   pyramid (default %d)\n",
13       SIFT_INTVLS);
14   fprintf(stderr, "  -s <sigma>       Set sigma for initial gaussian"    \
15       " smoothing at each octave\n");
16   fprintf(stderr, "                   (default %06.4f)\n", SIFT_SIGMA);
17   fprintf(stderr, "  -c <thresh>      Set threshold on keypoint contrast" \
18       " |D(x)| based on [0,1]\n");
19   fprintf(stderr, "                   pixel values (default %06.4f)\n",
20       SIFT_CONTR_THR);
21   fprintf(stderr, "  -r <thresh>      Set threshold on keypoint ratio of" \
22       " principle curvatures\n");
23   fprintf(stderr, "                   (default %d)\n", SIFT_CURV_THR);
24   fprintf(stderr, "  -n <width>       Set width of descriptor histogram" \
25       " array (default %d)\n", SIFT_DESCR_WIDTH);
26   fprintf(stderr, "  -b <bins>        Set number of bins per histogram" \
27       " in descriptor array\n");
28   fprintf(stderr, "                   (default %d)\n", SIFT_DESCR_HIST_BINS);
29   fprintf(stderr, "  -d               Toggle image doubling (default %s)\n",
30       SIFT_IMG_DBL == 0 ? "off" : "on");
31   fprintf(stderr, "  -x               Turn off keypoint display\n");
32 }
View Code

注釋原因:此函數是一些控制台操作,其中有許多Unix標准庫提供的函數,而我們不需要。

注釋掉main函數中的:

arg_parse( argc, argv );  

注釋原因:調用了上面那個arg_parse函數。

 

4. imgfeatures.c

在首行加入宏定義:

#define M_PI 3.14159265358979323846

原因:報錯“M_PI”未聲明。

 暫時這么多,可能還有些細節問題,但是很容易解決。

 
        

 

二. 運行程序

好了到目前為止可以進行試驗了,因為上文提到有4個main函數,所以可以分別運行來看看他們到底實現了什么功能。

1. siftfeat.c

利用siftfeat.c進行特征點的檢測,返回檢測到的特征點數目並在圖中標記出。

       

配置好的siftfeat.c文件:

 1 /*
 2   This program detects image features using SIFT keypoints. For more info,
 3   refer to:
 4   
 5   Lowe, D. Distinctive image features from scale-invariant keypoints.
 6   International Journal of Computer Vision, 60, 2 (2004), pp.91--110.
 7   
 8   Copyright (C) 2006-2012  Rob Hess <rob@iqengines.com>
 9 
10   Note: The SIFT algorithm is patented in the United States and cannot be
11   used in commercial products without a license from the University of
12   British Columbia.  For more information, refer to the file LICENSE.ubc
13   that accompanied this distribution.
14 
15   Version: 1.1.2-20100521
16 */
17 
18 #include "sift.h"
19 #include "imgfeatures.h"
20 #include "utils.h"
21 
22 #include <opencv/highgui.h>
23 
24 //#include <unistd.h> //unix 標准頭文件
25 
26 #define OPTIONS ":o:m:i:s:c:r:n:b:dxh"
27 
28 /*************************** Function Prototypes *****************************/
29 
30 static void usage( char* );
31 static void arg_parse( int, char** );
32 
33 /******************************** Globals ************************************/
34 
35 char* pname;
36 char* img_file_name = "G:\\360downloads\\pc.jpg";    //待檢測圖片的絕對路徑
37 char* out_file_name = NULL;   //導出特征點到此文件中
38 char* out_img_name = NULL;   //導出圖片的文件名
39 int intvls = SIFT_INTVLS;
40 double sigma = SIFT_SIGMA;
41 double contr_thr = SIFT_CONTR_THR;
42 int curv_thr = SIFT_CURV_THR;
43 int img_dbl = SIFT_IMG_DBL;
44 int descr_width = SIFT_DESCR_WIDTH;
45 int descr_hist_bins = SIFT_DESCR_HIST_BINS;
46 int display = 1;
47 
48 
49 /********************************** Main *************************************/
50 
51 int main( int argc, char** argv )
52 {
53   IplImage* img;
54   struct feature* features;
55   int n = 0;
56 
57   //arg_parse( argc, argv );
58 
59   fprintf( stderr, "Finding SIFT features...\n" );
60   img = cvLoadImage( img_file_name, 1 );
61   if( ! img )
62     fatal_error( "unable to load image from %s", img_file_name );
63   n = _sift_features( img, &features, intvls, sigma, contr_thr, curv_thr,
64               img_dbl, descr_width, descr_hist_bins );
65   fprintf( stderr, "Found %d features.\n", n );
66   
67   if( display )
68     {
69       draw_features( img, features, n );
70       display_big_img( img, img_file_name );
71       cvWaitKey( 0 );
72     }
73 
74   if( out_file_name != NULL )
75     export_features( out_file_name, features, n );
76 
77   if( out_img_name != NULL )
78     cvSaveImage( out_img_name, img, NULL );
79   return 0;
80 }
View Code

直接運行得到結果:

         

                                                 輸入圖像                                                                                                                                               輸出圖像

可以看到找到了3001個特征點。

 

2. match.c

注意這次調用match中的main函數,所以暫時將siftfeat.c移除。

             

配置好的match.c文件:

  1 /*
  2   Detects SIFT features in two images and finds matches between them.
  3 
  4   Copyright (C) 2006-2012  Rob Hess <rob@iqengines.com>
  5 
  6   @version 1.1.2-20100521
  7 */
  8 
  9 #include "sift.h"
 10 #include "imgfeatures.h"
 11 #include "kdtree.h"
 12 #include "utils.h"
 13 #include "xform.h"
 14 
 15 #include <opencv/cv.h>
 16 #include <opencv/cxcore.h>
 17 #include <opencv/highgui.h>
 18 
 19 #include <stdio.h>
 20 
 21 
 22 /* the maximum number of keypoint NN candidates to check during BBF search */
 23 #define KDTREE_BBF_MAX_NN_CHKS 200
 24 
 25 /* threshold on squared ratio of distances between NN and 2nd NN */
 26 #define NN_SQ_DIST_RATIO_THR 0.49
 27 
 28 
 29 int main( int argc, char** argv )
 30 {
 31   IplImage* img1, * img2, * stacked;
 32   struct feature* feat1, * feat2, * feat;
 33   struct feature** nbrs;
 34   struct kd_node* kd_root;
 35   CvPoint pt1, pt2;
 36   double d0, d1;
 37   int n1, n2, k, i, m = 0;
 38 
 39   if( argc != 3 )
 40     fatal_error( "usage: %s <img1> <img2>", argv[0] );
 41   
 42   img1 = cvLoadImage( argv[1], 1 );
 43   if( ! img1 )
 44     fatal_error( "unable to load image from %s", argv[1] );
 45   img2 = cvLoadImage( argv[2], 1 );
 46   if( ! img2 )
 47     fatal_error( "unable to load image from %s", argv[2] );
 48   stacked = stack_imgs( img1, img2 );
 49 
 50   fprintf( stderr, "Finding features in %s...\n", argv[1] );
 51   n1 = sift_features( img1, &feat1 );
 52   fprintf( stderr, "Finding features in %s...\n", argv[2] );
 53   n2 = sift_features( img2, &feat2 );
 54   fprintf( stderr, "Building kd tree...\n" );
 55   kd_root = kdtree_build( feat2, n2 );
 56   for( i = 0; i < n1; i++ )
 57     {
 58       feat = feat1 + i;
 59       k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );
 60       if( k == 2 )
 61     {
 62       d0 = descr_dist_sq( feat, nbrs[0] );
 63       d1 = descr_dist_sq( feat, nbrs[1] );
 64       if( d0 < d1 * NN_SQ_DIST_RATIO_THR )
 65         {
 66           pt1 = cvPoint( cvRound( feat->x ), cvRound( feat->y ) );
 67           pt2 = cvPoint( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );
 68           pt2.y += img1->height;
 69           cvLine( stacked, pt1, pt2, CV_RGB(255,0,255), 1, 8, 0 );
 70           m++;
 71           feat1[i].fwd_match = nbrs[0];
 72         }
 73     }
 74       free( nbrs );
 75     }
 76 
 77   fprintf( stderr, "Found %d total matches\n", m );
 78   display_big_img( stacked, "Matches" );
 79   cvWaitKey( 0 );
 80 
 81   /* 
 82      UNCOMMENT BELOW TO SEE HOW RANSAC FUNCTION WORKS
 83      
 84      Note that this line above:
 85      
 86      feat1[i].fwd_match = nbrs[0];
 87      
 88      is important for the RANSAC function to work.
 89   */
 90   /*
 91   {
 92     CvMat* H;
 93     IplImage* xformed;
 94     H = ransac_xform( feat1, n1, FEATURE_FWD_MATCH, lsq_homog, 4, 0.01,
 95               homog_xfer_err, 3.0, NULL, NULL );
 96     if( H )
 97       {
 98     xformed = cvCreateImage( cvGetSize( img2 ), IPL_DEPTH_8U, 3 );
 99     cvWarpPerspective( img1, xformed, H, 
100                CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS,
101                cvScalarAll( 0 ) );
102     cvNamedWindow( "Xformed", 1 );
103     cvShowImage( "Xformed", xformed );
104     cvWaitKey( 0 );
105     cvReleaseImage( &xformed );
106     cvReleaseMat( &H );
107       }
108   }
109   */
110 
111   cvReleaseImage( &stacked );
112   cvReleaseImage( &img1 );
113   cvReleaseImage( &img2 );
114   kdtree_release( kd_root );
115   free( feat1 );
116   free( feat2 );
117   return 0;
118 }
match.c

注意運行此程序的方法,以及圖片的存放路徑,具體步驟見博客

例如我的兩張圖片為:pc1.jpg 和 pc2.jpg,此外我都是在debug形式下調試,所以不要搞錯為release。

 

       

                                        pc1.jpg                                                                                                             pc2.jpg

 

直接運行結果:

      

可以看到總共找出1018對匹配點對。

此外其實注意到在match.c中的main函數有一部分代碼被注釋掉了,而這段代碼調用了xform.c,即(RANSAC算法(RANdom SAmple Consensus 隨機抽樣一致))的結果,所以將這部分代碼取消注釋后,直接執行:

/*
  Detects SIFT features in two images and finds matches between them.

  Copyright (C) 2006-2012  Rob Hess <rob@iqengines.com>

  @version 1.1.2-20100521
*/

#include "sift.h"
#include "imgfeatures.h"
#include "kdtree.h"
#include "utils.h"
#include "xform.h"

#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>

#include <stdio.h>


/* the maximum number of keypoint NN candidates to check during BBF search */
#define KDTREE_BBF_MAX_NN_CHKS 200

/* threshold on squared ratio of distances between NN and 2nd NN */
#define NN_SQ_DIST_RATIO_THR 0.49


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;

  if( argc != 3 )
    fatal_error( "usage: %s <img1> <img2>", argv[0] );
  
  img1 = cvLoadImage( argv[1], 1 );
  if( ! img1 )
    fatal_error( "unable to load image from %s", argv[1] );
  img2 = cvLoadImage( argv[2], 1 );
  if( ! img2 )
    fatal_error( "unable to load image from %s", argv[2] );
  stacked = stack_imgs( img1, img2 );

  fprintf( stderr, "Finding features in %s...\n", argv[1] );
  n1 = sift_features( img1, &feat1 );
  fprintf( stderr, "Finding features in %s...\n", argv[2] );
  n2 = sift_features( img2, &feat2 );
  fprintf( stderr, "Building kd tree...\n" );
  kd_root = kdtree_build( feat2, n2 );
  for( i = 0; i < n1; i++ )
    {
      feat = feat1 + i;
      k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );
      if( k == 2 )
    {
      d0 = descr_dist_sq( feat, nbrs[0] );
      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 );
  display_big_img( stacked, "Matches" );
  cvWaitKey( 0 );

  /* 
     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;
    IplImage* xformed;
    H = ransac_xform( feat1, n1, FEATURE_FWD_MATCH, lsq_homog, 4, 0.01,
              homog_xfer_err, 3.0, NULL, NULL );
    if( H )
      {
    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;
}
match.c

 

                                                            匹配結果

 

3. match_num.c

以下頭文件用到了linux下的多線程編程:

#include <pthread.h>

 Linux系統下的多線程遵循POSIX線程接口,稱為pthread。編寫Linux下的多線程程序,需要使用頭文件pthread.h,連接時需要使用庫libpthread.a。暫時不討論。

 

4.dspfeat.c 

以下頭文件用到了linux標准庫:

#include <unistd.h>

這個文件主要作用是可以從預先保存的特征點文件中讀取特征點並顯示在圖片上。暫時用不到不做討論。

 

源碼中除了論文中步驟的實現以外,還有kdtree以及ransac等經典算法值得一看,先挖個坑,待填。

綜上,可以利用sift源碼來實現圖像匹配,其實還可以用來作目標識別、全景圖像拼接、視頻跟蹤等等。

附上我改好的源碼鏈接,可以參考此文,直接運行  sift_c

 

 

參考:

RobHess的SIFT源碼分析:綜述

結合OPENSIFT源碼詳解SIFT算法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM