利用RANSAC算法筛选SIFT特征匹配

关于RANSAC算法的基本思想,可从网上搜索找到,这里只是RANSAC用于SIFT特征匹配筛选时的一些说明。

RANSAC算法在SIFT特征筛选中的主要流程是:

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

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

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

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

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

下面结合RobHess的源码说明一下RANSAC算法在SIFT特征匹配筛选中的实现,

具体的源码分析见此系列文章:RobHess的SIFT源码分析:综述

在RobHess的源码中,RANSAC算法的声明和实现在xform.h和xform.c文件中

实现RANSAC算法的主函数是ransac_xform,如下:

1 CvMat* ransac_xform( struct feature* features, int n, int mtype,
2              ransac_xform_fn xform_fn, int m, double p_badxform,
3              ransac_err_fn err_fn, double err_tol,
4              struct feature*** inliers, int* n_in )

函数说明:利用RANSAC算法进行特征点筛选,计算出最佳匹配的变换矩阵
参数:
features:特征点数组,只有当mtype类型的匹配点存在时才被用来进行单应性计算
n:特征点个数
mtype:决定使用每个特征点的哪个匹配域进行变换矩阵的计算,应该是FEATURE_MDL_MATCH,
    FEATURE_BCK_MATCH,FEATURE_MDL_MATCH中的一个。若是FEATURE_MDL_MATCH,
    对应的匹配点对坐标是每个特征点的img_pt域和其匹配点的mdl_pt域,
    否则,对应的匹配点对是每个特征点的img_pt域和其匹配点的img_pt域。
xform_fn:函数指针,指向根据输入的点对进行变换矩阵计算的函数,一般传入lsq_homog()函数
m:在函数xform_fn中计算变换矩阵需要的最小特征点对个数
p_badxform:允许的错误概率,即允许RANSAC算法计算出的变换矩阵错误的概率,当前计算出的模型的错误概率小于p_badxform时迭代停止
err_fn:函数指针,对于给定的变换矩阵,计算推定的匹配点对之间的变换误差,一般传入homog_xfer_err()函数
err_tol:容错度,对于给定的变换矩阵,在此范围内的点对被认为是内点
inliers:输出参数,指针数组,指向计算出的最终的内点集合,若为空,表示没计算出符合要求的一致集
           此数组的内存将在本函数中被分配,使用完后必须在调用出释放:free(*inliers)
n_in:输出参数,最终计算出的内点的数目
返回值:RANSAC算法计算出的变换矩阵,若为空,表示出错或无法计算出可接受矩阵

