特征提取函数:

  1. int _sift_features( IplImage* img, struct feature** feat, int intvls,
  2. double sigma, double contr_thr, int curv_thr,
  3. int img_dbl, int descr_width, int descr_hist_bins )
  4. {
  5. IplImage* init_img;
  6. IplImage*** gauss_pyr, *** dog_pyr;
  7. CvMemStorage* storage;
  8. CvSeq* features;
  9. int octvs, i, n = 0;
  10.  
  11. /* check arguments */
  12. if( ! img )
  13. fatal_error( "NULL pointer error, %s, line %d", __FILE__, __LINE__ );
  14.  
  15. if( ! feat )
  16. fatal_error( "NULL pointer error, %s, line %d", __FILE__, __LINE__ );
  17.  
  18. /* build scale space pyramid; smallest dimension of top level is ~4 pixels */
  19. init_img = create_init_img( img, img_dbl, sigma );//创建初始图像,灰度,每位32F(单精度浮点)来存储。
  20. octvs = log( MIN( init_img->width, init_img->height ) ) / log(2) - 2; //从原始图像构建金字塔的层数,-2 使得最小的一层图像有4个像素,而不是1个像素
  21. gauss_pyr = build_gauss_pyr( init_img, octvs, intvls, sigma );//创建高斯金字塔,octvs层数(0层是原图,向上每层降采样一次),intvls每层中尺寸相同但是模糊程度不同,sigma模糊的初始参数,intvals+3
  22. dog_pyr = build_dog_pyr( gauss_pyr, octvs, intvls );//差分金字塔,层数不变,每层中用相邻图像相减,故每层图像数intvls+2
  23.  
  24. storage = cvCreateMemStorage( 0 );
  25. features = scale_space_extrema( dog_pyr, octvs, intvls, contr_thr,
  26. curv_thr, storage );//检测极值点,在同一层中的图片,的一个像素点,如果是相邻另个模糊度图像对应3x3window中的max值(像素>0时),或者为min值(像素<0时),并且经过插值获得亚像素极值点的坐标,测试对比度,边缘影响,最后将该像素对应在原图中的坐标记录到feat中,将所有满足条件的像素的feat串联到featuresSeq中。
  27. calc_feature_scales( features, sigma, intvls );
  28. if( img_dbl )
  29. adjust_for_img_dbl( features );
  30. calc_feature_oris( features, gauss_pyr );
  31. compute_descriptors( features, gauss_pyr, descr_width, descr_hist_bins );
  32.  
  33. /* sort features by decreasing scale and move from CvSeq to array */
  34. cvSeqSort( features, (CvCmpFunc)feature_cmp, NULL );
  35. n = features->total;
  36. *feat = calloc( n, sizeof(struct feature) );
  37. *feat = cvCvtSeqToArray( features, *feat, CV_WHOLE_SEQ );
  38. for( i = 0; i < n; i++ )
  39. {
  40. free( (*feat)[i].feature_data );
  41. (*feat)[i].feature_data = NULL;
  42. }
  43.  
  44. cvReleaseMemStorage( &storage );
  45. cvReleaseImage( &init_img );
  46. release_pyr( &gauss_pyr, octvs, intvls + 3 );
  47. release_pyr( &dog_pyr, octvs, intvls + 2 );
  48. return n;
  49. }

这里的角度值是弧度值

通过计算特征向量的主曲率半径来判断特征是否是边缘which will导致不稳定,即去除边缘响应:

  1. static int is_too_edge_like( IplImage* dog_img, int r, int c, int curv_thr )
  2. {
  3. double d, dxx, dyy, dxy, tr, det;
  4.  
  5. /* principal curvatures are computed using the trace and det of Hessian */
  6. d = pixval32f(dog_img, r, c);
  7. dxx = pixval32f( dog_img, r, c+1 ) + pixval32f( dog_img, r, c-1 ) - 2 * d;
  8. dyy = pixval32f( dog_img, r+1, c ) + pixval32f( dog_img, r-1, c ) - 2 * d;
  9. dxy = ( pixval32f(dog_img, r+1, c+1) - pixval32f(dog_img, r+1, c-1) -
  10. pixval32f(dog_img, r-1, c+1) + pixval32f(dog_img, r-1, c-1) ) / 4.0;
  11. tr = dxx + dyy;
  12. det = dxx * dyy - dxy * dxy;
  13.  
  14. /* negative determinant -> curvatures have different signs; reject feature */
  15. if( det <= 0 )
  16. return 1;
  17.  
  18. if( tr * tr / det < ( curv_thr + 1.0 )*( curv_thr + 1.0 ) / curv_thr )
  19. return 0;
  20. return 1;
  21. }

