Update the changelog
[opencv] / apps / haartraining / src / performance.cpp
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 /*
43  * performance.cpp
44  *
45  * Measure performance of classifier
46  */
47 #include "cv.h"
48 #include <stdio.h>
49 #include <math.h>
50 #include <highgui.h>
51 #include <time.h>
52
53 #ifdef _WIN32
54 /* use clock() function insted of time() */
55 #define time( arg ) (((double) clock()) / CLOCKS_PER_SEC)
56 #endif /* _WIN32 */
57
58 #ifndef PATH_MAX
59 #define PATH_MAX 512
60 #endif /* PATH_MAX */
61
62 typedef struct HidCascade
63 {
64     int size;
65     int count;
66 } HidCascade;
67
68 typedef struct ObjectPos
69 {
70     float x;
71     float y;
72     float width;
73     int found;    /* for reference */
74     int neghbors;
75 } ObjectPos;
76
77 int main( int argc, char* argv[] )
78 {
79     int i, j;
80     char* classifierdir = NULL;
81     char* samplesdir    = NULL;
82     
83     int saveDetected = 1;
84     double scale_factor = 1.2;
85     float maxSizeDiff = 1.5F;
86     float maxPosDiff  = 0.3F;
87
88     /* number of stages. if <=0 all stages are used */
89     int nos = -1, nos0;
90
91     int width  = 24;
92     int height = 24;
93
94     int rocsize;
95     
96     FILE* info;
97     char* infoname;
98     char fullname[PATH_MAX];
99     char detfilename[PATH_MAX];
100     char* filename;
101     char detname[] = "det-";
102
103     CvHaarClassifierCascade* cascade;
104     CvMemStorage* storage;
105     CvSeq* objects;
106     
107     double totaltime;
108     
109     infoname = "";
110     rocsize = 40;
111     if( argc == 1 )
112     {
113         printf( "Usage: %s\n  -data <classifier_directory_name>\n"
114                 "  -info <collection_file_name>\n"
115                 "  [-maxSizeDiff <max_size_difference = %f>]\n"
116                 "  [-maxPosDiff <max_position_difference = %f>]\n"
117                 "  [-sf <scale_factor = %f>]\n"
118                 "  [-ni]\n"
119                 "  [-nos <number_of_stages = %d>]\n"
120                 "  [-rs <roc_size = %d>]\n"
121                 "  [-w <sample_width = %d>]\n"
122                 "  [-h <sample_height = %d>]\n",
123                 argv[0], maxSizeDiff, maxPosDiff, scale_factor, nos, rocsize,
124                 width, height );
125         
126         return 0;
127     }
128
129     for( i = 1; i < argc; i++ )
130     {
131         if( !strcmp( argv[i], "-data" ) )
132         {
133             classifierdir = argv[++i];
134         }
135         else if( !strcmp( argv[i], "-info" ) )
136         {
137             infoname = argv[++i];
138         }
139         else if( !strcmp( argv[i], "-maxSizeDiff" ) )
140         {
141             maxSizeDiff = (float) atof( argv[++i] );
142         }
143         else if( !strcmp( argv[i], "-maxPosDiff" ) )
144         {
145             maxPosDiff = (float) atof( argv[++i] );
146         }
147         else if( !strcmp( argv[i], "-sf" ) )
148         {
149             scale_factor = atof( argv[++i] );
150         }
151         else if( !strcmp( argv[i], "-ni" ) )
152         {
153             saveDetected = 0;
154         }
155         else if( !strcmp( argv[i], "-nos" ) )
156         {
157             nos = atoi( argv[++i] );
158         }
159         else if( !strcmp( argv[i], "-rs" ) )
160         {
161             rocsize = atoi( argv[++i] );
162         }
163         else if( !strcmp( argv[i], "-w" ) )
164         {
165             width = atoi( argv[++i] );
166         }
167         else if( !strcmp( argv[i], "-h" ) )
168         {
169             height = atoi( argv[++i] );
170         }
171     }
172
173     cascade = cvLoadHaarClassifierCascade( classifierdir, cvSize( width, height ) );
174     if( cascade == NULL )
175     {
176         printf( "Unable to load classifier from %s\n", classifierdir );
177
178         return 1;
179     }
180
181     int* numclassifiers = new int[cascade->count];
182     numclassifiers[0] = cascade->stage_classifier[0].count;
183     for( i = 1; i < cascade->count; i++ )
184     {
185         numclassifiers[i] = numclassifiers[i-1] + cascade->stage_classifier[i].count;
186     }
187
188     storage = cvCreateMemStorage();
189
190     nos0 = cascade->count;
191     if( nos <= 0 )
192         nos = nos0;
193
194     strcpy( fullname, infoname );
195     filename = strrchr( fullname, '\\' );
196     if( filename == NULL )
197     {
198         filename = strrchr( fullname, '/' );
199     }
200     if( filename == NULL )
201     {
202         filename = fullname;
203     }
204     else
205     {
206         filename++;
207     }
208
209     info = fopen( infoname, "r" );
210     totaltime = 0.0;
211     if( info != NULL )
212     {
213         int x, y, width, height;
214         IplImage* img;
215         int hits, missed, falseAlarms;
216         int totalHits, totalMissed, totalFalseAlarms;
217         int found;
218         float distance;
219         
220         int refcount;
221         ObjectPos* ref;
222         int detcount;
223         ObjectPos* det;
224         int error;
225
226         int* pos;
227         int* neg;
228
229         pos = (int*) cvAlloc( rocsize * sizeof( *pos ) );
230         neg = (int*) cvAlloc( rocsize * sizeof( *neg ) );
231         for( i = 0; i < rocsize; i++ ) { pos[i] = neg[i] = 0; }
232
233         printf( "+================================+======+======+======+\n" );
234         printf( "|            File Name           | Hits |Missed| False|\n" );
235         printf( "+================================+======+======+======+\n" );
236         
237         totalHits = totalMissed = totalFalseAlarms = 0;
238         while( !feof( info ) )
239         {
240             if( fscanf( info, "%s %d", filename, &refcount ) != 2 || refcount <= 0 ) break;
241
242             img = cvLoadImage( fullname );
243             if( !img ) continue;
244
245             ref = (ObjectPos*) cvAlloc( refcount * sizeof( *ref ) );
246             for( i = 0; i < refcount; i++ )
247             {
248                 error = (fscanf( info, "%d %d %d %d", &x, &y, &width, &height ) != 4);
249                 if( error ) break;
250                 ref[i].x = 0.5F * width  + x;
251                 ref[i].y = 0.5F * height + y;
252                 ref[i].width = sqrtf( 0.5F * (width * width + height * height) );
253                 ref[i].found = 0;
254                 ref[i].neghbors = 0;
255             }
256             if( !error )
257             {
258                 cvClearMemStorage( storage );
259
260                 cascade->count = nos;
261                 totaltime -= time( 0 );
262                 objects = cvHaarDetectObjects( img, cascade, storage, scale_factor, 1 );
263                 totaltime += time( 0 );
264                 cascade->count = nos0;
265                 
266                 detcount = ( objects ? objects->total : 0);                
267                 det = (detcount > 0) ?
268                     ( (ObjectPos*)cvAlloc( detcount * sizeof( *det )) ) : NULL;
269                 hits = missed = falseAlarms = 0;
270                 for( i = 0; i < detcount; i++ )
271                 {
272                     CvAvgComp r = *((CvAvgComp*) cvGetSeqElem( objects, i ));
273                     det[i].x = 0.5F * r.rect.width  + r.rect.x;
274                     det[i].y = 0.5F * r.rect.height + r.rect.y;
275                     det[i].width = sqrtf( 0.5F * (r.rect.width * r.rect.width +
276                                                   r.rect.height * r.rect.height) );
277                     det[i].neghbors = r.neighbors;
278
279                     if( saveDetected )
280                     {
281                         cvRectangle( img, cvPoint( r.rect.x, r.rect.y ),
282                             cvPoint( r.rect.x + r.rect.width, r.rect.y + r.rect.height ),
283                             CV_RGB( 255, 0, 0 ), 3 );
284                     }
285
286                     found = 0;
287                     for( j = 0; j < refcount; j++ )
288                     {
289                         distance = sqrtf( (det[i].x - ref[j].x) * (det[i].x - ref[j].x) + 
290                                           (det[i].y - ref[j].y) * (det[i].y - ref[j].y) );
291                         if( (distance < ref[j].width * maxPosDiff) &&
292                             (det[i].width > ref[j].width / maxSizeDiff) &&
293                             (det[i].width < ref[j].width * maxSizeDiff) )
294                         {
295                             ref[j].found = 1;
296                             ref[j].neghbors = MAX( ref[j].neghbors, det[i].neghbors );
297                             found = 1;
298                         }
299                     }
300                     if( !found )
301                     {
302                         falseAlarms++;
303                         neg[MIN(det[i].neghbors, rocsize - 1)]++;
304                     }
305                 }
306                 for( j = 0; j < refcount; j++ )
307                 {
308                     if( ref[j].found )
309                     {
310                         hits++;
311                         pos[MIN(ref[j].neghbors, rocsize - 1)]++;
312                     }
313                     else
314                     {
315                         missed++;
316                     }                            
317                 }
318
319                 totalHits += hits;
320                 totalMissed += missed;
321                 totalFalseAlarms += falseAlarms;
322                 printf( "|%32.32s|%6d|%6d|%6d|\n", filename, hits, missed, falseAlarms );
323                 printf( "+--------------------------------+------+------+------+\n" );
324                 fflush( stdout );
325
326                 if( saveDetected )
327                 {
328                     strcpy( detfilename, detname );
329                     strcat( detfilename, filename );
330                     strcpy( filename, detfilename );
331                     cvvSaveImage( fullname, img );
332                 }
333
334                 if( det ) { cvFree( &det ); det = NULL; }
335             } /* if( !error ) */
336             
337             cvReleaseImage( &img );
338             cvFree( &ref );
339         }
340         fclose( info );
341         
342         printf( "|%32.32s|%6d|%6d|%6d|\n", "Total",
343                 totalHits, totalMissed, totalFalseAlarms );
344         printf( "+================================+======+======+======+\n" );
345         printf( "Number of stages: %d\n", nos );
346         printf( "Number of weak classifiers: %d\n", numclassifiers[nos - 1] );
347         printf( "Total time: %f\n", totaltime );
348
349         /* print ROC to stdout */
350         for( i = rocsize - 1; i > 0; i-- )
351         {
352             pos[i-1] += pos[i];
353             neg[i-1] += neg[i];
354         }
355         fprintf( stderr, "%d\n", nos );
356         for( i = 0; i < rocsize; i++ )
357         {
358             fprintf( stderr, "\t%d\t%d\t%f\t%f\n", pos[i], neg[i],
359                 ((float)pos[i]) / (totalHits + totalMissed),
360                 ((float)neg[i]) / (totalHits + totalMissed) );
361         }
362
363         cvFree( &pos );
364         cvFree( &neg );
365     }
366
367     delete[] numclassifiers;
368
369     cvReleaseHaarClassifierCascade( &cascade );
370     cvReleaseMemStorage( &storage );
371
372     return 0;
373 }
374