注释如下:

  1 CvMat* ransac_xform( struct feature* features, int n, int mtype,
  2                     ransac_xform_fn xform_fn, int m, double p_badxform,
  3                     ransac_err_fn err_fn, double err_tol,
  4 struct feature*** inliers, int* n_in )
  5 {
  6     //matched:所有具有mtype类型匹配点的特征点的数组,也就是样本集
  7     //sample:单个样本,即4个特征点的数组
  8     //consensus:当前一致集;
  9     //consensus_max:当前最大一致集(即当前的最好结果的一致集)
 10     struct feature** matched, ** sample, ** consensus, ** consensus_max = NULL;
 11     struct ransac_data* rdata;//每个特征点的feature_data域的ransac数据指针
 12     CvPoint2D64f* pts, * mpts;//每个样本对应的两个坐标数组:特征点坐标数组pts和匹配点坐标数组mpts
 13     CvMat* M = NULL;//当前变换矩阵
 14     //p:当前计算出的模型的错误概率,当p小于p_badxform时迭代停止
 15     //in_frac:内点数目占样本总数目的百分比
 16     double p, in_frac = RANSAC_INLIER_FRAC_EST;
 17     //nm:输入的特征点数组中具有mtype类型匹配点的特征点个数
 18     //in:当前一致集中元素个数
 19     //in_min:一致集中元素个数允许的最小值,保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目
 20     //in_max:当前最优一致集(最大一致集)中元素的个数
 21     //k:迭代次数,与计算当前模型的错误概率有关
 22     int i, nm, in, in_min, in_max = 0, k = 0;
 23
 24     //找到特征点数组features中所有具有mtype类型匹配点的特征点,放到matched数组(样本集)中,返回值nm是matched数组的元素个数
 25     nm = get_matched_features( features, n, mtype, &matched );
 26     //若找到的具有匹配点的特征点个数小于计算变换矩阵需要的最小特征点对个数,出错
 27     if( nm < m )
 28     {   //出错处理,特征点对个数不足
 29         fprintf( stderr, "Warning: not enough matches to compute xform, %s"  30             " line %d\n", __FILE__, __LINE__ );
 31         goto end;
 32     }
 33
 34     /* initialize random number generator */
 35     srand( time(NULL) );//初始化随机数生成器
 36
 37     //计算保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目
 38     in_min = calc_min_inliers( nm, m, RANSAC_PROB_BAD_SUPP, p_badxform );
 39     //当前计算出的模型的错误概率,内点所占比例in_frac越大,错误概率越小;迭代次数k越大,错误概率越小
 40     p = pow( 1.0 - pow( in_frac, m ), k );
 41     i = 0;
 42
 43     //当前错误概率大于输入的允许错误概率p_badxform,继续迭代
 44     while( p > p_badxform )
 45     {
 46         //从样本集matched中随机抽选一个RANSAC样本(即一个4个特征点的数组),放到样本变量sample中
 47         sample = draw_ransac_sample( matched, nm, m );
 48         //从样本中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中
 49         extract_corresp_pts( sample, m, mtype, &pts, &mpts );
 50         //调用参数中传入的函数xform_fn,计算将m个点的数组pts变换为mpts的矩阵,返回变换矩阵给M
 51         M = xform_fn( pts, mpts, m );//一般传入lsq_homog()函数
 52         if( ! M )//出错判断
 53             goto iteration_end;
 54         //给定特征点集,变换矩阵,误差函数,计算出当前一致集consensus,返回一致集中元素个数给in
 55         in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus);
 56
 57         //若当前一致集大于历史最优一致集,即当前一致集为最优,则更新最优一致集consensus_max
 58         if( in > in_max )
 59         {
 60             if( consensus_max )//若之前有最优值,释放其空间
 61                 free( consensus_max );
 62             consensus_max = consensus;//更新最优一致集
 63             in_max = in;//更新最优一致集中元素个数
 64             in_frac = (double)in_max / nm;//最优一致集中元素个数占样本总个数的百分比
 65         }
 66         else//若当前一致集小于历史最优一致集,释放当前一致集
 67             free( consensus );
 68         cvReleaseMat( &M );
 69
 70 iteration_end:
 71         release_mem( pts, mpts, sample );
 72         p = pow( 1.0 - pow( in_frac, m ), ++k );
 73     }
 74
 75     //根据最优一致集计算最终的变换矩阵
 76     /* calculate final transform based on best consensus set */
 77     //若最优一致集中元素个数大于最低标准,即符合要求
 78     if( in_max >= in_min )
 79     {
 80         //从最优一致集中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中
 81         extract_corresp_pts( consensus_max, in_max, mtype, &pts, &mpts );
 82         //调用参数中传入的函数xform_fn,计算将in_max个点的数组pts变换为mpts的矩阵,返回变换矩阵给M
 83         M = xform_fn( pts, mpts, in_max );
 84         /***********下面会再进行一次迭代**********/
 85         //根据变换矩阵M从样本集matched中计算出一致集consensus,返回一致集中元素个数给in
 86         in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus);
 87         cvReleaseMat( &M );
 88         release_mem( pts, mpts, consensus_max );
 89         //从一致集中获取特征点和其对应匹配点的二维坐标,分别放到输出参数pts和mpts中
 90         extract_corresp_pts( consensus, in, mtype, &pts, &mpts );
 91         //调用参数中传入的函数xform_fn,计算将in个点的数组pts变换为mpts的矩阵,返回变换矩阵给M
 92         M = xform_fn( pts, mpts, in );
 93         if( inliers )
 94         {
 95             *inliers = consensus;//将最优一致集赋值给输出参数:inliers,即内点集合
 96             consensus = NULL;
 97         }
 98         if( n_in )
 99             *n_in = in;//将最优一致集中元素个数赋值给输出参数:n_in,即内点个数
