みんな黙々と作業していたので、実質3人しかつぶやいていなかったらしいtogetterはこれ。
自分は、C++版のOpenCVをちゃんと使った事無かったので、C++版を触ってみることにしました。
具体的に実施したのは、http://opencv.jp/のcookbookの画像処理の部分をちょこちょこ覗きつつ、最終的にtemplate matchingの項をほぼ写経してみました。
template matchingの結果(類似度のマップみたいなもの)と、オリジナル画像に一致した場所を表示したもの結合画像はこれを参照にしてます。
下記のコードになります。C++的にこういう書き方が良いのか分かりませんが。
#include <opencv2 core.hpp="" core=""> #include <opencv2 imgproc.hpp="" imgproc=""> #include <opencv2 highgui.hpp="" highgui=""> #include <iostream> cv::Mat mouseMat; void onMouse(int event, int x, int y, int flag, void*) { if ((x < 0 && mouseMat.size[0] < x) || (y < 0 && mouseMat.size[0] < y)) { return; } switch (event) { case cv::EVENT_LBUTTONUP: switch (mouseMat.channels()) { case 3: { uchar b = mouseMat.at<cv::vec3b>(y,x)[0]; uchar g = mouseMat.at<cv::vec3b>(y,x)[1]; uchar r = mouseMat.at<cv::vec3b>(y,x)[2]; std::cout << "(" << y << "," << x << ")" << int(r) << ":" << int(g) << ":" << int(b) << std::endl; break; } case 1: { uchar gray = mouseMat.at<uchar>(y,x); std::cout << "(" << y << "," << x << ")" << int(gray) << std::endl; break; } } break; } } void viewImage(cv::Mat img, std::string title) { mouseMat = img; cv::namedWindow(title, CV_WND_PROP_AUTOSIZE|CV_WINDOW_FREERATIO); cv::imshow(title, img); cv::setMouseCallback(title, onMouse, 0); while (1) { int key = cv::waitKey(0); if (key == 27) break; } } cv::Mat loadimage(std::string name, int flag=1) { cv::Mat image = cv::imread(name, flag); if (image.empty()) { std::cout << "can not open file " << name << std::endl; exit(1); } return image; } void templateMatching(std::string searchfile, std::string templatefile, std::string outputfile) { cv::Mat searchimg_orig = loadimage(searchfile); cv::Mat templateimg_orig = loadimage(templatefile); cv::Mat searchimg; cv::Mat templateimg; double s_factor = 320.0 / searchimg_orig.cols; cv::resize(searchimg_orig, searchimg, cv::Size(), s_factor , s_factor); cv::resize(templateimg_orig, templateimg, cv::Size(), s_factor, s_factor); cv::Mat resultimg; cv::matchTemplate(searchimg, templateimg, resultimg, CV_TM_CCORR_NORMED); cv::Rect answer(0,0,templateimg.cols, templateimg.rows); cv::Point max_point; double maxValue; cv::minMaxLoc(resultimg, NULL, &maxValue, NULL, &max_point); answer.x = max_point.x; answer.y = max_point.y; cv::rectangle(searchimg, answer, cv::Scalar(0,0,255), 3); cv::Mat combined_img(cv::Size(searchimg.cols + resultimg.cols, searchimg.rows), CV_8UC3, cv::Scalar(0,0,0)); cv::Rect roi_rect; roi_rect.width = searchimg.cols; roi_rect.height = searchimg.rows; cv::Mat roi(combined_img, roi_rect); searchimg.copyTo(roi); roi_rect.x += searchimg.cols; cv::Mat resultimg_3c; cv::Mat tmp_img; cv::convertScaleAbs(resultimg, tmp_img, 255); cv::cvtColor(tmp_img, resultimg_3c, CV_GRAY2BGR); roi_rect.width = resultimg_3c.cols; roi_rect.height = resultimg_3c.rows; cv::Mat roi2(combined_img, roi_rect); resultimg_3c.copyTo(roi2); //viewImage(resultimg_3c, "template matching"); cv::imwrite(outputfile, combined_img); } int main (int argc, const char * argv[]) { if (argc < 3) { std::cout << "bad argments" << std::endl; exit(1); } std::string imagefile = argv[1]; std::string templatefile = argv[2]; std::string outputfile = argv[3]; std::cout << "inputfile :" << imagefile << std::endl; std::cout << "tempatefile :" << templatefile << std::endl; std::cout << "outputfile :" << outputfile << std::endl; templateMatching(imagefile, templatefile, outputfile); }
故あってskytreeの写真が100枚以上あったので、この写真に対して実行してみました(shellなりスクリプトなりでさくっと実行しました)。対象が分かりやすいので、晴れの日の写真はほとんどうまく場所が取得出来ました。
全結果をのせる事はできないので、うまく言ったものと失敗したものを載せておきます。
テンプレート画像 |
成功したもの |
失敗したもの(曇りの時の写真だからしようがないか) |
0 件のコメント:
コメントを投稿