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

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

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

分类: 计算机视觉/OpenCV   91人阅读  评论(0)  收藏  举报

主要分为以下几个步骤:

(1) 读入两张图片并分别提取SIFT特征

(2) 利用k-d tree和BBF算法进行特征匹配查找

(3) 利用RANSAC算法筛选匹配点并计算变换矩阵

(3) 图像融合


SIFT算法以及RANSAC算法都是利用的RobHess的SIFT源码,前三个步骤RobHess的源码中都有自带的示例。


(1) SIFT特征提取

直接调用RobHess源码中的sift_features()函数进行默认参数的SIFT特征提取,主要代码如下:

[cpp]  view plain copy
  1. img1_Feat = cvCloneImage(img1);//复制图1,深拷贝,用来画特征点  
  2. img2_Feat = cvCloneImage(img2);//复制图2,深拷贝,用来画特征点  
  3.   
  4. //默认提取的是LOWE格式的SIFT特征点  
  5. //提取并显示第1幅图片上的特征点  
  6. n1 = sift_features( img1, &feat1 );//检测图1中的SIFT特征点,n1是图1的特征点个数  
  7. export_features("feature1.txt",feat1,n1);//将特征向量数据写入到文件  
  8. draw_features( img1_Feat, feat1, n1 );//画出特征点  
  9. cvNamedWindow(IMG1_FEAT);//创建窗口  
  10. cvShowImage(IMG1_FEAT,img1_Feat);//显示  
  11.   
  12. //提取并显示第2幅图片上的特征点  
  13. n2 = sift_features( img2, &feat2 );//检测图2中的SIFT特征点,n2是图2的特征点个数  
  14. export_features("feature2.txt",feat2,n2);//将特征向量数据写入到文件  
  15. draw_features( img2_Feat, feat2, n2 );//画出特征点  
  16. cvNamedWindow(IMG2_FEAT);//创建窗口  
  17. cvShowImage(IMG2_FEAT,img2_Feat);//显示  
检测出的SIFT特征点如下:

                 


(2) 利用k-d tree和BBF算法进行特征匹配查找,并根据最近邻和次近邻距离比值进行初步筛选

也是调用RobHess源码中的函数,加上之后的一些筛选处理,主要代码如下:

[cpp]  view plain copy
  1. //根据图1的特征点集feat1建立k-d树,返回k-d树根给kd_root  
  2. kd_root = kdtree_build( feat1, n1 );  
  3.   
  4. Point pt1,pt2;//连线的两个端点  
  5. double d0,d1;//feat2中每个特征点到最近邻和次近邻的距离  
  6. int matchNum = 0;//经距离比值法筛选后的匹配点对的个数  
  7.   
  8. //遍历特征点集feat2,针对feat2中每个特征点feat,选取符合距离比值条件的匹配点,放到feat的fwd_match域中  
  9. for(int i = 0; i < n2; i++ )  
  10. {  
  11.     feat = feat2+i;//第i个特征点的指针  
  12.     //在kd_root中搜索目标点feat的2个最近邻点,存放在nbrs中,返回实际找到的近邻点个数  
  13.     int k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );  
  14.     if( k == 2 )  
  15.     {  
  16.         d0 = descr_dist_sq( feat, nbrs[0] );//feat与最近邻点的距离的平方  
  17.         d1 = descr_dist_sq( feat, nbrs[1] );//feat与次近邻点的距离的平方  
  18.         //若d0和d1的比值小于阈值NN_SQ_DIST_RATIO_THR,则接受此匹配,否则剔除  
  19.         if( d0 < d1 * NN_SQ_DIST_RATIO_THR )  
  20.         {   //将目标点feat和最近邻点作为匹配点对  
  21.             pt2 = Point( cvRound( feat->x ), cvRound( feat->y ) );//图2中点的坐标  
  22.             pt1 = Point( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );//图1中点的坐标(feat的最近邻点)  
  23.             pt2.x += img1->width;//由于两幅图是左右排列的,pt2的横坐标加上图1的宽度,作为连线的终点  
  24.             cvLine( stacked, pt1, pt2, CV_RGB(255,0,255), 1, 8, 0 );//画出连线  
  25.             matchNum++;//统计匹配点对的个数  
  26.             feat2[i].fwd_match = nbrs[0];//使点feat的fwd_match域指向其对应的匹配点  
  27.         }  
  28.     }  
  29.     free( nbrs );//释放近邻数组  
  30. }  
  31. //显示并保存经距离比值法筛选后的匹配图  
  32. cvNamedWindow(IMG_MATCH1);//创建窗口  
  33. cvShowImage(IMG_MATCH1,stacked);//显示  
匹配结果如下:



(3) 利用RANSAC算法筛选匹配点并计算变换矩阵

此部分最主要的是RobHess源码中的ransac_xform()函数,此函数实现了用RANSAC算法筛选匹配点,返回结果是计算好的变换矩阵。

此部分中,我利用匹配点的坐标关系,对输入的两幅图像的左右关系进行了判断,并根据结果选择使用矩阵H或H的逆阵进行变换。

所以读入的两幅要拼接的图像的左右位置关系可以随意,程序中可自动调整。

主要代码如下:


[cpp]  view plain copy
  1. //利用RANSAC算法筛选匹配点,计算变换矩阵H,  
  2. //无论img1和img2的左右顺序,计算出的H永远是将feat2中的特征点变换为其匹配点,即将img2中的点变换为img1中的对应点  
  3. H = ransac_xform(feat2,n2,FEATURE_FWD_MATCH,lsq_homog,4,0.01,homog_xfer_err,3.0,&inliers,&n_inliers);  
  4.   
  5. //若能成功计算出变换矩阵,即两幅图中有共同区域  
  6. if( H )  
  7. {  
  8.     qDebug()<<tr("经RANSAC算法筛选后的匹配点对个数:")<<n_inliers<<endl; //输出筛选后的匹配点对个数  
  9.   
  10.     int invertNum = 0;//统计pt2.x > pt1.x的匹配点对的个数,来判断img1中是否右图  
  11.   
  12.     //遍历经RANSAC算法筛选后的特征点集合inliers,找到每个特征点的匹配点,画出连线  
  13.     for(int i=0; i<n_inliers; i++)  
  14.     {  
  15.         feat = inliers[i];//第i个特征点  
  16.         pt2 = Point(cvRound(feat->x), cvRound(feat->y));//图2中点的坐标  
  17.         pt1 = Point(cvRound(feat->fwd_match->x), cvRound(feat->fwd_match->y));//图1中点的坐标(feat的匹配点)  
  18.         //qDebug()<<"pt2:("<<pt2.x<<","<<pt2.y<<")--->pt1:("<<pt1.x<<","<<pt1.y<<")";//输出对应点对  
  19.   
  20.         //统计匹配点的左右位置关系,来判断图1和图2的左右位置关系  
  21.         if(pt2.x > pt1.x)  
  22.             invertNum++;  
  23.   
  24.         pt2.x += img1->width;//由于两幅图是左右排列的,pt2的横坐标加上图1的宽度,作为连线的终点  
  25.         cvLine(stacked_ransac,pt1,pt2,CV_RGB(255,0,255),1,8,0);//在匹配图上画出连线  
  26.     }  
  27.   
  28.     cvNamedWindow(IMG_MATCH2);//创建窗口  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值