OpenCV SIFT_SURF - eiichiromomma/CVMLAB GitHub Wiki

(OpenCV) SIFT SURF

SURFとSIFTの簡単な例(C++)

samples/cppに収録されたSURFを用いたマッチングの例。 DescriptorExtractorの派生としてSIFTも用意されているので比較してみた。

drawMatchesのDEFAULT出力がイマイチなので自前で出力画像を用意する。

ソース

    #include <stdio.h>
    #include <opencv2/core/core.hpp>
    #include <opencv2/features2d/features2d.hpp>
    #include <opencv2/highgui/highgui.hpp>

    //#define USE_SURF
    using namespace cv;

    int main(int argc, char** argv)
    {
      if(argc != 3)
      {
        printf("Usage: matcher_simple <image1> <image2>\n");
        return -1;
      }
      //画像を1チャネルで開く
      Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
      Mat img2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE);
      if(img1.empty() || img2.empty())
      {
        printf("Can't read one of the images\n");
        return -1;
      }

      // detecting keypoints
      //Surf特徴点の抽出器、第一引数はhessianの閾値
    #ifdef USE_SURF
      SurfFeatureDetector detector(400);
    #else
      SiftFeatureDetector detector;
    #endif
      //keypoint格納vector
      vector<KeyPoint> keypoints1, keypoints2;
      detector.detect(img1, keypoints1);
      detector.detect(img2, keypoints2);

      // computing descriptors
      //Surf記述子、keypointsについて算出
    #ifdef USE_SURF
      SurfDescriptorExtractor extractor;
    #else
      SiftDescriptorExtractor extractor;
    #endif
      Mat descriptors1, descriptors2;
      extractor.compute(img1, keypoints1, descriptors1);
      extractor.compute(img2, keypoints2, descriptors2);

      // matching descriptors

      //Brute-force descriptor matcherで近いdescriptorを探す
      //cv::L2はユークリッド平方距離
      BruteForceMatcher<L2<float> > matcher;
      vector<int> matches;
      matcher.add(descriptors2);
      matcher.match(descriptors1, matches);

      // drawing the results
      namedWindow("matches", 1);
      Mat img_matches;

      //DrawMatchesで対応点の描画。
    /* DrawMatchesFlagsは以下の通り。
        enum{ DEFAULT = 0, // Output image matrix will be created (Mat::create),
                           // i.e. existing memory of output image may be reused.
                           // Two source image, matches and single keypoints will be drawn.
              DRAW_OVER_OUTIMG = 1, // Output image matrix will not be created (Mat::create).
                                    // Matches will be drawn on existing content of output image.
              NOT_DRAW_SINGLE_POINTS = 2 // Single keypoints will not be drawn.
            };
    */
      //DEFAULTだとサイズが違う所を未定義で扱うので出力が汚い。
      //自前で出力先を作ってみる
      Mat imgout = Mat(Size(img1.cols+img2.cols, img1.rows>img2.rows? img1.rows: img2.rows), CV_8UC3);
      //0で塗り潰し
      imgout.setTo(Scalar::all(0));
      //merge(img1, img1, img1, NULL, img1C3)と同じ意味の作業
      Mat img1C3(img1.size(), CV_8UC3);
      //mixChannelsが曲者
      //mixChannels(&src, srcのch数, &dst, dstのch数, fromto配列, ペア数)
      // fromto配列は srcの0ch->dstの0ch, srcの0ch->dstの1ch, srcの0ch->dstの2chの意
      //最後の引数はチャネルのペア数
      int fromto[] = {0,0, 0,1, 0,2};
      mixChannels(&img1,1, &img1C3, 3, fromto, 3);
      //MatにはROIの概念が無いのでcheatsheet参照
      Mat roi = imgout(Rect(0,0,img1.cols, img1.rows));
      img1C3.copyTo(roi);

      //img2はずらしてコピー
      Mat img2C3(img2.size(), CV_8UC3);
      mixChannels(&img2,1, &img2C3, 3, fromto, 3);
      roi = imgout(Rect(img1.cols, 0, img2.cols, img2.rows));
      img2C3.copyTo(roi);

      //maskのnull指定のやり方は適当
      //Flagsで自前の画像+非対応点は描かないよう指定
      drawMatches(img1, keypoints1, img2, keypoints2, matches, imgout,
        Scalar::all(-1), Scalar::all(-1), vector<char>(0), 
        DrawMatchesFlags::DRAW_OVER_OUTIMG+DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
      imshow("matches", imgout);
      waitKey(0);
    #ifdef USE_SURF
      imwrite("surfout.png)",imgout);
    #else
      imwrite("siftout.png)",imgout);
    #endif

      return 0;
    }

結果

原画像

SURF

SIFT

⚠️ **GitHub.com Fallback** ⚠️