100         release_mem( pts, mpts, consensus );
101     }
102     else if( consensus_max )
103     {   //没有计算出符合要求的一致集
104         if( inliers )
105             *inliers = NULL;
106         if( n_in )
107             *n_in = 0;
108         free( consensus_max );
109     }
110
111     //RANSAC算法结束:恢复特征点中被更改的数据域feature_data,并返回变换矩阵M
112 end:
113     for( i = 0; i < nm; i++ )
114     {
115         //利用宏feat_ransac_data来提取matched[i]中的feature_data成员并转换为ransac_data格式的指针
116         rdata = feat_ransac_data( matched[i] );
117         //恢复feature_data成员的以前的值
118         matched[i]->feature_data = rdata->orig_feat_data;
119         free( rdata );//释放内存
120     }
121     free( matched );
122
123     return M;//返回求出的变换矩阵M
124 }

实验测试:

 1 //特征提取和匹配
 2 void match(IplImage *img1,IplImage *img2)
 3 {
 4     IplImage *img1_Feat = cvCloneImage(img1);//复制图1,深拷贝,用来画特征点
 5     IplImage *img2_Feat = cvCloneImage(img2);//复制图2,深拷贝,用来画特征点
 6
 7     struct feature *feat1, *feat2;//feat1:图1的特征点数组,feat2:图2的特征点数组
 8     int n1, n2;//n1:图1中的特征点个数,n2:图2中的特征点个数
 9     struct feature *feat;//每个特征点
10     struct kd_node *kd_root;//k-d树的树根
11     struct feature **nbrs;//当前特征点的最近邻点数组
12     int matchNum;//经距离比值法筛选后的匹配点对的个数
13     struct feature **inliers;//精RANSAC筛选后的内点数组
14     int n_inliers;//经RANSAC算法筛选后的内点个数,即feat1中具有符合要求的特征点的个数
15
16     //默认提取的是LOWE格式的SIFT特征点
17     //提取并显示第1幅图片上的特征点
18     n1 = sift_features( img1, &feat1 );//检测图1中的SIFT特征点,n1是图1的特征点个数
19     export_features("feature1.txt",feat1,n1);//将特征向量数据写入到文件
20     draw_features( img1_Feat, feat1, n1 );//画出特征点
21     cvShowImage("img1_Feat",img1_Feat);//显示
22
23     //提取并显示第2幅图片上的特征点
24     n2 = sift_features( img2, &feat2 );//检测图2中的SIFT特征点,n2是图2的特征点个数
25     export_features("feature2.txt",feat2,n2);//将特征向量数据写入到文件
26     draw_features( img2_Feat, feat2, n2 );//画出特征点
27     cvShowImage("img2_Feat",img2_Feat);//显示
28
29     Point pt1,pt2;//连线的两个端点
30     double d0,d1;//feat1中每个特征点到最近邻和次近邻的距离
31     matchNum = 0;//经距离比值法筛选后的匹配点对的个数
32
33     //将2幅图片合成1幅图片,上下排列
34     stacked = stack_imgs( img1, img2 );//合成图像,显示经距离比值法筛选后的匹配结果
35     stacked_ransac = stack_imgs( img1, img2 );//合成图像,显示经RANSAC算法筛选后的匹配结果
36
37     //根据图2的特征点集feat2建立k-d树,返回k-d树根给kd_root
38     kd_root = kdtree_build( feat2, n2 );
39
40     //遍历特征点集feat1,针对feat1中每个特征点feat,选取符合距离比值条件的匹配点,放到feat的fwd_match域中
41     for(int i = 0; i < n1; i++ )
42     {
43         feat = feat1+i;//第i个特征点的指针
44         //在kd_root中搜索目标点feat的2个最近邻点,存放在nbrs中,返回实际找到的近邻点个数
45         int k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );
46         if( k == 2 )
47         {
48             d0 = descr_dist_sq( feat, nbrs[0] );//feat与最近邻点的距离的平方
49             d1 = descr_dist_sq( feat, nbrs[1] );//feat与次近邻点的距离的平方
50             //若d0和d1的比值小于阈值NN_SQ_DIST_RATIO_THR,则接受此匹配,否则剔除
51             if( d0 < d1 * NN_SQ_DIST_RATIO_THR )
52             {   //将目标点feat和最近邻点作为匹配点对
53                 pt1 = Point( cvRound( feat->x ), cvRound( feat->y ) );//图1中点的坐标
54                 pt2 = Point( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );//图2中点的坐标(feat的最近邻点)
55                 pt2.y += img1->height;//由于两幅图是上下排列的,pt2的纵坐标加上图1的高度,作为连线的终点
56                 cvLine( stacked, pt1, pt2, CV_RGB(255,0,255), 1, 8, 0 );//画出连线
57                 matchNum++;//统计匹配点对的个数
58                 feat1[i].fwd_match = nbrs[0];//使点feat的fwd_match域指向其对应的匹配点
59             }
60         }
61         free( nbrs );//释放近邻数组
62     }
63     qDebug()<<tr("经距离比值法筛选后的匹配点对个数:")<<matchNum<<endl;
64     //显示并保存经距离比值法筛选后的匹配图
65     cvNamedWindow(IMG_MATCH1);//创建窗口
66     cvShowImage(IMG_MATCH1,stacked);//显示
67
68     //利用RANSAC算法筛选匹配点,计算变换矩阵H
69     CvMat * H = ransac_xform(feat1,n1,FEATURE_FWD_MATCH,lsq_homog,4,0.01,homog_xfer_err,3.0,&inliers,&n_inliers);
70     qDebug()<<tr("经RANSAC算法筛选后的匹配点对个数:")<<n_inliers<<endl;
71     //遍历经RANSAC算法筛选后的特征点集合inliers,找到每个特征点的匹配点,画出连线
72     for(int i=0; i<n_inliers; i++)
73     {
74         feat = inliers[i];//第i个特征点
75         pt1 = Point(cvRound(feat->x), cvRound(feat->y));//图1中点的坐标
76         pt2 = Point(cvRound(feat->fwd_match->x), cvRound(feat->fwd_match->y));//图2中点的坐标(feat的匹配点)
77         qDebug()<<"("<<pt1.x<<","<<pt1.y<<")--->("<<pt2.x<<","<<pt2.y<<")"<<endl;
78         pt2.y += img1->height;//由于两幅图是上下排列的,pt2的纵坐标加上图1的高度,作为连线的终点
79         cvLine(stacked_ransac,pt1,pt2,CV_RGB(255,0,255),1,8,0);//画出连线
80     }
81     cvNamedWindow(IMG_MATCH2);//创建窗口
82     cvShowImage(IMG_MATCH2,stacked_ransac);//显示
83 }

