OPENCV下SIFT算法使用方法筆記

這幾天繼續在看Lowe大神的SIFT神作,看的眼花手腳抽筋。也是醉了!!!!實在看不下去,來點乾貨。我們知道opencv下自帶SIFT特徵檢測以及MATCH匹配的庫,這些庫完全可以讓我們進行傻瓜似的操作。但實際用起來的時候還不是那麼簡單。下文將對一個典型的基於OPENCV的SIFT特徵點提取以及匹配的例程進行分析,並由此分析詳細的對OPENCV中SIFT算法的使用進行一個介紹。

OPENCV下SIFT特徵點提取與匹配的大致流程如下:

讀取圖片-》特徵點檢測(位置,角度,層)-》特徵點描述的提取(16*8維的特徵向量)-》匹配-》顯示

其中,特徵點提取主要有兩個步驟,見上行黃子部分。下面做具體分析。

1、使用opencv內置的庫讀取兩幅圖片

2、生成一個SiftFeatureDetector的對象,這個對象顧名思義就是SIFT特徵的探測器,用它來探測衣服圖片中SIFT點的特徵,存到一個KeyPoint類型的vector中。這裏有必要說keypoint的數據結構,涉及內容較多,具體分析查看opencv中keypoint數據結構分析,裏面講的自認爲講的還算詳細(表打我……)。簡而言之最重要的一點在於:

keypoint只是保存了opencv的sift庫檢測到的特徵點的一些基本信息,但sift所提取出來的特徵向量其實不是在這個裏面,特徵向量通過SiftDescriptorExtractor 提取,結果放在一個Mat的數據結構中。這個數據結構才真正保存了該特徵點所對應的特徵向量。具體見後文對SiftDescriptorExtractor 所生成的對象的詳解。

就因爲這點沒有理解明白耽誤了一上午的時間。哭死!

3、對圖像所有KEYPOINT提取其特徵向量:

得到keypoint只是達到了關鍵點的位置,方向等信息,並無該特徵點的特徵向量,要想提取得到特徵向量就還要進行SiftDescriptorExtractor 的工作,建立了SiftDescriptorExtractor 對象後,通過該對象,對之前SIFT產生的特徵點進行遍歷,找到該特徵點所對應的128維特徵向量。具體方法參見opencv中SiftDescriptorExtractor所做的SIFT特徵向量提取工作簡單分析。通過這一步後,所有keypoint關鍵點的特徵向量被保存到了一個MAT的數據結構中,作爲特徵。

4、對兩幅圖的特徵向量進行匹配,得到匹配值。

兩幅圖片的特徵向量被提取出來後,我們就可以使用BruteForceMatcher對象對兩幅圖片的descriptor進行匹配,得到匹配的結果到matches中,這其中具體的匹配方法暫沒細看,過段時間補上。

至此,SIFT從特徵點的探測到最後的匹配都已經完成,雖然匹配部分不甚瞭解,只掃對於如何使用OPENCV進行sift特徵的提取有了一定的理解。接下來可以開始進行下一步的工作了。

附:使用OPENCV下SIFT庫做圖像匹配的例程

// opencv_empty_proj.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#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 _tmain(int argc, _TCHAR* argv[])
{
    const char* imagename = "img.jpg";

    //從文件中讀入圖像
    Mat img = imread(imagename);
    Mat img2=imread("img2.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;

    vector<KeyPoint>::iterator itvc;
    for(itvc=kp1.begin();itvc!=kp1.end();itvc++)
    {
        cout<<"angle:"<<itvc->angle<<"\t"<<itvc->class_id<<"\t"<<itvc->octave<<"\t"<<itvc->pt<<"\t"<<itvc->response<<endl;
    }

    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);


    imshow("desc",descriptor1);
    cout<<endl<<descriptor1<<endl;
    matcher.match(descriptor1,descriptor2,matches);

    drawMatches(img,kp1,img2,kp2,matches,img_matches);
    imshow("matches",img_matches);

    //此函數等待按鍵,按鍵盤任意鍵就返回
    waitKey();
    return 0;
}

轉自http://www.cnblogs.com/cj695/ 作者77695

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章