surf匹配算法opencv示例代码

来源:互联网 发布:c语言double输出格式 编辑:程序博客网 时间:2024/05/16 08:10

1、surf特征+FLANN特征匹配+knn筛选匹配点+单应性矩阵映射

  1. #include "stdafx.h"  
  2. #include <stdio.h>  
  3. #include <iostream>  
  4. #include <opencv2/core/core.hpp>  
  5. #include "opencv2/nonfree/features2d.hpp"  
  6. #include<opencv2/legacy/legacy.hpp>  
  7. #include <opencv2/highgui/highgui.hpp>  
  8.   
  9. using namespace cv;  
  10. using namespace std;  
  11.   
  12. int main( )  
  13. {  
  14.   Mat img_1 = imread( "C:\\temp\\PyramidPattern.jpg", CV_LOAD_IMAGE_GRAYSCALE );  
  15.   Mat img_2 = imread( "C:\\temp\\PyramidPatternTest.bmp", CV_LOAD_IMAGE_GRAYSCALE );  
  16.     
  17.   if( !img_1.data || !img_2.data )  
  18.   { return -1; }  
  19.   
  20.   //-- Step 1: Detect the keypoints using SURF Detector  
  21.   int minHessian = 400;  
  22.   
  23.   SurfFeatureDetector detector( minHessian );  
  24.   
  25.   vector<KeyPoint> keypoints_1, keypoints_2;  
  26.   
  27.   detector.detect( img_1, keypoints_1 );  
  28.   detector.detect( img_2, keypoints_2 );  
  29.   
  30.   //-- Step 2: Calculate descriptors (feature vectors)  
  31.   SurfDescriptorExtractor extractor;  
  32.   
  33.   Mat descriptors_1, descriptors_2;  
  34.   
  35.   extractor.compute( img_1, keypoints_1, descriptors_1 );  
  36.   extractor.compute( img_2, keypoints_2, descriptors_2 );  
  37.   
  38.   //-- Step 3: Matching descriptor vectors using FLANN matcher  
  39.   FlannBasedMatcher matcher;  
  40.   vector< DMatch > matches;  
  41.   vector<vector<DMatch>> m_knnMatches;  
  42.   
  43.   matches.clear();  
  44.   const float minRatio=1.f / 1.5f;  
  45.   matcher.knnMatch(descriptors_1,descriptors_2,m_knnMatches,2);  
  46.   
  47.   for (int i=0; i<m_knnMatches.size(); i++)  
  48.   {  
  49.       const DMatch& bestMatch=m_knnMatches[i][0];  
  50.       const DMatch& betterMatch=m_knnMatches[i][1];  
  51.   
  52.       float distanceRatio=bestMatch.distance/betterMatch.distance;  
  53.   
  54.       if (distanceRatio<minRatio)  
  55.       {  
  56.           matches.push_back(bestMatch);  
  57.       }  
  58.   }  
  59.   
  60.   vector< DMatch > good_matches;  
  61.   
  62.   if(!matches.size())  
  63.   {  
  64.       cout<<"matches is empty! "<<endl;  
  65.       return -1;  
  66.   }  
  67.   else if (matches.size()<4)  
  68.   {  
  69.       cout<<matches.size()<<" points matched is not enough "<<endl;  
  70.   }  
  71.   else //单应性矩阵的计算最少得使用4个点  
  72.   {  
  73.       forint i = 0; i < matches.size(); i++ )  
  74.       {   
  75.           good_matches.push_back(matches[i]);  
  76.       }    
  77.   
  78.       Mat img_matches;  
  79.       drawMatches( img_1, keypoints_1, img_2, keypoints_2,   
  80.           good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),   
  81.           vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );   
  82.       //☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★  
  83.       //-- Localize the object from img_1 in img_2   
  84.       vector<Point2f> obj;  
  85.       vector<Point2f> scene;  
  86.   
  87.       forint i = 0; i < good_matches.size(); i++ )  
  88.       {  
  89.           //-- Get the keypoints from the good matches  
  90.           obj.push_back( keypoints_1[ good_matches[i].queryIdx ].pt );  
  91.           scene.push_back( keypoints_2[ good_matches[i].trainIdx ].pt );   
  92.       }  
  93.       Mat H = findHomography( obj, scene, CV_RANSAC );  
  94.   
  95.       //-- Get the corners from the image_1 ( the object to be "detected" )  
  96.       vector<Point2f> obj_corners(4);  
  97.       obj_corners[0]=cvPoint(0,0);  
  98.       obj_corners[1]=cvPoint( img_1.cols, 0 );  
  99.       obj_corners[2]=cvPoint(img_1.cols,img_1.rows);  
  100.       obj_corners[3]=cvPoint(0,img_1.rows);  
  101.       vector<Point2f> scene_corners(4);  
  102.   
  103.       perspectiveTransform( obj_corners, scene_corners, H);   
  104.   
  105.       forint i = 0; i < 4; i++ )  
  106.       {  
  107.           /* 作用和perspectiveTransform一样 
  108.           double x = obj_corners[i].x;  
  109.           double y = obj_corners[i].y; 
  110.  
  111.           double Z = 1./( H.at<double>(2,0)*x + H.at<double>(2,1)*y + H.at<double>(2,2) ); 
  112.           double X = ( H.at<double>(0,0)*x + H.at<double>(0,1)*y + H.at<double>(0,2) )*Z; 
  113.           double Y = ( H.at<double>(1,0)*x + H.at<double>(1,1)*y + H.at<double>(1,2) )*Z; 
  114.           scene_corners[i] = cvPoint( cvRound(X) + img_1.cols, cvRound(Y) );*/  
  115.           scene_corners[i].x+=img_1.cols;  
  116.       }   
  117.   
  118.       line( img_matches, scene_corners[0], scene_corners[1], Scalar(0, 255, 0), 2 );  
  119.       line( img_matches, scene_corners[1], scene_corners[2], Scalar( 0, 255, 0), 2 );  
  120.       line( img_matches, scene_corners[2], scene_corners[3], Scalar( 0, 255, 0), 2 );  
  121.       line( img_matches, scene_corners[3], scene_corners[0], Scalar( 0, 255, 0), 2 );  
  122.       imshow( "Good Matches & Object detection", img_matches );  
  123.   }  
  124.   waitKey(0);  
  125.   
  126.   return 0;  
  127. }  

