四、尺度不變的SURF特征檢測
當我們想比對不同圖像時,經常會遇到圖像尺度不同的問題,不同圖像中特征點的距離變得不同,物體變成不同的尺寸,如果我們通過修正特征點的大小,就會造成強度不比對。為了解決這個問題,我們提出一個尺度不變的SURF特征檢測,在計算特征點的時候把尺度因素加入之中。SURF與SIFT算法相似,SIFT算法比較穩定,檢測特征點更多,但是複雜度較高,而SURF要運算簡單,效率高,運算時間短一點。
4.1 SURF算法簡介
為了實作尺度不變性的特征點檢測與比對,SURF算法與SIFT算法的第一步都是構造圖像多尺度空間(圖像金字塔)。sift算法使用高斯卷積,高斯函數有兩個參數,高斯核的尺寸K與σ值,預設最底層(0層)的σ = 1.6,原圖像的σ=0.5(σ越大圖像越模糊,是以源圖像是最清晰的),尺寸空間即圖像金字塔,Ksize決定有個塔,σ決定每個塔有幾層(Octave),不同K和σ構造出的尺寸空間。在這種多尺度空間計算特征點就滿足了尺度不變的特性。但是sift使用高斯卷積計算複雜,SURF算法則用高斯濾波與Hessian矩陣結合近似實作多尺度空間,計算複雜度降低多了。
同一層中k的值改變,不同層是σ的值改變
SURF第二步是根據非極大值抑制初步确定特征點,與SIFT相似。
第三步根據3維線性插值法得到半像素點的特征點,最後選取特征點的主方向,SURF是對特征點進行鄰域統計,取半徑為6S(機關)的圓區域,統計那個60°的扇形中haar小波特征總和最大,即為最大特征點主方向。
第四步構造特征點算術描述子,SURF算法是選取一個20S(機關)的區域,分成4X4分,每一份中有5X5S,統計一份中的∑dx,∑dy,∑|dx|,∑|dy|,這樣就得到4X4X4 = 64的向量描述子。SIFT是128個描述子,比SURF複雜一點。
4.2 opencv實作
4.2.1 SURF的函數接口
程式執行個體:
// Read input image
image= cv::imread("church03.jpg",0);
keypoints.clear();
// Construct the SURF feature detector object
cv::SurfFeatureDetector surf(2500);
// Detect the SURF features
surf.detect(image,keypoints);
cv::Mat featureImage;
cv::drawKeypoints(image,keypoints,featureImage,cv::Scalar(255,255,255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
// Display the corners
cv::namedWindow("SURF Features");
cv::imshow("SURF Features",featureImage);
cv::imwrite("SURF Features.jpg",featureImage);
程式結果:
4.2.2 SIFT函數接口
程式如下:
// Read input image
image= cv::imread("church01.jpg",0);
keypoints.clear();
// Construct the SURF feature detector object
cv::SiftFeatureDetector sift(
0.03, // feature threshold
10.); // threshold to reduce
// sensitivity to lines
// Detect the SURF features
sift.detect(image,keypoints);
cv::drawKeypoints(image,keypoints,featureImage,cv::Scalar(255,255,255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
// Display the corners
cv::namedWindow("SIFT Features");
cv::imshow("SIFT Features",featureImage);
cv::imwrite("SIFT Features.jpg",featureImage);
程式結果如下
五、 SURF特征點描述
如上面例子可以看出,SURF算法為每一個特征點都定義了一個位置和大小,這個大小因素可以用于定義一個特征點附近的相同視覺不同尺寸大小的視窗,用來識别特征點差別于其他特征點。根據特征描述符即SURF中64個向量,比較兩幅圖形中不同特征點的向量的歐拉距離,選取距離最小的前25個點,就是所尋找的最佳比對點。
5.1 SURF比對算法opencv實作
#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/legacy/legacy.hpp>
using namespace std;
using namespace cv;
int main()
{
// Read input images
cv::Mat image1= cv::imread("church01.jpg",0);
cv::Mat image2= cv::imread("church02.jpg",0);
if (!image1.data || !image2.data)
return 0;
// Display the images
cv::namedWindow("Right Image");
cv::imshow("Right Image",image1);
cv::namedWindow("Left Image");
cv::imshow("Left Image",image2);
// vector of keypoints
std::vector<cv::KeyPoint> keypoints1;
std::vector<cv::KeyPoint> keypoints2;
// Construction of the SURF feature detector
cv::SurfFeatureDetector surf(3000);
// Detection of the SURF features
surf.detect(image1,keypoints1);
surf.detect(image2,keypoints2);
std::cout << "Number of SURF points (1): " << keypoints1.size() << std::endl;
std::cout << "Number of SURF points (2): " << keypoints2.size() << std::endl;
// Draw the kepoints
cv::Mat imageKP;
cv::drawKeypoints(image1,keypoints1,imageKP,cv::Scalar(255,255,255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
cv::namedWindow("Right SURF Features");
cv::imshow("Right SURF Features",imageKP);
cv::drawKeypoints(image2,keypoints2,imageKP,cv::Scalar(255,255,255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
cv::namedWindow("Left SURF Features");
cv::imshow("Left SURF Features",imageKP);
// Construction of the SURF descriptor extractor
cv::SurfDescriptorExtractor surfDesc;
// Extraction of the SURF descriptors
cv::Mat descriptors1, descriptors2;
surfDesc.compute(image1,keypoints1,descriptors1);
surfDesc.compute(image2,keypoints2,descriptors2);
std::cout << "descriptor matrix size: " << descriptors1.rows << " by " << descriptors1.cols << std::endl;
// Construction of the matcher
cv::BruteForceMatcher<cv::L2<float>> matcher;
// Match the two image descriptors
std::vector<cv::DMatch> matches;
matcher.match(descriptors1,descriptors2, matches);
std::cout << "Number of matched points: " << matches.size() << std::endl;
std::nth_element(matches.begin(), // initial position
matches.begin()+24, // position of the sorted element
matches.end()); // end position
// remove all elements after the 25th
matches.erase(matches.begin()+25, matches.end());
cv::Mat imageMatches;
cv::drawMatches(image1,keypoints1, // 1st image and its keypoints
image2,keypoints2, // 2nd image and its keypoints
matches, // the matches
imageMatches, // the image produced
cv::Scalar(255,255,255)); // color of the lines
cv::namedWindow("Matches");
cv::imshow("Matches",imageMatches);
cv::imwrite("Matches.jpg",imageMatches);
cv::waitKey();
return 0;
}
程式結果顯示:
參考資料:
SIFT 特征提取算法總結 http://www.cnblogs.com/cfantaisie/archive/2011/06/14/2080917.html