计算机视觉
图像处理

尺度不变特征变换匹配算法SIFT(3)

通过SIFT(1)和SIFT(2)初步学会使用SIFT算法进行特征提取和匹配,但是我们从实践中会发现,直接通过SIFT特征提取的结果并不是非常乐观,存在比较多的错误匹配,如图1所示:图1中只是选择了50个匹配点,并进行了连线,很明显存在一些错误匹配点。如果我们选择讲所有匹配点进行连线,可以得到图2,从图2中可以发现,错误匹配点是相当多。
图1
   
图2
那么,为了剔除这些错误匹配,我们可以使用RANSAC方法,通过调用opencv函数库中的findFundamentalMat()函数,即可剔除掉错误匹配点(野点、无效数据点)。那么这部分工作需要两大步:(1)通过SIFT算法获取SIFT特征点;(2)通过findFundamentalMat()函数剔除错误匹配点。
我先贴出完整的代码,以方便探讨下面的内容。对于RANSAC方法的原理性学习将后续进行。
  1. #include <iostream>
  2. #include <opencv2\opencv.hpp>
  3. using namespace std;
  4. using namespace cv;
  5. int main()
  6. {
  7.     Mat firstImage=imread(“ww.jpg”);
  8.     Mat secondImage = imread(“ee.jpg”);
  9.     if(firstImage.empty()||secondImage.empty())
  10.     {
  11.         cout<<“error”<<endl;
  12.         return 0;
  13.     }
  14.     //resize(firstImage,firstImage,Size(800,1000),0,0,1);
  15.     //resize(secondImage,secondImage,Size(800,1000),0,0,1);
  16.     ////////////////////////////////////////////////////////////////////////////////
  17.     //第一步:获取SIFT特征
  18.     //@Author:code陈
  19.     ////////////////////////////////////////////////////////////////////////////////
  20.     //difine a sift detector
  21.     SiftFeatureDetector siftDetector;
  22.     //store key points
  23.     vector<KeyPoint> firstKeypoint,secondKeypoint;
  24.     //detect image with SIFT,get key points
  25.     siftDetector.detect(firstImage,firstKeypoint);
  26.     siftDetector.detect(secondImage,secondKeypoint);
  27.     Mat firstOutImage,secondOutImage;
  28.     //draw key points at the out image and show to the user
  29.     drawKeypoints(firstImage,firstKeypoint,firstOutImage,Scalar(255,0,0));
  30.     drawKeypoints(secondImage,secondKeypoint,secondOutImage,Scalar(0,255,0));
  31.     imshow(“first”,firstOutImage);
  32.     imshow(“second”,secondOutImage);
  33.     // difine a sift descriptor extractor
  34.     SiftDescriptorExtractor extractor;
  35.     //store the descriptor of each image
  36.     Mat firstDescriptor,secondDescriptor;
  37.     BruteForceMatcher<L2<float>> matcher;
  38.     vector<DMatch> matches;
  39.     Mat matcheImage;
  40.     //compute the descriptor of each image
  41.     extractor.compute(firstImage,firstKeypoint,firstDescriptor);
  42.     extractor.compute(secondImage,secondKeypoint,secondDescriptor);
  43.     //match
  44.     matcher.match(firstDescriptor,secondDescriptor,matches);
  45.     ////////////////////////////////////////////////////////////////////////////////
  46.     //第二步:RANSAC方法剔除outliner
  47.     //@Author:code陈
  48.     ////////////////////////////////////////////////////////////////////////////////
  49.     //将vector转化成Mat
  50.     Mat firstKeypointMat(matches.size(),2,CV_32F),secondKeypointMat(matches.size(),2,CV_32F);
  51.     for(int i = 0;i<matches.size();i++)
  52.     {
  53.         firstKeypointMat.at<float>(i,0) = firstKeypoint[matches[i].queryIdx].pt.x;
  54.         firstKeypointMat.at<float>(i,1) = firstKeypoint[matches[i].queryIdx].pt.y;
  55.         secondKeypointMat.at<float>(i,0) = secondKeypoint[matches[i].trainIdx].pt.x;
  56.         secondKeypointMat.at<float>(i,1) = secondKeypoint[matches[i].trainIdx].pt.y;
  57.     }
  58.     //Calculate the fundamental Mat;
  59.     vector<uchar> ransacStatus;
  60.     Mat fundamentalMat = findFundamentalMat(firstKeypointMat,secondKeypointMat,ransacStatus,FM_RANSAC);
  61.     cout<<fundamentalMat<<endl;
  62.     //Calculate the number of outliner points;
  63.     int outlinerCount = 0;
  64.     for(int i=0;i<matches.size();i++)
  65.     {
  66.         if(ransacStatus[i]==0)
  67.         {
  68.             outlinerCount++;
  69.         }
  70.     }
  71.     //Calculate inliner points;
  72.     vector<Point2f> firstInliner;
  73.     vector<Point2f> secondInliner;
  74.     vector<DMatch> inlinerMatches;
  75.     int inlinerCount = matches.size()-outlinerCount;
  76.     firstInliner.resize(inlinerCount);
  77.     secondInliner.resize(inlinerCount);
  78.     inlinerMatches.resize(inlinerCount);
  79.     int index = 0;
  80.     for(int i=0;i<matches.size();i++)
  81.     {
  82.         if(ransacStatus[i]!=0)
  83.         {
  84.             firstInliner[index].x = firstKeypointMat.at<float>(i,0);
  85.             firstInliner[index].y = firstKeypointMat.at<float>(i,1);
  86.             secondInliner[index].x = secondKeypointMat.at<float>(i,0);
  87.             secondInliner[index].y = secondKeypointMat.at<float>(i,1);
  88.             inlinerMatches[index].queryIdx = index;
  89.             inlinerMatches[index].trainIdx = index;
  90.             index ++;
  91.         }
  92.     }
  93.     vector<KeyPoint> inlinerFirstKeypoint(inlinerCount);
  94.     vector<KeyPoint> inlinerSecondKeypoint(inlinerCount);
  95.     KeyPoint::convert(firstInliner,inlinerFirstKeypoint);
  96.     KeyPoint::convert(secondInliner,inlinerSecondKeypoint);
  97.     //cout<<fundamentalMat<<endl;
  98.     //select 50 keypoints
  99.     //matches.erase(matches.begin()+50,matches.end());
  100.     //inlinerMatches.erase(inlinerMatches.begin()+50,inlinerMatches.end());
  101.     drawMatches(firstImage,inlinerFirstKeypoint,secondImage,inlinerSecondKeypoint,inlinerMatches,matcheImage);
  102.     imshow(“ransacMatches”,matcheImage);
  103.     drawMatches(firstImage,firstKeypoint,secondImage,secondKeypoint,matches,matcheImage);
  104.     imshow(“matches”,matcheImage);
  105.     //imshow();
  106.     waitKey(0);
  107.     return 0;
  108. }

