1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
48 #define DIST_E "distE"
\r
50 #define NO_PAIR_E "noPairE"
\r
51 //#define TOTAL_NO_PAIR_E "totalNoPairE"
53 #define DETECTOR_NAMES "detector_names"
54 #define DETECTORS "detectors"
55 #define IMAGE_FILENAMES "image_filenames"
56 #define VALIDATION "validation"
59 #define C_SCALE_CASCADE "scale_cascade"
61 class CV_DetectorTest : public CvTest
64 CV_DetectorTest( const char* test_name );
65 virtual int init( CvTS* system );
\r
67 virtual int prepareData( FileStorage& fs );
\r
68 virtual void run( int startFrom );
\r
69 virtual string& getValidationFilename();
\r
71 virtual void readDetector( const FileNode& fn ) = 0;
\r
72 virtual void writeDetector( FileStorage& fs, int di ) = 0;
\r
73 int runTestCase( int detectorIdx, vector<vector<Rect> >& objects );
\r
74 virtual int detectMultiScale( int di, const Mat& img, vector<Rect>& objects ) = 0;
\r
75 int validate( int detectorIdx, vector<vector<Rect> >& objects );
\r
82 //float totalNoPair;
\r
84 vector<string> detectorNames;
\r
85 vector<string> detectorFilenames;
\r
86 vector<string> imageFilenames;
\r
88 string validationFilename;
\r
89 FileStorage validationFS;
\r
92 CV_DetectorTest::CV_DetectorTest( const char* test_name ) : CvTest( test_name, "detectMultiScale" )
96 int CV_DetectorTest::init(CvTS *system)
100 string dataPath = ts->get_data_path();
101 validationFS.open( dataPath + getValidationFilename(), FileStorage::READ );
102 return prepareData( validationFS );
105 string& CV_DetectorTest::getValidationFilename()
107 return validationFilename;
110 int CV_DetectorTest::prepareData( FileStorage& _fs )
112 if( !_fs.isOpened() )
\r
113 test_case_count = -1;
\r
116 FileNode fn = _fs.getFirstTopLevelNode();
\r
118 fn[DIST_E] >> eps.dist;
\r
120 fn[NO_PAIR_E] >> eps.noPair;
\r
121 // fn[TOTAL_NO_PAIR_E] >> eps.totalNoPair;
\r
124 if( fn[DETECTOR_NAMES].node->data.seq != 0 )
\r
126 FileNodeIterator it = fn[DETECTOR_NAMES].begin();
\r
127 for( ; it != fn[DETECTOR_NAMES].end(); )
\r
131 detectorNames.push_back(name);
\r
132 readDetector(fn[DETECTORS][name]);
\r
135 test_case_count = (int)detectorNames.size();
\r
137 // read images filenames and images
\r
138 string dataPath = ts->get_data_path();
\r
139 if( fn[IMAGE_FILENAMES].node->data.seq != 0 )
\r
141 for( FileNodeIterator it = fn[IMAGE_FILENAMES].begin(); it != fn[IMAGE_FILENAMES].end(); )
145 imageFilenames.push_back(filename);
146 Mat img = imread( dataPath+filename, 1 );
147 images.push_back( img );
154 void CV_DetectorTest::run( int start_from )
160 validationFS.release();
161 string filename = ts->get_data_path();
162 filename += getValidationFilename();
163 validationFS.open( filename, FileStorage::WRITE );
164 validationFS << FileStorage::getDefaultObjectName(validationFilename) << "{";
166 validationFS << DIST_E << eps.dist;
\r
167 validationFS << S_E << eps.s;
\r
168 validationFS << NO_PAIR_E << eps.noPair;
\r
169 // validationFS << TOTAL_NO_PAIR_E << eps.totalNoPair;
171 // write detector names
172 validationFS << DETECTOR_NAMES << "[";
173 vector<string>::const_iterator nit = detectorNames.begin();
174 for( ; nit != detectorNames.end(); ++nit )
176 validationFS << *nit;
178 validationFS << "]"; // DETECTOR_NAMES
181 validationFS << DETECTORS << "{";
182 assert( detectorNames.size() == detectorFilenames.size() );
183 nit = detectorNames.begin();
184 for( int di = 0; di < detectorNames.size(), nit != detectorNames.end(); ++nit, di++ )
186 validationFS << *nit << "{";
187 writeDetector( validationFS, di );
192 // write image filenames
193 validationFS << IMAGE_FILENAMES << "[";
194 vector<string>::const_iterator it = imageFilenames.begin();
195 for( int ii = 0; it != imageFilenames.end(); ++it, ii++ )
198 sprintf( buf, "%s%d", "img_", ii );
199 cvWriteComment( validationFS.fs, buf, 0 );
202 validationFS << "]"; // IMAGE_FILENAMES
204 validationFS << VALIDATION << "{";
207 for( int di = 0; di < test_case_count; di++ )
210 validationFS << detectorNames[di] << "{";
212 vector<vector<Rect> > objects;
213 int temp_code = runTestCase( di, objects );
215 if (temp_code == CvTS::OK)
216 temp_code = validate( di, objects );
218 if (temp_code != CvTS::OK)
221 validationFS << "}"; // detectorNames[di]
226 validationFS << "}"; // VALIDATION
227 validationFS << "}"; // getDefaultObjectName
229 if ( test_case_count <= 0 || imageFilenames.size() <= 0 )
231 ts->printf( CvTS::LOG, "validation file is not determined or not correct" );
232 code = CvTS::FAIL_INVALID_TEST_DATA;
\r
234 ts->set_failed_test_info( code );
237 int CV_DetectorTest::runTestCase( int detectorIdx, vector<vector<Rect> >& objects )
\r
239 string dataPath = ts->get_data_path(), detectorFilename;
\r
240 if( !detectorFilenames[detectorIdx].empty() )
\r
241 detectorFilename = dataPath + detectorFilenames[detectorIdx];
\r
243 for( int ii = 0; ii < (int)imageFilenames.size(); ++ii )
245 vector<Rect> imgObjects;
246 Mat image = images[ii];
\r
250 sprintf( msg, "%s %d %s", "image ", ii, " can not be read" );
251 ts->printf( CvTS::LOG, msg );
252 return CvTS::FAIL_INVALID_TEST_DATA;
254 int code = detectMultiScale( detectorIdx, image, imgObjects );
\r
255 if( code != CvTS::OK )
\r
258 objects.push_back( imgObjects );
\r
262 sprintf( buf, "%s%d", "img_", ii );
263 string imageIdxStr = buf;
264 validationFS << imageIdxStr << "[:";
265 for( vector<Rect>::const_iterator it = imgObjects.begin();
266 it != imgObjects.end(); ++it )
268 validationFS << it->x << it->y << it->width << it->height;
270 validationFS << "]"; // imageIdxStr
277 bool isZero( uchar i ) {return i == 0;}
\r
279 int CV_DetectorTest::validate( int detectorIdx, vector<vector<Rect> >& objects )
281 assert( imageFilenames.size() == objects.size() );
283 int totalNoPair = 0, totalValRectCount = 0;
285 for( vector<vector<Rect> >::const_iterator it = objects.begin();
286 it != objects.end(); ++it, imageIdx++ ) // for image
288 Size imgSize = images[imageIdx].size();
289 float dist = min(imgSize.height, imgSize.width) * eps.dist;
290 float wDiff = imgSize.width * eps.s;
291 float hDiff = imgSize.height * eps.s;
295 // read validation rectangles
\r
297 sprintf( buf, "%s%d", "img_", imageIdx );
298 string imageIdxStr = buf;
\r
299 FileNode node = validationFS.getFirstTopLevelNode()[VALIDATION][detectorNames[detectorIdx]][imageIdxStr];
300 vector<Rect> valRects;
\r
301 if( node.node->data.seq != 0 )
\r
303 for( FileNodeIterator it = node.begin(); it != node.end(); )
306 it >> r.x >> r.y >> r.width >> r.height;
307 valRects.push_back(r);
310 totalValRectCount += (int)valRects.size();
312 // compare rectangles
313 vector<uchar> map(valRects.size(), 0);
314 for( vector<Rect>::const_iterator cr = it->begin();
315 cr != it->end(); ++cr )
317 // find nearest rectangle
318 Point2f cp1 = Point2f( cr->x + (float)cr->width/2.0f, cr->y + (float)cr->height/2.0f );
319 int minIdx = -1, vi = 0;
320 float minDist = (float)norm( Point(imgSize.width, imgSize.height) );
321 for( vector<Rect>::const_iterator vr = valRects.begin();
322 vr != valRects.end(); ++vr, vi++ )
324 Point2f cp2 = Point2f( vr->x + (float)vr->width/2.0f, vr->y + (float)vr->height/2.0f );
325 float curDist = (float)norm(cp1-cp2);
326 if( curDist < minDist )
338 Rect vr = valRects[minIdx];
339 if( map[minIdx] != 0 || (minDist > dist) || (abs(cr->width - vr.width) > wDiff) ||
340 (abs(cr->height - vr.height) > hDiff) )
346 noPair += (int)count_if( map.begin(), map.end(), isZero );
347 totalNoPair += noPair;
348 if( noPair > valRects.size()*eps.noPair+1 )
351 if( imageIdx < (int)imageFilenames.size() )
354 sprintf( msg, "detector %s has overrated count of rectangles without pair on %s-image",
355 detectorNames[detectorIdx].c_str(), imageFilenames[imageIdx].c_str() );
356 ts->printf( CvTS::LOG, msg );
357 return CvTS::FAIL_BAD_ACCURACY;
359 if ( totalNoPair > totalValRectCount*eps./*total*/noPair+1 )
\r
361 ts->printf( CvTS::LOG, "overrated count of rectangles without pair on all images set" );
362 return CvTS::FAIL_BAD_ACCURACY;
\r
368 //----------------------------------------------- CascadeDetectorTest -----------------------------------
\r
369 class CV_CascadeDetectorTest : public CV_DetectorTest
\r
372 CV_CascadeDetectorTest( const char* test_name );
374 virtual void readDetector( const FileNode& fn );
\r
375 virtual void writeDetector( FileStorage& fs, int di );
\r
376 virtual int detectMultiScale( int di, const Mat& img, vector<Rect>& objects );
\r
380 CV_CascadeDetectorTest::CV_CascadeDetectorTest(const char *test_name)
\r
381 : CV_DetectorTest( test_name )
\r
383 validationFilename = "cascadeandhog/cascade.xml";
\r
386 void CV_CascadeDetectorTest::readDetector( const FileNode& fn )
\r
390 fn[FILENAME] >> filename;
\r
391 detectorFilenames.push_back(filename);
\r
392 fn[C_SCALE_CASCADE] >> flag;
\r
394 flags.push_back( 0 );
\r
396 flags.push_back( CV_HAAR_SCALE_IMAGE );
\r
399 void CV_CascadeDetectorTest::writeDetector( FileStorage& fs, int di )
\r
401 int sc = flags[di] & CV_HAAR_SCALE_IMAGE ? 0 : 1;
402 fs << FILENAME << detectorFilenames[di];
403 fs << C_SCALE_CASCADE << sc;
406 int CV_CascadeDetectorTest::detectMultiScale( int di, const Mat& img,
\r
407 vector<Rect>& objects)
\r
409 string dataPath = ts->get_data_path(), filename;
\r
410 filename = dataPath + detectorFilenames[di];
\r
411 CascadeClassifier cascade( filename );
\r
412 if( cascade.empty() )
\r
414 ts->printf( CvTS::LOG, "cascade %s can not be opened");
\r
415 return CvTS::FAIL_INVALID_TEST_DATA;
\r
418 cvtColor( img, grayImg, CV_BGR2GRAY );
419 equalizeHist( grayImg, grayImg );
\r
420 cascade.detectMultiScale( grayImg, objects, 1.1, 3, flags[di] );
\r
424 //----------------------------------------------- HOGDetectorTest -----------------------------------
\r
425 class CV_HOGDetectorTest : public CV_DetectorTest
\r
428 CV_HOGDetectorTest( const char* test_name );
430 virtual void readDetector( const FileNode& fn );
\r
431 virtual void writeDetector( FileStorage& fs, int di );
\r
432 virtual int detectMultiScale( int di, const Mat& img, vector<Rect>& objects );
\r
435 CV_HOGDetectorTest::CV_HOGDetectorTest(const char *test_name)
\r
436 : CV_DetectorTest( test_name )
\r
438 validationFilename = "cascadeandhog/hog.xml";
\r
441 void CV_HOGDetectorTest::readDetector( const FileNode& fn )
\r
444 if( fn[FILENAME].node->data.seq != 0 )
\r
445 fn[FILENAME] >> filename;
\r
446 detectorFilenames.push_back( filename);
\r
449 void CV_HOGDetectorTest::writeDetector( FileStorage& fs, int di )
\r
451 fs << FILENAME << detectorFilenames[di];
454 int CV_HOGDetectorTest::detectMultiScale( int di, const Mat& img,
\r
455 vector<Rect>& objects)
\r
458 if( detectorFilenames[di].empty() )
459 hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
462 hog.detectMultiScale(img, objects);
\r
466 CV_CascadeDetectorTest cascadeTest("cascade-detector");
\r
467 CV_HOGDetectorTest hogTest("hog-detector");
\r