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 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 22 // * Redistribution's in binary form must reproduce the above copyright notice, 23 // this list of conditions and the following disclaimer in the documentation 24 // and/or other materials provided with the distribution. 25 // 26 // * The name of Intel Corporation may not be used to endorse or promote products 27 // derived from this software without specific prior written permission. 28 // 29 // This software is provided by the copyright holders and contributors "as is" and 30 // any express or implied warranties, including, but not limited to, the implied 31 // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 // In no event shall the Intel Corporation or contributors be liable for any direct, 33 // indirect, incidental, special, exemplary, or consequential damages 34 // (including, but not limited to, procurement of substitute goods or services; 35 // loss of use, data, or profits; or business interruption) however caused 36 // and on any theory of liability, whether in contract, strict liability, 37 // or tort (including negligence or otherwise) arising in any way out of 38 // the use of this software, even if advised of the possibility of such damage. 39 // 40 //M*/ 41 42 #include "test_precomp.hpp" 43 #include "opencv2/highgui.hpp" 44 45 using namespace std; 46 using namespace cv; 47 48 const string FEATURES2D_DIR = "features2d"; 49 const string IMAGE_FILENAME = "tsukuba.png"; 50 const string DETECTOR_DIR = FEATURES2D_DIR + "/feature_detectors"; 51 52 /****************************************************************************************\ 53 * Regression tests for feature detectors comparing keypoints. * 54 \****************************************************************************************/ 55 56 class CV_FeatureDetectorTest : public cvtest::BaseTest 57 { 58 public: 59 CV_FeatureDetectorTest( const string& _name, const Ptr<FeatureDetector>& _fdetector ) : 60 name(_name), fdetector(_fdetector) {} 61 62 protected: 63 bool isSimilarKeypoints( const KeyPoint& p1, const KeyPoint& p2 ); 64 void compareKeypointSets( const vector<KeyPoint>& validKeypoints, const vector<KeyPoint>& calcKeypoints ); 65 66 void emptyDataTest(); 67 void regressionTest(); // TODO test of detect() with mask 68 69 virtual void run( int ); 70 71 string name; 72 Ptr<FeatureDetector> fdetector; 73 }; 74 75 void CV_FeatureDetectorTest::emptyDataTest() 76 { 77 // One image. 78 Mat image; 79 vector<KeyPoint> keypoints; 80 try 81 { 82 fdetector->detect( image, keypoints ); 83 } 84 catch(...) 85 { 86 ts->printf( cvtest::TS::LOG, "detect() on empty image must not generate exception (1).\n" ); 87 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 88 } 89 90 if( !keypoints.empty() ) 91 { 92 ts->printf( cvtest::TS::LOG, "detect() on empty image must return empty keypoints vector (1).\n" ); 93 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 94 return; 95 } 96 97 // Several images. 98 vector<Mat> images; 99 vector<vector<KeyPoint> > keypointCollection; 100 try 101 { 102 fdetector->detect( images, keypointCollection ); 103 } 104 catch(...) 105 { 106 ts->printf( cvtest::TS::LOG, "detect() on empty image vector must not generate exception (2).\n" ); 107 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 108 } 109 } 110 111 bool CV_FeatureDetectorTest::isSimilarKeypoints( const KeyPoint& p1, const KeyPoint& p2 ) 112 { 113 const float maxPtDif = 1.f; 114 const float maxSizeDif = 1.f; 115 const float maxAngleDif = 2.f; 116 const float maxResponseDif = 0.1f; 117 118 float dist = (float)norm( p1.pt - p2.pt ); 119 return (dist < maxPtDif && 120 fabs(p1.size - p2.size) < maxSizeDif && 121 abs(p1.angle - p2.angle) < maxAngleDif && 122 abs(p1.response - p2.response) < maxResponseDif && 123 p1.octave == p2.octave && 124 p1.class_id == p2.class_id ); 125 } 126 127 void CV_FeatureDetectorTest::compareKeypointSets( const vector<KeyPoint>& validKeypoints, const vector<KeyPoint>& calcKeypoints ) 128 { 129 const float maxCountRatioDif = 0.01f; 130 131 // Compare counts of validation and calculated keypoints. 132 float countRatio = (float)validKeypoints.size() / (float)calcKeypoints.size(); 133 if( countRatio < 1 - maxCountRatioDif || countRatio > 1.f + maxCountRatioDif ) 134 { 135 ts->printf( cvtest::TS::LOG, "Bad keypoints count ratio (validCount = %d, calcCount = %d).\n", 136 validKeypoints.size(), calcKeypoints.size() ); 137 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); 138 return; 139 } 140 141 int progress = 0, progressCount = (int)(validKeypoints.size() * calcKeypoints.size()); 142 int badPointCount = 0, commonPointCount = max((int)validKeypoints.size(), (int)calcKeypoints.size()); 143 for( size_t v = 0; v < validKeypoints.size(); v++ ) 144 { 145 int nearestIdx = -1; 146 float minDist = std::numeric_limits<float>::max(); 147 148 for( size_t c = 0; c < calcKeypoints.size(); c++ ) 149 { 150 progress = update_progress( progress, (int)(v*calcKeypoints.size() + c), progressCount, 0 ); 151 float curDist = (float)norm( calcKeypoints[c].pt - validKeypoints[v].pt ); 152 if( curDist < minDist ) 153 { 154 minDist = curDist; 155 nearestIdx = (int)c; 156 } 157 } 158 159 assert( minDist >= 0 ); 160 if( !isSimilarKeypoints( validKeypoints[v], calcKeypoints[nearestIdx] ) ) 161 badPointCount++; 162 } 163 ts->printf( cvtest::TS::LOG, "badPointCount = %d; validPointCount = %d; calcPointCount = %d\n", 164 badPointCount, validKeypoints.size(), calcKeypoints.size() ); 165 if( badPointCount > 0.9 * commonPointCount ) 166 { 167 ts->printf( cvtest::TS::LOG, " - Bad accuracy!\n" ); 168 ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); 169 return; 170 } 171 ts->printf( cvtest::TS::LOG, " - OK\n" ); 172 } 173 174 void CV_FeatureDetectorTest::regressionTest() 175 { 176 assert( !fdetector.empty() ); 177 string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME; 178 string resFilename = string(ts->get_data_path()) + DETECTOR_DIR + "/" + string(name) + ".xml.gz"; 179 180 // Read the test image. 181 Mat image = imread( imgFilename ); 182 if( image.empty() ) 183 { 184 ts->printf( cvtest::TS::LOG, "Image %s can not be read.\n", imgFilename.c_str() ); 185 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); 186 return; 187 } 188 189 FileStorage fs( resFilename, FileStorage::READ ); 190 191 // Compute keypoints. 192 vector<KeyPoint> calcKeypoints; 193 fdetector->detect( image, calcKeypoints ); 194 195 if( fs.isOpened() ) // Compare computed and valid keypoints. 196 { 197 // TODO compare saved feature detector params with current ones 198 199 // Read validation keypoints set. 200 vector<KeyPoint> validKeypoints; 201 read( fs["keypoints"], validKeypoints ); 202 if( validKeypoints.empty() ) 203 { 204 ts->printf( cvtest::TS::LOG, "Keypoints can not be read.\n" ); 205 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); 206 return; 207 } 208 209 compareKeypointSets( validKeypoints, calcKeypoints ); 210 } 211 else // Write detector parameters and computed keypoints as validation data. 212 { 213 fs.open( resFilename, FileStorage::WRITE ); 214 if( !fs.isOpened() ) 215 { 216 ts->printf( cvtest::TS::LOG, "File %s can not be opened to write.\n", resFilename.c_str() ); 217 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); 218 return; 219 } 220 else 221 { 222 fs << "detector_params" << "{"; 223 fdetector->write( fs ); 224 fs << "}"; 225 226 write( fs, "keypoints", calcKeypoints ); 227 } 228 } 229 } 230 231 void CV_FeatureDetectorTest::run( int /*start_from*/ ) 232 { 233 if( !fdetector ) 234 { 235 ts->printf( cvtest::TS::LOG, "Feature detector is empty.\n" ); 236 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); 237 return; 238 } 239 240 emptyDataTest(); 241 regressionTest(); 242 243 ts->set_failed_test_info( cvtest::TS::OK ); 244 } 245 246 /****************************************************************************************\ 247 * Tests registrations * 248 \****************************************************************************************/ 249 250 TEST( Features2d_Detector_BRISK, regression ) 251 { 252 CV_FeatureDetectorTest test( "detector-brisk", BRISK::create() ); 253 test.safe_run(); 254 } 255 256 TEST( Features2d_Detector_FAST, regression ) 257 { 258 CV_FeatureDetectorTest test( "detector-fast", FastFeatureDetector::create() ); 259 test.safe_run(); 260 } 261 262 TEST( Features2d_Detector_AGAST, regression ) 263 { 264 CV_FeatureDetectorTest test( "detector-agast", AgastFeatureDetector::create() ); 265 test.safe_run(); 266 } 267 268 TEST( Features2d_Detector_GFTT, regression ) 269 { 270 CV_FeatureDetectorTest test( "detector-gftt", GFTTDetector::create() ); 271 test.safe_run(); 272 } 273 274 TEST( Features2d_Detector_Harris, regression ) 275 { 276 Ptr<GFTTDetector> gftt = GFTTDetector::create(); 277 gftt->setHarrisDetector(true); 278 CV_FeatureDetectorTest test( "detector-harris", gftt); 279 test.safe_run(); 280 } 281 282 TEST( Features2d_Detector_MSER, DISABLED_regression ) 283 { 284 CV_FeatureDetectorTest test( "detector-mser", MSER::create() ); 285 test.safe_run(); 286 } 287 288 TEST( Features2d_Detector_ORB, regression ) 289 { 290 CV_FeatureDetectorTest test( "detector-orb", ORB::create() ); 291 test.safe_run(); 292 } 293 294 TEST( Features2d_Detector_KAZE, regression ) 295 { 296 CV_FeatureDetectorTest test( "detector-kaze", KAZE::create() ); 297 test.safe_run(); 298 } 299 300 TEST( Features2d_Detector_AKAZE, regression ) 301 { 302 CV_FeatureDetectorTest test( "detector-akaze", AKAZE::create() ); 303 test.safe_run(); 304 } 305