下面对每一步进行简单描述:

(1)通过SIFT算法获取SIFT特征点
这一部分在SIFT(1)和SIFT(2)中已经做了相应说明,本文将不再阐述各个函数的作用和参数说明。该步骤的输入为两张图片,输出则为每张图片的特征点和每个特征点的SIFT特征描述子,每个描述子为128维。特征点如下图所示:
图3
图4
(2)通过findFundamentalMat()函数剔除错误匹配点
如果我们直接利用SIFT特征点进行匹配,那么结果如图2所示,现在我们利用findFundamentalMat()函数剔除,在前面贴出的代码中,对每一步已经做了相应的注释,剔除结果如图5所示。
图5
图5中我只选择了最新的50个匹配结果,显示效果非常理想。那么显示所有的结果呢?如图6所示。
图6
从图6中我们可以看出,经过RANSAC算法之后,剔除了大部分的错误匹配点,还存在少数的错误点,已经达到了非常理想的效果。findFundamentalMat()函数输入5个参数,返回的是一个3X3的基础矩阵:而对于该矩阵的利用,后续将继续学习。
其他说明:
(1)在代码中我使用了resize()函数对输入图像的尺寸进行了一定处理,因为SIFT算法的一个缺点就是计算量非常大,图片过大的时候,很容易因内存不足而崩~
(2)在代码中还是用了matches.erase()是为了SIFT匹配后,提高可视化度。
在这里再贴上一组对比图片:
RANSAC前
RANSAC后

转载注明来源:CV视觉网 » 尺度不变特征变换匹配算法SIFT(3)

分享到:更多 ()
扫描二维码,给作者 打赏
pay_weixinpay_weixin

请选择你看完该文章的感受:

0不错 0超赞 0无聊 0扯淡 0不解 0路过

评论 抢沙发

评论前必须登录!