最近、画像処理したりすることもなくはないので、勉強のためにSIFT特徴量を抽出するプログラムを作ってみました。
C++とOpenCVで書いています。Visual Studio利用で、今回はOpenCVの環境構築とかについては書かず、さらっとコードと結果だけ載せて、誰かにとって有益な情報になればよいなくらいのスタンスでいきます。
SIFTとは
ざくっと説明します(実はよくわかっていない)。
SIFTは画像の特徴量としてはメジャーなものの一つで、Scale-Invariant Feature Transformの頭文字を取ったものです。
論文的には、以下の二つが該当するようですが、個人的には②を読めば十分かなという次第です。
① 「Object Recognition from Local Scale-Invariant Features」
② 「Distinctive Image Features from Scale-Invariant Keypoints」
どちらもUniversity of British ColumbiaのDavid G. Lowe氏の論文で、有名な論文なので検索したら必ず出てきます。
回転や拡大・縮小に不変な特徴量で、照明等の影響にも頑健な特徴量です。詳しいアルゴリズムは他のサイトや、論文に譲って、OpenCVでの実装プログラムと実装結果を示していきましょう。
今回の環境
・OS : Windows10(64bit)
・GPU: GeForce GTX 950
・OpenCV 2.4.13
・Visual Studio Community 2015
ソースコード
// Open CV 2.4.13 | |
#include <iostream> | |
#include <opencv2/opencv.hpp> | |
#include <opencv2/features2d/features2d.hpp> | |
#include <opencv2/highgui/highgui.hpp> | |
#include <opencv2/nonfree/features2d.hpp> | |
using namespace cv; | |
using namespace std; | |
#if _DEBUG | |
#pragma comment(lib, "opencv_core2413d.lib") | |
#pragma comment(lib, "opencv_features2d2413d.lib") | |
#pragma comment(lib, "opencv_highgui2413d.lib") | |
#pragma comment(lib, "opencv_imgproc2413d.lib") | |
#pragma comment(lib, "opencv_nonfree2413d.lib") | |
#else | |
#pragma comment(lib, "opencv_core2413.lib") | |
#pragma comment(lib, "opencv_features2d2413.lib") | |
#pragma comment(lib, "opencv_highgui2413.lib") | |
#pragma comment(lib, "opencv_imgproc2413.lib") | |
#pragma comment(lib, "opencv_nonfree2413.lib") | |
#endif | |
int main(void) | |
{ | |
// 入力画像の取得 | |
Mat color_image = imread("input.jpg", 1); | |
if (color_image.empty()) { | |
return -1; | |
} | |
// カラー画像をグレースケールに変換 | |
Mat gray_image; | |
cvtColor(color_image, gray_image, CV_RGB2GRAY); | |
normalize(gray_image, gray_image, 0, 255, NORM_MINMAX); | |
// SIFT特徴点の抽出 | |
vector<KeyPoint> keypoints; | |
vector<KeyPoint>::iterator itk; | |
double threshold = 0.05; | |
double edge_threshold = 10.0; | |
SiftFeatureDetector detector(threshold, edge_threshold); | |
detector.detect(gray_image, keypoints); | |
// キーポイントの数を表示 | |
int keypoint_num = keypoints.size(); | |
cout << "keypoint_num :" << keypoint_num << endl; | |
// 結果を表示 | |
Mat output_image_1, output_image_2; | |
drawKeypoints(color_image, keypoints, output_image_1, Scalar(0, 255, 0), 0); | |
drawKeypoints(color_image, keypoints, output_image_2, Scalar(0, 255, 0), 4); | |
imshow("Result Keypoint", output_image_1); | |
imshow("Result Keypoint Size and Direction", output_image_2); | |
// 結果を保存 | |
imwrite("output_image_1.png", output_image_1); | |
imwrite("output_image_2.png", output_image_2); | |
waitKey(0); | |
} |
Visual StudioのプロジェクトはGithubにアップしときました。
SIFT特徴量のための関数がOpenCVには整備されているので、割と簡単に抽出できますね。
入力画像
「input.jpg」を以下の画像にして、入力しました。
出力結果
「output_image_1.png」が以下、
「output_image_2.png」が以下です。
表示方法を変えているだけで、出している特徴量は同じものとなります。
エッジ部分を中心に特徴量が現れているのがわかると思います。
まとめ
何に使うの? という話ではあるんですが、現在割とノープランです。
取りあえず、画像処理とかをやり始めた身としては知っておいた方が良いかなと思い作ってみました。
時間があれば他の特徴量についても試してみたいですね。