一、理論知識
Scale Invariant Feature Transform,尺度不變特徵變換匹配算法,對於算法的理論介紹,可以參考這篇文章http://blog.csdn.net/qq_20823641/article/details/51692415,裏面很詳細,可以更好的學習。這裏就不多介紹。後面就挑選重點的來說
二、SIFT 主要思想
SIFT算法是一種提取局部特徵的算法,在尺度空間尋找極值點,提取位置,尺度,旋轉不變量。
三、SIFT算法的主要特點:
a) SIFT特徵是圖像的局部特徵,其對旋轉、尺度縮放、亮度變化保持不變性,對視角變化、仿射變換、噪聲也保持一定程度的穩定性。
b) 獨特性(Distinctiveness)好,信息量豐富,適用於在海量特徵數據庫中進行快速、準確的匹配[23]。
c) 多量性,即使少數的幾個物體也可以產生大量SIFT特徵向量。
d) 高速性,經優化的SIFT匹配算法甚至可以達到實時的要求。
e) 可擴展性,可以很方便的與其他形式的特徵向量進行聯合。
四、SIFT算法步驟:
1)檢測尺度空間極值點
2)精確定位極值點
3)爲每個關鍵點指定方向參數
4)關鍵點描述子的生成
五、程序過程
- 使用SiftFeatureDetector的detect方法檢測特徵存入一個向量裏,並使用drawKeypoints在圖中標識出來
- SiftDescriptorExtractor 的compute方法提取特徵描述符,特徵描述符是一個矩陣
- 使用匹配器matcher對描述符進行匹配,匹配結果保存由DMatch的組成的向量裏
- 設置距離閾值,使得匹配的向量距離小於最小距離的2被才能進入最終的結果,用DrawMatch可以顯示
SIFT::SIFT(int nfeatures=0, int nOctaveLayers=3, double contrastThreshold=0.04, double edgeThreshold= 10, double sigma=1.6)
- nfeatures:特徵點數目(算法對檢測出的特徵點排名,返回最好的nfeatures個特徵點)。
- nOctaveLayers:金字塔中每組的層數(算法中會自己計算這個值,後面會介紹)。
- contrastThreshold:過濾掉較差的特徵點的對閾值。contrastThreshold越大,返回的特徵點越少。
- edgeThreshold:過濾掉邊緣效應的閾值。edgeThreshold越大,特徵點越多(被多濾掉的越少)。
- sigma:金字塔第0層圖像高斯濾波係數,也就是σ。
void SIFT::operator()(InputArray img, InputArray mask, vector<KeyPoint>& keypoints, OutputArray
descriptors, bool useProvidedKeypoints=false)
- img:8bit灰度圖像
- mask:圖像檢測區域(可選)
- keypoints:特徵向量矩陣
- descipotors:特徵點描述的輸出向量(如果不需要輸出,需要傳cv::noArray())。
- useProvidedKeypoints:是否進行特徵點檢測。ture,則檢測特徵點;false,只計算圖像特徵描述
<p>class keyPoint{<span style="font-family: Arial;">Point2f pt;</span><span style="font-family: Arial;">float size;</span><span style="font-family: Arial;">float angle;</span><span style="font-family: Arial;">float response;i</span><span style="font-family: Arial;">nt octave;</span><span style="font-family: Arial;">int class_id;</span><span style="font-family: Arial;">}</span></p>
<span style="font-size:18px;">void drawMatches(const Mat&img1, const vector<KeyPoint>&keypoints1, const Mat&img2, const vector<KeyPoint>&keypoints2,
const vector<DMatch>&matches1to2, Mat&outImg, const Scalar&matchColor=Scalar::all(-1),
const Scalar&singlePointColor=Scalar::all(-1), const vector<char>&matchesMask=vector<char>(),
intflags=DrawMatchesFlags::DEFAULT)</span>
Parameters: |
|
---|
七、函數注意事項
1.生成一個SiftFeatureDetector的對象,這個對象顧名思義就是SIFT特徵的探測器,用它來探測衣服圖片中SIFT點的特徵,存到一個KeyPoint類型的vector中,keypoint只是保存了opencv的sift庫檢測到的特徵點的一些基本信息,但sift所提取出來的特徵向量其實不是在這個裏面,特徵向量通過SiftDescriptorExtractor
提取,結果放在一個Mat的數據結構中。這個數據結構才真正保存了該特徵點所對應的特徵向量。
2.keypoint只是達到了關鍵點的位置,方向等信息,並無該特徵點的特徵向量,要想提取得到特徵向量就還要進行SiftDescriptorExtractor 的工作,建立了SiftDescriptorExtractor 對象後,通過該對象,對之前SIFT產生的特徵點進行遍歷,找到該特徵點所對應的128維特徵向量
<span style="font-size:18px;">#include <opencv2/opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
#include<opencv2/nonfree/nonfree.hpp>
#include<opencv2/legacy/legacy.hpp>
#include<vector>
using namespace std;
using namespace cv;
int main(int argc,uchar* argv[])
{
const char* imagename = "hand1.jpg";
//從文件中讀入圖像
Mat img = imread(imagename);
Mat img2=imread("hand3.jpg");
//如果讀入圖像失敗
if(img.empty())
{
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
}
if(img2.empty())
{
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
}
//顯示圖像
imshow("image before", img);
imshow("image2 before",img2);
//sift特徵檢測
SiftFeatureDetector siftdtc;
vector<KeyPoint>kp1,kp2;
siftdtc.detect(img,kp1);
Mat outimg1;
drawKeypoints(img,kp1,outimg1);
imshow("image1 keypoints",outimg1);
KeyPoint kp;
siftdtc.detect(img2,kp2);
Mat outimg2;
drawKeypoints(img2,kp2,outimg2);
imshow("image2 keypoints",outimg2);
SiftDescriptorExtractor extractor;
Mat descriptor1,descriptor2;
BruteForceMatcher<L2<float>> matcher;
vector<DMatch> matches;
Mat img_matches;
extractor.compute(img,kp1,descriptor1);
extractor.compute(img2,kp2,descriptor2);
matcher.match(descriptor1,descriptor2,matches);
drawMatches(img,kp1,img2,kp2,matches,img_matches);
imshow("matches",img_matches);
//此函數等待按鍵,按鍵盤任意鍵就返回
waitKey();
return 0;
}</span>
Demo Software: SIFT Keypoint Detector 代碼參考大牛的,網址如下
http://www.cs.ubc.ca/~lowe/keypoints/
i1=imread('hand1.jpg');
i2=imread('hand3.jpg');
i11=rgb2gray(i1);
i22=rgb2gray(i2);
imwrite(i11,'v1.jpg','quality',80);
imwrite(i22,'v2.jpg','quality',80);
match('v1.jpg','v2.jpg');
http://www.cnblogs.com/cj695/p/4041478.html
http://blog.csdn.net/xiaowei_cqu/article/details/8069548
圖像識別算法交流 QQ羣:145076161,歡迎圖像識別與圖像算法,共同學習與交流