BE CREATIVE

OpenCVよりな理系大学生による主に研究ブログ(個人用) - Egocentric Vision・SURF・SIFT・Optical Flow・AR・ Motion Analyses・Kinect・Leap Motion - 最近、VCでアルバイト始めました。

SIFT SURFを用いた特徴点マッチング

回転やスケール変化にも頑健なSIFTとSURFを用いて特徴点の対応づけをしてみた。
計算時間とマッチング数もそれぞれ算出。

プログラム

#include <iostream>
#include <opencv/cxcore.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/legacy/legacy.hpp>   
int main(int argc, char *argv[])
{

    //画像読み込み
    cv::Mat colorImg1 = cv::imread("/image/lena2.png");
    cv::Mat colorImg2 = cv::imread("/image/lena3.png");
    if(colorImg1.empty() || colorImg2.empty()){
        std::cout << "No Image" << std::endl;
        return -1;
    }
    //特徴点抽出用のグレー画像用意
    cv::Mat grayImg1, grayImg2;
    cv::cvtColor(colorImg1, grayImg1, CV_BGR2GRAY);
    cv::normalize(grayImg1, grayImg1, 0, 255, cv::NORM_MINMAX);
    cv::cvtColor(colorImg2, grayImg2, CV_BGR2GRAY);
    cv::normalize(grayImg2, grayImg2, 0, 255, cv::NORM_MINMAX);

    //SIFT
    //cv::SiftFeatureDetector detector;
    //cv::SiftDescriptorExtractor extractor;

    //SURF
    cv::SurfFeatureDetector detector(1000);
    cv::SurfDescriptorExtractor extractor;


    //------------ 処理時間計測 開始 --------------
    double ticFrequency;    // 1マイクロ秒あたりのTick数
    double processTime;     // 実行時間
    int    startTic;        // 開始
    int    stopTic;         // 終了時間   
    ticFrequency = cvGetTickFrequency();
    // 計測開始点でのTick数を得ます。
    startTic = (int)cvGetTickCount();
    //-------------------------------------------

    //画像から特徴点を検出
    std::vector<cv::KeyPoint> keypoints1;
    detector.detect(grayImg1, keypoints1);
    std::cout << "Detected " << (int) keypoints1.size() << " keypoints1" <<std::endl;   //特徴点算出
    std::vector<cv::KeyPoint> keypoints2;
    detector.detect(grayImg2, keypoints2);
    std::cout << "Detected " << (int) keypoints2.size() << " keypoints2" <<std::endl;   //特徴点算出

    //画像の特徴点における特徴量を抽出
    cv::Mat descriptors1;
    extractor.compute(grayImg1, keypoints1, descriptors1);
    cv::Mat descriptors2;
    extractor.compute(grayImg2, keypoints2, descriptors2);

    
    //特徴点の対応付け
    std::vector<cv::DMatch> matches;
    cv::BruteForceMatcher<cv::L2<float> > matcher;
    matcher.match(descriptors1, descriptors2, matches);
    std::cout << "Matching " << (int) matches.size() << " matching" <<std::endl;   //特徴点算出
    //ソートしたn番目までの対応線を表示させる。nth_elementは要素を基準要素よりも手前に移動させるある種のソート

    int N=50;
    nth_element(matches.begin(), matches.begin()+N-1, matches.end());
    matches.erase(matches.begin()+N, matches.end());

    //------------ 処理時間計測 終了 --------------
    // 計測終了点でのTick数を得ます。
    stopTic = (int)cvGetTickCount();
    // 実行時間を計算します。単位はマイクロ秒であることに注意してください。
    processTime = (stopTic-startTic)/ticFrequency;
    printf("%f",processTime);

    //-----------------------------------------
    //対応づけされた画像の用意
    cv::Mat matchedImg;
    cv::drawMatches(colorImg1, keypoints1, colorImg2, keypoints2, matches, matchedImg);
    
    /// 画像を表示するウィンドウの名前,プロパティ
    // CV_WINDOW_AUTOSIZE : ウィンドウサイズを画像サイズに合わせる
    // CV_WINDOW_FREERATIO : ウィンドウのアスペクト比を固定しない
    cv::namedWindow("SURF", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);

    // ウィンドウ名でウィンドウを指定して,そこに画像を描画
    cv::imshow("SURF", matchedImg);
    // キー入力を(無限に)待つ
    cv::waitKey(0);
    return 0;

}

参考サイト:http://kesin.hatenablog.com/entry/20120810/1344582180

実行結果
SIFT
f:id:junn511:20140711161634p:plain
SURF
f:id:junn511:20140711161710p:plain

SURFの方が計算処理は速かったです。
他にも局所勾配特徴点を抽出する方法はSIFT SURF FAST BRIEF RIFF DAISYがあるみたい。
でも特徴量を記述するのはSIFT SURFぐらいなのか。
次はFAST使って同じようなことができるか試してみよう。

SURFによる特徴点の抽出とそのオプティカルフローの描画で
PTAMみたいな映像を作ってみるのも面白いかも。