calc_features_scales函数很简单,就是填充所有特征点对应的scl和scl_octv变量:

  1. static void calc_feature_scales( CvSeq* features, double sigma, int intvls )
  2. {
  3. struct feature* feat;
  4. struct detection_data* ddata;
  5. double intvl;
  6. int i, n;
  7.  
  8. n = features->total;
  9. for( i = 0; i < n; i++ )
  10. {
  11. feat = CV_GET_SEQ_ELEM( struct feature, features, i );
  12. ddata = feat_detection_data( feat );
  13. intvl = ddata->intvl + ddata->subintvl;
  14. feat->scl = sigma * pow( 2.0, ddata->octv + intvl / intvls );
  15. ddata->scl_octv = sigma * pow( 2.0, intvl / intvls );
  16. }
  17. }
  1. 函数adjust_for_img_dbl(),如果在开始的时候将图像dbl扩大了,这是就需要将特征点中的坐标值/2处理:
  1. n = features->total;
  2. for( i = 0; i < n; i++ )
  3. {
  4. feat = CV_GET_SEQ_ELEM( struct feature, features, i );
  5. feat->x /= 2.0;
  6. feat->y /= 2.0;
  7. feat->scl /= 2.0;
  8. feat->img_pt.x /= 2.0;
  9. feat->img_pt.y /= 2.0;
  10. }

在计算机中真是说不清‘2’这个数字有多重要,金字塔中也到处是它:)

下面是计算特征方向的函数:

  1. static void calc_feature_oris( CvSeq* features, IplImage*** gauss_pyr )
  2. {
  3. struct feature* feat;
  4. struct detection_data* ddata;
  5. double* hist;
  6. double omax;
  7. int i, j, n = features->total;
  8.  
  9. for( i = 0; i < n; i++ )
  10. {
  11. feat = malloc( sizeof( struct feature ) );
  12. cvSeqPopFront( features, feat );
  13. ddata = feat_detection_data( feat );
  14. hist = ori_hist( gauss_pyr[ddata->octv][ddata->intvl],
  15. ddata->r, ddata->c, SIFT_ORI_HIST_BINS,
  16. cvRound( SIFT_ORI_RADIUS * ddata->scl_octv ),
  17. SIFT_ORI_SIG_FCTR * ddata->scl_octv );
  18. for( j = 0; j < SIFT_ORI_SMOOTH_PASSES; j++ )
  19. smooth_ori_hist( hist, SIFT_ORI_HIST_BINS );
  20. omax = dominant_ori( hist, SIFT_ORI_HIST_BINS );
  21. add_good_ori_features( features, hist, SIFT_ORI_HIST_BINS,
  22. omax * SIFT_ORI_PEAK_RATIO, feat );
  23. free( ddata );
  24. free( feat );
  25. free( hist );
  26. }
  27. }

还是将每个特征取出来[函数cvSeqPopFront删除序列的头部元素],针对每个特征像素点统计其所在窗口图像中的方向梯度直方图,主要就是函数ori_hist():

aaarticlea/png;base64,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" alt="" />

直方图用一个double数组在存储,统计窗口图像中每个像素所在的dx dy ->梯度的角度和梯度的模,然后将角度转换为hist数组的index,累加值是梯度的模(距离加权后)。窗口的半径大小跟所在的尺度有关。

对得到的hist通过函数smooth_ori_hist()多次进行平滑,也是通过相加求平均的方法。

函数dominant_ori()用来求得直方图中值最大的那个方向的值,然后用这个值乘上一个系数作为阈值用于add_good_ori_fetures()函数:

  1. static void add_good_ori_features( CvSeq* features, double* hist, int n,
  2. double mag_thr, struct feature* feat )
  3. {
  4. struct feature* new_feat;
  5. double bin, PI2 = CV_PI * 2.0;
  6. int l, r, i;
  7.  
  8. for( i = 0; i < n; i++ )
  9. {
  10. l = ( i == 0 )? n - 1 : i-1;
  11. r = ( i + 1 ) % n;
  12.  
  13. if( hist[i] > hist[l] && hist[i] > hist[r] && hist[i] >= mag_thr )
  14. {
  15. bin = i + interp_hist_peak( hist[l], hist[i], hist[r] );
  16. bin = ( bin < 0 )? n + bin : ( bin >= n )? bin - n : bin;
  17. new_feat = clone_feature( feat );
  18. new_feat->ori = ( ( PI2 * bin ) / n ) - CV_PI;
  19. cvSeqPush( features, new_feat );
  20. free( new_feat );
  21. }
  22. }
  23. }

