Update to 2.0.0 tree from current Fremantle build
[opencv] / apps / haartraining / cvhaartraining.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  * cvhaartraining.cpp
44  *
45  * training of cascade of boosted classifiers based on haar features
46  */
47
48 #include "cvhaartraining.h"
49 #include "_cvhaartraining.h"
50
51 #include <cstdio>
52 #include <cstdlib>
53 #include <cmath>
54 #include <climits>
55
56 #include <highgui.h>
57
58 #ifdef CV_VERBOSE
59 #include <ctime>
60
61 #ifdef _WIN32
62 /* use clock() function insted of time() */
63 #define TIME( arg ) (((double) clock()) / CLOCKS_PER_SEC)
64 #else
65 #define TIME( arg ) (time( arg ))
66 #endif /* _WIN32 */
67
68 #endif /* CV_VERBOSE */
69
70 #if defined CV_OPENMP && (defined _MSC_VER || defined CV_ICC)
71 #define CV_OPENMP 1
72 #else
73 #undef CV_OPENMP
74 #endif
75
76 typedef struct CvBackgroundData
77 {
78     int    count;
79     char** filename;
80     int    last;
81     int    round;
82     CvSize winsize;
83 } CvBackgroundData;
84
85 typedef struct CvBackgroundReader
86 {
87     CvMat   src;
88     CvMat   img;
89     CvPoint offset;
90     float   scale;
91     float   scalefactor;
92     float   stepfactor;
93     CvPoint point;
94 } CvBackgroundReader;
95
96 /*
97  * Background reader
98  * Created in each thread
99  */
100 CvBackgroundReader* cvbgreader = NULL;
101
102 #if defined CV_OPENMP
103 #pragma omp threadprivate(cvbgreader)
104 #endif
105
106 CvBackgroundData* cvbgdata = NULL;
107
108
109 /*
110  * get sum image offsets for <rect> corner points 
111  * step - row step (measured in image pixels!) of sum image
112  */
113 #define CV_SUM_OFFSETS( p0, p1, p2, p3, rect, step )                      \
114     /* (x, y) */                                                          \
115     (p0) = (rect).x + (step) * (rect).y;                                  \
116     /* (x + w, y) */                                                      \
117     (p1) = (rect).x + (rect).width + (step) * (rect).y;                   \
118     /* (x + w, y) */                                                      \
119     (p2) = (rect).x + (step) * ((rect).y + (rect).height);                \
120     /* (x + w, y + h) */                                                  \
121     (p3) = (rect).x + (rect).width + (step) * ((rect).y + (rect).height);
122
123 /*
124  * get tilted image offsets for <rect> corner points 
125  * step - row step (measured in image pixels!) of tilted image
126  */
127 #define CV_TILTED_OFFSETS( p0, p1, p2, p3, rect, step )                   \
128     /* (x, y) */                                                          \
129     (p0) = (rect).x + (step) * (rect).y;                                  \
130     /* (x - h, y + h) */                                                  \
131     (p1) = (rect).x - (rect).height + (step) * ((rect).y + (rect).height);\
132     /* (x + w, y + w) */                                                  \
133     (p2) = (rect).x + (rect).width + (step) * ((rect).y + (rect).width);  \
134     /* (x + w - h, y + w + h) */                                          \
135     (p3) = (rect).x + (rect).width - (rect).height                        \
136            + (step) * ((rect).y + (rect).width + (rect).height);
137
138
139 /*
140  * icvCreateIntHaarFeatures
141  *
142  * Create internal representation of haar features
143  *
144  * mode:
145  *  0 - BASIC = Viola
146  *  1 - CORE  = All upright
147  *  2 - ALL   = All features
148  */
149 static
150 CvIntHaarFeatures* icvCreateIntHaarFeatures( CvSize winsize,
151                                              int mode,
152                                              int symmetric )
153 {
154     CvIntHaarFeatures* features = NULL;
155     CvTHaarFeature haarFeature;
156     
157     CvMemStorage* storage = NULL;
158     CvSeq* seq = NULL;
159     CvSeqWriter writer;
160
161     int s0 = 36; /* minimum total area size of basic haar feature     */
162     int s1 = 12; /* minimum total area size of tilted haar features 2 */
163     int s2 = 18; /* minimum total area size of tilted haar features 3 */
164     int s3 = 24; /* minimum total area size of tilted haar features 4 */
165
166     int x  = 0;
167     int y  = 0;
168     int dx = 0;
169     int dy = 0;
170
171     float factor = 1.0F;
172
173     factor = ((float) winsize.width) * winsize.height / (24 * 24);
174 #if 0    
175     s0 = (int) (s0 * factor);
176     s1 = (int) (s1 * factor);
177     s2 = (int) (s2 * factor);
178     s3 = (int) (s3 * factor);
179 #else
180     s0 = 1;
181     s1 = 1;
182     s2 = 1;
183     s3 = 1;
184 #endif
185
186     /* CV_VECTOR_CREATE( vec, CvIntHaarFeature, size, maxsize ) */
187     storage = cvCreateMemStorage();
188     cvStartWriteSeq( 0, sizeof( CvSeq ), sizeof( haarFeature ), storage, &writer );
189
190     for( x = 0; x < winsize.width; x++ )
191     {
192         for( y = 0; y < winsize.height; y++ )
193         {
194             for( dx = 1; dx <= winsize.width; dx++ )
195             {
196                 for( dy = 1; dy <= winsize.height; dy++ )
197                 {
198                     // haar_x2
199                     if ( (x+dx*2 <= winsize.width) && (y+dy <= winsize.height) ) {
200                         if (dx*2*dy < s0) continue;
201                         if (!symmetric || (x+x+dx*2 <=winsize.width)) {
202                             haarFeature = cvHaarFeature( "haar_x2",
203                                 x,    y, dx*2, dy, -1,
204                                 x+dx, y, dx  , dy, +2 );
205                             /* CV_VECTOR_PUSH( vec, CvIntHaarFeature, haarFeature, size, maxsize, step ) */
206                             CV_WRITE_SEQ_ELEM( haarFeature, writer );
207                         }
208                     }
209
210                         // haar_y2
211                     if ( (x+dx*2 <= winsize.height) && (y+dy <= winsize.width) ) {
212                         if (dx*2*dy < s0) continue;
213                         if (!symmetric || (y+y+dy <= winsize.width)) {
214                             haarFeature = cvHaarFeature( "haar_y2",
215                                 y, x,    dy, dx*2, -1,
216                                 y, x+dx, dy, dx,   +2 );
217                             CV_WRITE_SEQ_ELEM( haarFeature, writer );
218                         }
219                     }
220
221                     // haar_x3
222                     if ( (x+dx*3 <= winsize.width) && (y+dy <= winsize.height) ) {
223                         if (dx*3*dy < s0) continue;
224                         if (!symmetric || (x+x+dx*3 <=winsize.width)) {
225                             haarFeature = cvHaarFeature( "haar_x3",
226                                 x,    y, dx*3, dy, -1,
227                                 x+dx, y, dx,   dy, +3 );
228                             CV_WRITE_SEQ_ELEM( haarFeature, writer );
229                         }
230                     }
231
232                     // haar_y3
233                     if ( (x+dx*3 <= winsize.height) && (y+dy <= winsize.width) ) {
234                         if (dx*3*dy < s0) continue;
235                         if (!symmetric || (y+y+dy <= winsize.width)) {
236                             haarFeature = cvHaarFeature( "haar_y3",
237                                 y, x,    dy, dx*3, -1,
238                                 y, x+dx, dy, dx,   +3 );
239                             CV_WRITE_SEQ_ELEM( haarFeature, writer );
240                         }
241                     }
242
243                     if( mode != 0 /*BASIC*/ ) {
244                         // haar_x4
245                         if ( (x+dx*4 <= winsize.width) && (y+dy <= winsize.height) ) {
246                             if (dx*4*dy < s0) continue;
247                             if (!symmetric || (x+x+dx*4 <=winsize.width)) {
248                                 haarFeature = cvHaarFeature( "haar_x4",
249                                     x,    y, dx*4, dy, -1,
250                                     x+dx, y, dx*2, dy, +2 );
251                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
252                             }
253                         }
254                             
255                         // haar_y4
256                         if ( (x+dx*4 <= winsize.height) && (y+dy <= winsize.width ) ) {
257                             if (dx*4*dy < s0) continue;
258                             if (!symmetric || (y+y+dy   <=winsize.width)) {
259                                 haarFeature = cvHaarFeature( "haar_y4",
260                                     y, x,    dy, dx*4, -1,
261                                     y, x+dx, dy, dx*2, +2 );
262                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
263                             }
264                         }
265                     }
266
267                     // x2_y2
268                     if ( (x+dx*2 <= winsize.width) && (y+dy*2 <= winsize.height) ) {
269                         if (dx*4*dy < s0) continue;
270                         if (!symmetric || (x+x+dx*2 <=winsize.width)) {
271                             haarFeature = cvHaarFeature( "haar_x2_y2",
272                                 x   , y,    dx*2, dy*2, -1,
273                                 x   , y   , dx  , dy,   +2,
274                                 x+dx, y+dy, dx  , dy,   +2 );
275                             CV_WRITE_SEQ_ELEM( haarFeature, writer );
276                         }
277                     }
278
279                     if (mode != 0 /*BASIC*/) {                
280                         // point
281                         if ( (x+dx*3 <= winsize.width) && (y+dy*3 <= winsize.height) ) {
282                             if (dx*9*dy < s0) continue;
283                             if (!symmetric || (x+x+dx*3 <=winsize.width))  {
284                                 haarFeature = cvHaarFeature( "haar_point",
285                                     x   , y,    dx*3, dy*3, -1,
286                                     x+dx, y+dy, dx  , dy  , +9);
287                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
288                             }
289                         }
290                     }
291                     
292                     if (mode == 2 /*ALL*/) {                
293                         // tilted haar_x2                                      (x, y, w, h, b, weight)
294                         if ( (x+2*dx <= winsize.width) && (y+2*dx+dy <= winsize.height) && (x-dy>= 0) ) {
295                             if (dx*2*dy < s1) continue;
296                             
297                             if (!symmetric || (x <= (winsize.width / 2) )) {
298                                 haarFeature = cvHaarFeature( "tilted_haar_x2",
299                                     x, y, dx*2, dy, -1,
300                                     x, y, dx  , dy, +2 );
301                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
302                             }
303                         }
304                         
305                         // tilted haar_y2                                      (x, y, w, h, b, weight)
306                         if ( (x+dx <= winsize.width) && (y+dx+2*dy <= winsize.height) && (x-2*dy>= 0) ) {
307                             if (dx*2*dy < s1) continue;
308                             
309                             if (!symmetric || (x <= (winsize.width / 2) )) {
310                                 haarFeature = cvHaarFeature( "tilted_haar_y2",
311                                     x, y, dx, 2*dy, -1,
312                                     x, y, dx,   dy, +2 );
313                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
314                             }
315                         }
316                         
317                         // tilted haar_x3                                   (x, y, w, h, b, weight)
318                         if ( (x+3*dx <= winsize.width) && (y+3*dx+dy <= winsize.height) && (x-dy>= 0) ) {
319                             if (dx*3*dy < s2) continue;
320                             
321                             if (!symmetric || (x <= (winsize.width / 2) )) {
322                                 haarFeature = cvHaarFeature( "tilted_haar_x3",
323                                     x,    y,    dx*3, dy, -1,
324                                     x+dx, y+dx, dx  , dy, +3 );
325                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
326                             }
327                         }
328                         
329                         // tilted haar_y3                                      (x, y, w, h, b, weight)
330                         if ( (x+dx <= winsize.width) && (y+dx+3*dy <= winsize.height) && (x-3*dy>= 0) ) {
331                             if (dx*3*dy < s2) continue;
332                             
333                             if (!symmetric || (x <= (winsize.width / 2) )) {
334                                 haarFeature = cvHaarFeature( "tilted_haar_y3",
335                                     x,    y,    dx, 3*dy, -1,
336                                     x-dy, y+dy, dx,   dy, +3 );
337                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
338                             }
339                         }
340                         
341                         
342                         // tilted haar_x4                                   (x, y, w, h, b, weight)
343                         if ( (x+4*dx <= winsize.width) && (y+4*dx+dy <= winsize.height) && (x-dy>= 0) ) {
344                             if (dx*4*dy < s3) continue;
345                             
346                             if (!symmetric || (x <= (winsize.width / 2) )) {
347                                 haarFeature = cvHaarFeature( "tilted_haar_x4",
348
349
350                                     x,    y,    dx*4, dy, -1,
351                                     x+dx, y+dx, dx*2, dy, +2 );
352                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
353                             }
354                         }
355                         
356                         // tilted haar_y4                                      (x, y, w, h, b, weight)
357                         if ( (x+dx <= winsize.width) && (y+dx+4*dy <= winsize.height) && (x-4*dy>= 0) ) {
358                             if (dx*4*dy < s3) continue;
359                             
360                             if (!symmetric || (x <= (winsize.width / 2) )) {
361                                 haarFeature = cvHaarFeature( "tilted_haar_y4",
362                                     x,    y,    dx, 4*dy, -1,
363                                     x-dy, y+dy, dx, 2*dy, +2 );
364                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
365                             }
366                         }
367                         
368
369                         /*
370                         
371                           // tilted point
372                           if ( (x+dx*3 <= winsize.width - 1) && (y+dy*3 <= winsize.height - 1) && (x-3*dy>= 0)) {
373                           if (dx*9*dy < 36) continue;
374                           if (!symmetric || (x <= (winsize.width / 2) ))  {
375                             haarFeature = cvHaarFeature( "tilted_haar_point",
376                                 x, y,    dx*3, dy*3, -1,
377                                 x, y+dy, dx  , dy,   +9 );
378                                 CV_WRITE_SEQ_ELEM( haarFeature, writer );
379                           }
380                           }
381                         */
382                     }
383                 }
384             }
385         }
386     }
387
388     seq = cvEndWriteSeq( &writer );
389     features = (CvIntHaarFeatures*) cvAlloc( sizeof( CvIntHaarFeatures ) +
390         ( sizeof( CvTHaarFeature ) + sizeof( CvFastHaarFeature ) ) * seq->total );
391     features->feature = (CvTHaarFeature*) (features + 1);
392     features->fastfeature = (CvFastHaarFeature*) ( features->feature + seq->total );
393     features->count = seq->total;
394     features->winsize = winsize;
395     cvCvtSeqToArray( seq, (CvArr*) features->feature );
396     cvReleaseMemStorage( &storage );
397     
398     icvConvertToFastHaarFeature( features->feature, features->fastfeature,
399                                  features->count, (winsize.width + 1) );
400     
401     return features;
402 }
403
404 static
405 void icvReleaseIntHaarFeatures( CvIntHaarFeatures** intHaarFeatures )
406 {
407     if( intHaarFeatures != NULL && (*intHaarFeatures) != NULL )
408     {
409         cvFree( intHaarFeatures );
410         (*intHaarFeatures) = NULL;
411     }
412 }
413
414
415 void icvConvertToFastHaarFeature( CvTHaarFeature* haarFeature,
416                                   CvFastHaarFeature* fastHaarFeature,
417                                   int size, int step )
418 {
419     int i = 0;
420     int j = 0;
421
422     for( i = 0; i < size; i++ )
423     {
424         fastHaarFeature[i].tilted = haarFeature[i].tilted;
425         if( !fastHaarFeature[i].tilted )
426         {
427             for( j = 0; j < CV_HAAR_FEATURE_MAX; j++ )
428             {
429                 fastHaarFeature[i].rect[j].weight = haarFeature[i].rect[j].weight;
430                 if( fastHaarFeature[i].rect[j].weight == 0.0F )
431                 {
432                     break;
433                 }
434                 CV_SUM_OFFSETS( fastHaarFeature[i].rect[j].p0,
435                                 fastHaarFeature[i].rect[j].p1,
436                                 fastHaarFeature[i].rect[j].p2,
437                                 fastHaarFeature[i].rect[j].p3,
438                                 haarFeature[i].rect[j].r, step )
439             }
440             
441         }
442         else
443         {
444             for( j = 0; j < CV_HAAR_FEATURE_MAX; j++ )
445             {
446                 fastHaarFeature[i].rect[j].weight = haarFeature[i].rect[j].weight;
447                 if( fastHaarFeature[i].rect[j].weight == 0.0F )
448                 {
449                     break;
450                 }
451                 CV_TILTED_OFFSETS( fastHaarFeature[i].rect[j].p0,
452                                    fastHaarFeature[i].rect[j].p1,
453                                    fastHaarFeature[i].rect[j].p2,
454                                    fastHaarFeature[i].rect[j].p3,
455                                    haarFeature[i].rect[j].r, step )
456             }
457         }
458     }
459 }
460
461
462 /*
463  * icvCreateHaarTrainingData
464  *
465  * Create haar training data used in stage training
466  */
467 static
468 CvHaarTrainigData* icvCreateHaarTrainingData( CvSize winsize, int maxnumsamples )
469 {
470     CvHaarTrainigData* data;
471     
472     CV_FUNCNAME( "icvCreateHaarTrainingData" );
473     
474     __BEGIN__;
475
476     data = NULL;
477     uchar* ptr = NULL;
478     size_t datasize = 0;
479     
480     datasize = sizeof( CvHaarTrainigData ) +
481           /* sum and tilted */
482         ( 2 * (winsize.width + 1) * (winsize.height + 1) * sizeof( sum_type ) +
483           sizeof( float ) +      /* normfactor */
484           sizeof( float ) +      /* cls */
485           sizeof( float )        /* weight */
486         ) * maxnumsamples;
487
488     CV_CALL( data = (CvHaarTrainigData*) cvAlloc( datasize ) );
489     memset( (void*)data, 0, datasize );
490     data->maxnum = maxnumsamples;
491     data->winsize = winsize;
492     ptr = (uchar*)(data + 1);
493     data->sum = cvMat( maxnumsamples, (winsize.width + 1) * (winsize.height + 1),
494                        CV_SUM_MAT_TYPE, (void*) ptr );
495     ptr += sizeof( sum_type ) * maxnumsamples * (winsize.width+1) * (winsize.height+1);
496     data->tilted = cvMat( maxnumsamples, (winsize.width + 1) * (winsize.height + 1),
497                        CV_SUM_MAT_TYPE, (void*) ptr );
498     ptr += sizeof( sum_type ) * maxnumsamples * (winsize.width+1) * (winsize.height+1);
499     data->normfactor = cvMat( 1, maxnumsamples, CV_32FC1, (void*) ptr );
500     ptr += sizeof( float ) * maxnumsamples;
501     data->cls = cvMat( 1, maxnumsamples, CV_32FC1, (void*) ptr );
502     ptr += sizeof( float ) * maxnumsamples;
503     data->weights = cvMat( 1, maxnumsamples, CV_32FC1, (void*) ptr );
504
505     data->valcache = NULL;
506     data->idxcache = NULL;
507
508     __END__;
509
510     return data;
511 }
512
513 static
514 void icvReleaseHaarTrainingDataCache( CvHaarTrainigData** haarTrainingData )
515 {
516     if( haarTrainingData != NULL && (*haarTrainingData) != NULL )
517     {
518         if( (*haarTrainingData)->valcache != NULL )
519         {
520             cvReleaseMat( &(*haarTrainingData)->valcache );
521             (*haarTrainingData)->valcache = NULL;
522         }
523         if( (*haarTrainingData)->idxcache != NULL )
524         {
525             cvReleaseMat( &(*haarTrainingData)->idxcache );
526             (*haarTrainingData)->idxcache = NULL;
527         }
528     }
529 }
530
531 static
532 void icvReleaseHaarTrainingData( CvHaarTrainigData** haarTrainingData )
533 {
534     if( haarTrainingData != NULL && (*haarTrainingData) != NULL )
535     {
536         icvReleaseHaarTrainingDataCache( haarTrainingData );
537
538         cvFree( haarTrainingData );
539     }
540 }
541
542 static
543 void icvGetTrainingDataCallback( CvMat* mat, CvMat* sampleIdx, CvMat*,
544                                  int first, int num, void* userdata )
545 {
546     int i = 0;
547     int j = 0;
548     float val = 0.0F;
549     float normfactor = 0.0F;
550     
551     CvHaarTrainingData* training_data;
552     CvIntHaarFeatures* haar_features;
553
554 #ifdef CV_COL_ARRANGEMENT
555     assert( mat->rows >= num );
556 #else
557     assert( mat->cols >= num );
558 #endif
559
560     training_data = ((CvUserdata*) userdata)->trainingData;
561     haar_features = ((CvUserdata*) userdata)->haarFeatures;
562     if( sampleIdx == NULL )
563     {
564         int num_samples;
565
566 #ifdef CV_COL_ARRANGEMENT
567         num_samples = mat->cols;
568 #else
569         num_samples = mat->rows;
570 #endif
571         for( i = 0; i < num_samples; i++ )
572         {
573             for( j = 0; j < num; j++ )
574             {
575                 val = cvEvalFastHaarFeature(
576                         ( haar_features->fastfeature
577                             + first + j ),
578                         (sum_type*) (training_data->sum.data.ptr
579                             + i * training_data->sum.step),
580                         (sum_type*) (training_data->tilted.data.ptr
581                             + i * training_data->tilted.step) );
582                 normfactor = training_data->normfactor.data.fl[i];
583                 val = ( normfactor == 0.0F ) ? 0.0F : (val / normfactor);
584
585 #ifdef CV_COL_ARRANGEMENT
586                 CV_MAT_ELEM( *mat, float, j, i ) = val;
587 #else
588                 CV_MAT_ELEM( *mat, float, i, j ) = val;
589 #endif
590             }
591         }
592     }
593     else
594     {
595         uchar* idxdata = NULL;
596         size_t step    = 0;
597         int    numidx  = 0;
598         int    idx     = 0;
599
600         assert( CV_MAT_TYPE( sampleIdx->type ) == CV_32FC1 );
601
602         idxdata = sampleIdx->data.ptr;
603         if( sampleIdx->rows == 1 )
604         {
605             step = sizeof( float );
606             numidx = sampleIdx->cols;
607         }
608         else
609         {
610             step = sampleIdx->step;
611             numidx = sampleIdx->rows;
612         }
613
614         for( i = 0; i < numidx; i++ )
615         {
616             for( j = 0; j < num; j++ )
617             {
618                 idx = (int)( *((float*) (idxdata + i * step)) );
619                 val = cvEvalFastHaarFeature(
620                         ( haar_features->fastfeature
621                             + first + j ),
622                         (sum_type*) (training_data->sum.data.ptr
623                             + idx * training_data->sum.step),
624                         (sum_type*) (training_data->tilted.data.ptr
625                             + idx * training_data->tilted.step) );
626                 normfactor = training_data->normfactor.data.fl[idx];
627                 val = ( normfactor == 0.0F ) ? 0.0F : (val / normfactor);
628
629 #ifdef CV_COL_ARRANGEMENT
630                 CV_MAT_ELEM( *mat, float, j, idx ) = val;
631 #else
632                 CV_MAT_ELEM( *mat, float, idx, j ) = val;
633 #endif
634
635             }
636         }
637     }
638 #if 0 /*def CV_VERBOSE*/
639     if( first % 5000 == 0 )
640     {
641         fprintf( stderr, "%3d%%\r", (int) (100.0 * first / 
642             haar_features->count) );
643         fflush( stderr );
644     }
645 #endif /* CV_VERBOSE */
646 }
647
648 static
649 void icvPrecalculate( CvHaarTrainingData* data, CvIntHaarFeatures* haarFeatures,
650                       int numprecalculated )
651 {
652     CV_FUNCNAME( "icvPrecalculate" );
653
654     __BEGIN__;
655
656     icvReleaseHaarTrainingDataCache( &data );
657
658     numprecalculated -= numprecalculated % CV_STUMP_TRAIN_PORTION;
659     numprecalculated = MIN( numprecalculated, haarFeatures->count );
660
661     if( numprecalculated > 0 )
662     {
663         //size_t datasize;
664         int m;
665         CvUserdata userdata;
666
667         /* private variables */
668         #ifdef CV_OPENMP
669         CvMat t_data;
670         CvMat t_idx;
671         int first;
672         int t_portion;
673         int portion = CV_STUMP_TRAIN_PORTION;
674         #endif /* CV_OPENMP */
675
676         m = data->sum.rows;
677
678 #ifdef CV_COL_ARRANGEMENT
679         CV_CALL( data->valcache = cvCreateMat( numprecalculated, m, CV_32FC1 ) );
680 #else
681         CV_CALL( data->valcache = cvCreateMat( m, numprecalculated, CV_32FC1 ) );
682 #endif
683         CV_CALL( data->idxcache = cvCreateMat( numprecalculated, m, CV_IDX_MAT_TYPE ) );
684
685         userdata = cvUserdata( data, haarFeatures );
686
687         #ifdef CV_OPENMP
688         #pragma omp parallel for private(t_data, t_idx, first, t_portion)
689         for( first = 0; first < numprecalculated; first += portion )
690         {
691             t_data = *data->valcache;
692             t_idx = *data->idxcache;
693             t_portion = MIN( portion, (numprecalculated - first) );
694             
695             /* indices */
696             t_idx.rows = t_portion;
697             t_idx.data.ptr = data->idxcache->data.ptr + first * ((size_t)t_idx.step);
698
699             /* feature values */
700 #ifdef CV_COL_ARRANGEMENT
701             t_data.rows = t_portion;
702             t_data.data.ptr = data->valcache->data.ptr +
703                 first * ((size_t) t_data.step );
704 #else
705             t_data.cols = t_portion;
706             t_data.data.ptr = data->valcache->data.ptr +
707                 first * ((size_t) CV_ELEM_SIZE( t_data.type ));
708 #endif
709             icvGetTrainingDataCallback( &t_data, NULL, NULL, first, t_portion,
710                                         &userdata );
711 #ifdef CV_COL_ARRANGEMENT
712             cvGetSortedIndices( &t_data, &t_idx, 0 );
713 #else
714             cvGetSortedIndices( &t_data, &t_idx, 1 );
715 #endif
716
717 #ifdef CV_VERBOSE
718             putc( '.', stderr );
719             fflush( stderr );
720 #endif /* CV_VERBOSE */
721
722         }
723
724 #ifdef CV_VERBOSE
725         fprintf( stderr, "\n" );
726         fflush( stderr );
727 #endif /* CV_VERBOSE */
728
729         #else
730         icvGetTrainingDataCallback( data->valcache, NULL, NULL, 0, numprecalculated,
731                                     &userdata );
732 #ifdef CV_COL_ARRANGEMENT
733         cvGetSortedIndices( data->valcache, data->idxcache, 0 );
734 #else
735         cvGetSortedIndices( data->valcache, data->idxcache, 1 );
736 #endif
737         #endif /* CV_OPENMP */
738     }
739
740     __END__;
741 }
742
743 static
744 void icvSplitIndicesCallback( int compidx, float threshold,
745                               CvMat* idx, CvMat** left, CvMat** right,
746                               void* userdata )
747 {
748     CvHaarTrainingData* data;
749     CvIntHaarFeatures* haar_features;
750     int i;
751     int m;
752     CvFastHaarFeature* fastfeature;
753
754     data = ((CvUserdata*) userdata)->trainingData;
755     haar_features = ((CvUserdata*) userdata)->haarFeatures;
756     fastfeature = &haar_features->fastfeature[compidx];
757
758     m = data->sum.rows;
759     *left = cvCreateMat( 1, m, CV_32FC1 );
760     *right = cvCreateMat( 1, m, CV_32FC1 );
761     (*left)->cols = (*right)->cols = 0;
762     if( idx == NULL )
763     {
764         for( i = 0; i < m; i++ )
765         {
766             if( cvEvalFastHaarFeature( fastfeature,
767                     (sum_type*) (data->sum.data.ptr + i * data->sum.step),
768                     (sum_type*) (data->tilted.data.ptr + i * data->tilted.step) ) 
769                 < threshold * data->normfactor.data.fl[i] )
770             {
771                 (*left)->data.fl[(*left)->cols++] = (float) i;
772             }
773             else
774             {
775                 (*right)->data.fl[(*right)->cols++] = (float) i;
776             }
777         }
778     }
779     else
780     {
781         uchar* idxdata;
782         int    idxnum;
783         size_t idxstep;
784         int    index;
785
786         idxdata = idx->data.ptr;
787         idxnum = (idx->rows == 1) ? idx->cols : idx->rows;
788         idxstep = (idx->rows == 1) ? CV_ELEM_SIZE( idx->type ) : idx->step;
789         for( i = 0; i < idxnum; i++ )
790         {
791             index = (int) *((float*) (idxdata + i * idxstep));
792             if( cvEvalFastHaarFeature( fastfeature,
793                     (sum_type*) (data->sum.data.ptr + index * data->sum.step),
794                     (sum_type*) (data->tilted.data.ptr + index * data->tilted.step) ) 
795                 < threshold * data->normfactor.data.fl[index] )
796             {
797                 (*left)->data.fl[(*left)->cols++] = (float) index;
798             }
799             else
800             {
801                 (*right)->data.fl[(*right)->cols++] = (float) index;
802             }
803         }
804     }
805 }
806
807 /*
808  * icvCreateCARTStageClassifier
809  *
810  * Create stage classifier with trees as weak classifiers
811  * data             - haar training data. It must be created and filled before call
812  * minhitrate       - desired min hit rate
813  * maxfalsealarm    - desired max false alarm rate
814  * symmetric        - if not 0 it is assumed that samples are vertically symmetric
815  * numprecalculated - number of features that will be precalculated. Each precalculated
816  *   feature need (number_of_samples*(sizeof( float ) + sizeof( short ))) bytes of memory
817  * weightfraction   - weight trimming parameter
818  * numsplits        - number of binary splits in each tree
819  * boosttype        - type of applied boosting algorithm
820  * stumperror       - type of used error if Discrete AdaBoost algorithm is applied
821  * maxsplits        - maximum total number of splits in all weak classifiers.
822  *   If it is not 0 then NULL returned if total number of splits exceeds <maxsplits>.
823  */
824 static
825 CvIntHaarClassifier* icvCreateCARTStageClassifier( CvHaarTrainingData* data,
826                                                    CvMat* sampleIdx,
827                                                    CvIntHaarFeatures* haarFeatures,
828                                                    float minhitrate,
829                                                    float maxfalsealarm,
830                                                    int   symmetric,
831                                                    float weightfraction,
832                                                    int numsplits,
833                                                    CvBoostType boosttype,
834                                                    CvStumpError stumperror,
835                                                    int maxsplits )
836 {
837
838 #ifdef CV_COL_ARRANGEMENT
839     int flags = CV_COL_SAMPLE;
840 #else
841     int flags = CV_ROW_SAMPLE;
842 #endif
843
844     CvStageHaarClassifier* stage = NULL;
845     CvBoostTrainer* trainer;
846     CvCARTClassifier* cart = NULL;
847     CvCARTTrainParams trainParams;
848     CvMTStumpTrainParams stumpTrainParams;
849     //CvMat* trainData = NULL;
850     //CvMat* sortedIdx = NULL;
851     CvMat eval;
852     int n = 0;
853     int m = 0;
854     int numpos = 0;
855     int numneg = 0;
856     int numfalse = 0;
857     float sum_stage = 0.0F;
858     float threshold = 0.0F;
859     float falsealarm = 0.0F;
860     
861     //CvMat* sampleIdx = NULL;
862     CvMat* trimmedIdx;
863     //float* idxdata = NULL;
864     //float* tempweights = NULL;
865     //int    idxcount = 0;
866     CvUserdata userdata;
867
868     int i = 0;
869     int j = 0;
870     int idx;
871     int numsamples;
872     int numtrimmed;
873     
874     CvCARTHaarClassifier* classifier;
875     CvSeq* seq = NULL;
876     CvMemStorage* storage = NULL;
877     CvMat* weakTrainVals;
878     float alpha;
879     float sumalpha;
880     int num_splits; /* total number of splits in all weak classifiers */
881
882 #ifdef CV_VERBOSE
883     printf( "+----+----+-+---------+---------+---------+---------+\n" );
884     printf( "|  N |%%SMP|F|  ST.THR |    HR   |    FA   | EXP. ERR|\n" );
885     printf( "+----+----+-+---------+---------+---------+---------+\n" );
886 #endif /* CV_VERBOSE */
887     
888     n = haarFeatures->count;
889     m = data->sum.rows;
890     numsamples = (sampleIdx) ? MAX( sampleIdx->rows, sampleIdx->cols ) : m;
891
892     userdata = cvUserdata( data, haarFeatures );
893
894     stumpTrainParams.type = ( boosttype == CV_DABCLASS )
895         ? CV_CLASSIFICATION_CLASS : CV_REGRESSION;
896     stumpTrainParams.error = ( boosttype == CV_LBCLASS || boosttype == CV_GABCLASS )
897         ? CV_SQUARE : stumperror;
898     stumpTrainParams.portion = CV_STUMP_TRAIN_PORTION;
899     stumpTrainParams.getTrainData = icvGetTrainingDataCallback;
900     stumpTrainParams.numcomp = n;
901     stumpTrainParams.userdata = &userdata;
902     stumpTrainParams.sortedIdx = data->idxcache;
903
904     trainParams.count = numsplits;
905     trainParams.stumpTrainParams = (CvClassifierTrainParams*) &stumpTrainParams;
906     trainParams.stumpConstructor = cvCreateMTStumpClassifier;
907     trainParams.splitIdx = icvSplitIndicesCallback;
908     trainParams.userdata = &userdata;
909
910     eval = cvMat( 1, m, CV_32FC1, cvAlloc( sizeof( float ) * m ) );
911     
912     storage = cvCreateMemStorage();
913     seq = cvCreateSeq( 0, sizeof( *seq ), sizeof( classifier ), storage );
914
915     weakTrainVals = cvCreateMat( 1, m, CV_32FC1 );
916     trainer = cvBoostStartTraining( &data->cls, weakTrainVals, &data->weights,
917                                     sampleIdx, boosttype );
918     num_splits = 0;
919     sumalpha = 0.0F;
920     do
921     {     
922
923 #ifdef CV_VERBOSE
924         int v_wt = 0;
925         int v_flipped = 0;
926 #endif /* CV_VERBOSE */
927
928         trimmedIdx = cvTrimWeights( &data->weights, sampleIdx, weightfraction );
929         numtrimmed = (trimmedIdx) ? MAX( trimmedIdx->rows, trimmedIdx->cols ) : m;
930
931 #ifdef CV_VERBOSE
932         v_wt = 100 * numtrimmed / numsamples;
933         v_flipped = 0;
934
935 #endif /* CV_VERBOSE */
936
937         cart = (CvCARTClassifier*) cvCreateCARTClassifier( data->valcache,
938                         flags,
939                         weakTrainVals, 0, 0, 0, trimmedIdx,
940                         &(data->weights),
941                         (CvClassifierTrainParams*) &trainParams );
942
943         classifier = (CvCARTHaarClassifier*) icvCreateCARTHaarClassifier( numsplits );
944         icvInitCARTHaarClassifier( classifier, cart, haarFeatures );
945
946         num_splits += classifier->count;
947
948         cart->release( (CvClassifier**) &cart );
949         
950         if( symmetric && (seq->total % 2) )
951         {
952             float normfactor = 0.0F;
953             CvStumpClassifier* stump;
954             
955             /* flip haar features */
956             for( i = 0; i < classifier->count; i++ )
957             {
958                 if( classifier->feature[i].desc[0] == 'h' )
959                 {
960                     for( j = 0; j < CV_HAAR_FEATURE_MAX &&
961                                     classifier->feature[i].rect[j].weight != 0.0F; j++ )
962                     {
963                         classifier->feature[i].rect[j].r.x = data->winsize.width - 
964                             classifier->feature[i].rect[j].r.x -
965                             classifier->feature[i].rect[j].r.width;                
966                     }
967                 }
968                 else
969                 {
970                     int tmp = 0;
971
972                     /* (x,y) -> (24-x,y) */
973                     /* w -> h; h -> w    */
974                     for( j = 0; j < CV_HAAR_FEATURE_MAX &&
975                                     classifier->feature[i].rect[j].weight != 0.0F; j++ )
976                     {
977                         classifier->feature[i].rect[j].r.x = data->winsize.width - 
978                             classifier->feature[i].rect[j].r.x;
979                         CV_SWAP( classifier->feature[i].rect[j].r.width,
980                                  classifier->feature[i].rect[j].r.height, tmp );
981                     }
982                 }
983             }
984             icvConvertToFastHaarFeature( classifier->feature,
985                                          classifier->fastfeature,
986                                          classifier->count, data->winsize.width + 1 );
987
988             stumpTrainParams.getTrainData = NULL;
989             stumpTrainParams.numcomp = 1;
990             stumpTrainParams.userdata = NULL;
991             stumpTrainParams.sortedIdx = NULL;
992
993             for( i = 0; i < classifier->count; i++ )
994             {
995                 for( j = 0; j < numtrimmed; j++ )
996                 {
997                     idx = icvGetIdxAt( trimmedIdx, j );
998
999                     eval.data.fl[idx] = cvEvalFastHaarFeature( &classifier->fastfeature[i],
1000                         (sum_type*) (data->sum.data.ptr + idx * data->sum.step),
1001                         (sum_type*) (data->tilted.data.ptr + idx * data->tilted.step) );
1002                     normfactor = data->normfactor.data.fl[idx];
1003                     eval.data.fl[idx] = ( normfactor == 0.0F )
1004                         ? 0.0F : (eval.data.fl[idx] / normfactor);
1005                 }
1006
1007                 stump = (CvStumpClassifier*) trainParams.stumpConstructor( &eval,
1008                     CV_COL_SAMPLE,
1009                     weakTrainVals, 0, 0, 0, trimmedIdx,
1010                     &(data->weights),
1011                     trainParams.stumpTrainParams );
1012             
1013                 classifier->threshold[i] = stump->threshold;
1014                 if( classifier->left[i] <= 0 )
1015                 {
1016                     classifier->val[-classifier->left[i]] = stump->left;
1017                 }
1018                 if( classifier->right[i] <= 0 )
1019                 {
1020                     classifier->val[-classifier->right[i]] = stump->right;
1021                 }
1022
1023                 stump->release( (CvClassifier**) &stump );        
1024                 
1025             }
1026
1027             stumpTrainParams.getTrainData = icvGetTrainingDataCallback;
1028             stumpTrainParams.numcomp = n;
1029             stumpTrainParams.userdata = &userdata;
1030             stumpTrainParams.sortedIdx = data->idxcache;
1031
1032 #ifdef CV_VERBOSE
1033             v_flipped = 1;
1034 #endif /* CV_VERBOSE */
1035
1036         } /* if symmetric */
1037         if( trimmedIdx != sampleIdx )
1038         {
1039             cvReleaseMat( &trimmedIdx );
1040             trimmedIdx = NULL;
1041         }
1042         
1043         for( i = 0; i < numsamples; i++ )
1044         {
1045             idx = icvGetIdxAt( sampleIdx, i );
1046
1047             eval.data.fl[idx] = classifier->eval( (CvIntHaarClassifier*) classifier,
1048                 (sum_type*) (data->sum.data.ptr + idx * data->sum.step),
1049                 (sum_type*) (data->tilted.data.ptr + idx * data->tilted.step),
1050                 data->normfactor.data.fl[idx] );
1051         }
1052
1053         alpha = cvBoostNextWeakClassifier( &eval, &data->cls, weakTrainVals,
1054                                            &data->weights, trainer );
1055         sumalpha += alpha;
1056         
1057         for( i = 0; i <= classifier->count; i++ )
1058         {
1059             if( boosttype == CV_RABCLASS ) 
1060             {
1061                 classifier->val[i] = cvLogRatio( classifier->val[i] );
1062             }
1063             classifier->val[i] *= alpha;
1064         }
1065
1066         cvSeqPush( seq, (void*) &classifier );
1067
1068         numpos = 0;
1069         for( i = 0; i < numsamples; i++ )
1070         {
1071             idx = icvGetIdxAt( sampleIdx, i );
1072
1073             if( data->cls.data.fl[idx] == 1.0F )
1074             {
1075                 eval.data.fl[numpos] = 0.0F;
1076                 for( j = 0; j < seq->total; j++ )
1077                 {
1078                     classifier = *((CvCARTHaarClassifier**) cvGetSeqElem( seq, j ));
1079                     eval.data.fl[numpos] += classifier->eval( 
1080                         (CvIntHaarClassifier*) classifier,
1081                         (sum_type*) (data->sum.data.ptr + idx * data->sum.step),
1082                         (sum_type*) (data->tilted.data.ptr + idx * data->tilted.step),
1083                         data->normfactor.data.fl[idx] );
1084                 }
1085                 /* eval.data.fl[numpos] = 2.0F * eval.data.fl[numpos] - seq->total; */
1086                 numpos++;
1087             }
1088         }
1089         icvSort_32f( eval.data.fl, numpos, 0 );
1090         threshold = eval.data.fl[(int) ((1.0F - minhitrate) * numpos)];
1091
1092         numneg = 0;
1093         numfalse = 0;
1094         for( i = 0; i < numsamples; i++ )
1095         {
1096             idx = icvGetIdxAt( sampleIdx, i );
1097
1098             if( data->cls.data.fl[idx] == 0.0F )
1099             {
1100                 numneg++;
1101                 sum_stage = 0.0F;
1102                 for( j = 0; j < seq->total; j++ )
1103                 {
1104                    classifier = *((CvCARTHaarClassifier**) cvGetSeqElem( seq, j ));
1105                    sum_stage += classifier->eval( (CvIntHaarClassifier*) classifier,
1106                         (sum_type*) (data->sum.data.ptr + idx * data->sum.step),
1107                         (sum_type*) (data->tilted.data.ptr + idx * data->tilted.step),
1108                         data->normfactor.data.fl[idx] );
1109                 }
1110                 /* sum_stage = 2.0F * sum_stage - seq->total; */
1111                 if( sum_stage >= (threshold - CV_THRESHOLD_EPS) )
1112                 {
1113                     numfalse++;
1114                 }
1115             }
1116         }
1117         falsealarm = ((float) numfalse) / ((float) numneg);
1118
1119 #ifdef CV_VERBOSE
1120         {
1121             float v_hitrate    = 0.0F;
1122             float v_falsealarm = 0.0F;
1123             /* expected error of stage classifier regardless threshold */
1124             float v_experr = 0.0F;
1125
1126             for( i = 0; i < numsamples; i++ )
1127             {
1128                 idx = icvGetIdxAt( sampleIdx, i );
1129
1130                 sum_stage = 0.0F;
1131                 for( j = 0; j < seq->total; j++ )
1132                 {
1133                     classifier = *((CvCARTHaarClassifier**) cvGetSeqElem( seq, j ));
1134                     sum_stage += classifier->eval( (CvIntHaarClassifier*) classifier,
1135                         (sum_type*) (data->sum.data.ptr + idx * data->sum.step),
1136                         (sum_type*) (data->tilted.data.ptr + idx * data->tilted.step),
1137                         data->normfactor.data.fl[idx] );
1138                 }
1139                 /* sum_stage = 2.0F * sum_stage - seq->total; */
1140                 if( sum_stage >= (threshold - CV_THRESHOLD_EPS) )
1141                 {
1142                     if( data->cls.data.fl[idx] == 1.0F )
1143                     {
1144                         v_hitrate += 1.0F;
1145                     }
1146                     else
1147                     {
1148                         v_falsealarm += 1.0F;
1149                     }
1150                 }
1151                 if( ( sum_stage >= 0.0F ) != (data->cls.data.fl[idx] == 1.0F) )
1152                 {
1153                     v_experr += 1.0F;
1154                 }
1155             }
1156             v_experr /= numsamples;
1157             printf( "|%4d|%3d%%|%c|%9f|%9f|%9f|%9f|\n",
1158                 seq->total, v_wt, ( (v_flipped) ? '+' : '-' ),
1159                 threshold, v_hitrate / numpos, v_falsealarm / numneg,
1160                 v_experr );
1161             printf( "+----+----+-+---------+---------+---------+---------+\n" );
1162             fflush( stdout );
1163         }
1164 #endif /* CV_VERBOSE */
1165         
1166     } while( falsealarm > maxfalsealarm && (!maxsplits || (num_splits < maxsplits) ) );
1167     cvBoostEndTraining( &trainer );
1168
1169     if( falsealarm > maxfalsealarm )
1170     {
1171         stage = NULL;
1172     }
1173     else
1174     {
1175         stage = (CvStageHaarClassifier*) icvCreateStageHaarClassifier( seq->total,
1176                                                                        threshold );
1177         cvCvtSeqToArray( seq, (CvArr*) stage->classifier );
1178     }
1179     
1180     /* CLEANUP */
1181     cvReleaseMemStorage( &storage );
1182     cvReleaseMat( &weakTrainVals );
1183     cvFree( &(eval.data.ptr) );
1184     
1185     return (CvIntHaarClassifier*) stage;
1186 }
1187
1188
1189 static
1190 CvBackgroundData* icvCreateBackgroundData( const char* filename, CvSize winsize )
1191 {
1192     CvBackgroundData* data = NULL;
1193
1194     const char* dir = NULL;    
1195     char full[PATH_MAX];
1196     char* imgfilename = NULL;
1197     size_t datasize = 0;
1198     int    count = 0;
1199     FILE*  input = NULL;
1200     char*  tmp   = NULL;
1201     int    len   = 0;
1202
1203     assert( filename != NULL );
1204     
1205     dir = strrchr( filename, '\\' );
1206     if( dir == NULL )
1207     {
1208         dir = strrchr( filename, '/' );
1209     }
1210     if( dir == NULL )
1211     {
1212         imgfilename = &(full[0]);
1213     }
1214     else
1215     {
1216         strncpy( &(full[0]), filename, (dir - filename + 1) );
1217         imgfilename = &(full[(dir - filename + 1)]);
1218     }
1219
1220     input = fopen( filename, "r" );
1221     if( input != NULL )
1222     {
1223         count = 0;
1224         datasize = 0;
1225         
1226         /* count */
1227         while( !feof( input ) )
1228         {
1229             *imgfilename = '\0';
1230             if( !fscanf( input, "%s", imgfilename ))
1231                 break;
1232             len = (int)strlen( imgfilename );
1233             if( len > 0 )
1234             {
1235                 if( (*imgfilename) == '#' ) continue; /* comment */
1236                 count++;
1237                 datasize += sizeof( char ) * (strlen( &(full[0]) ) + 1);
1238             }
1239         }
1240         if( count > 0 )
1241         {
1242             //rewind( input );
1243             fseek( input, 0, SEEK_SET );
1244             datasize += sizeof( *data ) + sizeof( char* ) * count;
1245             data = (CvBackgroundData*) cvAlloc( datasize );
1246             memset( (void*) data, 0, datasize );
1247             data->count = count;
1248             data->filename = (char**) (data + 1);
1249             data->last = 0;
1250             data->round = 0;
1251             data->winsize = winsize;
1252             tmp = (char*) (data->filename + data->count);
1253             count = 0;
1254             while( !feof( input ) )
1255             {
1256                 *imgfilename = '\0';
1257                 if( !fscanf( input, "%s", imgfilename ))
1258                     break;
1259                 len = (int)strlen( imgfilename );
1260                 if( len > 0 )
1261                 {
1262                     if( (*imgfilename) == '#' ) continue; /* comment */
1263                     data->filename[count++] = tmp;
1264                     strcpy( tmp, &(full[0]) );
1265                     tmp += strlen( &(full[0]) ) + 1;
1266                 }
1267             }
1268         }
1269         fclose( input );
1270     }
1271
1272     return data;
1273 }
1274
1275 static
1276 void icvReleaseBackgroundData( CvBackgroundData** data )
1277 {
1278     assert( data != NULL && (*data) != NULL );
1279
1280     cvFree( data );
1281 }
1282
1283 static
1284 CvBackgroundReader* icvCreateBackgroundReader()
1285 {
1286     CvBackgroundReader* reader = NULL;
1287
1288     reader = (CvBackgroundReader*) cvAlloc( sizeof( *reader ) );
1289     memset( (void*) reader, 0, sizeof( *reader ) );
1290     reader->src = cvMat( 0, 0, CV_8UC1, NULL );
1291     reader->img = cvMat( 0, 0, CV_8UC1, NULL );
1292     reader->offset = cvPoint( 0, 0 );
1293     reader->scale       = 1.0F;
1294     reader->scalefactor = 1.4142135623730950488016887242097F;
1295     reader->stepfactor  = 0.5F;
1296     reader->point = reader->offset;
1297
1298     return reader;
1299 }
1300
1301 static
1302 void icvReleaseBackgroundReader( CvBackgroundReader** reader )
1303 {
1304     assert( reader != NULL && (*reader) != NULL );
1305
1306     if( (*reader)->src.data.ptr != NULL )
1307     {
1308         cvFree( &((*reader)->src.data.ptr) );
1309     }
1310     if( (*reader)->img.data.ptr != NULL )
1311     {
1312         cvFree( &((*reader)->img.data.ptr) );
1313     }
1314
1315     cvFree( reader );
1316 }
1317
1318 static
1319 void icvGetNextFromBackgroundData( CvBackgroundData* data,
1320                                    CvBackgroundReader* reader )
1321 {
1322     IplImage* img = NULL;
1323     size_t datasize = 0;
1324     int round = 0;
1325     int i = 0;
1326     CvPoint offset = cvPoint(0,0);
1327
1328     assert( data != NULL && reader != NULL );
1329
1330     if( reader->src.data.ptr != NULL )
1331     {
1332         cvFree( &(reader->src.data.ptr) );
1333         reader->src.data.ptr = NULL;
1334     }
1335     if( reader->img.data.ptr != NULL )
1336     {
1337         cvFree( &(reader->img.data.ptr) );
1338         reader->img.data.ptr = NULL;
1339     }
1340
1341     #ifdef CV_OPENMP
1342     #pragma omp critical(c_background_data)
1343     #endif /* CV_OPENMP */
1344     {
1345         for( i = 0; i < data->count; i++ )
1346         {
1347             round = data->round;
1348
1349 //#ifdef CV_VERBOSE 
1350 //            printf( "Open background image: %s\n", data->filename[data->last] );
1351 //#endif /* CV_VERBOSE */
1352           
1353             img = cvLoadImage( data->filename[data->last++], 0 );
1354             if( !img )
1355                 continue;
1356             data->round += data->last / data->count;
1357             data->round = data->round % (data->winsize.width * data->winsize.height);
1358             data->last %= data->count;
1359
1360             offset.x = round % data->winsize.width;
1361             offset.y = round / data->winsize.width;
1362
1363             offset.x = MIN( offset.x, img->width - data->winsize.width );
1364             offset.y = MIN( offset.y, img->height - data->winsize.height );
1365             
1366             if( img != NULL && img->depth == IPL_DEPTH_8U && img->nChannels == 1 &&
1367                 offset.x >= 0 && offset.y >= 0 )
1368             {
1369                 break;
1370             }
1371             if( img != NULL )
1372                 cvReleaseImage( &img );
1373             img = NULL;
1374         }
1375     }
1376     if( img == NULL )
1377     {
1378         /* no appropriate image */
1379
1380 #ifdef CV_VERBOSE
1381         printf( "Invalid background description file.\n" );
1382 #endif /* CV_VERBOSE */
1383
1384         assert( 0 );
1385         exit( 1 );
1386     }
1387     datasize = sizeof( uchar ) * img->width * img->height;
1388     reader->src = cvMat( img->height, img->width, CV_8UC1, (void*) cvAlloc( datasize ) );
1389     cvCopy( img, &reader->src, NULL );
1390     cvReleaseImage( &img );
1391     img = NULL;
1392
1393     //reader->offset.x = round % data->winsize.width;
1394     //reader->offset.y = round / data->winsize.width;
1395     reader->offset = offset;
1396     reader->point = reader->offset;
1397     reader->scale = MAX(
1398         ((float) data->winsize.width + reader->point.x) / ((float) reader->src.cols),
1399         ((float) data->winsize.height + reader->point.y) / ((float) reader->src.rows) );
1400     
1401     reader->img = cvMat( (int) (reader->scale * reader->src.rows + 0.5F),
1402                          (int) (reader->scale * reader->src.cols + 0.5F),
1403                           CV_8UC1, (void*) cvAlloc( datasize ) );
1404     cvResize( &(reader->src), &(reader->img) );
1405 }
1406
1407
1408 /*
1409  * icvGetBackgroundImage
1410  *
1411  * Get an image from background
1412  * <img> must be allocated and have size, previously passed to icvInitBackgroundReaders
1413  *
1414  * Usage example:
1415  * icvInitBackgroundReaders( "bg.txt", cvSize( 24, 24 ) );
1416  * ...
1417  * #pragma omp parallel
1418  * {
1419  *     ...
1420  *     icvGetBackgourndImage( cvbgdata, cvbgreader, img );
1421  *     ...
1422  * }
1423  * ...
1424  * icvDestroyBackgroundReaders();
1425  */
1426 static
1427 void icvGetBackgroundImage( CvBackgroundData* data,
1428                             CvBackgroundReader* reader,
1429                             CvMat* img )
1430 {
1431     CvMat mat;
1432
1433     assert( data != NULL && reader != NULL && img != NULL );
1434     assert( CV_MAT_TYPE( img->type ) == CV_8UC1 );
1435     assert( img->cols == data->winsize.width );
1436     assert( img->rows == data->winsize.height );
1437
1438     if( reader->img.data.ptr == NULL )
1439     {
1440         icvGetNextFromBackgroundData( data, reader );
1441     }
1442
1443     mat = cvMat( data->winsize.height, data->winsize.width, CV_8UC1 );
1444     cvSetData( &mat, (void*) (reader->img.data.ptr + reader->point.y * reader->img.step
1445                               + reader->point.x * sizeof( uchar )), reader->img.step );
1446
1447     cvCopy( &mat, img, 0 );
1448     if( (int) ( reader->point.x + (1.0F + reader->stepfactor ) * data->winsize.width )
1449             < reader->img.cols )
1450     {
1451         reader->point.x += (int) (reader->stepfactor * data->winsize.width);
1452     }
1453     else
1454     {
1455         reader->point.x = reader->offset.x;
1456         if( (int) ( reader->point.y + (1.0F + reader->stepfactor ) * data->winsize.height )
1457                 < reader->img.rows )
1458         {
1459             reader->point.y += (int) (reader->stepfactor * data->winsize.height);
1460         }
1461         else
1462         {
1463             reader->point.y = reader->offset.y;
1464             reader->scale *= reader->scalefactor;
1465             if( reader->scale <= 1.0F )
1466             {
1467                 reader->img = cvMat( (int) (reader->scale * reader->src.rows),
1468                                      (int) (reader->scale * reader->src.cols),
1469                                       CV_8UC1, (void*) (reader->img.data.ptr) );
1470                 cvResize( &(reader->src), &(reader->img) );
1471             }
1472             else
1473             {
1474                 icvGetNextFromBackgroundData( data, reader );
1475             }
1476         }
1477     }
1478 }
1479
1480
1481 /*
1482  * icvInitBackgroundReaders
1483  *
1484  * Initialize background reading process.
1485  * <cvbgreader> and <cvbgdata> are initialized.
1486  * Must be called before any usage of background
1487  *
1488  * filename - name of background description file
1489  * winsize  - size of images will be obtained from background
1490  *
1491  * return 1 on success, 0 otherwise.
1492  */
1493 static
1494 int icvInitBackgroundReaders( const char* filename, CvSize winsize )
1495 {
1496     if( cvbgdata == NULL && filename != NULL )
1497     {
1498         cvbgdata = icvCreateBackgroundData( filename, winsize );
1499     }
1500
1501     if( cvbgdata )
1502     {
1503
1504         #ifdef CV_OPENMP
1505         #pragma omp parallel
1506         #endif /* CV_OPENMP */
1507         {
1508             #ifdef CV_OPENMP
1509             #pragma omp critical(c_create_bg_data)
1510             #endif /* CV_OPENMP */
1511             {
1512                 if( cvbgreader == NULL )
1513                 {
1514                     cvbgreader = icvCreateBackgroundReader();
1515                 }
1516             }
1517         }
1518
1519     }
1520
1521     return (cvbgdata != NULL);
1522 }
1523
1524
1525 /*
1526  * icvDestroyBackgroundReaders
1527  *
1528  * Finish backgournd reading process
1529  */
1530 static
1531 void icvDestroyBackgroundReaders()
1532 {
1533     /* release background reader in each thread */
1534     #ifdef CV_OPENMP
1535     #pragma omp parallel
1536     #endif /* CV_OPENMP */
1537     {
1538         #ifdef CV_OPENMP
1539         #pragma omp critical(c_release_bg_data)
1540         #endif /* CV_OPENMP */
1541         {
1542             if( cvbgreader != NULL )
1543             {
1544                 icvReleaseBackgroundReader( &cvbgreader );
1545                 cvbgreader = NULL;
1546             }
1547         }
1548     }
1549
1550     if( cvbgdata != NULL )
1551     {
1552         icvReleaseBackgroundData( &cvbgdata );
1553         cvbgdata = NULL;
1554     }
1555 }
1556
1557
1558 /*
1559  * icvGetAuxImages
1560  *
1561  * Get sum, tilted, sqsum images and calculate normalization factor
1562  * All images must be allocated.
1563  */
1564 static
1565 void icvGetAuxImages( CvMat* img, CvMat* sum, CvMat* tilted,
1566                       CvMat* sqsum, float* normfactor )
1567 {
1568     CvRect normrect;
1569     int p0, p1, p2, p3;
1570     sum_type   valsum   = 0;
1571     sqsum_type valsqsum = 0;
1572     double area = 0.0;
1573     
1574     cvIntegralImage( img, sum, sqsum, tilted );
1575     normrect = cvRect( 1, 1, img->cols - 2, img->rows - 2 );
1576     CV_SUM_OFFSETS( p0, p1, p2, p3, normrect, img->cols + 1 )
1577     
1578     area = normrect.width * normrect.height;
1579     valsum = ((sum_type*) (sum->data.ptr))[p0] - ((sum_type*) (sum->data.ptr))[p1]
1580            - ((sum_type*) (sum->data.ptr))[p2] + ((sum_type*) (sum->data.ptr))[p3];
1581     valsqsum = ((sqsum_type*) (sqsum->data.ptr))[p0]
1582              - ((sqsum_type*) (sqsum->data.ptr))[p1]
1583              - ((sqsum_type*) (sqsum->data.ptr))[p2]
1584              + ((sqsum_type*) (sqsum->data.ptr))[p3];
1585
1586     /* sqrt( valsqsum / area - ( valsum / are )^2 ) * area */
1587     (*normfactor) = (float) sqrt( (double) (area * valsqsum - (double)valsum * valsum) );
1588 }
1589
1590
1591 /* consumed counter */
1592 typedef uint64 ccounter_t;
1593
1594 #define CCOUNTER_MAX CV_BIG_UINT(0xffffffffffffffff)
1595 #define CCOUNTER_SET_ZERO(cc) ((cc) = 0)
1596 #define CCOUNTER_INC(cc) ( (CCOUNTER_MAX > (cc) ) ? (++(cc)) : (CCOUNTER_MAX) )
1597 #define CCOUNTER_ADD(cc0, cc1) ( ((CCOUNTER_MAX-(cc1)) > (cc0) ) ? ((cc0) += (cc1)) : ((cc0) = CCOUNTER_MAX) )
1598 #define CCOUNTER_DIV(cc0, cc1) ( ((cc1) == 0) ? 0 : ( ((double)(cc0))/(double)(int64)(cc1) ) )
1599
1600
1601
1602 /*
1603  * icvGetHaarTrainingData
1604  *
1605  * Unified method that can now be used for vec file, bg file and bg vec file
1606  *
1607  * Fill <data> with samples, passed <cascade>
1608  */
1609 static
1610 int icvGetHaarTrainingData( CvHaarTrainingData* data, int first, int count,
1611                             CvIntHaarClassifier* cascade,
1612                             CvGetHaarTrainingDataCallback callback, void* userdata,
1613                             int* consumed, double* acceptance_ratio )
1614 {
1615     int i = 0;
1616     ccounter_t getcount = 0;
1617     ccounter_t thread_getcount = 0;
1618     ccounter_t consumed_count; 
1619     ccounter_t thread_consumed_count;
1620     
1621     /* private variables */
1622     CvMat img;
1623     CvMat sum;
1624     CvMat tilted;
1625     CvMat sqsum;
1626     
1627     sum_type* sumdata;
1628     sum_type* tilteddata;
1629     float*    normfactor;
1630     
1631     /* end private variables */
1632     
1633     assert( data != NULL );
1634     assert( first + count <= data->maxnum );
1635     assert( cascade != NULL );
1636     assert( callback != NULL );
1637     
1638     // if( !cvbgdata ) return 0; this check needs to be done in the callback for BG
1639     
1640     CCOUNTER_SET_ZERO(getcount);
1641     CCOUNTER_SET_ZERO(thread_getcount);
1642     CCOUNTER_SET_ZERO(consumed_count);
1643     CCOUNTER_SET_ZERO(thread_consumed_count);
1644
1645     #ifdef CV_OPENMP
1646     #pragma omp parallel private(img, sum, tilted, sqsum, sumdata, tilteddata, \
1647                                  normfactor, thread_consumed_count, thread_getcount)
1648     #endif /* CV_OPENMP */
1649     {
1650         sumdata    = NULL;
1651         tilteddata = NULL;
1652         normfactor = NULL;
1653
1654         CCOUNTER_SET_ZERO(thread_getcount);
1655         CCOUNTER_SET_ZERO(thread_consumed_count);
1656         int ok = 1;
1657
1658         img = cvMat( data->winsize.height, data->winsize.width, CV_8UC1,
1659             cvAlloc( sizeof( uchar ) * data->winsize.height * data->winsize.width ) );
1660         sum = cvMat( data->winsize.height + 1, data->winsize.width + 1,
1661                      CV_SUM_MAT_TYPE, NULL );
1662         tilted = cvMat( data->winsize.height + 1, data->winsize.width + 1,
1663                         CV_SUM_MAT_TYPE, NULL );
1664         sqsum = cvMat( data->winsize.height + 1, data->winsize.width + 1, CV_SQSUM_MAT_TYPE,
1665                        cvAlloc( sizeof( sqsum_type ) * (data->winsize.height + 1)
1666                                                      * (data->winsize.width + 1) ) );
1667
1668         #ifdef CV_OPENMP
1669         #pragma omp for schedule(static, 1)
1670         #endif /* CV_OPENMP */
1671         for( i = first; (i < first + count); i++ )
1672         {
1673             if( !ok )
1674                 continue;
1675             for( ; ; )
1676             {
1677                 ok = callback( &img, userdata );
1678                 if( !ok )
1679                     break;
1680
1681                 CCOUNTER_INC(thread_consumed_count);
1682
1683                 sumdata = (sum_type*) (data->sum.data.ptr + i * data->sum.step);
1684                 tilteddata = (sum_type*) (data->tilted.data.ptr + i * data->tilted.step);
1685                 normfactor = data->normfactor.data.fl + i;
1686                 sum.data.ptr = (uchar*) sumdata;
1687                 tilted.data.ptr = (uchar*) tilteddata;
1688                 icvGetAuxImages( &img, &sum, &tilted, &sqsum, normfactor );            
1689                 if( cascade->eval( cascade, sumdata, tilteddata, *normfactor ) != 0.0F )
1690                 {
1691                     CCOUNTER_INC(thread_getcount);
1692                     break;
1693                 }
1694             }
1695             
1696 #ifdef CV_VERBOSE
1697             if( (i - first) % 500 == 0 )
1698             {
1699                 fprintf( stderr, "%3d%%\r", (int) ( 100.0 * (i - first) / count ) );
1700                 fflush( stderr );
1701             }
1702 #endif /* CV_VERBOSE */
1703         }
1704
1705         cvFree( &(img.data.ptr) );
1706         cvFree( &(sqsum.data.ptr) );
1707
1708         #ifdef CV_OPENMP
1709         #pragma omp critical (c_consumed_count)
1710         #endif /* CV_OPENMP */
1711         {
1712             /* consumed_count += thread_consumed_count; */
1713             CCOUNTER_ADD(getcount, thread_getcount);
1714             CCOUNTER_ADD(consumed_count, thread_consumed_count);
1715         }
1716     } /* omp parallel */
1717     
1718     if( consumed != NULL )
1719     {
1720         *consumed = (int)consumed_count;
1721     }
1722
1723     if( acceptance_ratio != NULL )
1724     {
1725         /* *acceptance_ratio = ((double) count) / consumed_count; */
1726         *acceptance_ratio = CCOUNTER_DIV(count, consumed_count);
1727     }
1728     
1729     return static_cast<int>(getcount);
1730 }
1731
1732 /*
1733  * icvGetHaarTrainingDataFromBG
1734  *
1735  * Fill <data> with background samples, passed <cascade>
1736  * Background reading process must be initialized before call.
1737  */
1738 //static
1739 //int icvGetHaarTrainingDataFromBG( CvHaarTrainingData* data, int first, int count,
1740 //                                  CvIntHaarClassifier* cascade, double* acceptance_ratio )
1741 //{
1742 //    int i = 0;
1743 //    ccounter_t consumed_count;
1744 //    ccounter_t thread_consumed_count;
1745 //
1746 //    /* private variables */
1747 //    CvMat img;
1748 //    CvMat sum;
1749 //    CvMat tilted;
1750 //    CvMat sqsum;
1751 //
1752 //    sum_type* sumdata;
1753 //    sum_type* tilteddata;
1754 //    float*    normfactor;
1755 //
1756 //    /* end private variables */
1757 //
1758 //    assert( data != NULL );
1759 //    assert( first + count <= data->maxnum );
1760 //    assert( cascade != NULL );
1761 //
1762 //    if( !cvbgdata ) return 0;
1763 //
1764 //    CCOUNTER_SET_ZERO(consumed_count);
1765 //    CCOUNTER_SET_ZERO(thread_consumed_count);
1766 //
1767 //    #ifdef CV_OPENMP
1768 //    #pragma omp parallel private(img, sum, tilted, sqsum, sumdata, tilteddata,
1769 //                                 normfactor, thread_consumed_count)
1770 //    #endif /* CV_OPENMP */
1771 //    {
1772 //        sumdata    = NULL;
1773 //        tilteddata = NULL;
1774 //        normfactor = NULL;
1775 //
1776 //        CCOUNTER_SET_ZERO(thread_consumed_count);
1777 //
1778 //        img = cvMat( data->winsize.height, data->winsize.width, CV_8UC1,
1779 //            cvAlloc( sizeof( uchar ) * data->winsize.height * data->winsize.width ) );
1780 //        sum = cvMat( data->winsize.height + 1, data->winsize.width + 1,
1781 //                     CV_SUM_MAT_TYPE, NULL );
1782 //        tilted = cvMat( data->winsize.height + 1, data->winsize.width + 1,
1783 //                        CV_SUM_MAT_TYPE, NULL );
1784 //        sqsum = cvMat( data->winsize.height + 1, data->winsize.width + 1,
1785 //                       CV_SQSUM_MAT_TYPE,
1786 //                       cvAlloc( sizeof( sqsum_type ) * (data->winsize.height + 1)
1787 //                                                     * (data->winsize.width + 1) ) );
1788 //        
1789 //        #ifdef CV_OPENMP
1790 //        #pragma omp for schedule(static, 1)
1791 //        #endif /* CV_OPENMP */
1792 //        for( i = first; i < first + count; i++ )
1793 //        {
1794 //            for( ; ; )
1795 //            {
1796 //                icvGetBackgroundImage( cvbgdata, cvbgreader, &img );
1797 //                
1798 //                CCOUNTER_INC(thread_consumed_count);
1799 //
1800 //                sumdata = (sum_type*) (data->sum.data.ptr + i * data->sum.step);
1801 //                tilteddata = (sum_type*) (data->tilted.data.ptr + i * data->tilted.step);
1802 //                normfactor = data->normfactor.data.fl + i;
1803 //                sum.data.ptr = (uchar*) sumdata;
1804 //                tilted.data.ptr = (uchar*) tilteddata;
1805 //                icvGetAuxImages( &img, &sum, &tilted, &sqsum, normfactor );            
1806 //                if( cascade->eval( cascade, sumdata, tilteddata, *normfactor ) != 0.0F )
1807 //                {
1808 //                    break;
1809 //                }
1810 //            }
1811 //
1812 //#ifdef CV_VERBOSE
1813 //            if( (i - first) % 500 == 0 )
1814 //            {
1815 //                fprintf( stderr, "%3d%%\r", (int) ( 100.0 * (i - first) / count ) );
1816 //                fflush( stderr );
1817 //            }
1818 //#endif /* CV_VERBOSE */
1819 //            
1820 //        }
1821 //
1822 //        cvFree( &(img.data.ptr) );
1823 //        cvFree( &(sqsum.data.ptr) );
1824 //
1825 //        #ifdef CV_OPENMP
1826 //        #pragma omp critical (c_consumed_count)
1827 //        #endif /* CV_OPENMP */
1828 //        {
1829 //            /* consumed_count += thread_consumed_count; */
1830 //            CCOUNTER_ADD(consumed_count, thread_consumed_count);
1831 //        }
1832 //    } /* omp parallel */
1833 //
1834 //    if( acceptance_ratio != NULL )
1835 //    {
1836 //        /* *acceptance_ratio = ((double) count) / consumed_count; */
1837 //        *acceptance_ratio = CCOUNTER_DIV(count, consumed_count);
1838 //    }
1839 //    
1840 //    return count;
1841 //}
1842
1843 int icvGetHaarTraininDataFromVecCallback( CvMat* img, void* userdata )
1844 {
1845     uchar tmp = 0;
1846     int r = 0;
1847     int c = 0;
1848
1849     assert( img->rows * img->cols == ((CvVecFile*) userdata)->vecsize );
1850     
1851     fread( &tmp, sizeof( tmp ), 1, ((CvVecFile*) userdata)->input );
1852     fread( ((CvVecFile*) userdata)->vector, sizeof( short ),
1853            ((CvVecFile*) userdata)->vecsize, ((CvVecFile*) userdata)->input );
1854     
1855     if( feof( ((CvVecFile*) userdata)->input ) || 
1856         (((CvVecFile*) userdata)->last)++ >= ((CvVecFile*) userdata)->count )
1857     {
1858         return 0;
1859     }
1860     
1861     for( r = 0; r < img->rows; r++ )
1862     {
1863         for( c = 0; c < img->cols; c++ )
1864         {
1865             CV_MAT_ELEM( *img, uchar, r, c ) = 
1866                 (uchar) ( ((CvVecFile*) userdata)->vector[r * img->cols + c] );
1867         }
1868     }
1869
1870     return 1;
1871 }
1872
1873 int icvGetHaarTrainingDataFromBGCallback ( CvMat* img, void* /*userdata*/ )
1874 {
1875     if (! cvbgdata)
1876       return 0;
1877     
1878     if (! cvbgreader)
1879       return 0;
1880     
1881     // just in case icvGetBackgroundImage is not thread-safe ...
1882     #ifdef CV_OPENMP
1883     #pragma omp critical (get_background_image_callback)
1884     #endif /* CV_OPENMP */
1885     {
1886       icvGetBackgroundImage( cvbgdata, cvbgreader, img );
1887     }
1888     
1889     return 1;
1890 }
1891
1892 /*
1893  * icvGetHaarTrainingDataFromVec
1894  * Get training data from .vec file
1895  */
1896 static
1897 int icvGetHaarTrainingDataFromVec( CvHaarTrainingData* data, int first, int count,                                   
1898                                    CvIntHaarClassifier* cascade,
1899                                    const char* filename,
1900                                    int* consumed )
1901 {
1902     int getcount = 0;
1903
1904     CV_FUNCNAME( "icvGetHaarTrainingDataFromVec" );
1905
1906     __BEGIN__;
1907
1908     CvVecFile file;
1909     short tmp = 0;    
1910     
1911     file.input = NULL;
1912     if( filename ) file.input = fopen( filename, "rb" );
1913
1914     if( file.input != NULL )
1915     {
1916         fread( &file.count, sizeof( file.count ), 1, file.input );
1917         fread( &file.vecsize, sizeof( file.vecsize ), 1, file.input );
1918         fread( &tmp, sizeof( tmp ), 1, file.input );
1919         fread( &tmp, sizeof( tmp ), 1, file.input );
1920         if( !feof( file.input ) )
1921         {
1922             if( file.vecsize != data->winsize.width * data->winsize.height )
1923             {
1924                 fclose( file.input );
1925                 CV_ERROR( CV_StsError, "Vec file sample size mismatch" );
1926             }
1927
1928             file.last = 0;
1929             file.vector = (short*) cvAlloc( sizeof( *file.vector ) * file.vecsize );
1930             getcount = icvGetHaarTrainingData( data, first, count, cascade,
1931                 icvGetHaarTraininDataFromVecCallback, &file, consumed, NULL);
1932             cvFree( &file.vector );
1933         }
1934         fclose( file.input );
1935     }
1936
1937     __END__;
1938
1939     return getcount;
1940 }
1941
1942 /*
1943  * icvGetHaarTrainingDataFromBG
1944  *
1945  * Fill <data> with background samples, passed <cascade>
1946  * Background reading process must be initialized before call, alternaly, a file
1947  * name to a vec file may be passed, a NULL filename indicates old behaviour
1948  */
1949 static
1950 int icvGetHaarTrainingDataFromBG( CvHaarTrainingData* data, int first, int count,
1951                                   CvIntHaarClassifier* cascade, double* acceptance_ratio, const char * filename = NULL )
1952 {
1953     CV_FUNCNAME( "icvGetHaarTrainingDataFromBG" );
1954
1955     __BEGIN__;
1956
1957     if (filename)
1958     {
1959         CvVecFile file;
1960         short tmp = 0;    
1961         
1962         file.input = NULL;
1963         if( filename ) file.input = fopen( filename, "rb" );
1964
1965         if( file.input != NULL )
1966         {
1967             fread( &file.count, sizeof( file.count ), 1, file.input );
1968             fread( &file.vecsize, sizeof( file.vecsize ), 1, file.input );
1969             fread( &tmp, sizeof( tmp ), 1, file.input );
1970             fread( &tmp, sizeof( tmp ), 1, file.input );
1971             if( !feof( file.input ) )
1972             {
1973                 if( file.vecsize != data->winsize.width * data->winsize.height )
1974                 {
1975                     fclose( file.input );
1976                     CV_ERROR( CV_StsError, "Vec file sample size mismatch" );
1977                 }
1978
1979                 file.last = 0;
1980                 file.vector = (short*) cvAlloc( sizeof( *file.vector ) * file.vecsize );
1981                 icvGetHaarTrainingData( data, first, count, cascade,
1982                     icvGetHaarTraininDataFromVecCallback, &file, NULL, acceptance_ratio);
1983                 cvFree( &file.vector );
1984             }
1985             fclose( file.input );
1986         }
1987     }
1988     else
1989     {
1990         icvGetHaarTrainingData( data, first, count, cascade,
1991             icvGetHaarTrainingDataFromBGCallback, NULL, NULL, acceptance_ratio);
1992     }
1993
1994     __END__;
1995
1996     return count;
1997 }
1998
1999 void cvCreateCascadeClassifier( const char* dirname,
2000                                 const char* vecfilename,
2001                                 const char* bgfilename, 
2002                                 int npos, int nneg, int nstages,
2003                                 int numprecalculated,
2004                                 int numsplits,
2005                                 float minhitrate, float maxfalsealarm,
2006                                 float weightfraction,
2007                                 int mode, int symmetric,
2008                                 int equalweights,
2009                                 int winwidth, int winheight,
2010                                 int boosttype, int stumperror )
2011 {
2012     CvCascadeHaarClassifier* cascade = NULL;
2013     CvHaarTrainingData* data = NULL;
2014     CvIntHaarFeatures* haar_features;
2015     CvSize winsize;
2016     int i = 0;
2017     int j = 0;
2018     int poscount = 0;
2019     int negcount = 0;
2020     int consumed = 0;
2021     double false_alarm = 0;
2022     char stagename[PATH_MAX];
2023     float posweight = 1.0F;
2024     float negweight = 1.0F;
2025     FILE* file;
2026
2027 #ifdef CV_VERBOSE
2028     double proctime = 0.0F;
2029 #endif /* CV_VERBOSE */
2030
2031     assert( dirname != NULL );
2032     assert( bgfilename != NULL );
2033     assert( vecfilename != NULL );
2034     assert( nstages > 0 );
2035
2036     winsize = cvSize( winwidth, winheight );
2037
2038     cascade = (CvCascadeHaarClassifier*) icvCreateCascadeHaarClassifier( nstages );
2039     cascade->count = 0;
2040     
2041     if( icvInitBackgroundReaders( bgfilename, winsize ) )
2042     {
2043         data = icvCreateHaarTrainingData( winsize, npos + nneg );
2044         haar_features = icvCreateIntHaarFeatures( winsize, mode, symmetric );
2045
2046 #ifdef CV_VERBOSE
2047         printf("Number of features used : %d\n", haar_features->count);
2048 #endif /* CV_VERBOSE */
2049
2050         for( i = 0; i < nstages; i++, cascade->count++ )
2051         {
2052             sprintf( stagename, "%s%d/%s", dirname, i, CV_STAGE_CART_FILE_NAME );
2053             cascade->classifier[i] = 
2054                 icvLoadCARTStageHaarClassifier( stagename, winsize.width + 1 );
2055
2056             if( !icvMkDir( stagename ) )
2057             {
2058
2059 #ifdef CV_VERBOSE
2060                 printf( "UNABLE TO CREATE DIRECTORY: %s\n", stagename );
2061 #endif /* CV_VERBOSE */
2062
2063                 break;
2064             }
2065             if( cascade->classifier[i] != NULL )
2066             {
2067
2068 #ifdef CV_VERBOSE
2069                 printf( "STAGE: %d LOADED.\n", i );
2070 #endif /* CV_VERBOSE */
2071
2072                 continue;
2073             }
2074
2075 #ifdef CV_VERBOSE
2076             printf( "STAGE: %d\n", i );
2077 #endif /* CV_VERBOSE */
2078
2079             poscount = icvGetHaarTrainingDataFromVec( data, 0, npos,
2080                 (CvIntHaarClassifier*) cascade, vecfilename, &consumed );
2081 #ifdef CV_VERBOSE
2082             printf( "POS: %d %d %f\n", poscount, consumed,
2083                     ((float) poscount) / consumed );
2084 #endif /* CV_VERBOSE */
2085
2086             if( poscount <= 0 )
2087             {
2088
2089 #ifdef CV_VERBOSE
2090             printf( "UNABLE TO OBTAIN POS SAMPLES\n" );
2091 #endif /* CV_VERBOSE */
2092
2093                 break;
2094             }
2095
2096 #ifdef CV_VERBOSE
2097             proctime = -TIME( 0 );
2098 #endif /* CV_VERBOSE */
2099
2100             negcount = icvGetHaarTrainingDataFromBG( data, poscount, nneg,
2101                 (CvIntHaarClassifier*) cascade, &false_alarm );
2102 #ifdef CV_VERBOSE
2103             printf( "NEG: %d %g\n", negcount, false_alarm );
2104             printf( "BACKGROUND PROCESSING TIME: %.2f\n",
2105                 (proctime + TIME( 0 )) );
2106 #endif /* CV_VERBOSE */
2107
2108             if( negcount <= 0 )
2109             {
2110
2111 #ifdef CV_VERBOSE
2112             printf( "UNABLE TO OBTAIN NEG SAMPLES\n" );
2113 #endif /* CV_VERBOSE */
2114
2115                 break;
2116             }
2117
2118             data->sum.rows = data->tilted.rows = poscount + negcount;
2119             data->normfactor.cols = data->weights.cols = data->cls.cols =
2120                     poscount + negcount;
2121         
2122             posweight = (equalweights) ? 1.0F / (poscount + negcount) : (0.5F / poscount);
2123             negweight = (equalweights) ? 1.0F / (poscount + negcount) : (0.5F / negcount);
2124             for( j = 0; j < poscount; j++ )
2125             {
2126                 data->weights.data.fl[j] = posweight;
2127                 data->cls.data.fl[j] = 1.0F;
2128
2129             }
2130             for( j = poscount; j < poscount + negcount; j++ )
2131             {
2132                 data->weights.data.fl[j] = negweight;
2133                 data->cls.data.fl[j] = 0.0F;
2134             }
2135
2136 #ifdef CV_VERBOSE
2137             proctime = -TIME( 0 );
2138 #endif /* CV_VERBOSE */
2139
2140             icvPrecalculate( data, haar_features, numprecalculated );
2141
2142 #ifdef CV_VERBOSE
2143             printf( "PRECALCULATION TIME: %.2f\n", (proctime + TIME( 0 )) );
2144 #endif /* CV_VERBOSE */
2145
2146 #ifdef CV_VERBOSE
2147             proctime = -TIME( 0 );
2148 #endif /* CV_VERBOSE */
2149
2150             cascade->classifier[i] = icvCreateCARTStageClassifier(  data, NULL,
2151                 haar_features, minhitrate, maxfalsealarm, symmetric, weightfraction,
2152                 numsplits, (CvBoostType) boosttype, (CvStumpError) stumperror, 0 );
2153
2154 #ifdef CV_VERBOSE
2155             printf( "STAGE TRAINING TIME: %.2f\n", (proctime + TIME( 0 )) );
2156 #endif /* CV_VERBOSE */
2157
2158             file = fopen( stagename, "w" );
2159             if( file != NULL )
2160             {
2161                 cascade->classifier[i]->save( 
2162                     (CvIntHaarClassifier*) cascade->classifier[i], file );
2163                 fclose( file );
2164             }
2165             else
2166             {
2167
2168 #ifdef CV_VERBOSE
2169                 printf( "FAILED TO SAVE STAGE CLASSIFIER IN FILE %s\n", stagename );
2170 #endif /* CV_VERBOSE */
2171
2172             }
2173
2174         }
2175         icvReleaseIntHaarFeatures( &haar_features );
2176         icvReleaseHaarTrainingData( &data );
2177
2178         if( i == nstages )
2179         {
2180             char xml_path[1024];
2181             int len = (int)strlen(dirname);
2182             CvHaarClassifierCascade* cascade = 0;
2183             strcpy( xml_path, dirname );
2184             if( xml_path[len-1] == '\\' || xml_path[len-1] == '/' )
2185                 len--;
2186             strcpy( xml_path + len, ".xml" );
2187             cascade = cvLoadHaarClassifierCascade( dirname, cvSize(winwidth,winheight) );
2188             if( cascade )
2189                 cvSave( xml_path, cascade );
2190             cvReleaseHaarClassifierCascade( &cascade );
2191         }
2192     }
2193     else
2194     {
2195 #ifdef CV_VERBOSE
2196         printf( "FAILED TO INITIALIZE BACKGROUND READERS\n" );
2197 #endif /* CV_VERBOSE */
2198     }
2199     
2200     /* CLEAN UP */
2201     icvDestroyBackgroundReaders();
2202     cascade->release( (CvIntHaarClassifier**) &cascade );
2203 }
2204
2205 /* tree cascade classifier */
2206
2207 int icvNumSplits( CvStageHaarClassifier* stage )
2208 {
2209     int i;
2210     int num;
2211
2212     num = 0;
2213     for( i = 0; i < stage->count; i++ )
2214     {
2215         num += ((CvCARTHaarClassifier*) stage->classifier[i])->count;
2216     }
2217
2218     return num;
2219 }
2220
2221 void icvSetNumSamples( CvHaarTrainingData* training_data, int num )
2222 {
2223     assert( num <= training_data->maxnum );
2224
2225     training_data->sum.rows = training_data->tilted.rows = num;
2226     training_data->normfactor.cols = num;
2227     training_data->cls.cols = training_data->weights.cols = num;
2228 }
2229
2230 void icvSetWeightsAndClasses( CvHaarTrainingData* training_data,
2231                               int num1, float weight1, float cls1,
2232                               int num2, float weight2, float cls2 )
2233 {
2234     int j;
2235
2236     assert( num1 + num2 <= training_data->maxnum );
2237
2238     for( j = 0; j < num1; j++ )
2239     {
2240         training_data->weights.data.fl[j] = weight1;
2241         training_data->cls.data.fl[j] = cls1;
2242     }
2243     for( j = num1; j < num1 + num2; j++ )
2244     {
2245         training_data->weights.data.fl[j] = weight2;
2246         training_data->cls.data.fl[j] = cls2;
2247     }
2248 }
2249
2250 CvMat* icvGetUsedValues( CvHaarTrainingData* training_data,
2251                          int start, int num,
2252                          CvIntHaarFeatures* haar_features,
2253                          CvStageHaarClassifier* stage )
2254 {
2255     CvMat* ptr = NULL;
2256     CvMat* feature_idx = NULL;
2257
2258     CV_FUNCNAME( "icvGetUsedValues" );
2259
2260     __BEGIN__;
2261
2262     int num_splits;
2263     int i, j;
2264     int r;
2265     int total, last;
2266
2267     num_splits = icvNumSplits( stage );
2268
2269     CV_CALL( feature_idx = cvCreateMat( 1, num_splits, CV_32SC1 ) );
2270
2271     total = 0;
2272     for( i = 0; i < stage->count; i++ )
2273     {
2274         CvCARTHaarClassifier* cart;
2275
2276         cart = (CvCARTHaarClassifier*) stage->classifier[i];
2277         for( j = 0; j < cart->count; j++ )
2278         {
2279             feature_idx->data.i[total++] = cart->compidx[j];
2280         }
2281     }
2282     icvSort_32s( feature_idx->data.i, total, 0 );
2283
2284     last = 0;
2285     for( i = 1; i < total; i++ )
2286     {
2287         if( feature_idx->data.i[i] != feature_idx->data.i[last] )
2288         {
2289             feature_idx->data.i[++last] = feature_idx->data.i[i];
2290         }
2291     }
2292     total = last + 1;
2293     CV_CALL( ptr = cvCreateMat( num, total, CV_32FC1 ) );
2294     
2295
2296     #ifdef CV_OPENMP
2297     #pragma omp parallel for
2298     #endif
2299     for( r = start; r < start + num; r++ )
2300     {
2301         int c;
2302
2303         for( c = 0; c < total; c++ )
2304         {
2305             float val, normfactor;
2306             int fnum;
2307
2308             fnum = feature_idx->data.i[c];
2309
2310             val = cvEvalFastHaarFeature( haar_features->fastfeature + fnum,
2311                 (sum_type*) (training_data->sum.data.ptr
2312                         + r * training_data->sum.step),
2313                 (sum_type*) (training_data->tilted.data.ptr
2314                         + r * training_data->tilted.step) );
2315             normfactor = training_data->normfactor.data.fl[r];
2316             val = ( normfactor == 0.0F ) ? 0.0F : (val / normfactor);
2317             CV_MAT_ELEM( *ptr, float, r - start, c ) = val;
2318         }
2319     }
2320
2321     __END__;
2322
2323     cvReleaseMat( &feature_idx );
2324
2325     return ptr;
2326 }
2327
2328 /* possible split in the tree */
2329 typedef struct CvSplit
2330 {
2331     CvTreeCascadeNode* parent;
2332     CvTreeCascadeNode* single_cluster;
2333     CvTreeCascadeNode* multiple_clusters;
2334     int num_clusters;
2335     float single_multiple_ratio;
2336
2337     struct CvSplit* next;
2338 } CvSplit;
2339
2340
2341 void cvCreateTreeCascadeClassifier( const char* dirname,
2342                                     const char* vecfilename,
2343                                     const char* bgfilename, 
2344                                     int npos, int nneg, int nstages,
2345                                     int numprecalculated,
2346                                     int numsplits,
2347                                     float minhitrate, float maxfalsealarm,
2348                                     float weightfraction,
2349                                     int mode, int symmetric,
2350                                     int equalweights,
2351                                     int winwidth, int winheight,
2352                                     int boosttype, int stumperror,
2353                                     int maxtreesplits, int minpos, bool bg_vecfile )
2354 {
2355     CvTreeCascadeClassifier* tcc = NULL;
2356     CvIntHaarFeatures* haar_features = NULL;
2357     CvHaarTrainingData* training_data = NULL;
2358     CvMat* vals = NULL;
2359     CvMat* cluster_idx = NULL;
2360     CvMat* idx = NULL;
2361     CvMat* features_idx = NULL;
2362
2363     CV_FUNCNAME( "cvCreateTreeCascadeClassifier" );
2364
2365     __BEGIN__;
2366
2367     int i, k;
2368     CvTreeCascadeNode* leaves;
2369     int best_num, cur_num;
2370     CvSize winsize;
2371     char stage_name[PATH_MAX];
2372     char buf[PATH_MAX];
2373     char* suffix;
2374     int total_splits;
2375
2376     int poscount;
2377     int negcount;
2378     int consumed;
2379     double false_alarm;
2380     double proctime;
2381
2382     int nleaves;
2383     double required_leaf_fa_rate;
2384     float neg_ratio;
2385
2386     int max_clusters;
2387
2388     max_clusters = CV_MAX_CLUSTERS;
2389     neg_ratio = (float) nneg / npos;
2390
2391     nleaves = 1 + MAX( 0, maxtreesplits );
2392     required_leaf_fa_rate = pow( (double) maxfalsealarm, (double) nstages ) / nleaves;
2393
2394     printf( "Required leaf false alarm rate: %g\n", required_leaf_fa_rate );
2395
2396     total_splits = 0;
2397
2398     winsize = cvSize( winwidth, winheight );
2399
2400     CV_CALL( cluster_idx = cvCreateMat( 1, npos + nneg, CV_32SC1 ) );
2401     CV_CALL( idx = cvCreateMat( 1, npos + nneg, CV_32SC1 ) );
2402
2403     CV_CALL( tcc = (CvTreeCascadeClassifier*)
2404         icvLoadTreeCascadeClassifier( dirname, winwidth + 1, &total_splits ) );
2405     CV_CALL( leaves = icvFindDeepestLeaves( tcc ) );
2406
2407     CV_CALL( icvPrintTreeCascade( tcc->root ) );
2408
2409     haar_features = icvCreateIntHaarFeatures( winsize, mode, symmetric );
2410
2411     printf( "Number of features used : %d\n", haar_features->count );
2412
2413     training_data = icvCreateHaarTrainingData( winsize, npos + nneg );
2414
2415     sprintf( stage_name, "%s/", dirname );
2416     suffix = stage_name + strlen( stage_name );
2417     
2418     if (! bg_vecfile)
2419       if( !icvInitBackgroundReaders( bgfilename, winsize ) && nstages > 0 )
2420           CV_ERROR( CV_StsError, "Unable to read negative images" );
2421     
2422     if( nstages > 0 )
2423     {
2424         /* width-first search in the tree */
2425         do
2426         {
2427             CvSplit* first_split;
2428             CvSplit* last_split;
2429             CvSplit* cur_split;
2430             
2431             CvTreeCascadeNode* parent;
2432             CvTreeCascadeNode* cur_node;
2433             CvTreeCascadeNode* last_node;
2434
2435             first_split = last_split = cur_split = NULL;
2436             parent = leaves;
2437             leaves = NULL;
2438             do
2439             {                
2440                 int best_clusters; /* best selected number of clusters */
2441                 float posweight, negweight;
2442                 double leaf_fa_rate;
2443
2444                 if( parent ) sprintf( buf, "%d", parent->idx );
2445                 else sprintf( buf, "NULL" );
2446                 printf( "\nParent node: %s\n\n", buf );
2447
2448                 printf( "*** 1 cluster ***\n" );
2449
2450                 tcc->eval = icvEvalTreeCascadeClassifierFilter;
2451                 /* find path from the root to the node <parent> */
2452                 icvSetLeafNode( tcc, parent );
2453
2454                 /* load samples */
2455                 consumed = 0;
2456                 poscount = icvGetHaarTrainingDataFromVec( training_data, 0, npos,
2457                     (CvIntHaarClassifier*) tcc, vecfilename, &consumed );
2458
2459                 printf( "POS: %d %d %f\n", poscount, consumed, ((double) poscount)/consumed );
2460
2461                 if( poscount <= 0 )
2462                     CV_ERROR( CV_StsError, "Unable to obtain positive samples" );
2463
2464                 fflush( stdout );
2465
2466                 proctime = -TIME( 0 );
2467
2468                 nneg = (int) (neg_ratio * poscount);
2469                 negcount = icvGetHaarTrainingDataFromBG( training_data, poscount, nneg,
2470                     (CvIntHaarClassifier*) tcc, &false_alarm, bg_vecfile ? bgfilename : NULL );
2471                 printf( "NEG: %d %g\n", negcount, false_alarm );
2472
2473                 printf( "BACKGROUND PROCESSING TIME: %.2f\n", (proctime + TIME( 0 )) );
2474
2475                 if( negcount <= 0 )
2476                     CV_ERROR( CV_StsError, "Unable to obtain negative samples" );
2477
2478                 leaf_fa_rate = false_alarm;
2479                 if( leaf_fa_rate <= required_leaf_fa_rate )
2480                 {
2481                     printf( "Required leaf false alarm rate achieved. "
2482                             "Branch training terminated.\n" );
2483                 }
2484                 else if( nleaves == 1 && tcc->next_idx == nstages )
2485                 {
2486                     printf( "Required number of stages achieved. "
2487                             "Branch training terminated.\n" );
2488                 }
2489                 else
2490                 {
2491                     CvTreeCascadeNode* single_cluster;
2492                     CvTreeCascadeNode* multiple_clusters;
2493                     CvSplit* cur_split;
2494                     int single_num;
2495
2496                     icvSetNumSamples( training_data, poscount + negcount );
2497                     posweight = (equalweights) ? 1.0F / (poscount + negcount) : (0.5F/poscount);
2498                     negweight = (equalweights) ? 1.0F / (poscount + negcount) : (0.5F/negcount);
2499                     icvSetWeightsAndClasses( training_data,
2500                         poscount, posweight, 1.0F, negcount, negweight, 0.0F );
2501
2502                     fflush( stdout );
2503
2504                     /* precalculate feature values */
2505                     proctime = -TIME( 0 );
2506                     icvPrecalculate( training_data, haar_features, numprecalculated );
2507                     printf( "Precalculation time: %.2f\n", (proctime + TIME( 0 )) );
2508
2509                     /* train stage classifier using all positive samples */
2510                     CV_CALL( single_cluster = icvCreateTreeCascadeNode() );
2511                     fflush( stdout );
2512
2513                     proctime = -TIME( 0 );
2514                     single_cluster->stage =
2515                         (CvStageHaarClassifier*) icvCreateCARTStageClassifier(
2516                             training_data, NULL, haar_features,
2517                             minhitrate, maxfalsealarm, symmetric,
2518                             weightfraction, numsplits, (CvBoostType) boosttype,
2519                             (CvStumpError) stumperror, 0 );
2520                     printf( "Stage training time: %.2f\n", (proctime + TIME( 0 )) );
2521
2522                     single_num = icvNumSplits( single_cluster->stage );
2523                     best_num = single_num;
2524                     best_clusters = 1;
2525                     multiple_clusters = NULL;
2526
2527                     printf( "Number of used features: %d\n", single_num );
2528                     
2529                     if( maxtreesplits >= 0 )
2530                     {
2531                         max_clusters = MIN( max_clusters, maxtreesplits - total_splits + 1 );
2532                     }
2533
2534                     /* try clustering */
2535                     vals = NULL;
2536                     for( k = 2; k <= max_clusters; k++ )
2537                     {
2538                         int cluster;
2539                         int stop_clustering;
2540
2541                         printf( "*** %d clusters ***\n", k );
2542
2543                         /* check whether clusters are big enough */
2544                         stop_clustering = ( k * minpos > poscount );
2545                         if( !stop_clustering )
2546                         {
2547                             int num[CV_MAX_CLUSTERS];
2548
2549                             if( k == 2 )
2550                             {
2551                                 proctime = -TIME( 0 );
2552                                 CV_CALL( vals = icvGetUsedValues( training_data, 0, poscount,
2553                                     haar_features, single_cluster->stage ) );
2554                                 printf( "Getting values for clustering time: %.2f\n", (proctime + TIME(0)) );
2555                                 printf( "Value matirx size: %d x %d\n", vals->rows, vals->cols );
2556                                 fflush( stdout );
2557
2558                                 cluster_idx->cols = vals->rows;
2559                                 for( i = 0; i < negcount; i++ ) idx->data.i[i] = poscount + i;
2560                             }
2561
2562                             proctime = -TIME( 0 );
2563
2564                             CV_CALL( cvKMeans2( vals, k, cluster_idx, CV_TERM_CRITERIA() ) );
2565
2566                             printf( "Clustering time: %.2f\n", (proctime + TIME( 0 )) );
2567
2568                             for( cluster = 0; cluster < k; cluster++ ) num[cluster] = 0;
2569                             for( i = 0; i < cluster_idx->cols; i++ )
2570                                 num[cluster_idx->data.i[i]]++;
2571                             for( cluster = 0; cluster < k; cluster++ )
2572                             {
2573                                 if( num[cluster] < minpos )
2574                                 {
2575                                     stop_clustering = 1;
2576                                     break;
2577                                 }
2578                             }
2579                         }
2580
2581                         if( stop_clustering )
2582                         {
2583                             printf( "Clusters are too small. Clustering aborted.\n" );
2584                             break;
2585                         }
2586                         
2587                         cur_num = 0;
2588                         cur_node = last_node = NULL;
2589                         for( cluster = 0; (cluster < k) && (cur_num < best_num); cluster++ )
2590                         {
2591                             CvTreeCascadeNode* new_node;
2592
2593                             int num_splits;
2594                             int last_pos;
2595                             int total_pos;
2596
2597                             printf( "Cluster: %d\n", cluster );
2598
2599                             last_pos = negcount;
2600                             for( i = 0; i < cluster_idx->cols; i++ )
2601                             {
2602                                 if( cluster_idx->data.i[i] == cluster )
2603                                 {
2604                                     idx->data.i[last_pos++] = i;
2605                                 }
2606                             }
2607                             idx->cols = last_pos;
2608
2609                             total_pos = idx->cols - negcount;
2610                             printf( "# pos: %d of %d. (%d%%)\n", total_pos, poscount,
2611                                 100 * total_pos / poscount );
2612
2613                             CV_CALL( new_node = icvCreateTreeCascadeNode() );
2614                             if( last_node ) last_node->next = new_node;
2615                             else cur_node = new_node;
2616                             last_node = new_node;
2617
2618                             posweight = (equalweights)
2619                                 ? 1.0F / (total_pos + negcount) : (0.5F / total_pos);
2620                             negweight = (equalweights)
2621                                 ? 1.0F / (total_pos + negcount) : (0.5F / negcount);
2622
2623                             icvSetWeightsAndClasses( training_data,
2624                                 poscount, posweight, 1.0F, negcount, negweight, 0.0F );
2625
2626                             /* CV_DEBUG_SAVE( idx ); */
2627
2628                             fflush( stdout );
2629
2630                             proctime = -TIME( 0 );
2631                             new_node->stage = (CvStageHaarClassifier*)
2632                                 icvCreateCARTStageClassifier( training_data, idx, haar_features,
2633                                     minhitrate, maxfalsealarm, symmetric,
2634                                     weightfraction, numsplits, (CvBoostType) boosttype,
2635                                     (CvStumpError) stumperror, best_num - cur_num );
2636                             printf( "Stage training time: %.2f\n", (proctime + TIME( 0 )) );
2637
2638                             if( !(new_node->stage) )
2639                             {
2640                                 printf( "Stage training aborted.\n" );
2641                                 cur_num = best_num + 1;
2642                             }
2643                             else
2644                             {
2645                                 num_splits = icvNumSplits( new_node->stage );
2646                                 cur_num += num_splits;
2647
2648                                 printf( "Number of used features: %d\n", num_splits );
2649                             }
2650                         } /* for each cluster */
2651
2652                         if( cur_num < best_num )
2653                         {
2654                             icvReleaseTreeCascadeNodes( &multiple_clusters );
2655                             best_num = cur_num;
2656                             best_clusters = k;
2657                             multiple_clusters = cur_node;
2658                         }
2659                         else
2660                         {
2661                             icvReleaseTreeCascadeNodes( &cur_node );
2662                         }
2663                     } /* try different number of clusters */
2664                     cvReleaseMat( &vals );
2665
2666                     CV_CALL( cur_split = (CvSplit*) cvAlloc( sizeof( *cur_split ) ) );
2667                     CV_ZERO_OBJ( cur_split );
2668                     
2669                     if( last_split ) last_split->next = cur_split;
2670                     else first_split = cur_split;
2671                     last_split = cur_split;
2672
2673                     cur_split->single_cluster = single_cluster;
2674                     cur_split->multiple_clusters = multiple_clusters;
2675                     cur_split->num_clusters = best_clusters;
2676                     cur_split->parent = parent;
2677                     cur_split->single_multiple_ratio = (float) single_num / best_num;
2678                 }
2679
2680                 if( parent ) parent = parent->next_same_level;
2681             } while( parent );
2682
2683             /* choose which nodes should be splitted */
2684             do
2685             {
2686                 float max_single_multiple_ratio;
2687
2688                 cur_split = NULL;
2689                 max_single_multiple_ratio = 0.0F;
2690                 last_split = first_split;
2691                 while( last_split )
2692                 {
2693                     if( last_split->single_cluster && last_split->multiple_clusters &&
2694                         last_split->single_multiple_ratio > max_single_multiple_ratio )
2695                     {
2696                         max_single_multiple_ratio = last_split->single_multiple_ratio;
2697                         cur_split = last_split;
2698                     }
2699                     last_split = last_split->next;
2700                 }
2701                 if( cur_split )
2702                 {
2703                     if( maxtreesplits < 0 ||
2704                         cur_split->num_clusters <= maxtreesplits - total_splits + 1 )
2705                     {
2706                         cur_split->single_cluster = NULL;
2707                         total_splits += cur_split->num_clusters - 1;
2708                     }
2709                     else
2710                     {
2711                         icvReleaseTreeCascadeNodes( &(cur_split->multiple_clusters) );
2712                         cur_split->multiple_clusters = NULL;
2713                     }
2714                 }
2715             } while( cur_split );
2716
2717             /* attach new nodes to the tree */
2718             leaves = last_node = NULL;
2719             last_split = first_split;
2720             while( last_split )
2721             {
2722                 cur_node = (last_split->multiple_clusters)
2723                     ? last_split->multiple_clusters : last_split->single_cluster;
2724                 parent = last_split->parent;
2725                 if( parent ) parent->child = cur_node;
2726                 
2727                 /* connect leaves via next_same_level and save them */
2728                 for( ; cur_node; cur_node = cur_node->next )
2729                 {
2730                     FILE* file;
2731
2732                     if( last_node ) last_node->next_same_level = cur_node;
2733                     else leaves = cur_node;
2734                     last_node = cur_node;
2735                     cur_node->parent = parent;
2736
2737                     cur_node->idx = tcc->next_idx;
2738                     tcc->next_idx++;
2739                     sprintf( suffix, "%d/%s", cur_node->idx, CV_STAGE_CART_FILE_NAME );
2740                     file = NULL;
2741                     if( icvMkDir( stage_name ) && (file = fopen( stage_name, "w" )) != 0 )
2742                     {
2743                         cur_node->stage->save( (CvIntHaarClassifier*) cur_node->stage, file );
2744                         fprintf( file, "\n%d\n%d\n",
2745                             ((parent) ? parent->idx : -1),
2746                             ((cur_node->next) ? tcc->next_idx : -1) );
2747                     }
2748                     else
2749                     {
2750                         printf( "Failed to save classifier into %s\n", stage_name );
2751                     }
2752                     if( file ) fclose( file );
2753                 }
2754
2755                 if( parent ) sprintf( buf, "%d", parent->idx );
2756                 else sprintf( buf, "NULL" );
2757                 printf( "\nParent node: %s\n", buf );
2758                 printf( "Chosen number of splits: %d\n\n", (last_split->multiple_clusters)
2759                     ? (last_split->num_clusters - 1) : 0 );
2760                 
2761                 cur_split = last_split;
2762                 last_split = last_split->next;
2763                 cvFree( &cur_split );
2764             } /* for each split point */
2765
2766             printf( "Total number of splits: %d\n", total_splits );
2767             
2768             if( !(tcc->root) ) tcc->root = leaves;
2769             CV_CALL( icvPrintTreeCascade( tcc->root ) );
2770
2771         } while( leaves );
2772
2773         /* save the cascade to xml file */
2774         {
2775             char xml_path[1024];
2776             int len = (int)strlen(dirname);
2777             CvHaarClassifierCascade* cascade = 0;
2778             strcpy( xml_path, dirname );
2779             if( xml_path[len-1] == '\\' || xml_path[len-1] == '/' )
2780                 len--;
2781             strcpy( xml_path + len, ".xml" );
2782             cascade = cvLoadHaarClassifierCascade( dirname, cvSize(winwidth,winheight) );
2783             if( cascade )
2784                 cvSave( xml_path, cascade );
2785             cvReleaseHaarClassifierCascade( &cascade );
2786         }
2787
2788     } /* if( nstages > 0 ) */
2789
2790     /* check cascade performance */
2791     printf( "\nCascade performance\n" );
2792
2793     tcc->eval = icvEvalTreeCascadeClassifier;
2794
2795     /* load samples */
2796     consumed = 0;
2797     poscount = icvGetHaarTrainingDataFromVec( training_data, 0, npos,
2798         (CvIntHaarClassifier*) tcc, vecfilename, &consumed );
2799
2800     printf( "POS: %d %d %f\n", poscount, consumed,
2801         (consumed > 0) ? (((float) poscount)/consumed) : 0 );
2802
2803     if( poscount <= 0 )
2804         fprintf( stderr, "Warning: unable to obtain positive samples\n" );
2805
2806     proctime = -TIME( 0 );
2807
2808     negcount = icvGetHaarTrainingDataFromBG( training_data, poscount, nneg,
2809         (CvIntHaarClassifier*) tcc, &false_alarm, bg_vecfile ? bgfilename : NULL );
2810
2811     printf( "NEG: %d %g\n", negcount, false_alarm );
2812
2813     printf( "BACKGROUND PROCESSING TIME: %.2f\n", (proctime + TIME( 0 )) );
2814
2815     if( negcount <= 0 )
2816         fprintf( stderr, "Warning: unable to obtain negative samples\n" );
2817
2818     __END__;
2819
2820     if (! bg_vecfile)
2821       icvDestroyBackgroundReaders();
2822
2823     if( tcc ) tcc->release( (CvIntHaarClassifier**) &tcc );
2824     icvReleaseIntHaarFeatures( &haar_features );
2825     icvReleaseHaarTrainingData( &training_data );
2826     cvReleaseMat( &cluster_idx );
2827     cvReleaseMat( &idx );
2828     cvReleaseMat( &vals );
2829     cvReleaseMat( &features_idx );
2830 }
2831
2832
2833
2834 void cvCreateTrainingSamples( const char* filename,
2835                               const char* imgfilename, int bgcolor, int bgthreshold,
2836                               const char* bgfilename, int count,
2837                               int invert, int maxintensitydev,
2838                               double maxxangle, double maxyangle, double maxzangle,
2839                               int showsamples,
2840                               int winwidth, int winheight )
2841 {
2842     CvSampleDistortionData data;
2843
2844     assert( filename != NULL );
2845     assert( imgfilename != NULL );
2846
2847     if( !icvMkDir( filename ) )
2848     {
2849         fprintf( stderr, "Unable to create output file: %s\n", filename );
2850         return;
2851     }
2852     if( icvStartSampleDistortion( imgfilename, bgcolor, bgthreshold, &data ) )
2853     {
2854         FILE* output = NULL;
2855
2856         output = fopen( filename, "wb" );
2857         if( output != NULL )
2858         {
2859             int hasbg;
2860             int i;
2861             CvMat sample;
2862             int inverse;
2863
2864             hasbg = 0;
2865             hasbg = (bgfilename != NULL && icvInitBackgroundReaders( bgfilename,
2866                      cvSize( winwidth,winheight ) ) );
2867
2868             sample = cvMat( winheight, winwidth, CV_8UC1, cvAlloc( sizeof( uchar ) *
2869                             winheight * winwidth ) );
2870
2871             icvWriteVecHeader( output, count, sample.cols, sample.rows );
2872
2873             if( showsamples )
2874             {
2875                 cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
2876             }
2877
2878             inverse = invert;
2879             for( i = 0; i < count; i++ )
2880             {
2881                 if( hasbg )
2882                 {
2883                     icvGetBackgroundImage( cvbgdata, cvbgreader, &sample );
2884                 }
2885                 else
2886                 {
2887                     cvSet( &sample, cvScalar( bgcolor ) );
2888                 }
2889
2890                 if( invert == CV_RANDOM_INVERT )
2891                 {
2892                     inverse = (rand() > (RAND_MAX/2));
2893                 }
2894                 icvPlaceDistortedSample( &sample, inverse, maxintensitydev,
2895                     maxxangle, maxyangle, maxzangle, 
2896                     0   /* nonzero means placing image without cut offs */,
2897                     0.0 /* nozero adds random shifting                  */,
2898                     0.0 /* nozero adds random scaling                   */,
2899                     &data );
2900
2901                 if( showsamples )
2902                 {
2903                     cvShowImage( "Sample", &sample );
2904                     if( cvWaitKey( 0 ) == 27 )
2905                     {
2906                         showsamples = 0;
2907                     }
2908                 }
2909
2910                 icvWriteVecSample( output, &sample );
2911
2912 #ifdef CV_VERBOSE
2913                 if( i % 500 == 0 )
2914                 {
2915                     printf( "\r%3d%%", 100 * i / count );
2916                 }
2917 #endif /* CV_VERBOSE */
2918             }
2919             icvDestroyBackgroundReaders();
2920             cvFree( &(sample.data.ptr) );
2921             fclose( output );
2922         } /* if( output != NULL ) */
2923         
2924         icvEndSampleDistortion( &data );
2925     }
2926     
2927 #ifdef CV_VERBOSE
2928     printf( "\r      \r" );
2929 #endif /* CV_VERBOSE */ 
2930
2931 }
2932
2933 #define CV_INFO_FILENAME "info.dat"
2934
2935
2936 void cvCreateTestSamples( const char* infoname,
2937                           const char* imgfilename, int bgcolor, int bgthreshold,
2938                           const char* bgfilename, int count,
2939                           int invert, int maxintensitydev,
2940                           double maxxangle, double maxyangle, double maxzangle,
2941                           int showsamples,
2942                           int winwidth, int winheight )
2943 {
2944     CvSampleDistortionData data;
2945
2946     assert( infoname != NULL );
2947     assert( imgfilename != NULL );
2948     assert( bgfilename != NULL );
2949
2950     if( !icvMkDir( infoname ) )
2951     {
2952
2953 #if CV_VERBOSE
2954         fprintf( stderr, "Unable to create directory hierarchy: %s\n", infoname );
2955 #endif /* CV_VERBOSE */
2956
2957         return;
2958     }
2959     if( icvStartSampleDistortion( imgfilename, bgcolor, bgthreshold, &data ) )
2960     {
2961         char fullname[PATH_MAX];
2962         char* filename;
2963         CvMat win;
2964         FILE* info;
2965
2966         if( icvInitBackgroundReaders( bgfilename, cvSize( 10, 10 ) ) )
2967         {
2968             int i;
2969             int x, y, width, height;
2970             float scale;
2971             float maxscale;
2972             int inverse;
2973
2974             if( showsamples )
2975             {
2976                 cvNamedWindow( "Image", CV_WINDOW_AUTOSIZE );
2977             }
2978             
2979             info = fopen( infoname, "w" );
2980             strcpy( fullname, infoname );
2981             filename = strrchr( fullname, '\\' );
2982             if( filename == NULL )
2983             {
2984                 filename = strrchr( fullname, '/' );
2985             }
2986             if( filename == NULL )
2987             {
2988                 filename = fullname;
2989             }
2990             else
2991             {
2992                 filename++;
2993             }
2994
2995             count = MIN( count, cvbgdata->count );
2996             inverse = invert;
2997             for( i = 0; i < count; i++ )
2998             {
2999                 icvGetNextFromBackgroundData( cvbgdata, cvbgreader );
3000                 
3001                 maxscale = MIN( 0.7F * cvbgreader->src.cols / winwidth,
3002                                    0.7F * cvbgreader->src.rows / winheight );
3003                 if( maxscale < 1.0F ) continue;
3004
3005                 scale = (maxscale - 1.0F) * rand() / RAND_MAX + 1.0F;
3006                 width = (int) (scale * winwidth);
3007                 height = (int) (scale * winheight);
3008                 x = (int) ((0.1+0.8 * rand()/RAND_MAX) * (cvbgreader->src.cols - width));
3009                 y = (int) ((0.1+0.8 * rand()/RAND_MAX) * (cvbgreader->src.rows - height));
3010
3011                 cvGetSubArr( &cvbgreader->src, &win, cvRect( x, y ,width, height ) );
3012                 if( invert == CV_RANDOM_INVERT )
3013                 {
3014                     inverse = (rand() > (RAND_MAX/2));
3015                 }
3016                 icvPlaceDistortedSample( &win, inverse, maxintensitydev,
3017                                          maxxangle, maxyangle, maxzangle, 
3018                                          1, 0.0, 0.0, &data );
3019                 
3020                 
3021                 sprintf( filename, "%04d_%04d_%04d_%04d_%04d.jpg",
3022                          (i + 1), x, y, width, height );
3023                 
3024                 if( info ) 
3025                 {
3026                     fprintf( info, "%s %d %d %d %d %d\n",
3027                         filename, 1, x, y, width, height );
3028                 }
3029
3030                 cvSaveImage( fullname, &cvbgreader->src );
3031                 if( showsamples )
3032                 {
3033                     cvShowImage( "Image", &cvbgreader->src );
3034                     if( cvWaitKey( 0 ) == 27 )
3035                     {
3036                         showsamples = 0;
3037                     }
3038                 }
3039             }
3040             if( info ) fclose( info );
3041             icvDestroyBackgroundReaders();
3042         }
3043         icvEndSampleDistortion( &data );
3044     }
3045 }
3046
3047
3048 /* End of file. */