1. 程式人生 > >OpenCV檢測影象SURF特徵

OpenCV檢測影象SURF特徵

SURF特徵

SURF特徵——speeded up robust features 加速魯棒特徵。具有尺度不變性,計算相對高效。
所謂尺度不變性,在特徵點匹配上,個人比較白話的理解是:
相同內容的不同尺度的兩張圖片(例,影象1:張三的正面照。影象2:張三正面照縮小一半。)。
假設兩張圖片上張三的鼻子中心是一個特徵點,那麼這兩張圖片,在該點處的SURF特徵,應該相互匹配(確切說是SURF特徵描述子匹配)。也就是說,大小變化,特徵匹配不變。不管物體大小如何變化,同一物體在不同大小下具有的SURF特徵,這些特徵點(描述子)相互匹配。
SURF特徵,具有尺寸和方向,使其具有方向不變性和尺寸不變性。


該部落格講了SURF特徵原理,可以參看。
http://www.cnblogs.com/tornadomeet/archive/2012/08/17/2644903.html
這裡只簡單講下,SURF特徵,大體是怎麼回事

SURF特徵,定義特徵點為具有較高局部曲率的點。
怎麼計算局部曲率?通過Hessian矩陣。
這裡寫圖片描述
該矩陣的行列式給出了曲率的強度,也就是,矩陣的行列式越大,曲率強度越高。具體計算特徵點時,要考慮用不同尺寸高斯核濾波產生的金塔字上下層的曲率值,用當前層某點的曲率值,和本層、上層、下層一定範圍進行比較。(說起來好麻煩,具體的看SURF演算法,網上很多資料)。
特徵怎麼具有尺寸不變性?


SURF,通過對圖片用不同尺寸的高斯核濾波,然後計算其Hessian矩陣(類似高斯金字塔,但影象的尺寸不變)。實際應用中,為了加快計算速度,常常用近似的高斯核,直接計算Hessian矩陣中的值。
對y二階導相當於:
這裡寫圖片描述
對xy二階導相當於:
這裡寫圖片描述
這樣,不同尺寸高斯核下的Hessian矩陣,便計算出來。
為了說明白尺寸不變,以下是個人的簡單理解,可能跟演算法實際過程不同(僅為好理解,勿噴)
1、一張圖片,在尺寸為NxN的高斯核下,檢測到了一個SURF特徵點。那麼這個檢測到的特徵點,與N成正比,也可以說特徵點的尺寸與N成正比。
2、假設,圖片縮小一半,拍攝角度不變。那麼在尺寸為(N/2)的高斯核下,檢測到一個SURF特徵點(同1,為同一物體的同一點)。該特徵點的尺寸與N/2成正比。
也就是說,當影象縮減一半時,該特徵點的尺寸也縮減一半。那麼在匹配這兩個不同尺度的特徵點時,由於考慮到了尺寸的變化(原來的1/2),那麼匹配時,他們的強度模版就不會出錯。
(再簡單的理解,計算特徵點的描述子時,由於不瞭解物體尺寸的變換,所以往往會出錯。但是,SURF特徵包含了尺寸變化的資訊,從而讓同一物體的同一點在不同尺寸下的SURF特徵(點)描述子(向量)相互匹配)
這裡,只講了SURF個人的大體理解,其實我看該演算法時也挺蒙,有些地方來回看了幾遍。個人理解肯定由疏漏、不準確的地方,推薦去系統學習一下SURF詳細原理。
示例:

#include<opencv2\core\core.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\features2d\features2d.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include<opencv2\legacy\legacy.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include<iostream>
int main()
{
    //兩張同一物體,不同尺寸的圖片
    cv::Mat image = cv::imread("D:/images/church01.jpg");
    cv::Mat image1 = cv::imread("D:/images/church03.jpg");
    ///計算SURF特徵點
    std::vector<cv::KeyPoint> pts;
    std::vector<cv::KeyPoint> pts1;
    //定義SURF特徵檢測類 物件,閾值設定為2500
    cv::SurfFeatureDetector surf(2500.);
    surf.detect(image, pts);
    surf.detect(image1, pts1);

    ///提取SURF特徵點的描述子
    cv::SurfDescriptorExtractor surfD;
    //特徵點集合的描述子以矩陣形式儲存
    cv::Mat descri;
    cv::Mat descri1;
    surfD.compute(image, pts, descri);
    surfD.compute(image1, pts1, descri1);

    //利用描述子,匹配兩張影象中的SURF特點
    cv::BruteForceMatcher<cv::L2<float>>mather;
    std::vector<cv::DMatch>matches;
    //matches,儲存匹配結果
    mather.match(descri, descri1, matches);

    //選取匹配值最高的25個點
    std::nth_element(matches.begin(), matches.begin() + 24, matches.end());
    matches.erase(matches.begin() + 25, matches.end());
    //畫出匹配影象
    cv::Mat imageMatches;
    cv::drawMatches(image, pts, image1, pts1,
        matches, imageMatches, cv::Scalar(255, 0, 0));
    //顯示結果
    cv::namedWindow("Match", CV_WINDOW_FREERATIO);
    cv::imshow("Match", imageMatches);
    cv::waitKey(0);
    return 0;
}

這裡寫圖片描述