该函数通过遍历整个hist直方图中的所有方向,然后找到局部极值点并且满足阈值的,填充ori变量,构成新特征,然后将此特征再添加会队列中。(可能有多个满足条件的点)

----

好了至此,所有特征点的坐标、所在尺度、其方向都已经得到,就剩下构成特征向量了:

  1. static void compute_descriptors( CvSeq* features, IplImage*** gauss_pyr, int d, int n)
  2. {
  3. struct feature* feat;
  4. struct detection_data* ddata;
  5. double*** hist;
  6. int i, k = features->total;
  7.  
  8. for( i = 0; i < k; i++ )
  9. {
  10. feat = CV_GET_SEQ_ELEM( struct feature, features, i );
  11. ddata = feat_detection_data( feat );
  12. hist = descr_hist( gauss_pyr[ddata->octv][ddata->intvl], ddata->r,
  13. ddata->c, feat->ori, ddata->scl_octv, d, n );
  14. hist_to_descr( hist, d, n, feat );
  15. release_descr_hist( &hist, d );
  16. }
  17. }

这里的descr_hist函数也是计算特征点所在窗口中的梯度方向分布->由于需要具有旋转不变性的特征,所以这里的梯度方向是相对于上面检测出来的特征像素的主方向的角度差来统计的:

函数里面有个坐标变换和求角度差的过程

  1. static double*** descr_hist( IplImage* img, int r, int c, double ori,
  2. double scl, int d, int n )
  3. {
  4. double*** hist;
  5. double cos_t, sin_t, hist_width, exp_denom, r_rot, c_rot, grad_mag,
  6. grad_ori, w, rbin, cbin, obin, bins_per_rad, PI2 = 2.0 * CV_PI;
  7. int radius, i, j;
  8.  
  9. hist = calloc( d, sizeof( double** ) );
  10. for( i = 0; i < d; i++ )
  11. {
  12. hist[i] = calloc( d, sizeof( double* ) );
  13. for( j = 0; j < d; j++ )
  14. hist[i][j] = calloc( n, sizeof( double ) );
  15. }
  16.  
  17. cos_t = cos( ori );
  18. sin_t = sin( ori );
  19. bins_per_rad = n / PI2;
  20. exp_denom = d * d * 0.5;
  21. hist_width = SIFT_DESCR_SCL_FCTR * scl;
  22. radius = hist_width * sqrt(2) * ( d + 1.0 ) * 0.5 + 0.5;
  23. for( i = -radius; i <= radius; i++ )
  24. for( j = -radius; j <= radius; j++ )
  25. {
  26. /*
  27. Calculate sample's histogram array coords rotated relative to ori.
  28. Subtract 0.5 so samples that fall e.g. in the center of row 1 (i.e.
  29. r_rot = 1.5) have full weight placed in row 1 after interpolation.
  30. */
  31. c_rot = ( j * cos_t - i * sin_t ) / hist_width;
  32. r_rot = ( j * sin_t + i * cos_t ) / hist_width;
  33. rbin = r_rot + d / 2 - 0.5;
  34. cbin = c_rot + d / 2 - 0.5;
  35.  
  36. if( rbin > -1.0 && rbin < d && cbin > -1.0 && cbin < d )
  37. if( calc_grad_mag_ori( img, r + i, c + j, &grad_mag, &grad_ori ))
  38. {
  39. grad_ori -= ori;
  40. while( grad_ori < 0.0 )
  41. grad_ori += PI2;
  42. while( grad_ori >= PI2 )
  43. grad_ori -= PI2;
  44.  
  45. obin = grad_ori * bins_per_rad;
  46. w = exp( -(c_rot * c_rot + r_rot * r_rot) / exp_denom );
  47. interp_hist_entry( hist, rbin, cbin, obin, grad_mag * w, d, n );
  48. }
  49. }
  50.  
  51. return hist;
  52. }

