1. 程式人生 > >特徵點檢測之surf演算法

特徵點檢測之surf演算法

四、尺度不變的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

特徵點檢測學習_2(surf演算法) http://www.cnblogs.com/tornadomeet/archive/2012/08/17/2644903.html