test_detectors_regression.impl.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html
  4. namespace opencv_test { namespace {
  5. /****************************************************************************************\
  6. * Regression tests for feature detectors comparing keypoints. *
  7. \****************************************************************************************/
  8. class CV_FeatureDetectorTest : public cvtest::BaseTest
  9. {
  10. public:
  11. CV_FeatureDetectorTest( const string& _name, const Ptr<FeatureDetector>& _fdetector ) :
  12. name(_name), fdetector(_fdetector) {}
  13. protected:
  14. bool isSimilarKeypoints( const KeyPoint& p1, const KeyPoint& p2 );
  15. void compareKeypointSets( const vector<KeyPoint>& validKeypoints, const vector<KeyPoint>& calcKeypoints );
  16. void emptyDataTest();
  17. void regressionTest(); // TODO test of detect() with mask
  18. virtual void run( int );
  19. string name;
  20. Ptr<FeatureDetector> fdetector;
  21. };
  22. void CV_FeatureDetectorTest::emptyDataTest()
  23. {
  24. // One image.
  25. Mat image;
  26. vector<KeyPoint> keypoints;
  27. try
  28. {
  29. fdetector->detect( image, keypoints );
  30. }
  31. catch(...)
  32. {
  33. ts->printf( cvtest::TS::LOG, "detect() on empty image must not generate exception (1).\n" );
  34. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  35. }
  36. if( !keypoints.empty() )
  37. {
  38. ts->printf( cvtest::TS::LOG, "detect() on empty image must return empty keypoints vector (1).\n" );
  39. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  40. return;
  41. }
  42. // Several images.
  43. vector<Mat> images;
  44. vector<vector<KeyPoint> > keypointCollection;
  45. try
  46. {
  47. fdetector->detect( images, keypointCollection );
  48. }
  49. catch(...)
  50. {
  51. ts->printf( cvtest::TS::LOG, "detect() on empty image vector must not generate exception (2).\n" );
  52. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  53. }
  54. }
  55. bool CV_FeatureDetectorTest::isSimilarKeypoints( const KeyPoint& p1, const KeyPoint& p2 )
  56. {
  57. const float maxPtDif = 1.f;
  58. const float maxSizeDif = 1.f;
  59. const float maxAngleDif = 2.f;
  60. const float maxResponseDif = 0.1f;
  61. float dist = (float)cv::norm( p1.pt - p2.pt );
  62. return (dist < maxPtDif &&
  63. fabs(p1.size - p2.size) < maxSizeDif &&
  64. abs(p1.angle - p2.angle) < maxAngleDif &&
  65. abs(p1.response - p2.response) < maxResponseDif &&
  66. p1.octave == p2.octave &&
  67. p1.class_id == p2.class_id );
  68. }
  69. void CV_FeatureDetectorTest::compareKeypointSets( const vector<KeyPoint>& validKeypoints, const vector<KeyPoint>& calcKeypoints )
  70. {
  71. const float maxCountRatioDif = 0.01f;
  72. // Compare counts of validation and calculated keypoints.
  73. float countRatio = (float)validKeypoints.size() / (float)calcKeypoints.size();
  74. if( countRatio < 1 - maxCountRatioDif || countRatio > 1.f + maxCountRatioDif )
  75. {
  76. ts->printf( cvtest::TS::LOG, "Bad keypoints count ratio (validCount = %d, calcCount = %d).\n",
  77. validKeypoints.size(), calcKeypoints.size() );
  78. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  79. return;
  80. }
  81. int progress = 0, progressCount = (int)(validKeypoints.size() * calcKeypoints.size());
  82. int badPointCount = 0, commonPointCount = max((int)validKeypoints.size(), (int)calcKeypoints.size());
  83. for( size_t v = 0; v < validKeypoints.size(); v++ )
  84. {
  85. int nearestIdx = -1;
  86. float minDist = std::numeric_limits<float>::max();
  87. for( size_t c = 0; c < calcKeypoints.size(); c++ )
  88. {
  89. progress = update_progress( progress, (int)(v*calcKeypoints.size() + c), progressCount, 0 );
  90. float curDist = (float)cv::norm( calcKeypoints[c].pt - validKeypoints[v].pt );
  91. if( curDist < minDist )
  92. {
  93. minDist = curDist;
  94. nearestIdx = (int)c;
  95. }
  96. }
  97. assert( minDist >= 0 );
  98. if( !isSimilarKeypoints( validKeypoints[v], calcKeypoints[nearestIdx] ) )
  99. badPointCount++;
  100. }
  101. ts->printf( cvtest::TS::LOG, "badPointCount = %d; validPointCount = %d; calcPointCount = %d\n",
  102. badPointCount, validKeypoints.size(), calcKeypoints.size() );
  103. if( badPointCount > 0.9 * commonPointCount )
  104. {
  105. ts->printf( cvtest::TS::LOG, " - Bad accuracy!\n" );
  106. ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
  107. return;
  108. }
  109. ts->printf( cvtest::TS::LOG, " - OK\n" );
  110. }
  111. void CV_FeatureDetectorTest::regressionTest()
  112. {
  113. assert( !fdetector.empty() );
  114. string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME;
  115. string resFilename = string(ts->get_data_path()) + DETECTOR_DIR + "/" + string(name) + ".xml.gz";
  116. // Read the test image.
  117. Mat image = imread( imgFilename );
  118. if( image.empty() )
  119. {
  120. ts->printf( cvtest::TS::LOG, "Image %s can not be read.\n", imgFilename.c_str() );
  121. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
  122. return;
  123. }
  124. FileStorage fs( resFilename, FileStorage::READ );
  125. // Compute keypoints.
  126. vector<KeyPoint> calcKeypoints;
  127. fdetector->detect( image, calcKeypoints );
  128. if( fs.isOpened() ) // Compare computed and valid keypoints.
  129. {
  130. // TODO compare saved feature detector params with current ones
  131. // Read validation keypoints set.
  132. vector<KeyPoint> validKeypoints;
  133. read( fs["keypoints"], validKeypoints );
  134. if( validKeypoints.empty() )
  135. {
  136. ts->printf( cvtest::TS::LOG, "Keypoints can not be read.\n" );
  137. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
  138. return;
  139. }
  140. compareKeypointSets( validKeypoints, calcKeypoints );
  141. }
  142. else // Write detector parameters and computed keypoints as validation data.
  143. {
  144. fs.open( resFilename, FileStorage::WRITE );
  145. if( !fs.isOpened() )
  146. {
  147. ts->printf( cvtest::TS::LOG, "File %s can not be opened to write.\n", resFilename.c_str() );
  148. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
  149. return;
  150. }
  151. else
  152. {
  153. fs << "detector_params" << "{";
  154. fdetector->write( fs );
  155. fs << "}";
  156. write( fs, "keypoints", calcKeypoints );
  157. }
  158. }
  159. }
  160. void CV_FeatureDetectorTest::run( int /*start_from*/ )
  161. {
  162. if( !fdetector )
  163. {
  164. ts->printf( cvtest::TS::LOG, "Feature detector is empty.\n" );
  165. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
  166. return;
  167. }
  168. emptyDataTest();
  169. regressionTest();
  170. ts->set_failed_test_info( cvtest::TS::OK );
  171. }
  172. }} // namespace