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