结果:

    

RANSAC筛选前                    RANSAC筛选后

    

RANSAC筛选前                                                       RANSAC筛选后

    

RANSAC筛选前                     RANSAC筛选后

         

RANSAC筛选前                                                           RANSAC筛选后

    

RANSAC筛选前                    RANSAC筛选后

     

RANSAC筛选前                    RANSAC筛选后

      

RANSAC筛选前                                                         RANSAC筛选后

       

RANSAC筛选前                                                        RANSAC筛选后

      

RANSAC筛选前                                                         RANSAC筛选后

RANSAC筛选前

RANSAC筛选后

RANSAC筛选前

RANSAC筛选后

RANSAC筛选前

RANSAC筛选后

时间: 2024-10-15 01:49:01

利用RANSAC算法筛选SIFT特征匹配的相关文章

OpenCV2.4.4中调用SIFT特征检测器进行图像匹配

OpenCV中一些相关结构说明: 特征点类: class KeyPoint { Point2f pt; //坐标 float size; //特征点邻域直径 float angle; //特征点的方向,值为[0,360),负值表示不使用 float response; // int octave; //特征点所在的图像金字塔的组 int class_id; //用于聚类的id } 存放匹配结果的结构: 1 struct DMatch 2 { 3 //三个构造函数 4 DMatch(): quer

基于SIFT特征的全景图像拼接

基于SIFT特征的全景图像拼接 分类: image Machine learning2013-07-05 13:33 2554人阅读 评论(3) 收藏 举报 基于SIFT特征的全景图像拼接 分类: 计算机视觉/OpenCV2013-07-04 21:43 91人阅读 评论(0) 收藏 举报 主要分为以下几个步骤: (1) 读入两张图片并分别提取SIFT特征 (2) 利用k-d tree和BBF算法进行特征匹配查找 (3) 利用RANSAC算法筛选匹配点并计算变换矩阵 (3) 图像融合 SIFT算

Random Sample Consensus(RANSAC)算法介绍

转眼间2012年过了三个月了,最近在做目标跟踪,需要利用ransac算法进行图像匹配,使用Opencv+vs进行实现.终于初见成效啊,很激动也很兴奋,在这里mark一下,以备查用 !这里就不贴源码了,想想都是泪啊! RANSAC是"RANdom SAmple Consensus(随机抽样一致)"的缩写.它可以从一组包含"局外点"的观测数据集中,通过迭代方式估计数学模型的参数.它是一种不确定的算法--它有一定的概率得出一个合理的结果:为了提高概率必须提高迭代次数.该算

【特征匹配】RANSAC算法原理与源码解析

转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/50217655 随机抽样一致性(RANSAC)算法,可以在一组包含"外点"的数据集中,采用不断迭代的方法,寻找最优参数模型,不符合最优模型的点,被定义为"外点".在图像配准以及拼接上得到广泛的应用,本文将对RANSAC算法在OpenCV中角点误匹配对的检测中进行解析. 1.RANSAC原理 OpenCV中滤除误匹配对采用RANSAC算法寻找一个最佳

【特征匹配】SIFT原理之KD树+BBF算法解析

继上一篇中已经介绍了SIFT原理点击打开链接,最后得到了一系列特征点,每个特征点对应一个128维向量.假如现在有两副图片都已经提取到特征点,现在要做的就是匹配上相似的特征点. 相似性查询有两种基本方式:1.范围查询:即给点查询点和查询阈值,从数据集中找出所有与查询点距离小于阈值的点. 2.K近邻查询:给点查询点及正整数K,从数据集中找到与查询点最近的K个数据,当K=1时,就是最近邻查询. 特征匹配算子可以分为两类:1.穷举法:即将数据集中的点与查询点逐一计算距离,如果图1提取到N1个特征点,图2

视觉SLAM之RANSAC算法用于消除图像误匹配的原理

在基于特征点的视觉SLAM中,通常情况下,在特征匹配过程中往往会存在误匹配信息,使得计算获取的位姿精度低,易产生位姿估计失败的问题,因此,剔除这些错配点有很大的必要性.常会用到RANSAC算法进行消除两两匹配图像的误匹配点,如果只停留在应用的层面上很简单,直接调用opencv函数就行,看到效果时,感觉好神奇,到底怎么实现的啊,以前一直也没弄太明白,与图像结合的博客也比较少,在查阅了一些资料后,笔者似乎明白了一点,希望笔者的总结会对您的理解有帮助. 首先先介绍一下RANSAC算法(RANdom S

【特征匹配】SIFT原理与C源码剖析

关于SIFT的原理已经有很多大牛的博客上做了解析,本文重点将以Rob Hess等人用C实现的代码做解析,结合代码SIFT原理会更容易理解.一些难理解点的用了☆标注. 欢迎大家批评指正! SIFT(Scale-invariant feature transform)即尺度不变特征转换,提取的局部特征点具有尺度不变性,且对于旋转,亮度,噪声等有很高的稳定性. SIFT特征点提取 本文将以下函数为参照顺序介绍SIFT特征点提取与描述方法. 1.图像预处理 2.构建高斯金字塔(不同尺度下的图像) 3.生

[翻译]鲁棒的尺度不变特征匹配在遥感图像配准中应用(Robust Scale-Invariant Feature Matching for Remote Sensing Image Registration)

李乔亮,汪国有,刘建国,会员,IEEE,和陈少波 2008年8月7日接收;2008年10月22日和2008年11月27日修改.2009年2月2日首版:当前版本出版于2009年4月17日.本项工作由中国国家基础研究项目60672060资助. 中国湖北省武汉市华中科技大学模式识别与人工智能国家重点实验室,邮编430074(邮箱:[email protected];   [email protected];  [email protected];  [email protected]) 数字对象识别编

openCV中的findHomography函数分析以及RANSAC算法的详解

本文将openCV中的RANSAC代码全部挑选出来,进行分析和讲解,以便大家更好的理解RANSAC算法.代码我都试过,可以直接运行. 在计算机视觉和图像处理等很多领域,都需要用到RANSAC算法.openCV中也有封装好的RANSAC算法,以便于人们使用.关于RANSAC算法的一些应用,可以看我的另一篇博客: 利用SIFT和RANSAC算法(openCV框架)实现物体的检测与定位,并求出变换矩阵(findFundamentalMat和findHomography的比较) 但是前几天师弟在使用op