RobHess的SIFT源码分析:imgfeatures.h和imgfeatures.c文件

时间:2021-05-08 16:14:29

SIFT源码分析系列文章的索引在这里:RobHess的SIFT源码分析:综述

imgfeatures.h中有SIFT特征点结构struct feature的定义,除此之外还有一些特征点的导入导出以及特征点绘制函数的声明。

对应的imgfeatures.c文件中是特征点的导入导出以及特征点绘制函数的实现。

特征点的类型有两种,一种是是牛津大学VGG提供的源码中的特征点格式,另一种是David.Lowe提供的源码中的特征点格式。

struct feature结构可以兼容这两种特征点格式,但一般用的多的还是Lowe格式的特征点,源码中默认的特征点格式也是Lowe格式的。

特征点结构体struct feature的定义如下

  1. /*特征点结构体
  2. 此结构体可存储2中类型的特征点:
  3. FEATURE_OXFD表示是牛津大学VGG提供的源码中的特征点格式,
  4. FEATURE_LOWE表示是David.Lowe提供的源码中的特征点格式。
  5. 如果是OXFD类型的特征点,结构体中的a,b,c成员描述了特征点周围的仿射区域(椭圆的参数),即邻域。
  6. 如果是LOWE类型的特征点,结构体中的scl和ori成员描述了特征点的大小和方向。
  7. fwd_match,bck_match,mdl_match一般同时只有一个起作用,用来指明此特征点对应的匹配点
  8. */
  9. struct feature
  10. {
  11. double x;                      /**< x coord */ //特征点的x坐标
  12. double y;                      /**< y coord */ //特征点的y坐标
  13. double a;                      /**< Oxford-type affine region parameter */ //OXFD特征点中椭圆的参数
  14. double b;                      /**< Oxford-type affine region parameter */ //OXFD特征点中椭圆的参数
  15. double c;                      /**< Oxford-type affine region parameter */ //OXFD特征点中椭圆的参数
  16. double scl;                    /**< scale of a Lowe-style feature *///LOWE特征点的尺度
  17. double ori;                    /**< orientation of a Lowe-style feature */ //LOWE特征点的方向
  18. int d;                         /**< descriptor length */ //特征描述子的长度,即维数,一般是128
  19. double descr[FEATURE_MAX_D];   /**< descriptor */ //128维的特征描述子,即一个double数组
  20. int type;                      /**< feature type, OXFD or LOWE */ //特征点类型
  21. int category;                  /**< all-purpose feature category */
  22. struct feature* fwd_match;     /**< matching feature from forward image */   //指明此特征点对应的匹配点
  23. struct feature* bck_match;     /**< matching feature from backmward image */ //指明此特征点对应的匹配点
  24. struct feature* mdl_match;     /**< matching feature from model */           //指明此特征点对应的匹配点
  25. CvPoint2D64f img_pt;           /**< location in image */ //特征点的坐标,等于(x,y)
  26. CvPoint2D64f mdl_pt;           /**< location in model */ //当匹配类型是mdl_match时用到
  27. void* feature_data;            /**< user-definable data */ //用户定义的数据:
  28. //在SIFT极值点检测中,是detection_data结构的指针
  29. //在k-d树搜索中,是bbf_data结构的指针
  30. //在RANSAC算法中,是ransac_data结构的指针
  31. };

将Lowe格式的特征点导出到txt文件后,文件的格式如下图

RobHess的SIFT源码分析:imgfeatures.h和imgfeatures.c文件

第一行的两个数分别是特征点的总个数(上图只截取了2个特征描述子)和特征描述子的维数(默认是128)

然后是每个特征点的数据,每个特征点的第一行的四个数分别是:特征点的y坐标,x坐标,特征点的尺度,特征点的方向

然后是128个整数,即128维的特征描述子,共7行,前6行每行20个,最后一行8个。

默认情况下,检测出的特征点是按照尺度的降序排列的。

下面是imgfeatures.h和imgfeatures.c文件的注释:

imgfeatures.h

  1. /**@file
  2. Functions and structures for dealing with image features
  3. Copyright (C) 2006-2010  Rob Hess <hess@eecs.oregonstate.edu>
  4. @version 1.1.2-20100521
  5. */
  6. /*
  7. 此文件中定义了存储特征点的结构体feature,以及几个函数原型的声明:
  8. 1、特征点的导入导出
  9. 2、特征点绘制
  10. */
  11. #ifndef IMGFEATURES_H
  12. #define IMGFEATURES_H
  13. #include "cxcore.h"
  14. /*特征点的类型:
  15. FEATURE_OXFD表示是牛津大学VGG提供的源码中的特征点格式,
  16. FEATURE_LOWE表示是David.Lowe提供的源码中的特征点格式
  17. */
  18. /** FEATURE_OXFD <BR> FEATURE_LOWE */
  19. enum feature_type
  20. {
  21. FEATURE_OXFD,
  22. FEATURE_LOWE,
  23. };
  24. /*特征点匹配类型:
  25. FEATURE_FWD_MATCH:表明feature结构中的fwd_match域是对应的匹配点
  26. FEATURE_BCK_MATCH:表明feature结构中的bck_match域是对应的匹配点
  27. FEATURE_MDL_MATCH:表明feature结构中的mdl_match域是对应的匹配点
  28. */
  29. /** FEATURE_FWD_MATCH <BR> FEATURE_BCK_MATCH <BR> FEATURE_MDL_MATCH */
  30. enum feature_match_type
  31. {
  32. FEATURE_FWD_MATCH,
  33. FEATURE_BCK_MATCH,
  34. FEATURE_MDL_MATCH,
  35. };
  36. /*画出的特征点的颜色*/
  37. /* colors in which to display different feature types */
  38. #define FEATURE_OXFD_COLOR CV_RGB(255,255,0)
  39. #define FEATURE_LOWE_COLOR CV_RGB(255,0,255)
  40. /*最大特征描述子长度,定为128*/
  41. /** max feature descriptor length */
  42. #define FEATURE_MAX_D 128
  43. /*特征点结构体
  44. 此结构体可存储2中类型的特征点:
  45. FEATURE_OXFD表示是牛津大学VGG提供的源码中的特征点格式,
  46. FEATURE_LOWE表示是David.Lowe提供的源码中的特征点格式。
  47. 如果是OXFD类型的特征点,结构体中的a,b,c成员描述了特征点周围的仿射区域(椭圆的参数),即邻域。
  48. 如果是LOWE类型的特征点,结构体中的scl和ori成员描述了特征点的大小和方向。
  49. fwd_match,bck_match,mdl_match一般同时只有一个起作用,用来指明此特征点对应的匹配点
  50. */
  51. /**
  52. Structure to represent an affine invariant image feature.  The fields
  53. x, y, a, b, c represent the affine region around the feature:
  54. a(x-u)(x-u) + 2b(x-u)(y-v) + c(y-v)(y-v) = 1
  55. */
  56. struct feature
  57. {
  58. double x;                      /**< x coord */ //特征点的x坐标
  59. double y;                      /**< y coord */ //特征点的y坐标
  60. double a;                      /**< Oxford-type affine region parameter */ //OXFD特征点中椭圆的参数
  61. double b;                      /**< Oxford-type affine region parameter */ //OXFD特征点中椭圆的参数
  62. double c;                      /**< Oxford-type affine region parameter */ //OXFD特征点中椭圆的参数
  63. double scl;                    /**< scale of a Lowe-style feature *///LOWE特征点的尺度
  64. double ori;                    /**< orientation of a Lowe-style feature */ //LOWE特征点的方向
  65. int d;                         /**< descriptor length */ //特征描述子的长度,即维数,一般是128
  66. double descr[FEATURE_MAX_D];   /**< descriptor */ //128维的特征描述子,即一个double数组
  67. int type;                      /**< feature type, OXFD or LOWE */ //特征点类型
  68. int category;                  /**< all-purpose feature category */
  69. struct feature* fwd_match;     /**< matching feature from forward image */   //指明此特征点对应的匹配点
  70. struct feature* bck_match;     /**< matching feature from backmward image */ //指明此特征点对应的匹配点
  71. struct feature* mdl_match;     /**< matching feature from model */           //指明此特征点对应的匹配点
  72. CvPoint2D64f img_pt;           /**< location in image */ //特征点的坐标,等于(x,y)
  73. CvPoint2D64f mdl_pt;           /**< location in model */ //当匹配类型是mdl_match时用到
  74. void* feature_data;            /**< user-definable data */ //用户定义的数据:
  75. //在SIFT极值点检测中,是detection_data结构的指针
  76. //在k-d树搜索中,是bbf_data结构的指针
  77. //在RANSAC算法中,是ransac_data结构的指针
  78. };
  79. /*从文件中读入图像特征
  80. 文件中的特征点格式必须是FEATURE_OXFD或FEATURE_LOWE格式
  81. 参数:
  82. filename:文件名
  83. type:特征点类型
  84. feat:用来存储特征点的feature数组的指针
  85. 返回值:导入的特征点个数
  86. */
  87. /**
  88. Reads image features from file.  The file should be formatted as from
  89. the code provided by the Visual Geometry Group at Oxford or from the
  90. code provided by David Lowe.
  91. @param filename location of a file containing image features
  92. @param type determines how features are input.  If \a type is FEATURE_OXFD,
  93. the input file is treated as if it is from the code provided by the VGG
  94. at Oxford: http://www.robots.ox.ac.uk:5000/~vgg/research/affine/index.html
  95. <BR><BR>
  96. If \a type is FEATURE_LOWE, the input file is treated as if it is from
  97. David Lowe's SIFT code: http://www.cs.ubc.ca/~lowe/keypoints
  98. @param feat pointer to an array in which to store imported features; memory for
  99. this array is allocated by this function and must be freed by the caller using free(*feat)
  100. @return Returns the number of features imported from filename or -1 on error
  101. */
  102. extern int import_features( char* filename, int type, struct feature** feat );
  103. /*导出feature数组到文件
  104. 参数:
  105. filename:文件名
  106. feat:特征数组
  107. n:特征点个数
  108. 返回值:0:成功;1:失败
  109. */
  110. /**
  111. Exports a feature set to a file formatted depending on the type of
  112. features, as specified in the feature struct's type field.
  113. @param filename name of file to which to export features
  114. @param feat feature array
  115. @param n number of features
  116. @return Returns 0 on success or 1 on error
  117. */
  118. extern int export_features( char* filename, struct feature* feat, int n );
  119. /*在图片上画出特征点
  120. 参数:
  121. img:图像
  122. feat:特征点数组
  123. n:特征点个数
  124. */
  125. /**
  126. Displays a set of features on an image
  127. @param img image on which to display features
  128. @param feat array of Oxford-type features
  129. @param n number of features
  130. */
  131. extern void draw_features( IplImage* img, struct feature* feat, int n );
  132. /*计算两个特征描述子间的欧氏距离的平方
  133. 参数:
  134. f1:第一个特征点
  135. f2:第二个特征点
  136. 返回值:欧氏距离的平方
  137. */
  138. /**
  139. Calculates the squared Euclidian distance between two feature descriptors.
  140. @param f1 first feature
  141. @param f2 second feature
  142. @return Returns the squared Euclidian distance between the descriptors of
  143. \a f1 and \a f2.
  144. */
  145. extern double descr_dist_sq( struct feature* f1, struct feature* f2 );
  146. #endif

