f21797612805079f46b5c214bc813e23af0434b2
[platform/upstream/opencv.git] / apps / haartraining / cvhaarclassifier.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  * cvhaarclassifier.cpp
44  *
45  * haar classifiers (stump, CART, stage, cascade)
46  */
47
48 #include "_cvhaartraining.h"
49
50
51 CvIntHaarClassifier* icvCreateCARTHaarClassifier( int count )
52 {
53     CvCARTHaarClassifier* cart;
54     size_t datasize;
55
56     datasize = sizeof( *cart ) +
57         ( sizeof( int ) +
58           sizeof( CvTHaarFeature ) + sizeof( CvFastHaarFeature ) +
59           sizeof( float ) + sizeof( int ) + sizeof( int ) ) * count +
60         sizeof( float ) * (count + 1);
61
62     cart = (CvCARTHaarClassifier*) cvAlloc( datasize );
63     memset( cart, 0, datasize );
64
65     cart->feature = (CvTHaarFeature*) (cart + 1);
66     cart->fastfeature = (CvFastHaarFeature*) (cart->feature + count);
67     cart->threshold = (float*) (cart->fastfeature + count);
68     cart->left = (int*) (cart->threshold + count);
69     cart->right = (int*) (cart->left + count);
70     cart->val = (float*) (cart->right + count);
71     cart->compidx = (int*) (cart->val + count + 1 );
72     cart->count = count;
73     cart->eval = icvEvalCARTHaarClassifier;
74     cart->save = icvSaveCARTHaarClassifier;
75     cart->release = icvReleaseHaarClassifier;
76
77     return (CvIntHaarClassifier*) cart;
78 }
79
80
81 void icvReleaseHaarClassifier( CvIntHaarClassifier** classifier )
82 {
83     cvFree( classifier );
84     *classifier = NULL;
85 }
86
87
88 void icvInitCARTHaarClassifier( CvCARTHaarClassifier* carthaar, CvCARTClassifier* cart,
89                                 CvIntHaarFeatures* intHaarFeatures )
90 {
91     int i;
92
93     for( i = 0; i < cart->count; i++ )
94     {
95         carthaar->feature[i] = intHaarFeatures->feature[cart->compidx[i]];
96         carthaar->fastfeature[i] = intHaarFeatures->fastfeature[cart->compidx[i]];
97         carthaar->threshold[i] = cart->threshold[i];
98         carthaar->left[i] = cart->left[i];
99         carthaar->right[i] = cart->right[i];
100         carthaar->val[i] = cart->val[i];
101         carthaar->compidx[i] = cart->compidx[i];
102     }
103     carthaar->count = cart->count;
104     carthaar->val[cart->count] = cart->val[cart->count];
105 }
106
107
108 float icvEvalCARTHaarClassifier( CvIntHaarClassifier* classifier,
109                                  sum_type* sum, sum_type* tilted, float normfactor )
110 {
111     int idx = 0;
112
113     do
114     {
115         if( cvEvalFastHaarFeature(
116                 ((CvCARTHaarClassifier*) classifier)->fastfeature + idx, sum, tilted )
117               < (((CvCARTHaarClassifier*) classifier)->threshold[idx] * normfactor) )
118         {
119             idx = ((CvCARTHaarClassifier*) classifier)->left[idx];
120         }
121         else
122         {
123             idx = ((CvCARTHaarClassifier*) classifier)->right[idx];
124         }
125     } while( idx > 0 );
126
127     return ((CvCARTHaarClassifier*) classifier)->val[-idx];
128 }
129
130
131 CvIntHaarClassifier* icvCreateStageHaarClassifier( int count, float threshold )
132 {
133     CvStageHaarClassifier* stage;
134     size_t datasize;
135
136     datasize = sizeof( *stage ) + sizeof( CvIntHaarClassifier* ) * count;
137     stage = (CvStageHaarClassifier*) cvAlloc( datasize );
138     memset( stage, 0, datasize );
139
140     stage->count = count;
141     stage->threshold = threshold;
142     stage->classifier = (CvIntHaarClassifier**) (stage + 1);
143
144     stage->eval = icvEvalStageHaarClassifier;
145     stage->save = icvSaveStageHaarClassifier;
146     stage->release = icvReleaseStageHaarClassifier;
147
148     return (CvIntHaarClassifier*) stage;
149 }
150
151
152 void icvReleaseStageHaarClassifier( CvIntHaarClassifier** classifier )
153 {
154     int i;
155
156     for( i = 0; i < ((CvStageHaarClassifier*) *classifier)->count; i++ )
157     {
158         if( ((CvStageHaarClassifier*) *classifier)->classifier[i] != NULL )
159         {
160             ((CvStageHaarClassifier*) *classifier)->classifier[i]->release(
161                 &(((CvStageHaarClassifier*) *classifier)->classifier[i]) );
162         }
163     }
164
165     cvFree( classifier );
166     *classifier = NULL;
167 }
168
169
170 float icvEvalStageHaarClassifier( CvIntHaarClassifier* classifier,
171                                   sum_type* sum, sum_type* tilted, float normfactor )
172 {
173     int i;
174     float stage_sum;
175
176     stage_sum = 0.0F;
177     for( i = 0; i < ((CvStageHaarClassifier*) classifier)->count; i++ )
178     {
179         stage_sum +=
180             ((CvStageHaarClassifier*) classifier)->classifier[i]->eval(
181                 ((CvStageHaarClassifier*) classifier)->classifier[i],
182                 sum, tilted, normfactor );
183     }
184
185     return stage_sum;
186 }
187
188
189 CvIntHaarClassifier* icvCreateCascadeHaarClassifier( int count )
190 {
191     CvCascadeHaarClassifier* ptr;
192     size_t datasize;
193
194     datasize = sizeof( *ptr ) + sizeof( CvIntHaarClassifier* ) * count;
195     ptr = (CvCascadeHaarClassifier*) cvAlloc( datasize );
196     memset( ptr, 0, datasize );
197
198     ptr->count = count;
199     ptr->classifier = (CvIntHaarClassifier**) (ptr + 1);
200
201     ptr->eval = icvEvalCascadeHaarClassifier;
202     ptr->save = NULL;
203     ptr->release = icvReleaseCascadeHaarClassifier;
204
205     return (CvIntHaarClassifier*) ptr;
206 }
207
208
209 void icvReleaseCascadeHaarClassifier( CvIntHaarClassifier** classifier )
210 {
211     int i;
212
213     for( i = 0; i < ((CvCascadeHaarClassifier*) *classifier)->count; i++ )
214     {
215         if( ((CvCascadeHaarClassifier*) *classifier)->classifier[i] != NULL )
216         {
217             ((CvCascadeHaarClassifier*) *classifier)->classifier[i]->release(
218                 &(((CvCascadeHaarClassifier*) *classifier)->classifier[i]) );
219         }
220     }
221
222     cvFree( classifier );
223     *classifier = NULL;
224 }
225
226
227 float icvEvalCascadeHaarClassifier( CvIntHaarClassifier* classifier,
228                                     sum_type* sum, sum_type* tilted, float normfactor )
229 {
230     int i;
231
232     for( i = 0; i < ((CvCascadeHaarClassifier*) classifier)->count; i++ )
233     {
234         if( ((CvCascadeHaarClassifier*) classifier)->classifier[i]->eval(
235                     ((CvCascadeHaarClassifier*) classifier)->classifier[i],
236                     sum, tilted, normfactor )
237             < ( ((CvStageHaarClassifier*)
238                     ((CvCascadeHaarClassifier*) classifier)->classifier[i])->threshold
239                             - CV_THRESHOLD_EPS) )
240         {
241             return 0.0;
242         }
243     }
244
245     return 1.0;
246 }
247
248
249 void icvSaveHaarFeature( CvTHaarFeature* feature, FILE* file )
250 {
251     fprintf( file, "%d\n", ( ( feature->rect[2].weight == 0.0F ) ? 2 : 3) );
252     fprintf( file, "%d %d %d %d %d %d\n",
253         feature->rect[0].r.x,
254         feature->rect[0].r.y,
255         feature->rect[0].r.width,
256         feature->rect[0].r.height,
257         0,
258         (int) (feature->rect[0].weight) );
259     fprintf( file, "%d %d %d %d %d %d\n",
260         feature->rect[1].r.x,
261         feature->rect[1].r.y,
262         feature->rect[1].r.width,
263         feature->rect[1].r.height,
264         0,
265         (int) (feature->rect[1].weight) );
266     if( feature->rect[2].weight != 0.0F )
267     {
268         fprintf( file, "%d %d %d %d %d %d\n",
269             feature->rect[2].r.x,
270             feature->rect[2].r.y,
271             feature->rect[2].r.width,
272             feature->rect[2].r.height,
273             0,
274             (int) (feature->rect[2].weight) );
275     }
276     fprintf( file, "%s\n", &(feature->desc[0]) );
277 }
278
279
280 void icvLoadHaarFeature( CvTHaarFeature* feature, FILE* file )
281 {
282     int nrect;
283     int j;
284     int tmp;
285     int weight;
286
287     nrect = 0;
288     int values_read = fscanf( file, "%d", &nrect );
289     CV_Assert(values_read == 1);
290
291     assert( nrect <= CV_HAAR_FEATURE_MAX );
292
293     for( j = 0; j < nrect; j++ )
294     {
295         values_read = fscanf( file, "%d %d %d %d %d %d",
296             &(feature->rect[j].r.x),
297             &(feature->rect[j].r.y),
298             &(feature->rect[j].r.width),
299             &(feature->rect[j].r.height),
300             &tmp, &weight );
301         CV_Assert(values_read == 6);
302         feature->rect[j].weight = (float) weight;
303     }
304     for( j = nrect; j < CV_HAAR_FEATURE_MAX; j++ )
305     {
306         feature->rect[j].r.x = 0;
307         feature->rect[j].r.y = 0;
308         feature->rect[j].r.width = 0;
309         feature->rect[j].r.height = 0;
310         feature->rect[j].weight = 0.0f;
311     }
312     values_read = fscanf( file, "%s", &(feature->desc[0]) );
313     CV_Assert(values_read == 1);
314     feature->tilted = ( feature->desc[0] == 't' );
315 }
316
317
318 void icvSaveCARTHaarClassifier( CvIntHaarClassifier* classifier, FILE* file )
319 {
320     int i;
321     int count;
322
323     count = ((CvCARTHaarClassifier*) classifier)->count;
324     fprintf( file, "%d\n", count );
325     for( i = 0; i < count; i++ )
326     {
327         icvSaveHaarFeature( &(((CvCARTHaarClassifier*) classifier)->feature[i]), file );
328         fprintf( file, "%e %d %d\n",
329             ((CvCARTHaarClassifier*) classifier)->threshold[i],
330             ((CvCARTHaarClassifier*) classifier)->left[i],
331             ((CvCARTHaarClassifier*) classifier)->right[i] );
332     }
333     for( i = 0; i <= count; i++ )
334     {
335         fprintf( file, "%e ", ((CvCARTHaarClassifier*) classifier)->val[i] );
336     }
337     fprintf( file, "\n" );
338 }
339
340
341 CvIntHaarClassifier* icvLoadCARTHaarClassifier( FILE* file, int step )
342 {
343     CvCARTHaarClassifier* ptr;
344     int i;
345     int count;
346
347     ptr = NULL;
348     int values_read = fscanf( file, "%d", &count );
349     CV_Assert(values_read == 1);
350
351     if( count > 0 )
352     {
353         ptr = (CvCARTHaarClassifier*) icvCreateCARTHaarClassifier( count );
354         for( i = 0; i < count; i++ )
355         {
356             icvLoadHaarFeature( &(ptr->feature[i]), file );
357             values_read = fscanf( file, "%f %d %d", &(ptr->threshold[i]), &(ptr->left[i]),
358                                       &(ptr->right[i]) );
359             CV_Assert(values_read == 3);
360         }
361         for( i = 0; i <= count; i++ )
362         {
363             values_read = fscanf( file, "%f", &(ptr->val[i]) );
364             CV_Assert(values_read == 1);
365         }
366         icvConvertToFastHaarFeature( ptr->feature, ptr->fastfeature, ptr->count, step );
367     }
368
369     return (CvIntHaarClassifier*) ptr;
370 }
371
372
373 void icvSaveStageHaarClassifier( CvIntHaarClassifier* classifier, FILE* file )
374 {
375     int count;
376     int i;
377     float threshold;
378
379     count = ((CvStageHaarClassifier*) classifier)->count;
380     fprintf( file, "%d\n", count );
381     for( i = 0; i < count; i++ )
382     {
383         ((CvStageHaarClassifier*) classifier)->classifier[i]->save(
384             ((CvStageHaarClassifier*) classifier)->classifier[i], file );
385     }
386
387     threshold = ((CvStageHaarClassifier*) classifier)->threshold;
388
389     /* to be compatible with the previous implementation */
390     /* threshold = 2.0F * ((CvStageHaarClassifier*) classifier)->threshold - count; */
391
392     fprintf( file, "%e\n", threshold );
393 }
394
395
396
397 static CvIntHaarClassifier* icvLoadCARTStageHaarClassifierF( FILE* file, int step )
398 {
399     CvStageHaarClassifier* ptr = NULL;
400
401     //CV_FUNCNAME( "icvLoadCARTStageHaarClassifierF" );
402
403     __BEGIN__;
404
405     if( file != NULL )
406     {
407         int count;
408         int i;
409         float threshold;
410
411         count = 0;
412         int values_read = fscanf( file, "%d", &count );
413         CV_Assert(values_read == 1);
414         if( count > 0 )
415         {
416             ptr = (CvStageHaarClassifier*) icvCreateStageHaarClassifier( count, 0.0F );
417             for( i = 0; i < count; i++ )
418             {
419                 ptr->classifier[i] = icvLoadCARTHaarClassifier( file, step );
420             }
421
422             values_read = fscanf( file, "%f", &threshold );
423             CV_Assert(values_read == 1);
424
425             ptr->threshold = threshold;
426             /* to be compatible with the previous implementation */
427             /* ptr->threshold = 0.5F * (threshold + count); */
428         }
429         if( feof( file ) )
430         {
431             ptr->release( (CvIntHaarClassifier**) &ptr );
432             ptr = NULL;
433         }
434     }
435
436     __END__;
437
438     return (CvIntHaarClassifier*) ptr;
439 }
440
441
442 CvIntHaarClassifier* icvLoadCARTStageHaarClassifier( const char* filename, int step )
443 {
444     CvIntHaarClassifier* ptr = NULL;
445
446     CV_FUNCNAME( "icvLoadCARTStageHaarClassifier" );
447
448     __BEGIN__;
449
450     FILE* file;
451
452     file = fopen( filename, "r" );
453     if( file )
454     {
455         CV_CALL( ptr = icvLoadCARTStageHaarClassifierF( file, step ) );
456         fclose( file );
457     }
458
459     __END__;
460
461     return ptr;
462 }
463
464 /* tree cascade classifier */
465
466 /* evaluates a tree cascade classifier */
467
468 float icvEvalTreeCascadeClassifier( CvIntHaarClassifier* classifier,
469                                     sum_type* sum, sum_type* tilted, float normfactor )
470 {
471     CvTreeCascadeNode* ptr;
472
473     ptr = ((CvTreeCascadeClassifier*) classifier)->root;
474
475     while( ptr )
476     {
477         if( ptr->stage->eval( (CvIntHaarClassifier*) ptr->stage,
478                               sum, tilted, normfactor )
479                 >= ptr->stage->threshold - CV_THRESHOLD_EPS )
480         {
481             ptr = ptr->child;
482         }
483         else
484         {
485             while( ptr && ptr->next == NULL ) ptr = ptr->parent;
486             if( ptr == NULL ) return 0.0F;
487             ptr = ptr->next;
488         }
489     }
490
491     return 1.0F;
492 }
493
494 /* sets path int the tree form the root to the leaf node */
495
496 void icvSetLeafNode( CvTreeCascadeClassifier* tcc, CvTreeCascadeNode* leaf )
497 {
498     CV_FUNCNAME( "icvSetLeafNode" );
499
500     __BEGIN__;
501
502     CvTreeCascadeNode* ptr;
503
504     ptr = NULL;
505     while( leaf )
506     {
507         leaf->child_eval = ptr;
508         ptr = leaf;
509         leaf = leaf->parent;
510     }
511
512     leaf = tcc->root;
513     while( leaf && leaf != ptr ) leaf = leaf->next;
514     if( leaf != ptr )
515         CV_ERROR( CV_StsError, "Invalid tcc or leaf node." );
516
517     tcc->root_eval = ptr;
518
519     __END__;
520 }
521
522 /* evaluates a tree cascade classifier. used in filtering */
523
524 float icvEvalTreeCascadeClassifierFilter( CvIntHaarClassifier* classifier, sum_type* sum,
525                                           sum_type* tilted, float normfactor )
526 {
527     CvTreeCascadeNode* ptr;
528     //CvTreeCascadeClassifier* tree;
529
530     //tree = (CvTreeCascadeClassifier*) classifier;
531
532
533
534     ptr = ((CvTreeCascadeClassifier*) classifier)->root_eval;
535     while( ptr )
536     {
537         if( ptr->stage->eval( (CvIntHaarClassifier*) ptr->stage,
538                               sum, tilted, normfactor )
539                 < ptr->stage->threshold - CV_THRESHOLD_EPS )
540         {
541             return 0.0F;
542         }
543         ptr = ptr->child_eval;
544     }
545
546     return 1.0F;
547 }
548
549 /* creates tree cascade node */
550
551 CvTreeCascadeNode* icvCreateTreeCascadeNode()
552 {
553     CvTreeCascadeNode* ptr = NULL;
554
555     CV_FUNCNAME( "icvCreateTreeCascadeNode" );
556
557     __BEGIN__;
558     size_t data_size;
559
560     data_size = sizeof( *ptr );
561     CV_CALL( ptr = (CvTreeCascadeNode*) cvAlloc( data_size ) );
562     memset( ptr, 0, data_size );
563
564     __END__;
565
566     return ptr;
567 }
568
569 /* releases all tree cascade nodes accessible via links */
570
571 void icvReleaseTreeCascadeNodes( CvTreeCascadeNode** node )
572 {
573     //CV_FUNCNAME( "icvReleaseTreeCascadeNodes" );
574
575     __BEGIN__;
576
577     if( node && *node )
578     {
579         CvTreeCascadeNode* ptr;
580         CvTreeCascadeNode* ptr_;
581
582         ptr = *node;
583
584         while( ptr )
585         {
586             while( ptr->child ) ptr = ptr->child;
587
588             if( ptr->stage ) ptr->stage->release( (CvIntHaarClassifier**) &ptr->stage );
589             ptr_ = ptr;
590
591             while( ptr && ptr->next == NULL ) ptr = ptr->parent;
592             if( ptr ) ptr = ptr->next;
593
594             cvFree( &ptr_ );
595         }
596     }
597
598     __END__;
599 }
600
601
602 /* releases tree cascade classifier */
603
604 void icvReleaseTreeCascadeClassifier( CvIntHaarClassifier** classifier )
605 {
606     if( classifier && *classifier )
607     {
608         icvReleaseTreeCascadeNodes( &((CvTreeCascadeClassifier*) *classifier)->root );
609         cvFree( classifier );
610         *classifier = NULL;
611     }
612 }
613
614
615 void icvPrintTreeCascade( CvTreeCascadeNode* root )
616 {
617     //CV_FUNCNAME( "icvPrintTreeCascade" );
618
619     __BEGIN__;
620
621     CvTreeCascadeNode* node;
622     CvTreeCascadeNode* n;
623     char buf0[256];
624     char buf[256];
625     int level;
626     int i;
627     int max_level;
628
629     node = root;
630     level = max_level = 0;
631     while( node )
632     {
633         while( node->child ) { node = node->child; level++; }
634         if( level > max_level ) { max_level = level; }
635         while( node && !node->next ) { node = node->parent; level--; }
636         if( node ) node = node->next;
637     }
638
639     printf( "\nTree Classifier\n" );
640     printf( "Stage\n" );
641     for( i = 0; i <= max_level; i++ ) printf( "+---" );
642     printf( "+\n" );
643     for( i = 0; i <= max_level; i++ ) printf( "|%3d", i );
644     printf( "|\n" );
645     for( i = 0; i <= max_level; i++ ) printf( "+---" );
646     printf( "+\n\n" );
647
648     node = root;
649
650     buf[0] = 0;
651     while( node )
652     {
653         sprintf( buf + strlen( buf ), "%3d", node->idx );
654         while( node->child )
655         {
656             node = node->child;
657             sprintf( buf + strlen( buf ),
658                 ((node->idx < 10) ? "---%d" : ((node->idx < 100) ? "--%d" : "-%d")),
659                 node->idx );
660         }
661         printf( " %s\n", buf );
662
663         while( node && !node->next ) { node = node->parent; }
664         if( node )
665         {
666             node = node->next;
667
668             n = node->parent;
669             buf[0] = 0;
670             while( n )
671             {
672                 if( n->next )
673                     sprintf( buf0, "  | %s", buf );
674                 else
675                     sprintf( buf0, "    %s", buf );
676                 strcpy( buf, buf0 );
677                 n = n->parent;
678             }
679             printf( " %s  |\n", buf );
680         }
681     }
682     printf( "\n" );
683     fflush( stdout );
684
685     __END__;
686 }
687
688
689
690 CvIntHaarClassifier* icvLoadTreeCascadeClassifier( const char* filename, int step,
691                                                    int* splits )
692 {
693     CvTreeCascadeClassifier* ptr = NULL;
694     CvTreeCascadeNode** nodes = NULL;
695
696     CV_FUNCNAME( "icvLoadTreeCascadeClassifier" );
697
698     __BEGIN__;
699
700     size_t data_size;
701     CvStageHaarClassifier* stage;
702     char stage_name[PATH_MAX];
703     char* suffix;
704     int i, num;
705     FILE* f;
706     int result, parent=0, next=0;
707     int stub;
708
709     if( !splits ) splits = &stub;
710
711     *splits = 0;
712
713     data_size = sizeof( *ptr );
714
715     CV_CALL( ptr = (CvTreeCascadeClassifier*) cvAlloc( data_size ) );
716     memset( ptr, 0, data_size );
717
718     ptr->eval = icvEvalTreeCascadeClassifier;
719     ptr->release = icvReleaseTreeCascadeClassifier;
720
721     sprintf( stage_name, "%s/", filename );
722     suffix = stage_name + strlen( stage_name );
723
724     for( i = 0; ; i++ )
725     {
726         sprintf( suffix, "%d/%s", i, CV_STAGE_CART_FILE_NAME );
727         f = fopen( stage_name, "r" );
728         if( !f ) break;
729         fclose( f );
730     }
731     num = i;
732
733     if( num < 1 ) EXIT;
734
735     data_size = sizeof( *nodes ) * num;
736     CV_CALL( nodes = (CvTreeCascadeNode**) cvAlloc( data_size ) );
737
738     for( i = 0; i < num; i++ )
739     {
740         sprintf( suffix, "%d/%s", i, CV_STAGE_CART_FILE_NAME );
741         f = fopen( stage_name, "r" );
742         CV_CALL( stage = (CvStageHaarClassifier*)
743             icvLoadCARTStageHaarClassifierF( f, step ) );
744
745         result = ( f && stage ) ? fscanf( f, "%d%d", &parent, &next ) : 0;
746         if( f ) fclose( f );
747
748         if( result != 2 )
749         {
750             num = i;
751             break;
752         }
753
754         printf( "Stage %d loaded\n", i );
755
756         if( parent >= i || (next != -1 && next != i + 1) )
757             CV_ERROR( CV_StsError, "Invalid tree links" );
758
759         CV_CALL( nodes[i] = icvCreateTreeCascadeNode() );
760         nodes[i]->stage = stage;
761         nodes[i]->idx = i;
762         nodes[i]->parent = (parent != -1 ) ? nodes[parent] : NULL;
763         nodes[i]->next = ( next != -1 ) ? nodes[i] : NULL;
764         nodes[i]->child = NULL;
765     }
766     for( i = 0; i < num; i++ )
767     {
768         if( nodes[i]->next )
769         {
770             (*splits)++;
771             nodes[i]->next = nodes[i+1];
772         }
773         if( nodes[i]->parent && nodes[i]->parent->child == NULL )
774         {
775             nodes[i]->parent->child = nodes[i];
776         }
777     }
778     ptr->root = nodes[0];
779     ptr->next_idx = num;
780
781     __END__;
782
783     cvFree( &nodes );
784
785     return (CvIntHaarClassifier*) ptr;
786 }
787
788
789 CvTreeCascadeNode* icvFindDeepestLeaves( CvTreeCascadeClassifier* tcc )
790 {
791     CvTreeCascadeNode* leaves;
792
793     //CV_FUNCNAME( "icvFindDeepestLeaves" );
794
795     __BEGIN__;
796
797     int level, cur_level;
798     CvTreeCascadeNode* ptr;
799     CvTreeCascadeNode* last;
800
801     leaves = last = NULL;
802
803     ptr = tcc->root;
804     level = -1;
805     cur_level = 0;
806
807     /* find leaves with maximal level */
808     while( ptr )
809     {
810         if( ptr->child ) { ptr = ptr->child; cur_level++; }
811         else
812         {
813             if( cur_level == level )
814             {
815                 last->next_same_level = ptr;
816                 ptr->next_same_level = NULL;
817                 last = ptr;
818             }
819             if( cur_level > level )
820             {
821                 level = cur_level;
822                 leaves = last = ptr;
823                 ptr->next_same_level = NULL;
824             }
825             while( ptr && ptr->next == NULL ) { ptr = ptr->parent; cur_level--; }
826             if( ptr ) ptr = ptr->next;
827         }
828     }
829
830     __END__;
831
832     return leaves;
833 }
834
835 /* End of file. */