test_detectors.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*M///////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
  4. //
  5. // By downloading, copying, installing or using the software you agree to this license.
  6. // If you do not agree to this license, do not download, install,
  7. // copy or use the software.
  8. //
  9. //
  10. // License Agreement
  11. // For Open Source Computer Vision Library
  12. //
  13. // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
  14. // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
  15. // Third party copyrights are property of their respective owners.
  16. //
  17. // Redistribution and use in source and binary forms, with or without modification,
  18. // are permitted provided that the following conditions are met:
  19. //
  20. // * Redistribution's of source code must retain the above copyright notice,
  21. // this list of conditions and the following disclaimer.
  22. //
  23. // * Redistribution's in binary form must reproduce the above copyright notice,
  24. // this list of conditions and the following disclaimer in the documentation
  25. // and/or other materials provided with the distribution.
  26. //
  27. // * The name of the copyright holders may not be used to endorse or promote products
  28. // derived from this software without specific prior written permission.
  29. //
  30. // This software is provided by the copyright holders and contributors "as is" and
  31. // any express or implied warranties, including, but not limited to, the implied
  32. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  33. // In no event shall the Intel Corporation or contributors be liable for any direct,
  34. // indirect, incidental, special, exemplary, or consequential damages
  35. // (including, but not limited to, procurement of substitute goods or services;
  36. // loss of use, data, or profits; or business interruption) however caused
  37. // and on any theory of liability, whether in contract, strict liability,
  38. // or tort (including negligence or otherwise) arising in any way out of
  39. // the use of this software, even if advised of the possibility of such damage.
  40. //
  41. //M*/
  42. #include "test_precomp.hpp"
  43. namespace opencv_test { namespace {
  44. class CV_DetectorsTest : public cvtest::BaseTest
  45. {
  46. public:
  47. CV_DetectorsTest();
  48. ~CV_DetectorsTest();
  49. protected:
  50. void run(int);
  51. bool testDetector(const Mat& img, Ptr<Feature2D> detector, vector<KeyPoint>& expected);
  52. void LoadExpected(const string& file, vector<KeyPoint>& out);
  53. };
  54. CV_DetectorsTest::CV_DetectorsTest()
  55. {
  56. }
  57. CV_DetectorsTest::~CV_DetectorsTest() {}
  58. void getRotation(const Mat& img, Mat& aff, Mat& out)
  59. {
  60. Point center(img.cols/2, img.rows/2);
  61. aff = getRotationMatrix2D(center, 30, 1);
  62. warpAffine( img, out, aff, img.size());
  63. }
  64. void getZoom(const Mat& img, Mat& aff, Mat& out)
  65. {
  66. const double mult = 1.2;
  67. aff.create(2, 3, CV_64F);
  68. double *data = aff.ptr<double>();
  69. data[0] = mult; data[1] = 0; data[2] = 0;
  70. data[3] = 0; data[4] = mult; data[5] = 0;
  71. warpAffine( img, out, aff, img.size());
  72. }
  73. void getBlur(const Mat& img, Mat& aff, Mat& out)
  74. {
  75. aff.create(2, 3, CV_64F);
  76. double *data = aff.ptr<double>();
  77. data[0] = 1; data[1] = 0; data[2] = 0;
  78. data[3] = 0; data[4] = 1; data[5] = 0;
  79. GaussianBlur(img, out, Size(5, 5), 2);
  80. }
  81. void getBrightness(const Mat& img, Mat& aff, Mat& out)
  82. {
  83. aff.create(2, 3, CV_64F);
  84. double *data = aff.ptr<double>();
  85. data[0] = 1; data[1] = 0; data[2] = 0;
  86. data[3] = 0; data[4] = 1; data[5] = 0;
  87. cv::add(img, Mat(img.size(), img.type(), Scalar(15)), out);
  88. }
  89. #if 0
  90. void showOrig(const Mat& img, const vector<KeyPoint>& orig_pts)
  91. {
  92. Mat img_color;
  93. cvtColor(img, img_color, COLOR_GRAY2BGR);
  94. for(size_t i = 0; i < orig_pts.size(); ++i)
  95. circle(img_color, orig_pts[i].pt, (int)orig_pts[i].size/2, Scalar(0, 255, 0));
  96. namedWindow("O"); imshow("O", img_color);
  97. }
  98. void show(const string& name, const Mat& new_img, const vector<KeyPoint>& new_pts, const vector<KeyPoint>& transf_pts)
  99. {
  100. Mat new_img_color;
  101. cvtColor(new_img, new_img_color, COLOR_GRAY2BGR);
  102. for(size_t i = 0; i < transf_pts.size(); ++i)
  103. circle(new_img_color, transf_pts[i].pt, (int)transf_pts[i].size/2, Scalar(255, 0, 0));
  104. for(size_t i = 0; i < new_pts.size(); ++i)
  105. circle(new_img_color, new_pts[i].pt, (int)new_pts[i].size/2, Scalar(0, 0, 255));
  106. namedWindow(name + "_T"); imshow(name + "_T", new_img_color);
  107. }
  108. #endif
  109. struct WrapPoint
  110. {
  111. const double* R;
  112. WrapPoint(const Mat& rmat) : R(rmat.ptr<double>()) { };
  113. KeyPoint operator()(const KeyPoint& kp) const
  114. {
  115. KeyPoint res = kp;
  116. res.pt.x = static_cast<float>(kp.pt.x * R[0] + kp.pt.y * R[1] + R[2]);
  117. res.pt.y = static_cast<float>(kp.pt.x * R[3] + kp.pt.y * R[4] + R[5]);
  118. return res;
  119. }
  120. };
  121. struct sortByR { bool operator()(const KeyPoint& kp1, const KeyPoint& kp2) { return cv::norm(kp1.pt) < cv::norm(kp2.pt); } };
  122. bool CV_DetectorsTest::testDetector(const Mat& img, Ptr<Feature2D> detector, vector<KeyPoint>& exp)
  123. {
  124. vector<KeyPoint> orig_kpts;
  125. detector->detect(img, orig_kpts);
  126. typedef void (*TransfFunc )(const Mat&, Mat&, Mat& FransfFunc);
  127. const TransfFunc transfFunc[] = { getRotation, getZoom, getBlur, getBrightness };
  128. //const string names[] = { "Rotation", "Zoom", "Blur", "Brightness" };
  129. const size_t case_num = sizeof(transfFunc)/sizeof(transfFunc[0]);
  130. vector<Mat> affs(case_num);
  131. vector<Mat> new_imgs(case_num);
  132. vector< vector<KeyPoint> > new_kpts(case_num);
  133. vector< vector<KeyPoint> > transf_kpts(case_num);
  134. //showOrig(img, orig_kpts);
  135. for(size_t i = 0; i < case_num; ++i)
  136. {
  137. transfFunc[i](img, affs[i], new_imgs[i]);
  138. detector->detect(new_imgs[i], new_kpts[i]);
  139. transform(orig_kpts.begin(), orig_kpts.end(), back_inserter(transf_kpts[i]), WrapPoint(affs[i]));
  140. //show(names[i], new_imgs[i], new_kpts[i], transf_kpts[i]);
  141. }
  142. const float thres = 3;
  143. const float nthres = 3;
  144. vector<KeyPoint> result;
  145. for(size_t i = 0; i < orig_kpts.size(); ++i)
  146. {
  147. const KeyPoint& okp = orig_kpts[i];
  148. int foundCounter = 0;
  149. for(size_t j = 0; j < case_num; ++j)
  150. {
  151. const KeyPoint& tkp = transf_kpts[j][i];
  152. size_t k = 0;
  153. for(; k < new_kpts[j].size(); ++k)
  154. if (cv::norm(new_kpts[j][k].pt - tkp.pt) < nthres && fabs(new_kpts[j][k].size - tkp.size) < thres)
  155. break;
  156. if (k != new_kpts[j].size())
  157. ++foundCounter;
  158. }
  159. if (foundCounter == (int)case_num)
  160. result.push_back(okp);
  161. }
  162. sort(result.begin(), result.end(), sortByR());
  163. sort(exp.begin(), exp.end(), sortByR());
  164. if (result.size() != exp.size())
  165. {
  166. ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
  167. return false;
  168. }
  169. int foundCounter1 = 0;
  170. for(size_t i = 0; i < exp.size(); ++i)
  171. {
  172. const KeyPoint& e = exp[i];
  173. size_t j = 0;
  174. for(; j < result.size(); ++j)
  175. {
  176. const KeyPoint& r = result[i];
  177. if (cv::norm(r.pt-e.pt) < nthres && fabs(r.size - e.size) < thres)
  178. break;
  179. }
  180. if (j != result.size())
  181. ++foundCounter1;
  182. }
  183. int foundCounter2 = 0;
  184. for(size_t i = 0; i < result.size(); ++i)
  185. {
  186. const KeyPoint& r = result[i];
  187. size_t j = 0;
  188. for(; j < exp.size(); ++j)
  189. {
  190. const KeyPoint& e = exp[i];
  191. if (cv::norm(r.pt-e.pt) < nthres && fabs(r.size - e.size) < thres)
  192. break;
  193. }
  194. if (j != exp.size())
  195. ++foundCounter2;
  196. }
  197. //showOrig(img, result); waitKey();
  198. const float errorRate = 0.9f;
  199. if (float(foundCounter1)/exp.size() < errorRate || float(foundCounter2)/result.size() < errorRate)
  200. {
  201. ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH);
  202. return false;
  203. }
  204. return true;
  205. }
  206. void CV_DetectorsTest::LoadExpected(const string& file, vector<KeyPoint>& out)
  207. {
  208. Mat mat_exp;
  209. FileStorage fs(file, FileStorage::READ);
  210. if (fs.isOpened())
  211. {
  212. read( fs["ResultVectorData"], mat_exp, Mat() );
  213. out.resize(mat_exp.cols / sizeof(KeyPoint));
  214. copy(mat_exp.ptr<KeyPoint>(), mat_exp.ptr<KeyPoint>() + out.size(), out.begin());
  215. }
  216. else
  217. {
  218. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA);
  219. out.clear();
  220. }
  221. }
  222. void CV_DetectorsTest::run( int /*start_from*/ )
  223. {
  224. Mat img = imread(string(ts->get_data_path()) + "shared/graffiti.png", 0);
  225. if (img.empty())
  226. {
  227. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
  228. return;
  229. }
  230. Mat to_test(img.size() * 2, img.type(), Scalar(0));
  231. Mat roi = to_test(Rect(img.rows/2, img.cols/2, img.cols, img.rows));
  232. img.copyTo(roi);
  233. GaussianBlur(to_test, to_test, Size(3, 3), 1.5);
  234. vector<KeyPoint> exp;
  235. #ifdef OPENCV_ENABLE_NONFREE
  236. LoadExpected(string(ts->get_data_path()) + "detectors/surf.xml", exp);
  237. if (exp.empty())
  238. return;
  239. if (!testDetector(to_test, SURF::create(1536+512+512, 2, 2, true, false), exp))
  240. return;
  241. #endif
  242. LoadExpected(string(ts->get_data_path()) + "detectors/star.xml", exp);
  243. if (exp.empty())
  244. return;
  245. if (!testDetector(to_test, StarDetector::create(45, 30, 10, 8, 5), exp))
  246. return;
  247. ts->set_failed_test_info( cvtest::TS::OK);
  248. }
  249. TEST(Features2d_Detectors, regression) { CV_DetectorsTest test; test.safe_run(); }
  250. }} // namespace