imgfeatures.c文件

  1. /*
  2. Functions and structures for dealing with image features
  3. Copyright (C) 2006-2010  Rob Hess <hess@eecs.oregonstate.edu>
  4. @version 1.1.2-20100521
  5. */
  6. /*
  7. 此文件中有几个函数的实现:特征点的导入导出,特征点的绘制
  8. */
  9. #include "utils.h"
  10. #include "imgfeatures.h"
  11. #include <cxcore.h>
  12. #include <math.h>
  13. /************************ 未暴露接口的一些本地函数的声明 **************************/
  14. static int import_oxfd_features( char*, struct feature** );//导入OXFD格式特征点
  15. static int export_oxfd_features( char*, struct feature*, int );//导出OXFD格式特征点
  16. static void draw_oxfd_features( IplImage*, struct feature*, int );//画OXFD格式特征点
  17. static void draw_oxfd_feature( IplImage*, struct feature*, CvScalar );//画单个点
  18. static int import_lowe_features( char*, struct feature** );//导入LOWE格式特征点
  19. static int export_lowe_features( char*, struct feature*, int );//导出LOWE格式特征点
  20. static void draw_lowe_features( IplImage*, struct feature*, int );//画LOWE格式特征点
  21. static void draw_lowe_feature( IplImage*, struct feature*, CvScalar );//画单个点
  22. /*从文件中读入图像特征
  23. 文件中的特征点格式必须是FEATURE_OXFD或FEATURE_LOWE格式
  24. 参数:
  25. filename:文件名
  26. type:特征点类型
  27. feat:用来存储特征点的feature数组的指针
  28. 返回值:导入的特征点个数
  29. */
  30. /*
  31. Reads image features from file.  The file should be formatted as from
  32. the code provided by the Visual Geometry Group at Oxford:
  33. @param filename location of a file containing image features
  34. @param type determines how features are input.  If \a type is FEATURE_OXFD,
  35. the input file is treated as if it is from the code provided by the VGG
  36. at Oxford:http://www.robots.ox.ac.uk:5000/~vgg/research/affine/index.html
  37. If \a type is FEATURE_LOWE, the input file is treated as if it is from
  38. David Lowe's SIFT code:http://www.cs.ubc.ca/~lowe/keypoints
  39. @param feat pointer to an array in which to store features
  40. @return Returns the number of features imported from filename or -1 on error
  41. */
  42. int import_features( char* filename, int type, struct feature** feat )
  43. {
  44. int n;
  45. //根据特征点类型,调用不同的函数完成导入功能
  46. switch( type )
  47. {
  48. case FEATURE_OXFD:
  49. n = import_oxfd_features( filename, feat );//调用函数,导入OXFD格式特征点
  50. break;
  51. case FEATURE_LOWE:
  52. n = import_lowe_features( filename, feat );//调用函数,导入LOWE格式特征点
  53. break;
  54. default: //特征点格式无法识别
  55. fprintf( stderr, "Warning: import_features(): unrecognized feature" \
  56. "type, %s, line %d\n", __FILE__, __LINE__ );
  57. return -1;
  58. }
  59. //导入失败
  60. if( n == -1 )
  61. fprintf( stderr, "Warning: unable to import features from %s,"  \
  62. " %s, line %d\n", filename, __FILE__, __LINE__ );
  63. return n;
  64. }
  65. /*导出feature数组到文件
  66. 参数:
  67. filename:文件名
  68. feat:特征数组
  69. n:特征点个数
  70. 返回值:0:成功;1:失败
  71. */
  72. /*
  73. Exports a feature set to a file formatted depending on the type of
  74. features, as specified in the feature struct's type field.
  75. @param filename name of file to which to export features
  76. @param feat feature array
  77. @param n number of features
  78. @return Returns 0 on success or 1 on error
  79. */
  80. int export_features( char* filename, struct feature* feat, int n )
  81. {
  82. int r, type;
  83. //参数合法性检查
  84. if( n <= 0  ||  ! feat )
  85. {
  86. fprintf( stderr, "Warning: no features to export, %s line %d\n",
  87. __FILE__, __LINE__ );
  88. return 1;
  89. }
  90. type = feat[0].type;//特征点的类型、
  91. //根据特征点类型,调用不同的函数完成导出功能
  92. switch( type )
  93. {
  94. case FEATURE_OXFD:
  95. r = export_oxfd_features( filename, feat, n );//调用函数,导出OXFD格式特征点
  96. break;
  97. case FEATURE_LOWE:
  98. r = export_lowe_features( filename, feat, n );//调用函数,导出LOWE格式特征点
  99. break;
  100. default:
  101. fprintf( stderr, "Warning: export_features(): unrecognized feature" \
  102. "type, %s, line %d\n", __FILE__, __LINE__ );
  103. return -1;
  104. }
  105. if( r ) //导出函数返回值非0,表示导出失败
  106. fprintf( stderr, "Warning: unable to export features to %s,"    \
  107. " %s, line %d\n", filename, __FILE__, __LINE__ );
  108. return r;
  109. }
  110. /*在图片上画出特征点
  111. 参数:
  112. img:图像
  113. feat:特征点数组
  114. n:特征点个数
  115. */
  116. /*
  117. Draws a set of features on an image
  118. @param img image on which to draw features
  119. @param feat array of features
  120. @param n number of features
  121. */
  122. void draw_features( IplImage* img, struct feature* feat, int n )
  123. {
  124. int type;
  125. //参数合法性检查
  126. if( n <= 0  ||  ! feat )
  127. {
  128. fprintf( stderr, "Warning: no features to draw, %s line %d\n",
  129. __FILE__, __LINE__ );
  130. return;
  131. }
  132. type = feat[0].type;//特征点的类型
  133. //根据特征点类型,调用不同的函数完成绘图功能
  134. switch( type )
  135. {
  136. case FEATURE_OXFD:
  137. draw_oxfd_features( img, feat, n );//调用函数,在图像上画OXFD格式特征点
  138. break;
  139. case FEATURE_LOWE:
  140. draw_lowe_features( img, feat, n );//调用函数,在图像上画LOWE格式特征点
  141. break;
  142. default:
  143. fprintf( stderr, "Warning: draw_features(): unrecognized feature" \
  144. " type, %s, line %d\n", __FILE__, __LINE__ );
  145. break;
  146. }
  147. }
  148. /*计算两个特征描述子间的欧氏距离的平方
  149. 参数:
  150. f1:第一个特征点
  151. f2:第二个特征点
  152. 返回值:欧氏距离的平方
  153. */
  154. /*
  155. Calculates the squared Euclidian distance between two feature descriptors.
  156. @param f1 first feature
  157. @param f2 second feature
  158. @return Returns the squared Euclidian distance between the descriptors off1 and f2.
  159. */
  160. double descr_dist_sq( struct feature* f1, struct feature* f2 )
  161. {
  162. double diff, dsq = 0;
  163. double* descr1, * descr2;
  164. int i, d;
  165. d = f1->d;//f1的特征描述子的长度
  166. if( f2->d != d )//若f1和f2的特征描述子长度不同,返回
  167. return DBL_MAX;
  168. descr1 = f1->descr;//f1的特征描述子,一个double数组
  169. descr2 = f2->descr;//f2的特征描述子,一个double数组
  170. //计算欧氏距离的平方,即对应元素的差的平方和
  171. for( i = 0; i < d; i++ )
  172. {
  173. diff = descr1[i] - descr2[i];
  174. dsq += diff*diff;
  175. }
  176. return dsq;
  177. }
  178. /***************************** 一些未暴露接口的内部函数 *******************************/
  179. /***************************** Local Functions *******************************/
  180. /*从文件中读入OXFD格式的图像特征
  181. 参数:
  182. filename:文件名
  183. features:用来存储特征点的feature数组的指针
  184. 返回值:导入的特征点个数
  185. */
  186. /*
  187. Reads image features from file.  The file should be formatted as from
  188. the code provided by the Visual Geometry Group at Oxford:
  189. http://www.robots.ox.ac.uk:5000/~vgg/research/affine/index.html
  190. @param filename location of a file containing image features
  191. @param features pointer to an array in which to store features
  192. @return Returns the number of features imported from filename or -1 on error
  193. */
  194. static int import_oxfd_features( char* filename, struct feature** features )
  195. {
  196. struct feature* f;//第一个特征点的指针
  197. int i, j, n, d;
  198. double x, y, a, b, c, dv;
  199. FILE* file;//文件指针
  200. if( ! features )
  201. fatal_error( "NULL pointer error, %s, line %d",  __FILE__, __LINE__ );
  202. //打开文件
  203. if( ! ( file = fopen( filename, "r" ) ) )
  204. {
  205. fprintf( stderr, "Warning: error opening %s, %s, line %d\n",
  206. filename, __FILE__, __LINE__ );
  207. return -1;
  208. }
  209. //读入特征描述子维数和特征点个数
  210. /* read dimension and number of features */
  211. if( fscanf( file, " %d %d ", &d, &n ) != 2 )
  212. {
  213. fprintf( stderr, "Warning: file read error, %s, line %d\n",
  214. __FILE__, __LINE__ );
  215. return -1;
  216. }
  217. //特征描述子维数大于定义的最大维数,出错
  218. if( d > FEATURE_MAX_D )
  219. {
  220. fprintf( stderr, "Warning: descriptor too long, %s, line %d\n",
  221. __FILE__, __LINE__ );
  222. return -1;
  223. }
  224. //分配内存,n个feature结构大小,返回首地址给f
  225. f = calloc( n, sizeof(struct feature) );
  226. //遍历文件中的n个特征点
  227. for( i = 0; i < n; i++ )
  228. {
  229. //读入仿射区域参数
  230. /* read affine region parameters */
  231. if( fscanf( file, " %lf %lf %lf %lf %lf ", &x, &y, &a, &b, &c ) != 5 )
  232. {
  233. fprintf( stderr, "Warning: error reading feature #%d, %s, line %d\n",
  234. i+1, __FILE__, __LINE__ );
  235. free( f );//发生错误后释放内存
  236. return -1;
  237. }
  238. //给第i个特征点赋值
  239. f[i].img_pt.x = f[i].x = x;//特征点的x坐标
  240. f[i].img_pt.y = f[i].y = y;//特征点的y坐标
  241. f[i].a = a;
  242. f[i].b = b;
  243. f[i].c = c;
  244. f[i].d = d;
  245. f[i].type = FEATURE_OXFD;//特征点类型
  246. //读入特征描述子
  247. /* read descriptor */
  248. for( j = 0; j < d; j++ )
  249. {
  250. if( ! fscanf( file, " %lf ", &dv ) )
  251. {
  252. fprintf( stderr, "Warning: error reading feature descriptor" \
  253. " #%d, %s, line %d\n", i+1, __FILE__, __LINE__ );
  254. free( f );//发生错误后释放内存
  255. return -1;
  256. }
  257. f[i].descr[j] = dv;//赋给第i个特征点的第j个特征描述符
  258. }
  259. //其他一些没什么用的参数
  260. f[i].scl = f[i].ori = 0;//OXFD特征点无此参数
  261. f[i].category = 0;
  262. f[i].fwd_match = f[i].bck_match = f[i].mdl_match = NULL;
  263. f[i].mdl_pt.x = f[i].mdl_pt.y = -1;
  264. f[i].feature_data = NULL;
  265. }
  266. //关闭文件
  267. if( fclose(file) )
  268. {
  269. fprintf( stderr, "Warning: file close error, %s, line %d\n",
  270. __FILE__, __LINE__ );
  271. free( f );//发生错误后释放内存
  272. return -1;
  273. }
  274. *features = f;//将第一个特征点的指针赋给*feature
  275. return n;//返回读入的特征点个数
  276. }
  277. /*导出OXFD格式的特征点集到文件
  278. 参数:
  279. filename:文件名
  280. feat:特征数组
  281. n:特征点个数
  282. 返回值:0:成功;1:失败
  283. */
  284. /*
  285. Exports a feature set to a file formatted as one from the code provided
  286. by the Visual Geometry Group at Oxford:
  287. http://www.robots.ox.ac.uk:5000/~vgg/research/affine/index.html
  288. @param filename name of file to which to export features
  289. @param feat feature array
  290. @param n number of features
  291. @return Returns 0 on success or 1 on error
  292. */
  293. static int export_oxfd_features( char* filename, struct feature* feat, int n )
  294. {
  295. FILE* file;
  296. int i, j, d;
  297. if( n <= 0 )
  298. {
  299. fprintf( stderr, "Warning: feature count %d, %s, line %s\n",
  300. n, __FILE__, __LINE__ );
  301. return 1;
  302. }
  303. //打开文件
  304. if( ! ( file = fopen( filename, "w" ) ) )
  305. {
  306. fprintf( stderr, "Warning: error opening %s, %s, line %d\n",
  307. filename, __FILE__, __LINE__ );
  308. return 1;
  309. }
  310. d = feat[0].d;//特征描述子的维数
  311. fprintf( file, "%d\n%d\n", d, n );//首先写入特征描述子的维数和特征点个数
  312. //依次写入每个特征点的信息
  313. for( i = 0; i < n; i++ )
  314. {
  315. //写入仿射区域参数
  316. fprintf( file, "%f %f %f %f %f", feat[i].x, feat[i].y, feat[i].a,
  317. feat[i].b, feat[i].c );
  318. //写入d个特征描述子的元素
  319. for( j = 0; j < d; j++ )
  320. fprintf( file, " %f", feat[i].descr[j] );
  321. fprintf( file, "\n" );//换行
  322. }
  323. //关闭文件
  324. if( fclose(file) )
  325. {
  326. fprintf( stderr, "Warning: file close error, %s, line %d\n",
  327. __FILE__, __LINE__ );
  328. return 1;
  329. }
  330. return 0;
  331. }
  332. /*在图像上画出OXFD类型的特征点
  333. 参数:
  334. img:图像指针
  335. feat:特征数组
  336. n:特征个数
  337. */
  338. /*
  339. Draws Oxford-type affine features
  340. @param img image on which to draw features
  341. @param feat array of Oxford-type features
  342. @param n number of features
  343. */
  344. static void draw_oxfd_features( IplImage* img, struct feature* feat, int n )
  345. {
  346. CvScalar color = CV_RGB( 255, 255, 255 );//颜色
  347. int i;
  348. if( img-> nChannels > 1 )
  349. color = FEATURE_OXFD_COLOR;
  350. //调用函数,依次画出每个特征点
  351. for( i = 0; i < n; i++ )
  352. draw_oxfd_feature( img, feat + i, color );
  353. }
  354. /*在图像上画单个OXFD特征点
  355. 参数:
  356. img:图像指针
  357. feat:要画的特征点
  358. color:颜色
  359. */
  360. /*
  361. Draws a single Oxford-type feature
  362. @param img image on which to draw
  363. @param feat feature to be drawn
  364. @param color color in which to draw
  365. */
  366. static void draw_oxfd_feature( IplImage* img, struct feature* feat, CvScalar color )
  367. {
  368. double m[4] = { feat->a, feat->b, feat->b, feat->c };
  369. double v[4] = { 0 };//特征向量的数据
  370. double e[2] = { 0 };//特征值的数据
  371. CvMat M, V, E;
  372. double alpha, l1, l2;
  373. //计算椭圆的轴线和方向
  374. /* compute axes and orientation of ellipse surrounding affine region */
  375. cvInitMatHeader( &M, 2, 2, CV_64FC1, m, CV_AUTOSTEP );//矩阵
  376. cvInitMatHeader( &V, 2, 2, CV_64FC1, v, CV_AUTOSTEP );//2个2*1的特征向量组成的矩阵
  377. cvInitMatHeader( &E, 2, 1, CV_64FC1, e, CV_AUTOSTEP );//特征值
  378. cvEigenVV( &M, &V, &E, DBL_EPSILON, 0, 0 );//计算特征值和特征向量
  379. l1 = 1 / sqrt( e[1] );
  380. l2 = 1 / sqrt( e[0] );
  381. alpha = -atan2( v[1], v[0] );
  382. alpha *= 180 / CV_PI;
  383. //画椭圆和十字星
  384. cvEllipse( img, cvPoint( feat->x, feat->y ), cvSize( l2, l1 ), alpha,
  385. 0, 360, CV_RGB(0,0,0), 3, 8, 0 );
  386. cvEllipse( img, cvPoint( feat->x, feat->y ), cvSize( l2, l1 ), alpha,
  387. 0, 360, color, 1, 8, 0 );
  388. cvLine( img, cvPoint( feat->x+2, feat->y ), cvPoint( feat->x-2, feat->y ),
  389. color, 1, 8, 0 );
  390. cvLine( img, cvPoint( feat->x, feat->y+2 ), cvPoint( feat->x, feat->y-2 ),
  391. color, 1, 8, 0 );
  392. }
  393. /*从文件中读入LOWE特征点
  394. 参数:
  395. filename:文件名
  396. features:存放特征点的特征数组的指针
  397. 返回值:读入的特征点个数
  398. */
  399. /*
  400. Reads image features from file.  The file should be formatted as from
  401. the code provided by David Lowe:http://www.cs.ubc.ca/~lowe/keypoints/
  402. @param filename location of a file containing image features
  403. @param features pointer to an array in which to store features
  404. @return Returns the number of features imported from filename or -1 on error
  405. */
  406. static int import_lowe_features( char* filename, struct feature** features )
  407. {
  408. struct feature* f;//第一个特征点的指针
  409. int i, j, n, d;
  410. double x, y, s, o, dv;
  411. FILE* file;
  412. if( ! features )
  413. fatal_error( "NULL pointer error, %s, line %d",  __FILE__, __LINE__ );
  414. //打开文件
  415. if( ! ( file = fopen( filename, "r" ) ) )
  416. {
  417. fprintf( stderr, "Warning: error opening %s, %s, line %d\n",
  418. filename, __FILE__, __LINE__ );
  419. return -1;
  420. }
  421. //首先读入特征点个数和特征描述子维数
  422. /* read number of features and dimension */
  423. if( fscanf( file, " %d %d ", &n, &d ) != 2 )
  424. {
  425. fprintf( stderr, "Warning: file read error, %s, line %d\n",
  426. __FILE__, __LINE__ );
  427. return -1;
  428. }
  429. //特征描述子维数大于定义的最大维数,出错
  430. if( d > FEATURE_MAX_D )
  431. {
  432. fprintf( stderr, "Warning: descriptor too long, %s, line %d\n",
  433. __FILE__, __LINE__ );
  434. return -1;
  435. }
  436. //分配内存,n个feature结构大小,返回首地址给f
  437. f = calloc( n, sizeof(struct feature) );
  438. //依次读入n个特征点
  439. for( i = 0; i < n; i++ )
  440. {
  441. //读入特征点的坐标(注意x,y顺序),尺度和方向
  442. /* read affine region parameters */
  443. if( fscanf( file, " %lf %lf %lf %lf ", &y, &x, &s, &o ) != 4 )
  444. {
  445. fprintf( stderr, "Warning: error reading feature #%d, %s, line %d\n",
  446. i+1, __FILE__, __LINE__ );
  447. free( f );//出错后释放内存
  448. return -1;
  449. }
  450. //给第i个特征点赋值
  451. f[i].img_pt.x = f[i].x = x;//特征点的x坐标
  452. f[i].img_pt.y = f[i].y = y;//特征点的y坐标
  453. f[i].scl = s;//特征点的大小,即其主方向的梯度的模值
  454. f[i].ori = o;//特征点的方向,即其主方向
  455. f[i].d = d;//特征描述子的维数
  456. f[i].type = FEATURE_LOWE;//类型
  457. //读入特征描述子
  458. /* read descriptor */
  459. for( j = 0; j < d; j++ )
  460. {
  461. if( ! fscanf( file, " %lf ", &dv ) )
  462. {
  463. fprintf( stderr, "Warning: error reading feature descriptor" \
  464. " #%d, %s, line %d\n", i+1, __FILE__, __LINE__ );
  465. free( f );//出错后释放内存
  466. return -1;
  467. }
  468. f[i].descr[j] = dv;
  469. }
  470. //其他一些没什么用的参数
  471. f[i].a = f[i].b = f[i].c = 0;
  472. f[i].category = 0;
  473. f[i].fwd_match = f[i].bck_match = f[i].mdl_match = NULL;
  474. f[i].mdl_pt.x = f[i].mdl_pt.y = -1;
  475. }
  476. //关闭文件
  477. if( fclose(file) )
  478. {
  479. fprintf( stderr, "Warning: file close error, %s, line %d\n",
  480. __FILE__, __LINE__ );
  481. free( f );//出错后释放内存
  482. return -1;
  483. }
  484. *features = f;//首地址赋给*features
  485. return n;//返回读入的特征点个数
  486. }
  487. /*导出LOWE格式特征点集合到文件
  488. 参数:
  489. filename:文件名
  490. feat:特征点数组
  491. n:特征点个数
  492. 返回值:0:成功;1:失败
  493. */
  494. /*
  495. Exports a feature set to a file formatted as one from the code provided
  496. by David Lowe:http://www.cs.ubc.ca/~lowe/keypoints/
  497. @param filename name of file to which to export features
  498. @param feat feature array
  499. @param n number of features
  500. @return Returns 0 on success or 1 on error
  501. */
  502. static int export_lowe_features( char* filename, struct feature* feat, int n )
  503. {
  504. FILE* file;
  505. int i, j, d;
  506. if( n <= 0 )
  507. {
  508. fprintf( stderr, "Warning: feature count %d, %s, line %s\n",
  509. n, __FILE__, __LINE__ );
  510. return 1;
  511. }
  512. //打开文件
  513. if( ! ( file = fopen( filename, "w" ) ) )
  514. {
  515. fprintf( stderr, "Warning: error opening %s, %s, line %d\n",
  516. filename, __FILE__, __LINE__ );
  517. return 1;
  518. }
  519. d = feat[0].d;//特征描述子维数
  520. fprintf( file, "%d %d\n", n, d );//首先写入特征点个数和特征描述子维数
  521. //依次写入每个特征点的信息
  522. for( i = 0; i < n; i++ )
  523. {
  524. //写入特征点坐标(注意x,y顺序),尺度,方向
  525. fprintf( file, "%f %f %f %f", feat[i].y, feat[i].x,
  526. feat[i].scl, feat[i].ori );
  527. //写入特征描述子
  528. for( j = 0; j < d; j++ )
  529. {
  530. //每行20个元素
  531. /* write 20 descriptor values per line */
  532. if( j % 20 == 0 )
  533. fprintf( file, "\n" );
  534. fprintf( file, " %d", (int)(feat[i].descr[j]) );
  535. }
  536. fprintf( file, "\n" );
  537. }
  538. //关闭文件
  539. if( fclose(file) )
  540. {
  541. fprintf( stderr, "Warning: file close error, %s, line %d\n",
  542. __FILE__, __LINE__ );
  543. return 1;
  544. }
  545. return 0;
  546. }
  547. /*在图像上画LOWE特征点
  548. 参数:
  549. img:图像指针
  550. feat:特征点数组
  551. n:特征点个数
  552. */
  553. /*
  554. Draws Lowe-type features
  555. @param img image on which to draw features
  556. @param feat array of Oxford-type features
  557. @param n number of features
  558. */
  559. static void draw_lowe_features( IplImage* img, struct feature* feat, int n )
  560. {
  561. CvScalar color = CV_RGB( 255, 255, 255 );//颜色
  562. int i;
  563. if( img-> nChannels > 1 )
  564. color = FEATURE_LOWE_COLOR;
  565. //调用函数,依次画n个特征点
  566. for( i = 0; i < n; i++ )
  567. draw_lowe_feature( img, feat + i, color );
  568. }
  569. /*画单个LOWE特征点
  570. 参数:
  571. img:图像指针
  572. feat:要画的特征点
  573. color:颜色
  574. */
  575. /*
  576. Draws a single Lowe-type feature
  577. @param img image on which to draw
  578. @param feat feature to be drawn
  579. @param color color in which to draw
  580. */
  581. static void draw_lowe_feature( IplImage* img, struct feature* feat, CvScalar color )
  582. {
  583. int len, hlen, blen, start_x, start_y, end_x, end_y, h1_x, h1_y, h2_x, h2_y;
  584. double scl, ori;
  585. double scale = 5.0;
  586. double hscale = 0.75;
  587. CvPoint start, end, h1, h2;
  588. /* compute points for an arrow scaled and rotated by feat's scl and ori */
  589. //箭头杆的起点的坐标
  590. start_x = cvRound( feat->x );
  591. start_y = cvRound( feat->y );
  592. scl = feat->scl;//特征点的大小
  593. ori = feat->ori;//特征点的方向,弧度
  594. len = cvRound( scl * scale );//箭头杆的长度
  595. hlen = cvRound( scl * hscale );//箭头分叉的长度
  596. blen = len - hlen;
  597. //箭头杆的终点的坐标
  598. end_x = cvRound( len *  cos( ori ) ) + start_x;
  599. end_y = cvRound( len * -sin( ori ) ) + start_y;
  600. //箭头的右分叉的起点的坐标
  601. h1_x = cvRound( blen *  cos( ori + CV_PI / 18.0 ) ) + start_x;
  602. h1_y = cvRound( blen * -sin( ori + CV_PI / 18.0 ) ) + start_y;
  603. //箭头的左分叉的起点的坐标
  604. h2_x = cvRound( blen *  cos( ori - CV_PI / 18.0 ) ) + start_x;
  605. h2_y = cvRound( blen * -sin( ori - CV_PI / 18.0 ) ) + start_y;
  606. start = cvPoint( start_x, start_y );//箭头杆的起点
  607. end = cvPoint( end_x, end_y );//箭头杆的终点
  608. h1 = cvPoint( h1_x, h1_y );//箭头的右分叉的起点
  609. h2 = cvPoint( h2_x, h2_y );//箭头的左分叉的起点
  610. cvLine( img, start, end, color, 1, 8, 0 );//画箭头杆
  611. cvLine( img, end, h1, color, 1, 8, 0 );//画右分叉
  612. cvLine( img, end, h2, color, 1, 8, 0 );//画左分叉
  613. }