From 8ab3fdbcca2a11bb8ab9766e231eb8d1828148fa Mon Sep 17 00:00:00 2001 From: Maria Dimashova Date: Fri, 17 Sep 2010 11:26:58 +0000 Subject: [PATCH] merged regression tests for FeatureDetector, DescriptorExtractor from branch .features2d; renamed createDetector to createFeatureDetector --- .../include/opencv2/features2d/features2d.hpp | 2 +- modules/features2d/src/detectors.cpp | 2 +- samples/cpp/build3dmodel.cpp | 2 +- samples/cpp/descriptor_extractor_matcher.cpp | 2 +- tests/cv/src/adetectordescriptor_evaluation.cpp | 4 +- tests/cv/src/afeatures2d.cpp | 334 +++++++++++++++++++++ 6 files changed, 340 insertions(+), 6 deletions(-) create mode 100644 tests/cv/src/afeatures2d.cpp diff --git a/modules/features2d/include/opencv2/features2d/features2d.hpp b/modules/features2d/include/opencv2/features2d/features2d.hpp index ad7ed21..7046377 100644 --- a/modules/features2d/include/opencv2/features2d/features2d.hpp +++ b/modules/features2d/include/opencv2/features2d/features2d.hpp @@ -1354,7 +1354,7 @@ protected: SURF surf; }; -CV_EXPORTS Ptr createDetector( const string& detectorType ); +CV_EXPORTS Ptr createFeatureDetector( const string& detectorType ); /* * Adapts a detector to partition the source image into a grid and detect diff --git a/modules/features2d/src/detectors.cpp b/modules/features2d/src/detectors.cpp index 7607252..a750ffa 100644 --- a/modules/features2d/src/detectors.cpp +++ b/modules/features2d/src/detectors.cpp @@ -316,7 +316,7 @@ void SurfFeatureDetector::detectImpl( const Mat& image, const Mat& mask, surf(image, mask, keypoints); } -Ptr createDetector( const string& detectorType ) +Ptr createFeatureDetector( const string& detectorType ) { FeatureDetector* fd = 0; if( !detectorType.compare( "FAST" ) ) diff --git a/samples/cpp/build3dmodel.cpp b/samples/cpp/build3dmodel.cpp index 4310511..b910e2b 100644 --- a/samples/cpp/build3dmodel.cpp +++ b/samples/cpp/build3dmodel.cpp @@ -651,7 +651,7 @@ int main(int argc, char** argv) Size calibratedImageSize; readCameraMatrix(intrinsicsFilename, cameraMatrix, distCoeffs, calibratedImageSize); - Ptr detector = createDetector(detectorName); + Ptr detector = createFeatureDetector(detectorName); Ptr descriptorExtractor = createDescriptorExtractor(descriptorExtractorName); string modelIndexFilename = format("%s_segm/frame_index.yml", modelName); diff --git a/samples/cpp/descriptor_extractor_matcher.cpp b/samples/cpp/descriptor_extractor_matcher.cpp index 154e9a8..ac7b2c2 100644 --- a/samples/cpp/descriptor_extractor_matcher.cpp +++ b/samples/cpp/descriptor_extractor_matcher.cpp @@ -143,7 +143,7 @@ int main(int argc, char** argv) ransacReprojThreshold = atof(argv[5]); cout << "< Creating detector, descriptor extractor and descriptor matcher ..." << endl; - Ptr detector = createDetector( argv[1] ); + Ptr detector = createFeatureDetector( argv[1] ); Ptr descriptorExtractor = createDescriptorExtractor( argv[2] ); Ptr descriptorMatcher = createDescriptorMatcher( "BruteForce" ); cout << ">" << endl; diff --git a/tests/cv/src/adetectordescriptor_evaluation.cpp b/tests/cv/src/adetectordescriptor_evaluation.cpp index c7259ee..89aaa3e 100644 --- a/tests/cv/src/adetectordescriptor_evaluation.cpp +++ b/tests/cv/src/adetectordescriptor_evaluation.cpp @@ -686,8 +686,8 @@ inline void readKeypoints( FileStorage& fs, vector& keypoints, int img void DetectorQualityTest::readAlgorithm () { - defaultDetector = createDetector( algName ); - specificDetector = createDetector( algName ); + defaultDetector = createFeatureDetector( algName ); + specificDetector = createFeatureDetector( algName ); if( defaultDetector == 0 ) { ts->printf(CvTS::LOG, "Algorithm can not be read\n"); diff --git a/tests/cv/src/afeatures2d.cpp b/tests/cv/src/afeatures2d.cpp new file mode 100644 index 0000000..b82b224 --- /dev/null +++ b/tests/cv/src/afeatures2d.cpp @@ -0,0 +1,334 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ +#include "cvtest.h" +#include "opencv2/core/core.hpp" + +using namespace std; +using namespace cv; + +const string FEATURES2D_DIR = "features2d"; +const string DETECTOR_DIR = FEATURES2D_DIR + "/feature_detectors"; +const string DESCRIPTOR_DIR = FEATURES2D_DIR + "/descriptor_extractors"; +const string IMAGE_FILENAME = "tsukuba.png"; + +/****************************************************************************************\ +* Regression tests for feature detectors comparing keypoints. * +\****************************************************************************************/ + +class CV_FeatureDetectorTest : public CvTest +{ +public: + CV_FeatureDetectorTest( const char* testName, const Ptr& _fdetector ) : + CvTest( testName, "cv::FeatureDetector::detect"), fdetector(_fdetector) {} + +protected: + virtual void run( int start_from ) + { + const float maxPtDif = 1.f; + const float maxSizeDif = 1.f; + const float maxAngleDif = 2.f; + const float maxResponseDif = 0.1f; + + string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME; + string resFilename = string(ts->get_data_path()) + DETECTOR_DIR + "/" + string(name) + "_res.xml.gz"; + + if( fdetector.empty() ) + { + ts->printf( CvTS::LOG, "Feature detector is empty" ); + ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat image = imread( imgFilename, 0 ); + if( image.empty() ) + { + ts->printf( CvTS::LOG, "image %s can not be read \n", imgFilename.c_str() ); + ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + return; + } + + FileStorage fs( resFilename, FileStorage::READ ); + + vector calcKeypoints; + fdetector->detect( image, calcKeypoints ); + + if( fs.isOpened() ) // compare computed and valid keypoints + { + // TODO compare saved feature detector params with current ones + vector validKeypoints; + read( fs["keypoints"], validKeypoints ); + if( validKeypoints.empty() ) + { + ts->printf( CvTS::LOG, "Keypoints can nod be read\n" ); + ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + return; + } + + int progress = 0, progressCount = validKeypoints.size() * calcKeypoints.size(); + int badPointCount = 0, commonPointCount = max(validKeypoints.size(), calcKeypoints.size()); + for( size_t v = 0; v < validKeypoints.size(); v++ ) + { + int nearestIdx = -1; + float minDist = std::numeric_limits::max(); + + for( size_t c = 0; c < calcKeypoints.size(); c++ ) + { + progress = update_progress( progress, v*calcKeypoints.size() + c, progressCount, 0 ); + float curDist = norm( calcKeypoints[c].pt - validKeypoints[v].pt ); + if( curDist < minDist ) + { + minDist = curDist; + nearestIdx = c; + } + } + + if( minDist > maxPtDif || + fabs(calcKeypoints[nearestIdx].size - validKeypoints[v].size) > maxSizeDif || + abs(calcKeypoints[nearestIdx].angle - validKeypoints[v].angle) > maxAngleDif || + abs(calcKeypoints[nearestIdx].response - validKeypoints[v].response) > maxResponseDif || + calcKeypoints[nearestIdx].octave != validKeypoints[v].octave + + // TODO !!!!!!! + /*|| + calcKeypoints[nearestIdx].class_id != validKeypoints[v].class_id*/ ) + { + badPointCount++; + } + } + ts->printf( CvTS::LOG, "badPointCount = %d; validPointCount = %d; calcPointCount = %d\n", + badPointCount, validKeypoints.size(), calcKeypoints.size() ); + if( badPointCount > 0.9 * commonPointCount ) + { + ts->printf( CvTS::LOG, "Bad accuracy!\n" ); + ts->set_failed_test_info( CvTS::FAIL_BAD_ACCURACY ); + return; + } + } + else // write + { + fs.open( resFilename, FileStorage::WRITE ); + if( !fs.isOpened() ) + { + ts->printf( CvTS::LOG, "file %s can not be opened to write\n", resFilename.c_str() ); + ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + return; + } + else + { + fs << "detector_params" << "{"; + fdetector->write( fs ); + fs << "}"; + + write( fs, "keypoints", calcKeypoints ); + } + } + ts->set_failed_test_info( CvTS::OK ); + } + + Ptr fdetector; +}; + +CV_FeatureDetectorTest fastTest( "detector_fast", createFeatureDetector("FAST") ); +CV_FeatureDetectorTest gfttTest( "detector_gftt", createFeatureDetector("GFTT") ); +CV_FeatureDetectorTest harrisTest( "detector_harris", createFeatureDetector("HARRIS") ); +CV_FeatureDetectorTest mserTest( "detector_mser", createFeatureDetector("MSER") ); +CV_FeatureDetectorTest siftTest( "detector_sift", createFeatureDetector("SIFT") ); +CV_FeatureDetectorTest starTest( "detector_star", createFeatureDetector("STAR") ); +CV_FeatureDetectorTest surfTest( "detector_surf", createFeatureDetector("SURF") ); + +/****************************************************************************************\ +* Regression tests for descriptor extractors. * +\****************************************************************************************/ +static void writeMatInBin( const Mat& mat, const string& filename ) +{ + FILE* f = fopen( filename.c_str(), "wb"); + if( f ) + { + int type = mat.type(); + fwrite( (void*)&mat.rows, sizeof(int), 1, f ); + fwrite( (void*)&mat.cols, sizeof(int), 1, f ); + fwrite( (void*)&type, sizeof(int), 1, f ); + fwrite( (void*)&mat.step, sizeof(int), 1, f ); + fwrite( (void*)mat.data, 1, mat.step*mat.rows, f ); + fclose(f); + } +} + +static Mat readMatFromBin( const string& filename ) +{ + FILE* f = fopen( filename.c_str(), "rb" ); + if( f ) + { + int rows, cols, type, step; + fread( (void*)&rows, sizeof(int), 1, f ); + fread( (void*)&cols, sizeof(int), 1, f ); + fread( (void*)&type, sizeof(int), 1, f ); + fread( (void*)&step, sizeof(int), 1, f ); + + uchar* data = (uchar*)cvAlloc(step*rows); + fread( (void*)data, 1, step*rows, f ); + fclose(f); + + return Mat( rows, cols, type, data ); + } + return Mat(); +} + +class CV_DescriptorExtractorTest : public CvTest +{ +public: + CV_DescriptorExtractorTest( const char* testName, float _normDif, const Ptr& _dextractor, float _prevTime ) : + CvTest( testName, "cv::DescriptorExtractor::compute" ), normDif(_normDif), prevTime(_prevTime), dextractor(_dextractor) {} +protected: + virtual void createDescriptorExtractor() {} + + void run(int) + { + createDescriptorExtractor(); + + if( dextractor.empty() ) + { + ts->printf(CvTS::LOG, "Descriptor extractor is empty\n"); + ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + return; + } + + string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME; + Mat img = imread( imgFilename, 0 ); + if( img.empty() ) + { + ts->printf( CvTS::LOG, "image %s can not be read\n", imgFilename.c_str() ); + ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + return; + } + + vector keypoints; + FileStorage fs( string(ts->get_data_path()) + FEATURES2D_DIR + "/keypoints.xml.gz", FileStorage::READ ); + if( fs.isOpened() ) + read( fs.getFirstTopLevelNode(), keypoints ); + else + { + ts->printf( CvTS::LOG, "Compute and write keypoints\n" ); + fs.open( string(ts->get_data_path()) + FEATURES2D_DIR + "/keypoints.xml.gz", FileStorage::WRITE ); + if( fs.isOpened() ) + { + SurfFeatureDetector fd; + fd.detect(img, keypoints); + write( fs, "keypoints", keypoints ); + } + else + { + ts->printf(CvTS::LOG, "File for writting keypoints can not be opened\n"); + ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + return; + } + } + + Mat calcDescriptors; + double t = (double)getTickCount(); + dextractor->compute( img, keypoints, calcDescriptors ); + t = getTickCount() - t; + ts->printf(CvTS::LOG, "\nAverage time of computiting one descriptor = %g ms (previous time = %g ms)\n", t/((double)cvGetTickFrequency()*1000.)/calcDescriptors.rows, prevTime ); + + // TODO read and write descriptor extractor parameters and check them + Mat validDescriptors = readDescriptors(); + if( !validDescriptors.empty() ) + { + double normVal = norm( calcDescriptors, validDescriptors, NORM_INF ); + ts->printf( CvTS::LOG, "nofm (inf) BTW valid and calculated float descriptors = %f\n", normVal ); + if( normVal > normDif ) + ts->set_failed_test_info( CvTS::FAIL_BAD_ACCURACY ); + } + else + { + if( !writeDescriptors( calcDescriptors ) ) + { + ts->printf( CvTS::LOG, "Descriptors can not be written\n" ); + ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); + return; + } + } + } + + virtual Mat readDescriptors() + { + Mat res = readMatFromBin( string(ts->get_data_path()) + DESCRIPTOR_DIR + "/" + string(name) ); + return res; + } + + virtual bool writeDescriptors( Mat& descs ) + { + writeMatInBin( descs, string(ts->get_data_path()) + DESCRIPTOR_DIR + "/" + string(name) ); + return true; + } + + const float normDif; + const float prevTime; + + Ptr dextractor; +}; + +template +class CV_CalonderDescriptorExtractorTest : public CV_DescriptorExtractorTest +{ +public: + CV_CalonderDescriptorExtractorTest( const char* testName, float _normDif, float _prevTime ) : + CV_DescriptorExtractorTest( testName, _normDif, Ptr(), _prevTime ) + {} + + virtual void createDescriptorExtractor() + { + dextractor = new CalonderDescriptorExtractor( string(ts->get_data_path()) + FEATURES2D_DIR + "/calonder_classifier.rtc"); + } +}; + +CV_DescriptorExtractorTest siftDescriptorTest( "descriptor_sift", std::numeric_limits::epsilon(), + createDescriptorExtractor("SIFT"), 8.06652f ); +CV_DescriptorExtractorTest surfDescriptorTest( "descriptor_surf", std::numeric_limits::epsilon(), + createDescriptorExtractor("SURF"), 0.147372f ); +#if CV_SSE2 +CV_CalonderDescriptorExtractorTest ucharCalonderTest( "descriptor_calonder_uchar", + std::numeric_limits::epsilon() + 1, + 0.0132175f ); +CV_CalonderDescriptorExtractorTest floatCalonderTest( "descriptor_calonder_float", + std::numeric_limits::epsilon(), + 0.0221308f ); +#endif // CV_SSE2 -- 2.7.4