/** 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 */ 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 ); //如果最先开始图像的尺寸被加倍了,那么调整features的参数 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 */ cvSeqSort( features, (CvCmpFunc)feature_cmp, NULL ); n = features->total; *feat = calloc( n, sizeof(struct feature) ); *feat = cvCvtSeqToArray( features, *feat, CV_WHOLE_SEQ );//features 里面放的是feature* 数据,所以*feat而不是feat for( i = 0; i < n; i++ )//释放feature结构体中的feature_data,因为已经计算完了,得到了描述子 { 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; }
/** 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; /* build scale space pyramid; smallest dimension of top level is ~4 pixels */ 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 ); 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 */ 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; }
/** 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 feat 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;//原图经初始化后的图像,归一化的32位灰度图 IplImage*** gauss_pyr, *** dog_pyr;//三级指针,高斯金字塔图像组,DoG金字塔图像组 CvMemStorage* storage;//存储器 CvSeq* features;//存储特征点的序列,序列中存放的是struct feature类型的指针 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 */ //██步骤一:██:建立尺度空间,即建立高斯差分(DoG)金字塔dog_pyr //将原图转换为32位灰度图并归一化,然后进行一次高斯平滑,并根据参数img_dbl决定是否将图像尺寸放大为原图的2倍 init_img = create_init_img( img, img_dbl, sigma ); //计算高斯金字塔的组数octvs octvs = log( MIN( init_img->width, init_img->height ) ) / log(2) - 2; //为了保证连续性,在每一层的顶层继续用高斯模糊生成3幅图像,所以高斯金字塔每组有intvls+3层,DOG金字塔每组有intvls+2层 //建立高斯金字塔gauss_pyr,是一个octvs*(intvls+3)的图像数组 gauss_pyr = build_gauss_pyr( init_img, octvs, intvls, sigma ); //建立高斯差分(DoG)金字塔dog_pyr,是一个octvs*(intvls+2)的图像数组 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 ); //计算特征点序列features中每个特征点的尺度 calc_feature_scales( features, sigma, intvls ); //若设置了将图像放大为原图的2倍 if( img_dbl )//将特征点序列中每个特征点的坐标减半(当设置了将图像放大为原图的2倍时,特征点检测完之后调用) 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是自定义的比较函数 cvSeqSort( features, (CvCmpFunc)feature_cmp, NULL ); //将CvSeq类型的特征点序列features转换为通用的struct feature类型的数组feat n = features->total;//特征点个数 *feat = calloc( n, sizeof(struct feature) );//分配控件 //将序列features中的元素拷贝到数组feat中,返回数组指针给feat *feat = cvCvtSeqToArray( features, *feat, CV_WHOLE_SEQ ); //释放特征点数组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;//返回检测到的特征点的个数 }