#include <string>\r
#include <iostream>\r
#include <fstream>\r
+#include <numeric>\r
+#include <algorithm>\r
#include <iterator>\r
#include "cvaux.h"\r
\r
CV_DetectorsTest();\r
~CV_DetectorsTest(); \r
protected: \r
- void run(int); \r
+ void run(int); \r
+ template <class T> bool testDedector(const Mat& img, const T& detector, vector<KeyPoint>& expected);\r
+\r
+ void LoadExpected(const string& file, vector<KeyPoint>& out);\r
};\r
\r
CV_DetectorsTest::CV_DetectorsTest(): CvTest( "feature-detectors", "?" )\r
}\r
CV_DetectorsTest::~CV_DetectorsTest() {}\r
\r
-struct OutOfMask\r
+void getRotation(const Mat& img, Mat& aff, Mat& out)\r
{\r
- const Mat& msk;\r
- OutOfMask(const Mat& mask) : msk(mask) {};\r
- OutOfMask& operator=(const OutOfMask&);\r
- bool operator()(const KeyPoint& kp) const { return msk.at<uchar>(kp.pt) == 0; }\r
-};\r
+ Point center(img.cols/2, img.rows/2);\r
+ aff = getRotationMatrix2D(center, 30, 1);\r
+ warpAffine( img, out, aff, img.size());\r
+}\r
+\r
+void getZoom(const Mat& img, Mat& aff, Mat& out)\r
+{\r
+ const double mult = 1.2;\r
+\r
+ aff.create(2, 3, CV_64F);\r
+ double *data = aff.ptr<double>();\r
+ data[0] = mult; data[1] = 0; data[2] = 0;\r
+ data[3] = 0; data[4] = mult; data[5] = 0;\r
+ \r
+ warpAffine( img, out, aff, img.size());\r
+}\r
+\r
+void getBlur(const Mat& img, Mat& aff, Mat& out)\r
+{ \r
+ aff.create(2, 3, CV_64F);\r
+ double *data = aff.ptr<double>();\r
+ data[0] = 1; data[1] = 0; data[2] = 0;\r
+ data[3] = 0; data[4] = 1; data[5] = 0;\r
+ \r
+ GaussianBlur(img, out, Size(5, 5), 2); \r
+}\r
+\r
+void getBrightness(const Mat& img, Mat& aff, Mat& out)\r
+{ \r
+ aff.create(2, 3, CV_64F);\r
+ double *data = aff.ptr<double>();\r
+ data[0] = 1; data[1] = 0; data[2] = 0;\r
+ data[3] = 0; data[4] = 1; data[5] = 0;\r
+ \r
+ add(img, Mat(img.size(), img.type(), Scalar(15)), out); \r
+}\r
+\r
+void showOrig(const Mat& img, const vector<KeyPoint>& orig_pts)\r
+{\r
+ \r
+ Mat img_color;\r
+ cvtColor(img, img_color, CV_GRAY2BGR); \r
+ \r
+ for(size_t i = 0; i < orig_pts.size(); ++i) \r
+ circle(img_color, orig_pts[i].pt, (int)orig_pts[i].size/2, CV_RGB(0, 255, 0)); \r
+ \r
+ namedWindow("O"); imshow("O", img_color); \r
+}\r
+\r
+void show(const string& name, const Mat& new_img, const vector<KeyPoint>& new_pts, const vector<KeyPoint>& transf_pts)\r
+{\r
+ \r
+ Mat new_img_color; \r
+ cvtColor(new_img, new_img_color, CV_GRAY2BGR); \r
+\r
+ for(size_t i = 0; i < transf_pts.size(); ++i)\r
+ circle(new_img_color, transf_pts[i].pt, (int)transf_pts[i].size/2, CV_RGB(255, 0, 0));\r
+\r
+ for(size_t i = 0; i < new_pts.size(); ++i) \r
+ circle(new_img_color, new_pts[i].pt, (int)new_pts[i].size/2, CV_RGB(0, 0, 255));\r
+ \r
+ namedWindow(name + "_T"); imshow(name + "_T", new_img_color); \r
+}\r
\r
struct WrapPoint\r
{\r
}\r
};\r
\r
-void CV_DetectorsTest::run( int /*start_from*/ )\r
-{ \r
- Mat oimg = imread(string(ts->get_data_path()) + "shared/baboon.jpg", 0);\r
- //Mat oimg = imread(string(ts->get_data_path()) + "shared/fruits.jpg", 0);\r
+struct sortByR { bool operator()(const KeyPoint& kp1, const KeyPoint& kp2) { return norm(kp1.pt) < norm(kp2.pt); } };\r
+\r
+template <class T> bool CV_DetectorsTest::testDedector(const Mat& img, const T& detector, vector<KeyPoint>& exp)\r
+{\r
+ vector<KeyPoint> orig_kpts;\r
+ detector(img, orig_kpts);\r
+\r
+ typedef void (*TransfFunc )(const Mat&, Mat&, Mat& FransfFunc); \r
+ const TransfFunc transfFunc[] = { getRotation, getZoom, getBlur, getBrightness };\r
+ //const string names[] = { "Rotation", "Zoom", "Blur", "Brightness" };\r
+ const size_t case_num = sizeof(transfFunc)/sizeof(transfFunc[0]);\r
\r
- if (oimg.empty())\r
+ vector<Mat> affs(case_num);\r
+ vector<Mat> new_imgs(case_num);\r
+\r
+ vector< vector<KeyPoint> > new_kpts(case_num);\r
+ vector< vector<KeyPoint> > transf_kpts(case_num);\r
+\r
+ //showOrig(img, orig_kpts);\r
+ for(size_t i = 0; i < case_num; ++i) \r
{\r
- ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA );\r
- return;\r
- } \r
+ transfFunc[i](img, affs[i], new_imgs[i]);\r
+ detector(new_imgs[i], new_kpts[i]);\r
+ transform(orig_kpts.begin(), orig_kpts.end(), back_inserter(transf_kpts[i]), WrapPoint(affs[i]));\r
+ //show(names[i], new_imgs[i], new_kpts[i], transf_kpts[i]);\r
+ }\r
\r
- Point center(oimg.cols/2, oimg.rows/2);\r
- \r
- Mat aff = getRotationMatrix2D(center, 45, 1);\r
+ const float thres = 3;\r
+ const float nthres = 3;\r
\r
- Mat rimg; \r
- warpAffine( oimg, rimg, aff, oimg.size());\r
+ vector<KeyPoint> result;\r
+ for(size_t i = 0; i < orig_kpts.size(); ++i)\r
+ {\r
+ const KeyPoint& okp = orig_kpts[i];\r
+ int foundCounter = 0;\r
+ for(size_t j = 0; j < case_num; ++j)\r
+ { \r
+ const KeyPoint& tkp = transf_kpts[j][i];\r
\r
- Mat mask(oimg.size(), CV_8U, Scalar(0)); \r
- circle(mask, center, std::min(center.x, center.y) - 10, Scalar(255), CV_FILLED);\r
- Mat inv_mask;\r
- mask.convertTo(inv_mask, CV_8U, -1, 255);\r
+ size_t k = 0;\r
+ \r
+ for(; k < new_kpts[j].size(); ++k)\r
+ if (norm(new_kpts[j][k].pt - tkp.pt) < nthres && fabs(new_kpts[j][k].size - tkp.size) < thres)\r
+ break;\r
\r
- Mat oimg_color, rimg_color;\r
- cvtColor(oimg, oimg_color, CV_GRAY2BGR); oimg_color.setTo(Scalar(0), inv_mask);\r
- cvtColor(rimg, rimg_color, CV_GRAY2BGR); rimg_color.setTo(Scalar(0), inv_mask); \r
+ if (k != new_kpts[j].size())\r
+ ++foundCounter;\r
\r
- SURF surf(1536, 2);\r
- StarDetector star(45, 30, 10, 8, 5);\r
+ }\r
+ if (foundCounter == case_num)\r
+ result.push_back(okp);\r
+ }\r
\r
- vector<KeyPoint> opoints_surf, rpoints_surf, opoints_star, rpoints_star;\r
- surf(oimg, mask, opoints_surf);\r
- surf(rimg, mask, rpoints_surf);\r
+ sort(result.begin(), result.end(), sortByR());\r
+ sort(exp.begin(), exp.end(), sortByR()); \r
\r
- star(oimg, opoints_star);\r
- star(rimg, rpoints_star);\r
- \r
- opoints_star.erase(\r
- remove_if(opoints_star.begin(), opoints_star.end(), OutOfMask(mask)), \r
- opoints_star.end());\r
+ int foundCounter1 = 0;\r
+ for(size_t i = 0; i < exp.size(); ++i)\r
+ {\r
+ const KeyPoint& e = exp[i]; \r
+ size_t j = 0;\r
+ for(; j < result.size(); ++j)\r
+ {\r
+ const KeyPoint& r = result[i];\r
+ if (norm(r.pt-e.pt) < nthres && fabs(r.size - e.size) < thres)\r
+ break;\r
+ }\r
+ if (j != result.size())\r
+ ++foundCounter1;\r
+ }\r
\r
- rpoints_star.erase(\r
- remove_if(rpoints_star.begin(), rpoints_star.end(), OutOfMask(mask)), \r
- rpoints_star.end());\r
+ int foundCounter2 = 0;\r
+ for(size_t i = 0; i < result.size(); ++i)\r
+ {\r
+ const KeyPoint& r = result[i]; \r
+ size_t j = 0;\r
+ for(; j < exp.size(); ++j)\r
+ {\r
+ const KeyPoint& e = exp[i];\r
+ if (norm(r.pt-e.pt) < nthres && fabs(r.size - e.size) < thres)\r
+ break;\r
+ }\r
+ if (j != exp.size())\r
+ ++foundCounter2;\r
+ }\r
+ //showOrig(img, result); waitKey();\r
\r
- vector<KeyPoint> exp_rpoints_surf(opoints_surf.size()), exp_rpoints_star(opoints_star.size());\r
- transform(opoints_surf.begin(), opoints_surf.end(), exp_rpoints_surf.begin(), WrapPoint(aff));\r
- transform(opoints_star.begin(), opoints_star.end(), exp_rpoints_star.begin(), WrapPoint(aff));\r
- \r
- for(size_t i = 0; i < opoints_surf.size(); ++i)\r
+ const float errorRate = 0.9f;\r
+ if (float(foundCounter1)/exp.size() < errorRate || float(foundCounter2)/result.size() < errorRate)\r
{\r
- circle(oimg_color, opoints_surf[i].pt, (int)opoints_surf[i].size/2, CV_RGB(0, 255, 0));\r
- circle(rimg_color, exp_rpoints_surf[i].pt, (int)exp_rpoints_surf[i].size/2, CV_RGB(255, 0, 0));\r
+ ts->set_failed_test_info( CvTS::FAIL_MISMATCH);\r
+ return false;\r
}\r
+ return true; \r
+}\r
\r
- for(size_t i = 0; i < rpoints_surf.size(); ++i)\r
- circle(rimg_color, rpoints_surf[i].pt, (int)rpoints_surf[i].size/2, CV_RGB(0, 255, 0));\r
+struct SurfNoMaskWrap \r
+{\r
+ const SURF& detector;\r
+ SurfNoMaskWrap(const SURF& surf) : detector(surf) {}\r
+ SurfNoMaskWrap& operator=(const SurfNoMaskWrap&);\r
+ void operator()(const Mat& img, vector<KeyPoint>& kpts) const { detector(img, Mat(), kpts); }\r
+};\r
\r
- for(size_t i = 0; i < opoints_star.size(); ++i)\r
+void CV_DetectorsTest::LoadExpected(const string& file, vector<KeyPoint>& out)\r
+{ \r
+ Mat mat_exp;\r
+ FileStorage fs(file, FileStorage::READ); \r
+ if (fs.isOpened())\r
{\r
- circle(oimg_color, opoints_star[i].pt, (int)opoints_star[i].size/2, CV_RGB(0, 0, 255));\r
- circle(rimg_color, exp_rpoints_surf[i].pt, (int)exp_rpoints_surf[i].size/2, CV_RGB(255, 0, 0));\r
+ read( fs["ResultVectorData"], mat_exp, Mat() ); \r
+ out.resize(mat_exp.cols / sizeof(KeyPoint));\r
+ copy(mat_exp.ptr<KeyPoint>(), mat_exp.ptr<KeyPoint>() + out.size(), out.begin()); \r
}\r
+ else\r
+ {\r
+ ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA);\r
+ out.clear();\r
+ } \r
+}\r
+\r
+void CV_DetectorsTest::run( int /*start_from*/ )\r
+{ \r
+ Mat img = imread(string(ts->get_data_path()) + "shared/graffiti.png", 0);\r
+\r
+ if (img.empty())\r
+ {\r
+ ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA );\r
+ return;\r
+ }\r
+ \r
+ Mat to_test(img.size() * 2, img.type(), Scalar(0));\r
+ Mat roi = to_test(Rect(img.rows/2, img.cols/2, img.cols, img.rows));\r
+ img.copyTo(roi);\r
+ GaussianBlur(to_test, to_test, Size(3, 3), 1.5);\r
+ \r
+ vector<KeyPoint> exp;\r
+ LoadExpected(string(ts->get_data_path()) + "detectors/surf.xml", exp); \r
+ if (exp.empty())\r
+ return;\r
\r
- for(size_t i = 0; i < rpoints_star.size(); ++i)\r
- circle(rimg_color, rpoints_star[i].pt, (int)rpoints_star[i].size/2, CV_RGB(0, 0, 255));\r
+ if (!testDedector(to_test, SurfNoMaskWrap(SURF(1536+512+512, 2)), exp))\r
+ return;\r
\r
- /* namedWindow("R"); imshow("R", rimg_color); \r
- namedWindow("O"); imshow("O", oimg_color); \r
- waitKey();*/\r
+ LoadExpected(string(ts->get_data_path()) + "detectors/star.xml", exp);\r
+ if (exp.empty())\r
+ return;\r
+\r
+ if (!testDedector(to_test, StarDetector(45, 30, 10, 8, 5), exp))\r
+ return;\r
\r
- ts->set_failed_test_info( CvTS::FAIL_GENERIC ); \r
+ ts->set_failed_test_info( CvTS::OK); \r
}\r
\r
\r