SIFT学习笔记之一 下载和调用
下面给出了多个参考地址,挑个能用的吧:
vs2010+Rob Hess SIFT: http://blog.csdn.net/lanbing510/article/details/8507341
Rob Hess主页:http://blogs.oregonstate.edu/hess/
SIFT的实现有好几个版本,Rob Hess的这个也是基于opencv的。
下载地址:http://robwhess.github.io/opensift/
(有windows平台下的和linux平台下的... ...)
sift-latest-win.zip: http://download.csdn.net/detail/rxy429/5812261#
sift-1.1.2_20101207_win:https://code.google.com/p/hlibrary/source/browse/#svn%2Fbranches%2Fsift-1.1.2_20101207_win
shioyng:http://blog.csdn.net/chen825919148/article/details/7685952
一 OpenCV内部的SIFT API:
Opencv中调用SIFT进行特征提取和匹配:
#include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/nonfree/nonfree.hpp> using namespace std; using namespace cv; int main() { initModule_nonfree();//if use SIFT or SURF Ptr<FeatureDetector> detector = FeatureDetector::create("SIFT"); Ptr<DescriptorExtractor> descriptor_extractor = DescriptorExtractor::create("SIFT"); Ptr<DescriptorMatcher> descriptor_matcher = DescriptorMatcher::create("BruteForce"); if (detector.empty() || descriptor_extractor.empty()) throw runtime_error("fail to create detector!"); Mat img1 = imread("d:/src/tc0.bmp");//image in clutter Mat img2 = imread("d:/src/tc1.bmp"); //detect keypoints; vector<KeyPoint> keypoints1, keypoints2; detector->detect(img1, keypoints1); detector->detect(img2, keypoints2); cout << "img1:" << keypoints1.size() << " points img2:" << keypoints2.size() << " points" << endl << ">" << endl; //compute descriptors for keypoints; cout << "< Computing descriptors for keypoints from images..." << endl; Mat descriptors1, descriptors2; descriptor_extractor->compute(img1, keypoints1, descriptors1); descriptor_extractor->compute(img2, keypoints2, descriptors2); cout << endl << "Descriptors Size: " << descriptors2.size() << " >" << endl; cout << endl << "Descriptor's Column: " << descriptors2.cols << endl << "Descriptor's Row: " << descriptors2.rows << endl; cout << ">" << endl; //Draw And Match img1,img2 keypoints Mat img_keypoints1, img_keypoints2; drawKeypoints(img1, keypoints1, img_keypoints1, Scalar::all(-1), 0); drawKeypoints(img2, keypoints2, img_keypoints2, Scalar::all(-1), 0); imshow("Box_in_scene keyPoints", img_keypoints1); imshow("Box keyPoints", img_keypoints2); descriptor_extractor->compute(img1, keypoints1, descriptors1); vector<DMatch> matches; descriptor_matcher->match(descriptors1, descriptors2, matches); Mat img_matches; drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches, Scalar::all(-1), CV_RGB(255, 255, 255), Mat(), 4); imshow("Mathc", img_matches); //waitKey(10000); waitKey(0); return 0; }
二. Rob Hess 的SIFT代码
(widows平台下,c语言版本)代码本站下载
下载下源码后,配置好opencv环境(包括vs中opencv相关的路径和库配置),本文使用的环境是vs2010+opencv244
导入工程后提示升级,升级完成进行编译,如果出现下面的错误:
在utils.c里加上#include <stdarg.h>即可。
代码中已经写好了sift的库函数和相关的调用程序,这里先看调用程序是怎样调用sift函数库的:
1.特征提取程序:
siftFeat工程文件
#include "sift.h" #include "imgfeatures.h" #include "utils.h" #include <highgui.h> #include <stdio.h> /******************************** Globals ************************************/ char* img_file_name = "..\\beaver.png"; char* out_file_name = "..\\beaver.sift";; char* out_img_name = NULL; int display = 1; int intvls = SIFT_INTVLS; //每层图像中不同模糊度的图像个数 double sigma = SIFT_SIGMA; //模糊参数 double contr_thr = SIFT_CONTR_THR; //扫描极值点时,对比度阈值 int curv_thr = SIFT_CURV_THR; //去除边界点时的阈值 int img_dbl = SIFT_IMG_DBL; //初始化图片的时候是否先double一下原始图片 int descr_width = SIFT_DESCR_WIDTH; //对应于特征点的窗口图像的边长 int descr_hist_bins = SIFT_DESCR_HIST_BINS;//对应于梯度方向直方图的下标个数(将360度划分成几个区间) //最后两个参数就决定了特征点的sift特征的int个数width*width*bins /********************************** Main *************************************/ int main( int argc, char** argv ) { IplImage* img; struct feature* features; //仅仅需要定义特征指针,在特征提取函数内部会进行内存的malloc int n = 0; fprintf( stderr, "Finding SIFT features...\n" ); img = cvLoadImage( img_file_name, 1 ); if( ! img ) { fprintf( stderr, "unable to load image from %s", img_file_name ); exit( 1 ); } n = _sift_features( img, &features, intvls, sigma, contr_thr, curv_thr, img_dbl, descr_width, descr_hist_bins ); fprintf( stderr, "Found %d features.\n", n ); if( display ) { draw_features( img, features, n ); cvNamedWindow( img_file_name, 1 ); cvShowImage( img_file_name, img ); cvWaitKey( 0 ); } if( out_file_name != NULL ) export_features( out_file_name, features, n ); if( out_img_name != NULL ) cvSaveImage( out_img_name, img, NULL ); return 0; }
主要为: 加载图像、提取特征、将特征绘制到图像中、显示图像、保存特征到文件中。
其中最关键的就是特征提取函数:
_sift_features( img, &features, intvls, sigma, contr_thr, curv_thr, img_dbl, descr_width, descr_hist_bins );
输入参数:
img为输入图像;
feat为所要提取的特征指针;
intvl指的是高斯金字塔和差分金字塔的层数;
sigma指的是图像初始化过程中高斯模糊所使用的参数;
contr_thr是归一化之后的去除不稳定特征的阈值;
curv_thr指的是去除边缘的特征的主曲率阈值;
img_dbl是是否将图像放大为之前的两倍;
descr_with用来计算特征描述子的方向直方图的宽度;
descr_hist_bins是直方图中的条数
siftFeat.exe运行结果:
将生成的特征保存到文件beaver.sift中:
2.match程序:
match工程文件
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 ); fprintf( stderr, "Finding features in %s...\n", img2_file ); n2 = sift_features( img2, &feat2 ); 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 ); cvNamedWindow( "Matches", 1 ); cvShowImage( "Matches", stacked ); cvWaitKey( 0 );
主要为:导入两幅图像、堆叠到一幅图像中、使用默认参数分别提取sift特征、对特征进行比较、显示图像
首先导入两幅待匹配的图像,然后通过函数stack_imgs将两幅图像堆叠到一幅图像中使图像1位于图像2的顶部。
其中sift_features函数是对_sift_features函数的简单封装,使用默认的参数:(这些默认的参数都在sift.h头文件中)
3. dispFeat
dispFeat工程:
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 ); cvNamedWindow( name, 1 ); cvShowImage( name, img ); cvWaitKey( 0 ); return 0; }
功能很简单就是从特征文件中import入特征,然后通过draw_features函数将特征绘制到图像中显示。
-------
综上,整个sift库中关键的就是 特征提取 + 相似性比较
很好的参考网址(这位作者对函数分析的已经很全面了):http://blog.csdn.net/xizero00/article/details/7328060