遍历窗口中的每一个像素,获得其梯度的新的相对角度,然后在相对坐标系中重新计算梯度方向直方图。这里涉及到一个3次插值,首先新坐标中的row、col、orientation都是浮点数,对

于离散化的图像来说,并不是简单的将其转换为整型数据,要利用精确数据的小数部分对两侧的数据进行加权然后累加。总而言之就是首先获得特征点窗口图像区域的梯度方向直方图,然后

计算新的相对坐标系中的点(浮点数),利用浮点数的小数部分对原梯度直方图中的数据(row、col、ori)进行加权累加到新的梯度直方图中,详见函数interp_hist_entry():

  1. static void interp_hist_entry( double*** hist, double rbin, double cbin,
  2. double obin, double mag, int d, int n )
  3. {
  4. double d_r, d_c, d_o, v_r, v_c, v_o;
  5. double** row, * h;
  6. int r0, c0, o0, rb, cb, ob, r, c, o;
  7.  
  8. r0 = cvFloor( rbin );
  9. c0 = cvFloor( cbin );
  10. o0 = cvFloor( obin );
  11. d_r = rbin - r0;
  12. d_c = cbin - c0;
  13. d_o = obin - o0;
  14.  
  15. /*
  16. The entry is distributed into up to 8 bins. Each entry into a bin
  17. is multiplied by a weight of 1 - d for each dimension, where d is the
  18. distance from the center value of the bin measured in bin units.
  19. */
  20. for( r = 0; r <= 1; r++ )
  21. {
  22. rb = r0 + r;
  23. if( rb >= 0 && rb < d )
  24. {
  25. v_r = mag * ( ( r == 0 )? 1.0 - d_r : d_r );
  26. row = hist[rb];
  27. for( c = 0; c <= 1; c++ )
  28. {
  29. cb = c0 + c;
  30. if( cb >= 0 && cb < d )
  31. {
  32. v_c = v_r * ( ( c == 0 )? 1.0 - d_c : d_c );
  33. h = row[cb];
  34. for( o = 0; o <= 1; o++ )
  35. {
  36. ob = ( o0 + o ) % n;
  37. v_o = v_c * ( ( o == 0 )? 1.0 - d_o : d_o );
  38. h[ob] += v_o;
  39. }
  40. }
  41. }
  42. }
  43. }
  44. }

好了,至此得到了一个三维数组,row、col对应于窗口图像中点的坐标,ori对应于该位置上的直方图,该直方图的ori元素中的值是由相邻亚像素位置的梯度模值加权累加得到的,下面对

这个三维数组进行简单处理得到最终的特征描述descriptor:

  1. static void hist_to_descr( double*** hist, int d, int n, struct feature* feat )
  2. {
  3. int int_val, i, r, c, o, k = 0;
  4.  
  5. for( r = 0; r < d; r++ )
  6. for( c = 0; c < d; c++ )
  7. for( o = 0; o < n; o++ )
  8. feat->descr[k++] = hist[r][c][o];
  9.  
  10. feat->d = k;
  11. normalize_descr( feat );
  12. for( i = 0; i < k; i++ )
  13. if( feat->descr[i] > SIFT_DESCR_MAG_THR )
  14. feat->descr[i] = SIFT_DESCR_MAG_THR;
  15. normalize_descr( feat );
  16.  
  17. /* convert floating-point descriptor to integer valued descriptor */
  18. for( i = 0; i < k; i++ )
  19. {
  20. int_val = SIFT_INT_DESCR_FCTR * feat->descr[i];
  21. feat->descr[i] = MIN( 255, int_val );
  22. }
  23. }

首先简单的将三维存储的数据一维化,然后进行归一化,处理下较大的值,再次归一化,然后将浮点类型的数据展开成0~255的整型特征,这样该特征点对应的sift特征就提取完成了。

整个过程和HOG算法有很多类似的地方,尤其是三次线性插值的过程。

--------------------

至此将适当的处理下数据类型,释放相关的中间变量之后整个_sift_features()特征提取函数就完成了。在调用该函数的时候会传入feat特征的指针,会在_sift_featrues()函数内部进行

特征内存的分配。

