OpenCV檢測影象SURF特徵
阿新 • • 發佈:2019-01-09
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詳細原理。
示例:
#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;
}