前回はHaar-like特徴で顔認識をしました。おじさんのような年齢になると顔認識できてもプログラムのお仕事ってなかなかないんです。若い時にもっとプログラムと英語を勉強しておけばよかったです。そこで今回はいま一番お金になりそうなSIFT、SURFという特徴抽出をつかって物体認識をしたいと思います。
物体認識はロボット、自動運転、ジェスチャーゲーム、指紋認証などいろいろな分野で応用を研究されています。これができるといって職安に行けば、おじさんも時給700円でプログラムのお仕事が見つかるかもしれません。
いままでOpenCV3.0でプログラムをしていたのですが、SIFTやSURFは特許があるらしく、OpenCV3.0ではこれらのライブラリが別モジュールになっています。ソースコードは公開されているのですが、バイナリーが公開されていないのでビルドするのがめんどくさいです。やっぱり、金になりそうなところは特許でおさえられているのね。
さらに、この辺の分野はどんどん研究や新規開発が行われているので、ライブラリのバージョンごとにクラスの構成が大きく異なります。これでは手軽に勉強できないですね。
なので、今回はOpenCV2.4.10で実装をしてみたいと思います。
---------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include "mygetopt.h"
#ifdef _WIN32
#pragma comment(lib,"opencv_core2410")
#pragma comment(lib,"opencv_highgui2410")
#pragma comment(lib,"opencv_features2d2410")
#pragma comment(lib,"opencv_contrib2410")
#pragma comment(lib,"opencv_flann2410")
#pragma comment(lib,"opencv_imgproc2410")
#pragma comment(lib,"opencv_nonfree2410")
#pragma comment(lib,"opencv_ocl2410")
#pragma comment(lib,"IlmImf")
#pragma comment(lib,"zlib")
#pragma comment(lib,"libjasper")
#pragma comment(lib,"libpng")
#pragma comment(lib,"libjpeg")
#pragma comment(lib,"libtiff")
#pragma comment(lib,"comctl32")
#endif
int main(int argc, char *argv[])
{
int c;
std::string file_img1="kitkat1.jpg", file_img2="kitkat2.jpg";
cv::Mat colorImg1,colorImg2;
cv::Mat grayImg1, grayImg2;
std::vector<cv::KeyPoint> keypoints1,keypoints2;
std::vector<cv::DMatch> matches;
cv::BFMatcher matcher;
int N = 30;
while (1)
{
int this_option_optind = myoptind ? myoptind : 1;
c = mygetopt(argc, argv, "i:c:");
if (c == EOF)break;
switch (c){
case 'i':
file_img1 = myoptarg;
break;
case 'c':
file_img2 = myoptarg;
break;
}
}
colorImg1 = cv::imread(file_img1);
colorImg2 = cv::imread(file_img2);
if (colorImg1.empty() || colorImg2.empty()){
return 1;
}
cv::cvtColor(colorImg1, grayImg1, CV_BGR2GRAY);
cv::cvtColor(colorImg2, grayImg2, CV_BGR2GRAY);
//cv::SiftFeatureDetector detector;
//cv::SiftDescriptorExtractor extractor;
cv::SurfFeatureDetector detector(1000);
cv::SurfDescriptorExtractor extractor;
detector.detect(grayImg1, keypoints1);
detector.detect(grayImg2, keypoints2);
cv::Mat descriptors1;
extractor.compute(grayImg1, keypoints1, descriptors1);
cv::Mat descriptors2;
extractor.compute(grayImg2, keypoints2, descriptors2);
matcher.match(descriptors1, descriptors2, matches);
nth_element(matches.begin(), matches.begin() + N - 1, matches.end());
matches.erase(matches.begin() + N, matches.end());
cv::Mat matchedImg;
cv::drawMatches(colorImg1, keypoints1, colorImg2, keypoints2, matches, matchedImg);
cv::imshow("image", matchedImg);
cv::waitKey(0);
return 0;
}
---------------------------------------------------------------
detector.detect()で特徴点を検出して、extractor.compute()で特徴ベクトルを計算して、matcher.match()で距離を計算してマッチングしてます。
プログラムはとっても簡単です。
みんなネットにはいい結果ばかり載せていますが、よく見るとけっこう特徴点が一致してない気が・・・・。だからみんなよいアルゴリズムを研究しているのね。