1. 程式人生 > >SURF匹配點單應性提純

SURF匹配點單應性提純

1、SURF簡介

  Speeded Up Robust Features(SURF,加速穩健特徵),是一種穩健的區域性特徵點檢測和描述演算法。最初由Herbert Bay發表在2006年的歐洲計算機視覺國際會議(Europen Conference on Computer Vision,ECCV)上,並在2008年正式發表在Computer Vision and Image Understanding期刊上。   Surf是對David Lowe在1999年提出的Sift演算法的改進,提升了演算法的執行效率,為演算法在實時計算機視覺系統中應用提供了可能。與Sift演算法一樣,Surf演算法的基本路程可以分為三大部分:區域性特徵點的提取、特徵點的描述、特徵點的匹配。

2、SURF匹配程式碼

// 讀入你所要匹配的圖片
Mat image1 = imread("D:/test2-1.jpg", 0);
Mat image2 = imread("D:/test2-2.jpg", 0);
if (!image1.data || !image2.data)
    return 0;

// 宣告兩個vector變數存放兩張圖的關鍵點
vector<KeyPoint> keypoints1;
vector<KeyPoint> keypoints2;

// 宣告一個SURF特徵檢測器
Ptr<SurfFeatureDetector> surf = SurfFeatureDetector::create(3000);

// 檢測 SURF 特徵關鍵點
surf->detect(image1, keypoints1);
surf->detect(image2, keypoints2);

if (keypoints1.size() == 0 || keypoints2.size() == 0) {
    return -1;
} else {
    cout << "Number of SURF points (1): " << keypoints1.size() << endl;
    cout << "Number of SURF points (2): " << keypoints2.size() << endl;
}

// 宣告一個SURF特徵點描述子抽取器
Ptr<SURF> surfDesc = SURF::create();

// 抽取特徵點描述子(以向量矩陣形式存入Mat中,用於匹配兩特徵點是否相似)
Mat descriptors1, descriptors2;
surfDesc->compute(image1, keypoints1, descriptors1);
surfDesc->compute(image2, keypoints2, descriptors2);

// 宣告一個匹配器 
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce");

// 匹配兩圖描述子(也即看特徵向量像不像)
vector<cv::DMatch> matches;
matcher->match(descriptors1, descriptors2, matches);

// 採用RANSAC計算單應矩陣,然後通過單應矩陣提純得到好的特徵點 
vector<Point2f> object;
vector<Point2f> scene;
for (size_t i = 0; i < matches.size(); i++)
{
    //從好的匹配中獲取關鍵點: 匹配關係是兩組關鍵點間具有的一一對應關係,可以根據此匹配關係獲得關鍵點的索引  
    //這裡的goodMatches[i].queryIdx和goodMatches[i].trainIdx是匹配中一對關鍵點的索引
    object.push_back(keypoints1[matches[i].queryIdx].pt);
    scene.push_back(keypoints2[matches[i].trainIdx].pt);
}

Mat H;
float reprojectionThreshold = 3;
vector<DMatch> inliers;
vector<unsigned char> inliersMask(object.size());
H = findHomography(object, scene, CV_RANSAC, reprojectionThreshold, inliersMask);
for (size_t i = 0; i < inliersMask.size(); i++)
{
    if (inliersMask[i])
        inliers.push_back(matches[i]);
}
matches.swap(inliers);

其中,findHomography()我們單獨拿出來解析,這個函式的引數中:

  • object和scene是好點在兩張圖中分別的座標集合,且他們是一一對應的,其中既有正確的匹配,也有錯誤的匹配,正確的稱為內點,錯誤的稱為外點,RANSAC方法就是從這些包含錯誤匹配的資料中,分離出正確的匹配,並且求得單應矩陣(H就是我們要求的單應矩陣)。
  • reprojThreshold為閾值,當某一個匹配小於閾值時,則被認為是一個內點。
  • inliersMask即為掩膜,它的長度和object、scene一樣長,當一個object和scene中的點為內點時,inliersMask的相應位置標記為1,反之為0,說白了,通過inliersMask我們最終可以知道序列中哪些是內點,哪些是外點。

匹配效果示例:

                                                                                         目標檢測示例圖