已经整理了sift算法四个步骤对应的基础理论和代码注释:
第一步:Sift:(第一步)建立高斯差分金字塔_zzz_zzzz_的博客-CSDN博客
第二步:Sift:(第二步)关键点位置的确定_zzz_zzzz_的博客-CSDN博客
第三步:sift:(第三步)为关键点赋予方向_zzz_zzzz_的博客-CSDN博客
第四步:Sift:(第四步)为关键点构造描述符_zzz_zzzz_的博客-CSDN博客
还差一个调用这些函数的、包括Sift实现框架的函数
/**
Finds SIFT features in an image using default parameter values. All
detected features are stored in the array pointed to by \a feat.
@param img the image in which to detect features(初始图像:相当于被相机捕捉到的图像)
@param feat a pointer to an array in which to store detected features(储存特征点)
@return Returns the number of features stored in \a feat or -1 on failure
@see _sift_features()
*/
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 );
}
/**
Finds SIFT features in an image using user-specified parameter values. All
detected features are stored in the array pointed to by \a feat.
@param img the image in which to detect features
@param fea a pointer to an array in which to store detected features
@param intvls the number of intervals sampled per octave of scale space
@param sigma the amount of Gaussian smoothing applied to each image level
before building the scale space representation for an octave
@param cont_thr a threshold on the value of the scale space function
\f$\left|D(\hat{x})\right|\f$, where \f$\hat{x}\f$ is a vector specifying
feature location and scale, used to reject unstable features; assumes
pixel values in the range [0, 1]
@param curv_thr threshold on a feature's ratio of principle curvatures
used to reject features that are too edge-like
@param img_dbl should be 1 if image doubling prior to scale space
construction is desired or 0 if not
@param descr_width the width, \f$n\f$, of the \f$n \times n\f$ array of
orientation histograms used to compute a feature's descriptor
@param descr_hist_bins the number of orientations in each of the
histograms in the array used to compute a feature's descriptor
@return Returns the number of keypoints stored in \a feat or -1 on failure
@see sift_keypoints()
*/
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 */
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 */
//构造高斯金字塔最底层的图像
/*如果img_dbl为1,初始图像先放大再进行sqrt(1.6^2-(2*0.5)^2)的高斯模糊
如果img_dbl为0,初始图像直接进行sqrt(1.6^2*0.5^2)的高斯模糊
这里用的时img_dbl为0 */
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_pyr = build_dog_pyr( gauss_pyr, octvs, intvls );
//第二步:精确极值点定位
storage = cvCreateMemStorage( 0 );
features = scale_space_extrema( dog_pyr, octvs, intvls, contr_thr,
curv_thr, storage );
//计算每个关键点的总尺度、层所在尺度等信息
calc_feature_scales( features, sigma, intvls );
//img_dbl为1时(先扩大了图像的那种情况)
if( img_dbl )
adjust_for_img_dbl( features );//消除扩大图像的影响,回归统一
//第三步:为关键点分配主方向
calc_feature_oris( features, gauss_pyr );
//第四步:构造关键点描述符
compute_descriptors( features, gauss_pyr, descr_width, descr_hist_bins );
/* sort features by decreasing scale and move from CvSeq to array */
//按照特征点尺度大小进行排序(从大尺度到小尺度)
/*调用了自定义的feature_cmp函数,按照sigma排序
feat1<feat2则返回1,feat1>feat2则返回-1,否则返回0
只有返回值为1时,cvSeqsort()才会执行一次位置交换 */
cvSeqSort( features, (CvCmpFunc)feature_cmp, NULL );
n = features->total;//n为特征点总个数
*feat = calloc( n, sizeof(struct feature) );//开辟空间
*feat = cvCvtSeqToArray( features, *feat, CV_WHOLE_SEQ ); //将序列features中的元素拷贝到数组feat中,返回数组指针给feat
//释放特征点数组feat中所有特征点的feature_data成员,因为此成员中的数据在检测完特征点后就没用了
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;//返回特征点个数
}
以上是进行sift的全部流程,除了在前几篇博客中介绍的函数(初始化图像+划分在一、二、三、四步骤中),还有:
//计算特征点的总尺度和层所在尺度的信息
/*
Calculates characteristic scale for each feature in an array.
@param features array of features
@param sigma amount of Gaussian smoothing per octave of scale space
@param intvls intervals per octave of scale space(想从多少张图像中检测极值点)
*/
static void calc_feature_scales( CvSeq* features, double sigma, int intvls )
{
struct feature* feat;
struct detection_data* ddata;
double intvl;
int i, n;
n = features->total;
for( i = 0; i < n; i++ )
{
feat = CV_GET_SEQ_ELEM( struct feature, features, i );
ddata = feat_detection_data( feat );
intvl = ddata->intvl + ddata->subintvl;//精确的尺度
feat->scl = sigma * pow( 2.0, ddata->octv + intvl / intvls );//sigma0*2^(o+s/S)
ddata->scl_octv = sigma * pow( 2.0, intvl / intvls );// sigma0*2^(s/S)
}
}
//img_dbl为1的情况下
/*
Halves feature coordinates and scale in case the input image was doubled
prior to scale space construction.
@param features array of features
*/
static void adjust_for_img_dbl( CvSeq* features )
{
struct feature* feat;
int i, n;
n = features->total;
for( i = 0; i < n; i++ )
{
feat = CV_GET_SEQ_ELEM( struct feature, features, i );
feat->x /= 2.0;
feat->y /= 2.0;
feat->scl /= 2.0;
feat->img_pt.x /= 2.0;
feat->img_pt.y /= 2.0;
}
}
//排序用,根据尺度比较大小返回1,-1或0
/*
Compares features for a decreasing-scale ordering. Intended for use with
CvSeqSort
@param feat1 first feature
@param feat2 second feature
@param param unused
@return Returns 1 if feat1's scale is greater than feat2's, -1 if vice versa,
and 0 if their scales are equal
*/
static int feature_cmp( void* feat1, void* feat2, void* param )
{
struct feature* f1 = (struct feature*) feat1;
struct feature* f2 = (struct feature*) feat2;
if( f1->scl < f2->scl )
return 1;
if( f1->scl > f2->scl )
return -1;
return 0;
}
//释放高斯金字塔空间
/*
De-allocates memory held by a scale space pyramid
@param pyr scale space pyramid
@param octvs number of octaves of scale space
@param n number of images per octave
*/
static void release_pyr( IplImage**** pyr, int octvs, int n )
{
int i, j;
for( i = 0; i < octvs; i++ )
{
for( j = 0; j < n; j++ )
cvReleaseImage( &(*pyr)[i][j] );
free( (*pyr)[i] );
}
free( *pyr );
*pyr = NULL;
}
到这里只是完成了Sift基本内容,关于进一步的实现,还要学习其他相关内容!