附带一些知识点:

2、图像特征:

1.边界

2.角点(兴趣点)

3.斑点(兴趣区域)

角点是图像的一个局部特征,常用的有harris角点,其算法是一种直接基于灰度图像的,稳定性高,尤其对L型角点检测精度高,但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇现象。具体在OpenCV中的实现就是使用函数cornerHarris。

除了Harris角点检测,还有Shi-Tomasi角点检测,goodFeaturesToTrack角点检测,将找到的点再用FindCornerSubPix()来找出强特征点。也可以自己制作角点检测的函数,需要用到cornerMinEigenVal函数和minMaxLoc函数,最后的特征点选取,判断条件要根据自己的情况编辑。如果对特征点,角点的精度要求更高,可以用cornerSubPix函数将角点定位到子像素。


3、OpenCV仿射变换、投影变换的重要函数

estimateRigidTransform():计算多个二维点对或者图像之间的最优仿射变换矩阵 (2行x3列),H可以是部分自由度,比如各向一致的切变。
getAffineTransform():计算3个二维点对之间的仿射变换矩阵H(2行x3列),自由度为6.
warpAffine():对输入图像进行仿射变换
findHomography: 计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列) ,使用最小均方误差或者RANSAC方法 。
getPerspectiveTransform():计算4个二维点对之间的透射变换矩阵 H(3行x3列)
warpPerspective(): 对输入图像进行透射变换
perspectiveTransform():对二维或者三维矢量进行透射变换,也就是对输入二维坐标点或者三维坐标点进行投射变换。
estimateAffine3D:计算多个三维点对之间的最优三维仿射变换矩阵H (3行x4列)
transform():对输入的N维矢量进行变换,可用于进行仿射变换、图像色彩变换.
findFundamentalMat:计算多个点对之间的基矩阵H。

cvStereoCalibrate():中T类型要求了3*1,对与其他形参float和double都支持

cvStereoRectigy():只支持double类型

cvStereoRectifyUncalibrated():立体校正算法Hartley算法效果和F矩阵及图像数量有关,

ps:

【如果用cvStereoCalibrate()函数计算处理的F矩阵效果和Bouguet算法(cvStereoRectigy())效果一样】

【如果用cvFindFundamentalMat()函数计算F矩阵,没有Bougut算法好】

【用Hartley算法(cvStereoRectifyUncalibrated())校正时,别忘了实现要用cvUndistortPoints()去除相机畸变,Bouguet算法(cvStereoRectigy())没有这个要求,实际上它在函数内部校正了相机的畸变。】


4、Q&A:

(1)计算变换矩阵
问题1:如何计算3个二维点对之间的仿射变换矩阵?
答:使用getAffineTransform()。
问题2:如何计算多个二维点对之间的仿射变换矩阵(使用误差最小准则 )?

答:使用estimateRigidTransform()。

问题3:如何计算4个二维点对之间的透视变换?
答:使用getPerspectiveTransform()。

问题4:如何计算多个二维点对之间的透视变换矩阵(使用误差最小准则 )

答:findHomography()。

问题5:如何计算多个三维点对之间的仿射变换?

答:使用estimateAffine3D。

(2)对输入图像应用变换矩阵进行变换

问题6:如何对输入图像进行仿射变换?
答:使用warpAffine()。
问题7:如何对输入图像进行透视变换?
答:使用perspectiveTransform()。
问题8:如何对输入的二维点对进行仿射变换?
答:使用transform()。
问题9:如何对输入的三维点对进行投影变换?
答:使用perspectiveTransform()。


5、注意:

1. 使用findHomography接口获取两张图之间的单应性矩阵H,获得的结果不具有可逆性。举例来说,两张图M1和M2,那么调用findHomography(M1, M2, CV_RANSAC, 4)得到的矩阵H12和findHomography(M2, M1, CV_RANSAC, 4)得到的矩阵H21不具有可逆关系,即:H12的逆不等于H21,H12和H21的逆存在一定的误差,这个误差的产生是因为这个单应性矩阵的求取本身就是采用了RANSAC算法,得到的估算矩阵,是个估算值,所以存在误差。

6、仿射变换和透视变换的关系

http://www.cnblogs.com/houkai/p/6660272.html

原创粉丝点击