RobHess的SIFT源码分析:xform.h和xform.c文件(来自于masikkk)

来源:互联网 发布:oracle数据库迁移方案 编辑:程序博客网 时间:2024/05/09 20:02

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

这两个文件中实现了RANSAC算法(RANdom SAmple Consensus 随机抽样一致)。

RANSAC算法可用来筛选两个图像间的SIFT特征匹配并计算变换矩阵。


利用RANSAC算法筛选SIFT特征匹配的主要流程是

(1) 从样本集中随机抽选一个RANSAC样本,即4个匹配点对

(2) 根据这4个匹配点对计算变换矩阵M

(3) 根据样本集,变换矩阵M,和误差度量函数计算满足当前变换矩阵的一致集consensus,并返回一致集中元素个数

(4) 根据当前一致集中元素个数判断是否最优(最大)一致集,若是则更新当前最优一致集

(5) 更新当前错误概率p,若p仍大于允许的最小错误概率则重复(1)至(4)继续迭代,直到当前错误概率p小于最小错误概率


RANSAC算法的迭代终止条件是当前错误概率p小于允许的最小错误概率p_badxform,一般传入的值为0.01,即要求正确率达到99%

当前错误概率p的计算公式为:p=( 1 - in_fracm)k

其中in_frac是当前最优一致集中元素(内点)个数占样本总数的百分比,表征了当前最优一致集的优劣;

m是计算变换矩阵需要的最小特征点对个数,是固定值,一般是4;k是迭代次数。

所以,内点所占比例in_frac越大,错误概率越小;迭代次数k越大,错误概率越小,用来保证收敛。

下面是这两个文件的详细分析:

xform.h文件

[cpp] view plain copy
  1. /**@file 
  2. Functions for computing transforms from image feature correspondences 
  3.  
  4. Copyright (C) 2006-2010  Rob Hess <hess@eecs.oregonstate.edu> 
  5. @version 1.1.2-20100521 
  6. */  
  7.   
  8. /* 
  9. 此文件中包括的函数声明有: 
  10. 1、RANSAC算法特征匹配筛选 
  11. 2、其他一些与RANSAC算法相关函数 
  12. */  
  13.   
  14.   
  15. #ifndef XFORM_H  
  16. #define XFORM_H  
  17.   
  18. #include <cxcore.h>  
  19.   
  20.   
  21. /********************************** Structures *******************************/  
  22.   
  23. struct feature;  
  24.   
  25. //RANSAC算法中用到的结构  
  26. //在RANSAC算法过程中,此类型数据会被赋值给feature结构的feature_data成员  
  27. /** holds feature data relevant to ransac */  
  28. struct ransac_data  
  29. {  
  30.     void* orig_feat_data; //保存此特征点的feature_data域的以前的值  
  31.     int sampled; //标识位,值为1标识此特征点是否被选为样本  
  32. };  
  33.   
  34. //一些宏定义  
  35. /******************************* Defs and macros *****************************/  
  36.   
  37. /*RANSAC算法的容错度 
  38. 对于匹配点对<pt,mpt>,以及变换矩阵H, 
  39. 如果pt经H变换后的点和mpt之间的距离的平方小于RANSAC_ERR_TOL,则可将其加入当前一致集 
  40. */  
  41. /* RANSAC error tolerance in pixels */  
  42. #define RANSAC_ERR_TOL 3  
  43.   
  44. //内点数目占样本总数目的百分比的最小值  
  45. /** pessimistic estimate of fraction of inliers for RANSAC */  
  46. #define RANSAC_INLIER_FRAC_EST 0.25  
  47.   
  48. //一个匹配点对支持错误模型的概率(不知道是干什么用的)  
  49. /** estimate of the probability that a correspondence supports a bad model */  
  50. #define RANSAC_PROB_BAD_SUPP 0.10  
  51.   
  52. //定义了一个带参数的函数宏,用来提取参数feat中的feature_data成员并转换为ransac_data格式的指针  
  53. /* extracts a feature's RANSAC data */  
  54. #define feat_ransac_data( feat ) ( (struct ransac_data*) (feat)->feature_data )  
  55.   
  56.   
  57. /*定义了一个函数指针类型ransac_xform_fn,其返回值是CvMat*类型,有三个参数 
  58. 之后可以用ransac_xform_fn来定义函数指针 
  59. 此类型的函数指针被用在ransac_form()函数的参数中 
  60. 此类型的函数会根据匹配点对集合计算出一个变换矩阵作为返回值 
  61. 参数: 
  62. pts:点的集合 
  63. mpts:点的集合,pts[i]与mpts[i]是互相对应的匹配点 
  64. n:pts和mpts数组中点的个数,pts和mpts中点的个数必须相同 
  65. 返回值:一个变换矩阵,将pts中的每一个点转换为mpts中的对应点,返回值为空表示失败 
  66. */  
  67. /** 
  68. Prototype for transformation functions passed to ransac_xform().  Functions 
  69. of this type should compute a transformation matrix given a set of point 
  70. correspondences. 
  71. @param pts array of points 
  72. @param mpts array of corresponding points; each \a pts[\a i], \a i=0..\a n-1, 
  73.     corresponds to \a mpts[\a i] 
  74. @param n number of points in both \a pts and \a mpts 
  75. @return Should return a transformation matrix that transforms each point in 
  76.     \a pts to the corresponding point in \a mpts or NULL on failure. 
  77. */  
  78. typedef CvMat* (*ransac_xform_fn)( CvPoint2D64f* pts, CvPoint2D64f* mpts,int n );  
  79.   
  80.   
  81. /*定义了一个函数指针类型ransac_err_fn,其返回值是double类型,有三个参数 
  82. 之后可以用ransac_err_fn来定义函数指针 
  83. 此类型的函数指针被用在ransac_form()函数的参数中 
  84. 此类型的函数会根据匹配点对(pt,mpt)和变换矩阵M计算出一个double类型的错误度量值作为返回值 
  85. 此错误度量值用来评判"点mpt"和"点pt经M矩阵变换后的点"之间是否相一致 
  86. 参数: 
  87. pt:一个点 
  88. mpt:点pt的对应匹配点 
  89. M:变换矩阵 
  90. 返回值:"点mpt"和"点pt经M矩阵变换后的点"之间的错误度量值 
  91. */  
  92. /** 
  93. Prototype for error functions passed to ransac_xform().  For a given 
  94. point, its correspondence, and a transform, functions of this type should 
  95. compute a measure of error between the correspondence and the point after 
  96. the point has been transformed by the transform. 
  97. @param pt a point 
  98. @param mpt \a pt's correspondence 
  99. @param T a transform 
  100. @return Should return a measure of error between \a mpt and \a pt after 
  101.     \a pt has been transformed by the transform \a T. 
  102. */  
  103. typedef double (*ransac_err_fn)( CvPoint2D64f pt, CvPoint2D64f mpt, CvMat* M );  
  104.   
  105.   
  106. /***************************** Function Prototypes ***************************/  
  107.   
  108. /*利用RANSAC算法进行特征点筛选,计算出最佳匹配的变换矩阵 
  109. 参数: 
  110. features:特征点数组,只有当mtype类型的匹配点存在时才被用来进行单应性计算 
  111. n:特征点个数 
  112. mtype:决定使用每个特征点的哪个匹配域进行变换矩阵的计算,应该是FEATURE_MDL_MATCH, 
  113.     FEATURE_BCK_MATCH,FEATURE_MDL_MATCH中的一个。若是FEATURE_MDL_MATCH, 
  114.     对应的匹配点对坐标是每个特征点的img_pt域和其匹配点的mdl_pt域, 
  115.     否则,对应的匹配点对是每个特征点的img_pt域和其匹配点的img_pt域。 
  116. xform_fn:函数指针,指向根据输入的点对进行变换矩阵计算的函数,一般传入lsq_homog()函数 
  117. m:在函数xform_fn中计算变换矩阵需要的最小特征点对个数 
  118. p_badxform:允许的错误概率,即允许RANSAC算法计算出的变换矩阵错误的概率,当前计算出的模型的错误概率小于p_badxform时迭代停止 
  119. err_fn:函数指针,对于给定的变换矩阵,计算推定的匹配点对之间的变换误差,一般传入homog_xfer_err()函数 
  120. err_tol:容错度,对于给定的变换矩阵,在此范围内的点对被认为是内点 
  121. inliers:输出参数,指针数组,指向计算出的最终的内点集合,若为空,表示没计算出符合要求的一致集。 
  122.         此数组的内存将在本函数中被分配,使用完后必须在调用出释放:free(*inliers) 
  123. n_in:输出参数,最终计算出的内点的数目 
  124. 返回值:RANSAC算法计算出的变换矩阵,若为空,表示出错或无法计算出可接受矩阵 
  125. */  
  126. /** 
  127. Calculates a best-fit image transform from image feature correspondences using RANSAC. 
  128.  
  129. For more information refer to: 
  130. Fischler, M. A. and Bolles, R. C.  Random sample consensus: a paradigm for 
  131. model fitting with applications to image analysis and automated cartography. 
  132. <EM>Communications of the ACM, 24</EM>, 6 (1981), pp. 381--395. 
  133.  
  134. @param features an array of features; only features with a non-NULL match 
  135.     of type \a mtype are used in homography computation 
  136. @param n number of features in \a feat 
  137. @param mtype determines which of each feature's match fields to use 
  138.     for transform computation; should be one of FEATURE_FWD_MATCH, 
  139.     FEATURE_BCK_MATCH, or FEATURE_MDL_MATCH; if this is FEATURE_MDL_MATCH, 
  140.     correspondences are assumed to be between a feature's img_pt field 
  141.     and its match's mdl_pt field, otherwise correspondences are assumed to 
  142.     be between the the feature's img_pt field and its match's img_pt field 
  143. @param xform_fn pointer to the function used to compute the desired 
  144.     transformation from feature correspondences 
  145. @param m minimum number of correspondences necessary to instantiate the 
  146.     transform computed by \a xform_fn 
  147. @param p_badxform desired probability that the final transformation 
  148.     returned by RANSAC is corrupted by outliers (i.e. the probability that 
  149.     no samples of all inliers were drawn) 
  150. @param err_fn pointer to the function used to compute a measure of error 
  151.     between putative correspondences for a given transform 
  152. @param err_tol correspondences within this distance of each other are 
  153.     considered as inliers for a given transform 
  154. @param inliers if not NULL, output as an array of pointers to the final 
  155.     set of inliers; memory for this array is allocated by this function and 
  156.     must be freed by the caller using free(*inliers) 
  157. @param n_in if not NULL, output as the final number of inliers 
  158.  
  159. @return Returns a transformation matrix computed using RANSAC or NULL 
  160.     on error or if an acceptable transform could not be computed. 
  161. */  
  162. extern CvMat* ransac_xform( struct feature* features, int n, int mtype,  
  163.                            ransac_xform_fn xform_fn, int m,  
  164.                            double p_badxform, ransac_err_fn err_fn,  
  165.                            double err_tol, struct feature*** inliers,  
  166.                            int* n_in );  
  167.   
  168.   
  169. /*运用线性变换,进行点匹配计算平面单应性 
  170. 参数: 
  171. pts:点的集合 
  172. mpts:点的集合,pts[i]与mpts[i]是互相对应的匹配点 
  173. n:pts和mpts数组中点的个数,pts和mpts中点的个数必须相同,并且点对个数至少为4 
  174. 返回值:变换矩阵,可将pts中的点变换为mpts中的点,若点个数少于4则返回空 
  175. */  
  176. /** 
  177. Calculates a planar homography from point correspondeces using the direct 
  178. linear transform.  Intended for use as a ransac_xform_fn. 
  179. @param pts array of points 
  180. @param mpts array of corresponding points; each \a pts[\a i], \a i=0..\a 
  181.     n-1, corresponds to \a mpts[\a i] 
  182. @param n number of points in both \a pts and \a mpts; must be at least 4 
  183. @return Returns the \f$3 \times 3\f$ planar homography matrix that 
  184.     transforms points in \a pts to their corresponding points in \a mpts 
  185.     or NULL if fewer than 4 correspondences were provided 
  186. */  
  187. extern CvMat* dlt_homog( CvPoint2D64f* pts, CvPoint2D64f* mpts, int n );  
  188.   
  189.   
  190. /*根据4对坐标点计算最小二乘平面单应性变换矩阵 
  191. 参数: 
  192. pts:点的集合 
  193. mpts:点的集合,pts[i]与mpts[i]是互相对应的匹配点 
  194. n:pts和mpts数组中点的个数,pts和mpts中点的个数必须相同,并且点对个数至少为4 
  195. 返回值:变换矩阵,可将pts中的点变换为mpts中的点,若点个数少于4则返回空 
  196. */  
  197. /** 
  198. Calculates a least-squares planar homography from point correspondeces. 
  199. Intended for use as a ransac_xform_fn. 
  200. @param pts array of points 
  201. @param mpts array of corresponding points; each \a pts[\a i], \a i=0..\a n-1, 
  202.     corresponds to \a mpts[\a i] 
  203. @param n number of points in both \a pts and \a mpts; must be at least 4 
  204. @return Returns the \f$3 \times 3\f$ least-squares planar homography 
  205.     matrix that transforms points in \a pts to their corresponding points 
  206.     in \a mpts or NULL if fewer than 4 correspondences were provided 
  207. */  
  208. extern CvMat* lsq_homog( CvPoint2D64f* pts, CvPoint2D64f* mpts, int n );  
  209.   
  210.   
  211. /*对于给定的单应性矩阵H,计算输入点pt精H变换后的点与其匹配点mpt之间的误差 
  212. 例如:给定点x,其对应点x',单应性矩阵H,则计算x'与Hx之间的距离的平方,d(x', Hx)^2 
  213. 参数: 
  214. pt:一个点 
  215. mpt:pt的对应匹配点 
  216. H:单应性矩阵 
  217. 返回值:转换误差 
  218. */  
  219. /** 
  220. Calculates the transfer error between a point and its correspondence for 
  221. a given homography, i.e. for a point \f$x\f$, it's correspondence \f$x'\f$, 
  222. and homography \f$H\f$, computes \f$d(x', Hx)^2\f$.  Intended for use as a 
  223. ransac_err_fn. 
  224. @param pt a point 
  225. @param mpt \a pt's correspondence 
  226. @param H a homography matrix 
  227. @return Returns the transfer error between \a pt and \a mpt given \a H 
  228. */  
  229. extern double homog_xfer_err( CvPoint2D64f pt, CvPoint2D64f mpt, CvMat* H );  
  230.   
  231.   
  232. /*计算点pt经透视变换后的点,即给定一点pt和透视变换矩阵T,计算变换后的点 
  233. 给定点(x,y),变换矩阵M,计算[x',y',w']^T = M * [x,y,1]^T(^T表示转置), 
  234. 则变换后的点是(u,v) = (x'/w', y'/w') 
  235. 注意:仿射变换是透视变换的特例 
  236. 参数: 
  237. pt:一个二维点 
  238. T:透视变换矩阵 
  239. 返回值:pt经透视变换后的点 
  240. */  
  241. /** 
  242. Performs a perspective transformation on a single point.  That is, for a 
  243. point \f$(x, y)\f$ and a \f$3 \times 3\f$ matrix \f$T\f$ this function 
  244. returns the point \f$(u, v)\f$, where<BR> 
  245. \f$[x' \ y' \ w']^T = T \times [x \ y \ 1]^T\f$,<BR> 
  246. and<BR> 
  247. \f$(u, v) = (x'/w', y'/w')\f$. 
  248. Note that affine transforms are a subset of perspective transforms. 
  249. @param pt a 2D point 
  250. @param T a perspective transformation matrix 
  251. @return Returns the point \f$(u, v)\f$ as above. 
  252. */  
  253. extern CvPoint2D64f persp_xform_pt( CvPoint2D64f pt, CvMat* T );  
  254.   
  255.   
  256. #endif  

xform.c文件

[cpp] view plain copy
  1. /* 
  2. This file contains definitions for functions to compute transforms from 
  3. image feature correspondences 
  4.  
  5. Copyright (C) 2006-2010  Rob Hess <hess@eecs.oregonstate.edu> 
  6.  
  7. @version 1.1.2-20100521 
  8. */  
  9.   
  10. /* 
  11. 此文件中包括的函数实现有: 
  12. 1、RANSAC算法特征匹配筛选 
  13. 2、其他一些与RANSAC算法相关函数 
  14. */  
  15.   
  16. #include "xform.h"  
  17. #include "imgfeatures.h"  
  18. #include "utils.h"  
  19.   
  20. #include <cxcore.h>  
  21.   
  22. #include <stdlib.h>  
  23. #include <time.h>  
  24.   
  25. /************************ 未暴露接口的一些本地函数的声明 **************************/  
  26. /************************* Local Function Prototypes *************************/  
  27.   
  28. //根据给定的匹配类型,返回输入特征点feat的匹配点  
  29. static __inline struct feature* get_match( struct feature*, int );  
  30. //找到所有具有mtype类型匹配点的特征点,将他们的指针存储在matched数组中  
  31. static int get_matched_features( struct feature*, intintstruct feature*** );  
  32. //计算保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目  
  33. static int calc_min_inliers( intintdoubledouble );  
  34. //计算n的阶乘的自然对数  
  35. static __inline double log_factorial( int );  
  36. //从给定的特征点集中随机抽选一个RANSAC样本(即一个4个特征点的数组)  
  37. static struct feature** draw_ransac_sample( struct feature**, intint );  
  38. //从特征点数组中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中  
  39. static void extract_corresp_pts( struct feature**, intint, CvPoint2D64f**,CvPoint2D64f** );  
  40. //对于给定的模型和错误度量函数,从特征点集和中找出一致集  
  41. static int find_consensus( struct feature**, intint, CvMat*, ransac_err_fn,doublestruct feature*** );  
  42. //释放输入参数的存储空间  
  43. static __inline void release_mem( CvPoint2D64f*, CvPoint2D64f*,struct feature** );  
  44.   
  45. /********************** Functions prototyped in xform.h **********************/  
  46.   
  47.   
  48. /*利用RANSAC算法进行特征点筛选,计算出最佳匹配的变换矩阵 
  49. 参数: 
  50. features:特征点数组,只有当mtype类型的匹配点存在时才被用来进行单应性计算 
  51. n:特征点个数 
  52. mtype:决定使用每个特征点的哪个匹配域进行变换矩阵的计算,应该是FEATURE_MDL_MATCH, 
  53.     FEATURE_BCK_MATCH,FEATURE_MDL_MATCH中的一个。若是FEATURE_MDL_MATCH, 
  54.     对应的匹配点对坐标是每个特征点的img_pt域和其匹配点的mdl_pt域, 
  55.     否则,对应的匹配点对是每个特征点的img_pt域和其匹配点的img_pt域。 
  56. xform_fn:函数指针,指向根据输入的点对进行变换矩阵计算的函数,一般传入lsq_homog()函数 
  57. m:在函数xform_fn中计算变换矩阵需要的最小特征点对个数 
  58. p_badxform:允许的错误概率,即允许RANSAC算法计算出的变换矩阵错误的概率,当前计算出的模型的错误概率小于p_badxform时迭代停止 
  59. err_fn:函数指针,对于给定的变换矩阵,计算推定的匹配点对之间的变换误差,一般传入homog_xfer_err()函数 
  60. err_tol:容错度,对于给定的变换矩阵,在此范围内的点对被认为是内点 
  61. inliers:输出参数,指针数组,指向计算出的最终的内点集合,若为空,表示没计算出符合要求的一致集 
  62.         此数组的内存将在本函数中被分配,使用完后必须在调用出释放:free(*inliers) 
  63. n_in:输出参数,最终计算出的内点的数目 
  64. 返回值:RANSAC算法计算出的变换矩阵,若为空,表示出错或无法计算出可接受矩阵 
  65. */  
  66. /* 
  67. Calculates a best-fit image transform from image feature correspondences 
  68. using RANSAC. 
  69.  
  70. For more information refer to: 
  71.  
  72. Fischler, M. A. and Bolles, R. C.  Random sample consensus: a paradigm for 
  73. model fitting with applications to image analysis and automated cartography. 
  74. <EM>Communications of the ACM, 24</EM>, 6 (1981), pp. 381--395. 
  75.  
  76. @param features an array of features; only features with a non-NULL match 
  77.     of type mtype are used in homography computation 
  78. @param n number of features in feat 
  79. @param mtype determines which of each feature's match fields to use 
  80.     for model computation; should be one of FEATURE_FWD_MATCH, 
  81.     FEATURE_BCK_MATCH, or FEATURE_MDL_MATCH; if this is FEATURE_MDL_MATCH, 
  82.     correspondences are assumed to be between a feature's img_pt field 
  83.     and its match's mdl_pt field, otherwise correspondences are assumed to 
  84.     be between the the feature's img_pt field and its match's img_pt field 
  85. @param xform_fn pointer to the function used to compute the desired 
  86.     transformation from feature correspondences 
  87. @param m minimum number of correspondences necessary to instantiate the 
  88.     model computed by xform_fn 
  89. @param p_badxform desired probability that the final transformation 
  90.     returned by RANSAC is corrupted by outliers (i.e. the probability that 
  91.     no samples of all inliers were drawn) 
  92. @param err_fn pointer to the function used to compute a measure of error 
  93.     between putative correspondences and a computed model 
  94. @param err_tol correspondences within this distance of a computed model are 
  95.     considered as inliers 
  96. @param inliers if not NULL, output as an array of pointers to the final 
  97.     set of inliers 
  98. @param n_in if not NULL and \a inliers is not NULL, output as the final 
  99.     number of inliers 
  100.  
  101. @return Returns a transformation matrix computed using RANSAC or NULL 
  102.     on error or if an acceptable transform could not be computed. 
  103. */  
  104. CvMat* ransac_xform( struct feature* features, int n, int mtype,  
  105.                     ransac_xform_fn xform_fn, int m, double p_badxform,  
  106.                     ransac_err_fn err_fn, double err_tol,  
  107.                     struct feature*** inliers, int* n_in )  
  108. {  
  109.     //matched:所有具有mtype类型匹配点的特征点的数组,也就是样本集  
  110.     //sample:单个样本,即4个特征点的数组  
  111.     //consensus:当前一致集;  
  112.     //consensus_max:当前最大一致集(即当前的最好结果的一致集)  
  113.     struct feature** matched, ** sample, ** consensus, ** consensus_max = NULL;  
  114.     struct ransac_data* rdata;//每个特征点的feature_data域的ransac数据指针  
  115.     CvPoint2D64f* pts, * mpts;//每个样本对应的两个坐标数组:特征点坐标数组pts和匹配点坐标数组mpts  
  116.     CvMat* M = NULL;//当前变换矩阵  
  117.     //p:当前计算出的模型的错误概率,当p小于p_badxform时迭代停止  
  118.     //in_frac:内点数目占样本总数目的百分比  
  119.     double p, in_frac = RANSAC_INLIER_FRAC_EST;  
  120.     //nm:输入的特征点数组中具有mtype类型匹配点的特征点个数  
  121.     //in:当前一致集中元素个数  
  122.     //in_min:一致集中元素个数允许的最小值,保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目  
  123.     //in_max:当前最优一致集(最大一致集)中元素的个数  
  124.     //k:迭代次数,与计算当前模型的错误概率有关  
  125.     int i, nm, in, in_min, in_max = 0, k = 0;  
  126.   
  127.     //找到特征点数组features中所有具有mtype类型匹配点的特征点,放到matched数组(样本集)中,返回值nm是matched数组的元素个数  
  128.     nm = get_matched_features( features, n, mtype, &matched );  
  129.     //若找到的具有匹配点的特征点个数小于计算变换矩阵需要的最小特征点对个数,出错  
  130.     if( nm < m )  
  131.     {   //出错处理,特征点对个数不足  
  132.         fprintf( stderr, "Warning: not enough matches to compute xform, %s" \  
  133.             " line %d\n", __FILE__, __LINE__ );  
  134.         goto end;  
  135.     }  
  136.   
  137.     /* initialize random number generator */  
  138.     srand( time(NULL) );//初始化随机数生成器  
  139.   
  140.     //计算保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目  
  141.     in_min = calc_min_inliers( nm, m, RANSAC_PROB_BAD_SUPP, p_badxform );  
  142.     //当前计算出的模型的错误概率,内点所占比例in_frac越大,错误概率越小;迭代次数k越大,错误概率越小  
  143.     p = pow( 1.0 - pow( in_frac, m ), k );  
  144.     i = 0;  
  145.   
  146.     //当前错误概率大于输入的允许错误概率p_badxform,继续迭代  
  147.     while( p > p_badxform )  
  148.     {  
  149.         //从样本集matched中随机抽选一个RANSAC样本(即一个4个特征点的数组),放到样本变量sample中  
  150.         sample = draw_ransac_sample( matched, nm, m );  
  151.         //从样本中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中  
  152.         extract_corresp_pts( sample, m, mtype, &pts, &mpts );  
  153.         //调用参数中传入的函数xform_fn,计算将m个点的数组pts变换为mpts的矩阵,返回变换矩阵给M  
  154.         M = xform_fn( pts, mpts, m );//一般传入lsq_homog()函数  
  155.         if( ! M )//出错判断  
  156.             goto iteration_end;  
  157.         //给定特征点集,变换矩阵,误差函数,计算出当前一致集consensus,返回一致集中元素个数给in  
  158.         in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus);  
  159.   
  160.         //若当前一致集大于历史最优一致集,即当前一致集为最优,则更新最优一致集consensus_max  
  161.         if( in > in_max )  
  162.         {  
  163.             if( consensus_max )//若之前有最优值,释放其空间  
  164.                 free( consensus_max );  
  165.             consensus_max = consensus;//更新最优一致集  
  166.             in_max = in;//更新最优一致集中元素个数  
  167.             in_frac = (double)in_max / nm;//最优一致集中元素个数占样本总个数的百分比  
  168.         }  
  169.         else//若当前一致集小于历史最优一致集,释放当前一致集  
  170.             free( consensus );  
  171.         cvReleaseMat( &M );  
  172.   
  173. iteration_end:  
  174.         release_mem( pts, mpts, sample );  
  175.         p = pow( 1.0 - pow( in_frac, m ), ++k );//更新当前错误概率  
  176.     }  
  177.   
  178.     //根据最优一致集计算最终的变换矩阵  
  179.     /* calculate final transform based on best consensus set */  
  180.     //若最优一致集中元素个数大于最低标准,即符合要求  
  181.     if( in_max >= in_min )  
  182.     {  
  183.         //从最优一致集中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中  
  184.         extract_corresp_pts( consensus_max, in_max, mtype, &pts, &mpts );  
  185.         //调用参数中传入的函数xform_fn,计算将in_max个点的数组pts变换为mpts的矩阵,返回变换矩阵给M  
  186.         M = xform_fn( pts, mpts, in_max );  
  187.         /***********下面会再进行一次迭代**********/  
  188.         //根据变换矩阵M从样本集matched中计算出一致集consensus,返回一致集中元素个数给in  
  189.         in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus);  
  190.         cvReleaseMat( &M );  
  191.         release_mem( pts, mpts, consensus_max );  
  192.         //从一致集中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中  
  193.         extract_corresp_pts( consensus, in, mtype, &pts, &mpts );  
  194.         //调用参数中传入的函数xform_fn,计算将in个点的数组pts变换为mpts的矩阵,返回变换矩阵给M  
  195.         M = xform_fn( pts, mpts, in );  
  196.         if( inliers )  
  197.         {  
  198.             *inliers = consensus;//将最优一致集赋值给输出参数:inliers,即内点集合  
  199.             consensus = NULL;  
  200.         }  
  201.         if( n_in )  
  202.             *n_in = in;//将最优一致集中元素个数赋值给输出参数:n_in,即内点个数  
  203.         release_mem( pts, mpts, consensus );  
  204.     }  
  205.     else if( consensus_max )  
  206.     {   //没有计算出符合要求的一致集  
  207.         if( inliers )  
  208.             *inliers = NULL;  
  209.         if( n_in )  
  210.             *n_in = 0;  
  211.         free( consensus_max );  
  212.     }  
  213.   
  214.     //RANSAC算法结束:恢复特征点中被更改的数据域feature_data,并返回变换矩阵M  
  215. end:  
  216.     for( i = 0; i < nm; i++ )  
  217.     {  
  218.         //利用宏feat_ransac_data来提取matched[i]中的feature_data成员并转换为ransac_data格式的指针  
  219.         rdata = feat_ransac_data( matched[i] );  
  220.         //恢复feature_data成员的以前的值  
  221.         matched[i]->feature_data = rdata->orig_feat_data;  
  222.         free( rdata );//释放内存  
  223.     }  
  224.     free( matched );  
  225.   
  226.     return M;//返回求出的变换矩阵M  
  227. }  
  228.   
  229.   
  230.   
  231. /* 
  232. Calculates a planar homography from point correspondeces using the direct 
  233. linear transform.  Intended for use as a ransac_xform_fn. 
  234.    
  235. @param pts array of points 
  236. @param mpts array of corresponding points; each pts[i], i=0..n-1, 
  237.   corresponds to mpts[i] 
  238. @param n number of points in both pts and mpts; must be at least 4 
  239.    
  240. @return Returns the 3x3 planar homography matrix that transforms points 
  241.   in pts to their corresponding points in mpts or NULL if fewer than 4 
  242.   correspondences were provided 
  243. */  
  244. CvMat* dlt_homog( CvPoint2D64f* pts, CvPoint2D64f* mpts, int n )  
  245. {  
  246.     CvMat* H, * A, * VT, * D, h, v9;  
  247.     double _h[9];  
  248.     int i;  
  249.   
  250.     if( n < 4 )  
  251.         return NULL;  
  252.   
  253.     /* set up matrices so we can unstack homography into h; Ah = 0 */  
  254.     A = cvCreateMat( 2*n, 9, CV_64FC1 );  
  255.     cvZero( A );  
  256.     for( i = 0; i < n; i++ )  
  257.     {  
  258.         cvmSet( A, 2*i, 3, -pts[i].x );  
  259.         cvmSet( A, 2*i, 4, -pts[i].y );  
  260.         cvmSet( A, 2*i, 5, -1.0  );  
  261.         cvmSet( A, 2*i, 6, mpts[i].y * pts[i].x );  
  262.         cvmSet( A, 2*i, 7, mpts[i].y * pts[i].y );  
  263.         cvmSet( A, 2*i, 8, mpts[i].y );  
  264.         cvmSet( A, 2*i+1, 0, pts[i].x );  
  265.         cvmSet( A, 2*i+1, 1, pts[i].y );  
  266.         cvmSet( A, 2*i+1, 2, 1.0  );  
  267.         cvmSet( A, 2*i+1, 6, -mpts[i].x * pts[i].x );  
  268.         cvmSet( A, 2*i+1, 7, -mpts[i].x * pts[i].y );  
  269.         cvmSet( A, 2*i+1, 8, -mpts[i].x );  
  270.     }  
  271.     D = cvCreateMat( 9, 9, CV_64FC1 );  
  272.     VT = cvCreateMat( 9, 9, CV_64FC1 );  
  273.     cvSVD( A, D, NULL, VT, CV_SVD_MODIFY_A + CV_SVD_V_T );  
  274.     v9 = cvMat( 1, 9, CV_64FC1, NULL );  
  275.     cvGetRow( VT, &v9, 8 );  
  276.     h = cvMat( 1, 9, CV_64FC1, _h );  
  277.     cvCopy( &v9, &h, NULL );  
  278.     h = cvMat( 3, 3, CV_64FC1, _h );  
  279.     H = cvCreateMat( 3, 3, CV_64FC1 );  
  280.     cvConvert( &h, H );  
  281.   
  282.     cvReleaseMat( &A );  
  283.     cvReleaseMat( &D );  
  284.     cvReleaseMat( &VT );  
  285.     return H;  
  286. }  
  287.   
  288.   
  289. /* 根据4对坐标点计算最小二乘平面单应性变换矩阵 
  290. 参数: 
  291. pts:坐标点数组 
  292. mpts:对应点数组,pts[i]与mpts[i]一一对应 
  293. n:pts和mpts数组中点的个数,pts和mpts中点的个数必须相同,一般是4 
  294. 返回值:一个3*3的变换矩阵,将pts中的每一个点转换为mpts中的对应点,返回值为空表示失败 
  295. */  
  296. /* 
  297. Calculates a least-squares planar homography from point correspondeces. 
  298. @param pts array of points 
  299. @param mpts array of corresponding points; each pts[i], i=0..n-1, corresponds to mpts[i] 
  300. @param n number of points in both pts and mpts; must be at least 4 
  301. @return Returns the 3 x 3 least-squares planar homography matrix that 
  302.     transforms points in pts to their corresponding points in mpts or NULL if 
  303.     fewer than 4 correspondences were provided 
  304. */  
  305. CvMat* lsq_homog( CvPoint2D64f* pts, CvPoint2D64f* mpts, int n )  
  306. {  
  307.     CvMat* H, * A, * B, X;  
  308.     double x[9];//数组x中的元素就是变换矩阵H中的值  
  309.     int i;  
  310.   
  311.     //输入点对个数不够4  
  312.     if( n < 4 )  
  313.     {  
  314.         fprintf( stderr, "Warning: too few points in lsq_homog(), %s line %d\n",  
  315.             __FILE__, __LINE__ );  
  316.         return NULL;  
  317.     }  
  318.   
  319.     //将变换矩阵H展开到一个8维列向量X中,使得AX=B,这样只需一次解线性方程组即可求出X,然后再根据X恢复H  
  320.     /* set up matrices so we can unstack homography into X; AX = B */  
  321.     A = cvCreateMat( 2*n, 8, CV_64FC1 );//创建2n*8的矩阵,一般是8*8  
  322.     B = cvCreateMat( 2*n, 1, CV_64FC1 );//创建2n*1的矩阵,一般是8*1  
  323.     X = cvMat( 8, 1, CV_64FC1, x );//创建8*1的矩阵,指定数据为x  
  324.     H = cvCreateMat(3, 3, CV_64FC1);//创建3*3的矩阵  
  325.     cvZero( A );//将A清零  
  326.   
  327.     //由于是展开计算,需要根据原来的矩阵计算法则重新分配矩阵A和B的值的排列  
  328.     for( i = 0; i < n; i++ )  
  329.     {  
  330.         cvmSet( A, i, 0, pts[i].x );//设置矩阵A的i行0列的值为pts[i].x  
  331.         cvmSet( A, i+n, 3, pts[i].x );  
  332.         cvmSet( A, i, 1, pts[i].y );  
  333.         cvmSet( A, i+n, 4, pts[i].y );  
  334.         cvmSet( A, i, 2, 1.0 );  
  335.         cvmSet( A, i+n, 5, 1.0 );  
  336.         cvmSet( A, i, 6, -pts[i].x * mpts[i].x );  
  337.         cvmSet( A, i, 7, -pts[i].y * mpts[i].x );  
  338.         cvmSet( A, i+n, 6, -pts[i].x * mpts[i].y );  
  339.         cvmSet( A, i+n, 7, -pts[i].y * mpts[i].y );  
  340.         cvmSet( B, i, 0, mpts[i].x );  
  341.         cvmSet( B, i+n, 0, mpts[i].y );  
  342.     }  
  343.   
  344.     //调用OpenCV函数,解线性方程组  
  345.     cvSolve( A, B, &X, CV_SVD );//求X,使得AX=B  
  346.     x[8] = 1.0;//变换矩阵的[3][3]位置的值为固定值1  
  347.     X = cvMat( 3, 3, CV_64FC1, x );  
  348.     cvConvert( &X, H );//将数组转换为矩阵  
  349.   
  350.     cvReleaseMat( &A );  
  351.     cvReleaseMat( &B );  
  352.     return H;  
  353. }  
  354.   
  355.   
  356. /*对于给定的单应性矩阵H,计算输入点pt精H变换后的点与其匹配点mpt之间的误差 
  357. 例如:给定点x,其对应点x',单应性矩阵H,则计算x'与Hx之间的距离的平方,d(x', Hx)^2 
  358. 参数: 
  359. pt:一个点 
  360. mpt:pt的对应匹配点 
  361. H:单应性矩阵 
  362. 返回值:转换误差 
  363. */  
  364. /* 
  365. Calculates the transfer error between a point and its correspondence for 
  366. a given homography, i.e. for a point x, it's correspondence x', and 
  367. homography H, computes d(x', Hx)^2. 
  368.  
  369. @param pt a point 
  370. @param mpt pt's correspondence 
  371. @param H a homography matrix 
  372.  
  373. @return Returns the transfer error between pt and mpt given H 
  374. */  
  375. double homog_xfer_err( CvPoint2D64f pt, CvPoint2D64f mpt, CvMat* H )  
  376. {  
  377.     CvPoint2D64f xpt = persp_xform_pt( pt, H );//pt经变换矩阵H变换后的点xpt,即H乘以x对应的向量  
  378.   
  379.     return sqrt( dist_sq_2D( xpt, mpt ) );//两点间距离的平方  
  380. }  
  381.   
  382.   
  383. /*计算点pt经透视变换后的点,即给定一点pt和透视变换矩阵T,计算变换后的点 
  384. 给定点(x,y),变换矩阵M,计算[x',y',w']^T = M * [x,y,1]^T(^T表示转置), 
  385. 则变换后的点是(u,v) = (x'/w', y'/w') 
  386. 注意:仿射变换是透视变换的特例 
  387. 参数: 
  388. pt:一个二维点 
  389. T:透视变换矩阵 
  390. 返回值:pt经透视变换后的点 
  391. */  
  392. /* 
  393. Performs a perspective transformation on a single point.  That is, for a 
  394. point (x, y) and a 3 x 3 matrix T this function returns the point 
  395. (u, v), where 
  396. [x' y' w']^T = T * [x y 1]^T, 
  397. and 
  398. (u, v) = (x'/w', y'/w'). 
  399. Note that affine transforms are a subset of perspective transforms. 
  400. @param pt a 2D point 
  401. @param T a perspective transformation matrix 
  402. @return Returns the point (u, v) as above. 
  403. */  
  404. CvPoint2D64f persp_xform_pt( CvPoint2D64f pt, CvMat* T )  
  405. {  
  406.     //XY:点pt对应的3*1列向量,UV:pt变换后的点对应的3*1列向量  
  407.     CvMat XY, UV;  
  408.     double xy[3] = { pt.x, pt.y, 1.0 }, uv[3] = { 0 };//对应的数据  
  409.     CvPoint2D64f rslt;//结果  
  410.   
  411.     //初始化矩阵头  
  412.     cvInitMatHeader( &XY, 3, 1, CV_64FC1, xy, CV_AUTOSTEP );  
  413.     cvInitMatHeader( &UV, 3, 1, CV_64FC1, uv, CV_AUTOSTEP );  
  414.     cvMatMul( T, &XY, &UV );//计算矩阵乘法,T*XY,结果放在UV中  
  415.     rslt = cvPoint2D64f( uv[0] / uv[2], uv[1] / uv[2] );//得到转换后的点  
  416.   
  417.     return rslt;  
  418. }  
  419.   
  420.   
  421. /************************ 本地函数的实现**************************************/  
  422. /************************ Local funciton definitions *************************/  
  423.   
  424. /*根据给定的匹配类型,返回输入特征点feat的匹配点 
  425. 参数: 
  426. feat:输入特征点 
  427. mtype:匹配类型,是FEATURE_FWD_MATCH,FEATURE_BCK_MATCH,FEATURE_MDL_MATCH之一 
  428. 返回值:feat的匹配点的指针,若为空表示mtype参数有误 
  429. */  
  430. /* 
  431. Returns a feature's match according to a specified match type 
  432. @param feat feature 
  433. @param mtype match type, one of FEATURE_FWD_MATCH, FEATURE_BCK_MATCH, or 
  434. FEATURE_MDL_MATCH 
  435. @return Returns feat's match corresponding to mtype or NULL for bad mtype 
  436. */  
  437. static __inline struct feature* get_match( struct feature* feat, int mtype )  
  438. {  
  439.     //FEATURE_MDL_MATCH:表明feature结构中的mdl_match域是对应的匹配点  
  440.     if( mtype == FEATURE_MDL_MATCH )  
  441.         return feat->mdl_match;  
  442.     //FEATURE_BCK_MATCH:表明feature结构中的bck_match域是对应的匹配点  
  443.     if( mtype == FEATURE_BCK_MATCH )  
  444.         return feat->bck_match;  
  445.     //FEATURE_FWD_MATCH:表明feature结构中的fwd_match域是对应的匹配点  
  446.     if( mtype == FEATURE_FWD_MATCH )  
  447.         return feat->fwd_match;  
  448.     return NULL;  
  449. }  
  450.   
  451.   
  452. /*找到所有具有mtype类型匹配点的特征点,将他们的指针存储在matched数组中, 
  453.   并初始化matched数组中每个特征点的feature_data域为ransac_data类型的数据指针 
  454. 参数: 
  455. features:特征点数组 
  456. n:特征点个数 
  457. mtype:匹配类型 
  458. matched:输出参数,含有mtype类型匹配点的特征点的指针数组 
  459. 返回值:matched数组中特征点的个数 
  460. */  
  461. /* 
  462. Finds all features with a match of a specified type and stores pointers 
  463. to them in an array.  Additionally initializes each matched feature's 
  464. feature_data field with a ransac_data structure. 
  465. @param features array of features 
  466. @param n number of features in features 
  467. @param mtype match type, one of FEATURE_{FWD,BCK,MDL}_MATCH 
  468. @param matched output as an array of pointers to features with a match of the specified type 
  469. @return Returns the number of features output in matched. 
  470. */  
  471. static int get_matched_features( struct feature* features, int n, int mtype, struct feature*** matched )  
  472. {  
  473.     struct feature** _matched;//输出数组,具有mtype类型匹配点的特征点指针数组  
  474.     struct ransac_data* rdata;//ransac_data类型数据指针  
  475.     int i, m = 0;  
  476.   
  477.     _matched = calloc( n, sizeofstruct feature* ) );  
  478.   
  479.     //遍历输入的特征点数组  
  480.     for( i = 0; i < n; i++ )  
  481.     {   //找第i个特征点的mtype类型匹配点,若能正确找到表明此特征点有mtype类型的匹配点,则将其放入_matched数组  
  482.         if( get_match( features + i, mtype ) )  
  483.         {  
  484.             rdata = malloc( sizeofstruct ransac_data ) );//为ransac_data结构分配空间  
  485.             memset( rdata, 0, sizeofstruct ransac_data ) );//清零  
  486.             rdata->orig_feat_data = features[i].feature_data;//保存第i个特征点的feature_data域之前的值  
  487.             _matched[m] = features + i;//放到_matched数组  
  488.             _matched[m]->feature_data = rdata;//其feature_data域赋值为ransac_data类型数据的指针  
  489.             m++;//_matched数组中元素个数  
  490.         }  
  491.     }  
  492.         *matched = _matched;//输出参数赋值  
  493.         return m;//返回值,元素个数  
  494. }  
  495.   
  496.   
  497. /*计算保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目 
  498. 参数: 
  499. n:推定的匹配点对的个数 
  500. m:计算模型所需的最小点对个数 
  501. p_badsupp:概率,错误模型被一个匹配点对支持的概率 
  502. p_badxform:概率,最终计算出的转换矩阵是错误的的概率 
  503. 返回值:保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目 
  504. */  
  505. /* 
  506. Calculates the minimum number of inliers as a function of the number of 
  507. putative correspondences.  Based on equation (7) in 
  508.  
  509. Chum, O. and Matas, J.  Matching with PROSAC -- Progressive Sample Consensus. 
  510. In <EM>Conference on Computer Vision and Pattern Recognition (CVPR)</EM>, 
  511. (2005), pp. 220--226. 
  512.  
  513. @param n number of putative correspondences 
  514. @param m min number of correspondences to compute the model in question 
  515. @param p_badsupp prob. that a bad model is supported by a correspondence 
  516. @param p_badxform desired prob. that the final transformation returned is bad 
  517. @return Returns the minimum number of inliers required to guarantee, based 
  518.     on p_badsupp, that the probability that the final transformation returned 
  519.     by RANSAC is less than p_badxform 
  520. */  
  521. static int calc_min_inliers( int n, int m, double p_badsupp, double p_badxform )  
  522. {  
  523.     //根据论文:Chum, O. and Matas, J.  Matching with PROSAC -- Progressive Sample Consensus  
  524.     //中的一个公式计算,看不懂  
  525.     double pi, sum;  
  526.     int i, j;  
  527.   
  528.     for( j = m+1; j <= n; j++ )  
  529.     {  
  530.         sum = 0;  
  531.         for( i = j; i <= n; i++ )  
  532.         {  
  533.             pi = ( i - m ) * log( p_badsupp ) + ( n - i + m ) * log( 1.0 - p_badsupp ) +  
  534.                 log_factorial( n - m ) - log_factorial( i - m ) -  
  535.                 log_factorial( n - i );  
  536.             /* 
  537.              * Last three terms above are equivalent to log( n-m choose i-m ) 
  538.              */  
  539.             sum += exp( pi );  
  540.         }  
  541.         if( sum < p_badxform )  
  542.             break;  
  543.     }  
  544.     return j;  
  545. }  
  546.   
  547.   
  548. //计算n的阶乘的自然对数  
  549. /* 
  550.   Calculates the natural log of the factorial of a number 
  551.   @param n number 
  552.   @return Returns log( n! ) 
  553. */  
  554. static __inline double log_factorial( int n )  
  555. {  
  556.   double f = 0;  
  557.   int i;  
  558.   
  559.   for( i = 1; i <= n; i++ )  
  560.     f += log( i );  
  561.   
  562.   return f;  
  563. }  
  564.   
  565.   
  566. /*从给定的特征点集中随机抽选一个RANSAC样本(即一个4个特征点的数组) 
  567. 参数: 
  568. features:作为样本集的特征点数组 
  569. n:features中元素个数 
  570. m:单个样本的尺寸,这里是4(至少需要4个点来计算变换矩阵) 
  571. 返回值:一个指针数组,其元素指向被选为样本的特征点,被选为样本的特征点的feature_data域的sampled被设为1 
  572. */  
  573. /* 
  574. Draws a RANSAC sample from a set of features. 
  575. @param features array of pointers to features from which to sample 
  576. @param n number of features in features 
  577. @param m size of the sample 
  578. @return Returns an array of pointers to the sampled features; the sampled 
  579.     field of each sampled feature's ransac_data is set to 1 
  580. */  
  581. static struct feature** draw_ransac_sample( struct feature** features, int n, int m )  
  582. {  
  583.     struct feature** sample, * feat;//sample:被选为样本的点的数组  
  584.     struct ransac_data* rdata;  
  585.     int i, x;  
  586.   
  587.     //将所有特征点的feature_data域的sampled值都初始化为0,即未被选为样本点  
  588.     for( i = 0; i < n; i++ )  
  589.     {  
  590.         //利用宏feat_ransac_data来提取参数中的feature_data成员并转换为ransac_data格式的指针  
  591.         rdata = feat_ransac_data( features[i] );  
  592.         rdata->sampled = 0;//sampled值设为0  
  593.     }  
  594.   
  595.     sample = calloc( m, sizeofstruct feature* ) );//为样本数组分配空间  
  596.   
  597.     //随机抽取m个特征点作为一个样本,将其指针保存在sample数组中  
  598.     for( i = 0; i < m; i++ )  
  599.     {  
  600.         do  
  601.         {  
  602.             x = rand() % n;//随机下标  
  603.             feat = features[x];  
  604.             rdata = feat_ransac_data( feat );//获得feature_data成员并转换为ransac_data格式的指针  
  605.         }  
  606.         while( rdata->sampled );//若抽取的特征点的sampled值为1,继续选取;否则停止,将其作为样本中的一个点  
  607.         sample[i] = feat;//放入sample数组  
  608.         rdata->sampled = 1;//该点的feature_data成员的sampled域值设为1  
  609.     }  
  610.   
  611.     return sample;//返回随机选取的样本  
  612. }  
  613.   
  614.   
  615. /*从特征点数组中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中 
  616. 参数: 
  617. features:特征点数组,将从其中抽取坐标点和其匹配点,此数组中所有特征点都应具有mtype类型的匹配点 
  618. n:feantures中特征点个数 
  619. mtype:匹配类型,若是FEATURE_MDL_MATCH,对应的匹配点对坐标是每个特征点的img_pt域和其匹配点的mdl_pt域, 
  620.        否则,对应的匹配点对是每个特征点的img_pt域和其匹配点的img_pt域。 
  621. pts:输出参数,从特征点数组features中获取的二维坐标数组 
  622. mpts:输出参数,从特征点数组features的对应匹配点中获取的二维坐标数组 
  623. */  
  624. /* 
  625. Extract raw point correspondence locations from a set of features 
  626.  
  627. @param features array of features from which to extract points and match 
  628.     points; each of these is assumed to have a match of type mtype 
  629. @param n number of features 
  630. @param mtype match type; if FEATURE_MDL_MATCH correspondences are assumed 
  631.     to be between each feature's img_pt field and it's match's mdl_pt field, 
  632.     otherwise, correspondences are assumed to be between img_pt and img_pt 
  633. @param pts output as an array of raw point locations from features 
  634. @param mpts output as an array of raw point locations from features' matches 
  635. */  
  636. static void extract_corresp_pts( struct feature** features, int n, int mtype,  
  637.                                  CvPoint2D64f** pts, CvPoint2D64f** mpts )  
  638. {  
  639.     struct feature* match;//每个特征点对应的匹配点  
  640.     CvPoint2D64f* _pts, * _mpts;  
  641.     int i;  
  642.   
  643.     _pts = calloc( n, sizeof( CvPoint2D64f ) );//特征点的坐标数组  
  644.     _mpts = calloc( n, sizeof( CvPoint2D64f ) );//对应匹配点的坐标数组  
  645.   
  646.     //匹配类型是FEATURE_MDL_MATCH,匹配点的坐标是mdl_pt域  
  647.     if( mtype == FEATURE_MDL_MATCH )  
  648.         for( i = 0; i < n; i++ )  
  649.         {  
  650.             //根据给定的匹配类型,返回输入特征点的匹配点  
  651.             match = get_match( features[i], mtype );  
  652.             if( ! match )  
  653.                 fatal_error( "feature does not have match of type %d, %s line %d",  
  654.                             mtype, __FILE__, __LINE__ );  
  655.             _pts[i] = features[i]->img_pt;//特征点的坐标  
  656.             _mpts[i] = match->mdl_pt;//对应匹配点的坐标  
  657.         }  
  658.     //匹配类型不是FEATURE_MDL_MATCH,匹配点的坐标是img_pt域  
  659.     else  
  660.         for( i = 0; i < n; i++ )  
  661.         {  
  662.             //根据给定的匹配类型,返回输入特征点的匹配点  
  663.             match = get_match( features[i], mtype );  
  664.             if( ! match )  
  665.                 fatal_error( "feature does not have match of type %d, %s line %d",  
  666.                             mtype, __FILE__, __LINE__ );  
  667.             _pts[i] = features[i]->img_pt;//特征点的坐标  
  668.             _mpts[i] = match->img_pt;//对应匹配点的坐标  
  669.         }  
  670.   
  671.         *pts = _pts;  
  672.         *mpts = _mpts;  
  673. }  
  674.   
  675.   
  676.   
  677. /*对于给定的模型和错误度量函数,从特征点集和中找出一致集 
  678. 参数: 
  679. features:特征点集合,其中的特征点都具有mtype类型的匹配点 
  680. n:特征点的个数 
  681. mtype:匹配类型,若是FEATURE_MDL_MATCH,对应的匹配点对坐标是每个特征点的img_pt域和其匹配点的mdl_pt域, 
  682.        否则,对应的匹配点对是每个特征点的img_pt域和其匹配点的img_pt域。 
  683. M:给定的模型,即一个变换矩阵 
  684. err_fn:错误度量函数,对于给定的变换矩阵,计算推定的匹配点对之间的变换误差 
  685. err_tol:容错度,用来衡量err_fn的返回值,小于err_tol的被加入一致集 
  686. consensus:输出参数,一致集,即一致集中特征点构成的数组 
  687. 返回值:一致集中特征点的个数 
  688. */  
  689. /* 
  690. For a given model and error function, finds a consensus from a set of 
  691. feature correspondences. 
  692.  
  693. @param features set of pointers to features; every feature is assumed to 
  694.     have a match of type mtype 
  695. @param n number of features in features 
  696. @param mtype determines the match field of each feature against which to 
  697.     measure error; if this is FEATURE_MDL_MATCH, correspondences are assumed 
  698.     to be between the feature's img_pt field and the match's mdl_pt field; 
  699.     otherwise matches are assumed to be between img_pt and img_pt 
  700. @param M model for which a consensus set is being found 
  701. @param err_fn error function used to measure distance from M 
  702. @param err_tol correspondences within this distance of M are added to the 
  703.     consensus set 
  704. @param consensus output as an array of pointers to features in the 
  705.     consensus set 
  706.  
  707. @return Returns the number of points in the consensus set 
  708. */  
  709. static int find_consensus( struct feature** features, int n, int mtype,  
  710.                            CvMat* M, ransac_err_fn err_fn, double err_tol,  
  711.                            struct feature*** consensus )  
  712. {  
  713.     struct feature** _consensus;//一致集  
  714.     struct feature* match;//每个特征点对应的匹配点  
  715.     CvPoint2D64f pt, mpt;//pt:当前特征点的坐标,mpt:当前特征点的匹配点的坐标  
  716.     double err;//变换误差  
  717.     int i, in = 0;  
  718.   
  719.     _consensus = calloc( n, sizeofstruct feature* ) );//给一致集分配空间  
  720.   
  721.     //匹配类型是FEATURE_MDL_MATCH,匹配点的坐标是mdl_pt域  
  722.     if( mtype == FEATURE_MDL_MATCH )  
  723.         for( i = 0; i < n; i++ )  
  724.         {  
  725.             //根据给定的匹配类型,返回输入特征点的匹配点  
  726.             match = get_match( features[i], mtype );  
  727.             if( ! match )  
  728.                 fatal_error( "feature does not have match of type %d, %s line %d",  
  729.                             mtype, __FILE__, __LINE__ );  
  730.             pt = features[i]->img_pt;//特征点的坐标  
  731.             mpt = match->mdl_pt;//对应匹配点的坐标  
  732.             err = err_fn( pt, mpt, M );//计算"pt经M变换后的点"和mpt之间的距离的平方,即变换误差  
  733.             if( err <= err_tol )//若变换误差小于容错度,将其加入一致集  
  734.                 _consensus[in++] = features[i];  
  735.         }  
  736.     //匹配类型不是FEATURE_MDL_MATCH,匹配点的坐标是img_pt域  
  737.     else  
  738.         for( i = 0; i < n; i++ )  
  739.         {  
  740.             //根据给定的匹配类型,返回输入特征点的匹配点  
  741.             match = get_match( features[i], mtype );  
  742.             if( ! match )  
  743.                 fatal_error( "feature does not have match of type %d, %s line %d",  
  744.                             mtype, __FILE__, __LINE__ );  
  745.             pt = features[i]->img_pt;//特征点的坐标  
  746.             mpt = match->img_pt;//对应匹配点的坐标  
  747.             err = err_fn( pt, mpt, M );//计算"pt经M变换后的点"和mpt之间的距离的平方,即变换误差  
  748.             if( err <= err_tol )//若变换误差小于容错度,将其加入一致集  
  749.                 _consensus[in++] = features[i];  
  750.         }  
  751.     *consensus = _consensus;  
  752.     return in;//返回一致集中元素个数  
  753. }  
  754.   
  755.   
  756. /*释放输入参数的存储空间 
  757. */  
  758. /* 
  759. Releases memory and reduces code size above 
  760. @param pts1 an array of points 
  761. @param pts2 an array of points 
  762. @param features an array of pointers to features; can be NULL 
  763. */  
  764. static __inline void release_mem( CvPoint2D64f* pts1, CvPoint2D64f* pts2,  
  765.                                   struct feature** features )  
  766. {  
  767.     free( pts1 );  
  768.     free( pts2 );  
  769.     if( features )  
  770.         free( features );  
  771. }  


0 0
原创粉丝点击