SIFT学习笔记之二 特征提取的更多相关文章

  1. 《Java编程思想》学习笔记(二)——类加载及执行顺序

    <Java编程思想>学习笔记(二)--类加载及执行顺序 (这是很久之前写的,保存在印象笔记上,今天写在博客上.) 今天看Java编程思想,看到这样一道代码 //: OrderOfIniti ...

  2. Hibernate学习笔记(二)

    2016/4/22 23:19:44 Hibernate学习笔记(二) 1.1 Hibernate的持久化类状态 1.1.1 Hibernate的持久化类状态 持久化:就是一个实体类与数据库表建立了映 ...

  3. X-Cart 学习笔记(二)X-Cart框架1

    目录 X-Cart 学习笔记(一)了解和安装X-Cart X-Cart 学习笔记(二)X-Cart框架1 X-Cart 学习笔记(三)X-Cart框架2 X-Cart 学习笔记(四)常见操作 四.X- ...

  4. C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)

    上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 请阅读:http://www.cnblogs.com/yunfeifei/p/392 ...

  5. DuiLib学习笔记(二) 扩展CScrollbar属性

    DuiLib学习笔记(二) 扩展CScrollbar属性 Duilib的滚动条滑块默认最小值为滚动条的高度(HScrollbar)或者宽度(VScrollbar).并且这个值默认为16.当采用系统样式 ...

  6. guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用

    guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用 1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection ...

  7. Dynamic CRM 2013学习笔记(二十八)用JS动态设置字段的change事件、必填、禁用以及可见

    我们知道通过界面设置字段的change事件,是否是必填,是否可见非常容易.但有时我们需要动态地根据某些条件来设置,这时有需要通过js来动态地控制了. 下面分别介绍如何用js来动态设置.   一.动态设 ...

  8. Dynamic CRM 2013学习笔记(二十七)无代码 复制/克隆方法

    前面介绍过二种复制/克隆方法:<Dynamic CRM 2013学习笔记(十四)复制/克隆记录> 和<Dynamic CRM 2013学习笔记(二十五)JS调用web service ...

  9. .NET Remoting学习笔记(二)激活方式

    目录 .NET Remoting学习笔记(一)概念 .NET Remoting学习笔记(二)激活方式 .NET Remoting学习笔记(三)信道 参考:百度百科  ♂风车车.Net 激活方式概念 在 ...

随机推荐

  1. 数组排序方法(join()、reverse()、sort())

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. JavaScript有趣的知识点

    JavaScript中总有一些有趣的小知识,而且又是很容易犯错的.我把我遇到的慢慢罗列一下,方便大家避坑 typeof(null)返回的结果是 object " "变成布尔类型为t ...

  3. Java面向对象4(P~U)

    P    3-1 Point类的构造函数 (SDUT 2670) import java.util.Arrays; import java.util.Scanner; public class Mai ...

  4. 1558:聚会 ybt

    1558:聚会 ybt 题解(看似很难,其实要是摸清了实质这就是个大水题) 上题目 1558:聚会 时间限制: 1000 ms         内存限制: 524288 KB提交数: 82     通 ...

  5. MySQL数据分析-(14)表补充:字符集

    大家好,我是jacky朱元禄,很高兴继续跟大家学习<MySQL数据分析实战>,本节课程jacky分享的主题是表补充之字符集 在分享课程之前,jacky在跟大家强调一下逻辑的重要性,我们学习 ...

  6. VUE项目开发流程

    前期准备 安装npm 安装webpack\vue-cli(2.9.6版本--版本不同可能会导致以下一些目录结构以及错误解决办法不符合实际情况) 创建项目 初始化创建项目,项目名称.项目描述.拥有者等等 ...

  7. hive 常用参数

    hive.exec.max.created.files •说明:所有hive运行的map与reduce任务可以产生的文件的和 •默认值:100000  hive.exec.dynamic.partit ...

  8. kotlin set get

    1.类定义属性 默认是public的. 2.var 一个变量,也是就是属性,自动生成set get方法. 3.val 常量,没有set方法. 4. 延迟初始化属性        对于非空类型的属性是必 ...

  9. 如果你的电脑想升级并且支持m.2接口

      便宜啊,赶紧入手.   文章来源:刘俊涛的博客 欢迎关注,有问题一起学习欢迎留言.评论

  10. 数据库中的几个概念 - LGWR, ARCH,ASYNC,SYNC,AFFIRM

    双机热备(双机容错)就是对于重要的服务,使用两台服务器,互相备份,共同执行同一服务.当一台服务器出现故障时,可以由另一台服务器承担服务任务,从而在不需要人工干预的情况下,自动保证系统能持续提供服务 双 ...