/* Calculates a best-fit image transform from image feature correspondences using RANSAC. For more information refer to: Fischler, M. A. and Bolles, R. C. Random sample consensus: a paradigm for model fitting with applications to image analysis and automated cartography. <EM>Communications of the ACM, 24</EM>, 6 (1981), pp. 381--395. @param features an array of features; only features with a non-NULL match of type mtype are used in homography computation @param n number of features in feat @param mtype determines which of each feature's match fields to use for model computation; should be one of FEATURE_FWD_MATCH, FEATURE_BCK_MATCH, or FEATURE_MDL_MATCH; if this is FEATURE_MDL_MATCH, correspondences are assumed to be between a feature's img_pt field and its match's mdl_pt field, otherwise correspondences are assumed to be between the the feature's img_pt field and its match's img_pt field @param xform_fn pointer to the function used to compute the desired transformation from feature correspondences @param m minimum number of correspondences necessary to instantiate the model computed by xform_fn @param p_badxform desired probability that the final transformation returned by RANSAC is corrupted by outliers (i.e. the probability that no samples of all inliers were drawn) @param err_fn pointer to the function used to compute a measure of error between putative correspondences and a computed model @param err_tol correspondences within this distance of a computed model are considered as inliers @param inliers if not NULL, output as an array of pointers to the final set of inliers @param n_in if not NULL and \a inliers is not NULL, output as the final number of inliers @return Returns a transformation matrix computed using RANSAC or NULL on error or if an acceptable transform could not be computed. */ CvMat* ransac_xform( struct feature* features, int n, int mtype, ransac_xform_fn xform_fn, int m, double p_badxform, ransac_err_fn err_fn, double err_tol, struct feature*** inliers, int* n_in ) { //matched:所有具有mtype类型匹配点的特征点的数组,也就是样本集 //sample:单个样本,即4个特征点的数组 //consensus:当前一致集; //consensus_max:当前最大一致集(即当前的最好结果的一致集) struct feature** matched, ** sample, ** consensus, ** consensus_max = NULL; struct ransac_data* rdata;//每个特征点的feature_data域的ransac数据指针 CvPoint2D64f* pts, * mpts;//每个样本对应的两个坐标数组:特征点坐标数组pts和匹配点坐标数组mpts CvMat* M = NULL;//当前变换矩阵 //p:当前计算出的模型的错误概率,当p小于p_badxform时迭代停止 //in_frac:内点数目占样本总数目的百分比 double p, in_frac = RANSAC_INLIER_FRAC_EST; //nm:输入的特征点数组中具有mtype类型匹配点的特征点个数 //in:当前一致集中元素个数 //in_min:一致集中元素个数允许的最小值,保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目 //in_max:当前最优一致集(最大一致集)中元素的个数 //k:迭代次数,与计算当前模型的错误概率有关 int i, nm, in, in_min, in_max = 0, k = 0; //找到特征点数组features中所有具有mtype类型匹配点的特征点,放到matched数组(样本集)中,返回值nm是matched数组的元素个数 nm = get_matched_features( features, n, mtype, &matched ); //若找到的具有匹配点的特征点个数小于计算变换矩阵需要的最小特征点对个数,出错 if( nm < m ) { //出错处理,特征点对个数不足 fprintf( stderr, "Warning: not enough matches to compute xform, %s" \ " line %d\n", __FILE__, __LINE__ ); goto end; } /* initialize random number generator */ srand( time(NULL) );//初始化随机数生成器 //计算保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目 in_min = calc_min_inliers( nm, m, RANSAC_PROB_BAD_SUPP, p_badxform ); //当前计算出的模型的错误概率,内点所占比例in_frac越大,错误概率越小;迭代次数k越大,错误概率越小 p = pow( 1.0 - pow( in_frac, m ), k ); i = 0; //当前错误概率大于输入的允许错误概率p_badxform,继续迭代 while( p > p_badxform ) { //从样本集matched中随机抽选一个RANSAC样本(即一个4个特征点的数组),放到样本变量sample中 sample = draw_ransac_sample( matched, nm, m ); //从样本中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中 extract_corresp_pts( sample, m, mtype, &pts, &mpts ); //调用参数中传入的函数xform_fn,计算将m个点的数组pts变换为mpts的矩阵,返回变换矩阵给M M = xform_fn( pts, mpts, m );//一般传入lsq_homog()函数 if( ! M )//出错判断 goto iteration_end; //给定特征点集,变换矩阵,误差函数,计算出当前一致集consensus,返回一致集中元素个数给in in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus); //若当前一致集大于历史最优一致集,即当前一致集为最优,则更新最优一致集consensus_max if( in > in_max ) { if( consensus_max )//若之前有最优值,释放其空间 free( consensus_max ); consensus_max = consensus;//更新最优一致集 in_max = in;//更新最优一致集中元素个数 in_frac = (double)in_max / nm;//最优一致集中元素个数占样本总个数的百分比 } else//若当前一致集小于历史最优一致集,释放当前一致集 free( consensus ); cvReleaseMat( &M ); iteration_end: release_mem( pts, mpts, sample ); p = pow( 1.0 - pow( in_frac, m ), ++k );//更新当前错误概率 } //根据最优一致集计算最终的变换矩阵 /* calculate final transform based on best consensus set */ //若最优一致集中元素个数大于最低标准,即符合要求 if( in_max >= in_min ) { //从最优一致集中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中 extract_corresp_pts( consensus_max, in_max, mtype, &pts, &mpts ); //调用参数中传入的函数xform_fn,计算将in_max个点的数组pts变换为mpts的矩阵,返回变换矩阵给M M = xform_fn( pts, mpts, in_max ); /***********下面会再进行一次迭代**********/ //根据变换矩阵M从样本集matched中计算出一致集consensus,返回一致集中元素个数给in in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus); cvReleaseMat( &M ); release_mem( pts, mpts, consensus_max ); //从一致集中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中 extract_corresp_pts( consensus, in, mtype, &pts, &mpts ); //调用参数中传入的函数xform_fn,计算将in个点的数组pts变换为mpts的矩阵,返回变换矩阵给M M = xform_fn( pts, mpts, in ); if( inliers ) { *inliers = consensus;//将最优一致集赋值给输出参数:inliers,即内点集合 consensus = NULL; } if( n_in ) *n_in = in;//将最优一致集中元素个数赋值给输出参数:n_in,即内点个数 release_mem( pts, mpts, consensus ); } else if( consensus_max ) { //没有计算出符合要求的一致集 if( inliers ) *inliers = NULL; if( n_in ) *n_in = 0; free( consensus_max ); } //RANSAC算法结束:恢复特征点中被更改的数据域feature_data,并返回变换矩阵M end: for( i = 0; i < nm; i++ ) { //利用宏feat_ransac_data来提取matched[i]中的feature_data成员并转换为ransac_data格式的指针 rdata = feat_ransac_data( matched[i] ); //恢复feature_data成员的以前的值 matched[i]->feature_data = rdata->orig_feat_data; free( rdata );//释放内存 } free( matched ); return M;//返回求出的变换矩阵M }
/* Calculates a best-fit image transform from image feature correspondences using RANSAC. For more information refer to: Fischler, M. A. and Bolles, R. C. Random sample consensus: a paradigm for model fitting with applications to image analysis and automated cartography. <EM>Communications of the ACM, 24</EM>, 6 (1981), pp. 381--395. @param features an array of features; only features with a non-NULL match of type mtype are used in homography computation @param n number of features in feat @param mtype determines which of each feature's match fields to use for model computation; should be one of FEATURE_FWD_MATCH, FEATURE_BCK_MATCH, or FEATURE_MDL_MATCH; if this is FEATURE_MDL_MATCH, correspondences are assumed to be between a feature's img_pt field and its match's mdl_pt field, otherwise correspondences are assumed to be between the the feature's img_pt field and its match's img_pt field @param xform_fn pointer to the function used to compute the desired transformation from feature correspondences @param m minimum number of correspondences necessary to instantiate the model computed by xform_fn @param p_badxform desired probability that the final transformation returned by RANSAC is corrupted by outliers (i.e. the probability that no samples of all inliers were drawn) @param err_fn pointer to the function used to compute a measure of error between putative correspondences and a computed model @param err_tol correspondences within this distance of a computed model are considered as inliers @param inliers if not NULL, output as an array of pointers to the final set of inliers @param n_in if not NULL and \a inliers is not NULL, output as the final number of inliers @return Returns a transformation matrix computed using RANSAC or NULL on error or if an acceptable transform could not be computed. */ CvMat* ransac_xform( struct feature* features, int n, int mtype, ransac_xform_fn xform_fn, int m, double p_badxform, ransac_err_fn err_fn, double err_tol, struct feature*** inliers, int* n_in ) { struct feature** matched, ** sample, ** consensus, ** consensus_max = NULL; struct ransac_data* rdata; CvPoint2D64f* pts, * mpts; CvMat* M = NULL; double p, in_frac = RANSAC_INLIER_FRAC_EST; int i, nm, in, in_min, in_max = 0, k = 0; nm = get_matched_features( features, n, mtype, &matched ); if( nm < m ) { fprintf( stderr, "Warning: not enough matches to compute xform, %s" \ " line %d\n", __FILE__, __LINE__ ); goto end; } srandom( time(NULL) ); in_min = calc_min_inliers( nm, m, RANSAC_PROB_BAD_SUPP, p_badxform ); p = pow( 1.0 - pow( in_frac, m ), k ); while( p > p_badxform ) { sample = draw_ransac_sample( matched, nm, m ); extract_corresp_pts( sample, m, mtype, &pts, &mpts ); M = xform_fn( pts, mpts, m ); if( ! M ) goto iteration_end; in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus); if( in > in_max ) { if( consensus_max ) free( consensus_max ); consensus_max = consensus; in_max = in; in_frac = (double)in_max / nm; } else free( consensus ); cvReleaseMat( &M ); iteration_end: release_mem( pts, mpts, sample ); p = pow( 1.0 - pow( in_frac, m ), ++k ); } /* calculate final transform based on best consensus set */ if( in_max >= in_min ) { extract_corresp_pts( consensus_max, in_max, mtype, &pts, &mpts ); M = xform_fn( pts, mpts, in_max ); in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus); cvReleaseMat( &M ); release_mem( pts, mpts, consensus_max ); extract_corresp_pts( consensus, in, mtype, &pts, &mpts ); M = xform_fn( pts, mpts, in ); if( inliers ) { *inliers = consensus; consensus = NULL; } if( n_in ) *n_in = in; release_mem( pts, mpts, consensus ); } else if( consensus_max ) { if( inliers ) *inliers = NULL; if( n_in ) *n_in = 0; free( consensus_max ); } end: for( i = 0; i < nm; i++ ) { rdata = feat_ransac_data( matched[i] ); matched[i]->feature_data = rdata->orig_feat_data; free( rdata ); } free( matched ); return M; }