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,它允許使用變量作為數組的長度定義數組。
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 }
修改后:
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 }

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 }
注釋原因:此函數是一些控制台操作,其中有許多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 }
直接運行得到結果:
輸入圖像 輸出圖像
可以看到找到了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 }
注意運行此程序的方法,以及圖片的存放路徑,具體步驟見博客。
例如我的兩張圖片為: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; }
匹配結果
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
參考: