1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
45 * training of cascade of boosted classifiers based on haar features
48 #include "cvhaartraining.h"
49 #include "_cvhaartraining.h"
62 /* use clock() function insted of time() */
63 #define TIME( arg ) (((double) clock()) / CLOCKS_PER_SEC)
65 #define TIME( arg ) (time( arg ))
68 #endif /* CV_VERBOSE */
70 #if defined CV_OPENMP && (defined _MSC_VER || defined CV_ICC)
76 typedef struct CvBackgroundData
85 typedef struct CvBackgroundReader
98 * Created in each thread
100 CvBackgroundReader* cvbgreader = NULL;
102 #if defined CV_OPENMP
103 #pragma omp threadprivate(cvbgreader)
106 CvBackgroundData* cvbgdata = NULL;
110 * get sum image offsets for <rect> corner points
111 * step - row step (measured in image pixels!) of sum image
113 #define CV_SUM_OFFSETS( p0, p1, p2, p3, rect, step ) \
115 (p0) = (rect).x + (step) * (rect).y; \
117 (p1) = (rect).x + (rect).width + (step) * (rect).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);
124 * get tilted image offsets for <rect> corner points
125 * step - row step (measured in image pixels!) of tilted image
127 #define CV_TILTED_OFFSETS( p0, p1, p2, p3, rect, step ) \
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);
140 * icvCreateIntHaarFeatures
142 * Create internal representation of haar features
146 * 1 - CORE = All upright
147 * 2 - ALL = All features
150 CvIntHaarFeatures* icvCreateIntHaarFeatures( CvSize winsize,
154 CvIntHaarFeatures* features = NULL;
155 CvTHaarFeature haarFeature;
157 CvMemStorage* storage = NULL;
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 */
173 factor = ((float) winsize.width) * winsize.height / (24 * 24);
175 s0 = (int) (s0 * factor);
176 s1 = (int) (s1 * factor);
177 s2 = (int) (s2 * factor);
178 s3 = (int) (s3 * factor);
186 /* CV_VECTOR_CREATE( vec, CvIntHaarFeature, size, maxsize ) */
187 storage = cvCreateMemStorage();
188 cvStartWriteSeq( 0, sizeof( CvSeq ), sizeof( haarFeature ), storage, &writer );
190 for( x = 0; x < winsize.width; x++ )
192 for( y = 0; y < winsize.height; y++ )
194 for( dx = 1; dx <= winsize.width; dx++ )
196 for( dy = 1; dy <= winsize.height; dy++ )
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",
204 x+dx, y, dx , dy, +2 );
205 /* CV_VECTOR_PUSH( vec, CvIntHaarFeature, haarFeature, size, maxsize, step ) */
206 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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",
216 y, x+dx, dy, dx, +2 );
217 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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",
227 x+dx, y, dx, dy, +3 );
228 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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",
238 y, x+dx, dy, dx, +3 );
239 CV_WRITE_SEQ_ELEM( haarFeature, writer );
243 if( mode != 0 /*BASIC*/ ) {
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",
250 x+dx, y, dx*2, dy, +2 );
251 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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",
261 y, x+dx, dy, dx*2, +2 );
262 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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,
274 x+dx, y+dy, dx , dy, +2 );
275 CV_WRITE_SEQ_ELEM( haarFeature, writer );
279 if (mode != 0 /*BASIC*/) {
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 );
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;
297 if (!symmetric || (x <= (winsize.width / 2) )) {
298 haarFeature = cvHaarFeature( "tilted_haar_x2",
301 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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;
309 if (!symmetric || (x <= (winsize.width / 2) )) {
310 haarFeature = cvHaarFeature( "tilted_haar_y2",
313 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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;
321 if (!symmetric || (x <= (winsize.width / 2) )) {
322 haarFeature = cvHaarFeature( "tilted_haar_x3",
324 x+dx, y+dx, dx , dy, +3 );
325 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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;
333 if (!symmetric || (x <= (winsize.width / 2) )) {
334 haarFeature = cvHaarFeature( "tilted_haar_y3",
336 x-dy, y+dy, dx, dy, +3 );
337 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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;
346 if (!symmetric || (x <= (winsize.width / 2) )) {
347 haarFeature = cvHaarFeature( "tilted_haar_x4",
351 x+dx, y+dx, dx*2, dy, +2 );
352 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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;
360 if (!symmetric || (x <= (winsize.width / 2) )) {
361 haarFeature = cvHaarFeature( "tilted_haar_y4",
363 x-dy, y+dy, dx, 2*dy, +2 );
364 CV_WRITE_SEQ_ELEM( haarFeature, writer );
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 );
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 );
398 icvConvertToFastHaarFeature( features->feature, features->fastfeature,
399 features->count, (winsize.width + 1) );
405 void icvReleaseIntHaarFeatures( CvIntHaarFeatures** intHaarFeatures )
407 if( intHaarFeatures != NULL && (*intHaarFeatures) != NULL )
409 cvFree( intHaarFeatures );
410 (*intHaarFeatures) = NULL;
415 void icvConvertToFastHaarFeature( CvTHaarFeature* haarFeature,
416 CvFastHaarFeature* fastHaarFeature,
422 for( i = 0; i < size; i++ )
424 fastHaarFeature[i].tilted = haarFeature[i].tilted;
425 if( !fastHaarFeature[i].tilted )
427 for( j = 0; j < CV_HAAR_FEATURE_MAX; j++ )
429 fastHaarFeature[i].rect[j].weight = haarFeature[i].rect[j].weight;
430 if( fastHaarFeature[i].rect[j].weight == 0.0F )
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 )
444 for( j = 0; j < CV_HAAR_FEATURE_MAX; j++ )
446 fastHaarFeature[i].rect[j].weight = haarFeature[i].rect[j].weight;
447 if( fastHaarFeature[i].rect[j].weight == 0.0F )
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 )
463 * icvCreateHaarTrainingData
465 * Create haar training data used in stage training
468 CvHaarTrainigData* icvCreateHaarTrainingData( CvSize winsize, int maxnumsamples )
470 CvHaarTrainigData* data;
472 CV_FUNCNAME( "icvCreateHaarTrainingData" );
480 datasize = sizeof( CvHaarTrainigData ) +
482 ( 2 * (winsize.width + 1) * (winsize.height + 1) * sizeof( sum_type ) +
483 sizeof( float ) + /* normfactor */
484 sizeof( float ) + /* cls */
485 sizeof( float ) /* weight */
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 );
505 data->valcache = NULL;
506 data->idxcache = NULL;
514 void icvReleaseHaarTrainingDataCache( CvHaarTrainigData** haarTrainingData )
516 if( haarTrainingData != NULL && (*haarTrainingData) != NULL )
518 if( (*haarTrainingData)->valcache != NULL )
520 cvReleaseMat( &(*haarTrainingData)->valcache );
521 (*haarTrainingData)->valcache = NULL;
523 if( (*haarTrainingData)->idxcache != NULL )
525 cvReleaseMat( &(*haarTrainingData)->idxcache );
526 (*haarTrainingData)->idxcache = NULL;
532 void icvReleaseHaarTrainingData( CvHaarTrainigData** haarTrainingData )
534 if( haarTrainingData != NULL && (*haarTrainingData) != NULL )
536 icvReleaseHaarTrainingDataCache( haarTrainingData );
538 cvFree( haarTrainingData );
543 void icvGetTrainingDataCallback( CvMat* mat, CvMat* sampleIdx, CvMat*,
544 int first, int num, void* userdata )
549 float normfactor = 0.0F;
551 CvHaarTrainingData* training_data;
552 CvIntHaarFeatures* haar_features;
554 #ifdef CV_COL_ARRANGEMENT
555 assert( mat->rows >= num );
557 assert( mat->cols >= num );
560 training_data = ((CvUserdata*) userdata)->trainingData;
561 haar_features = ((CvUserdata*) userdata)->haarFeatures;
562 if( sampleIdx == NULL )
566 #ifdef CV_COL_ARRANGEMENT
567 num_samples = mat->cols;
569 num_samples = mat->rows;
571 for( i = 0; i < num_samples; i++ )
573 for( j = 0; j < num; j++ )
575 val = cvEvalFastHaarFeature(
576 ( haar_features->fastfeature
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);
585 #ifdef CV_COL_ARRANGEMENT
586 CV_MAT_ELEM( *mat, float, j, i ) = val;
588 CV_MAT_ELEM( *mat, float, i, j ) = val;
595 uchar* idxdata = NULL;
600 assert( CV_MAT_TYPE( sampleIdx->type ) == CV_32FC1 );
602 idxdata = sampleIdx->data.ptr;
603 if( sampleIdx->rows == 1 )
605 step = sizeof( float );
606 numidx = sampleIdx->cols;
610 step = sampleIdx->step;
611 numidx = sampleIdx->rows;
614 for( i = 0; i < numidx; i++ )
616 for( j = 0; j < num; j++ )
618 idx = (int)( *((float*) (idxdata + i * step)) );
619 val = cvEvalFastHaarFeature(
620 ( haar_features->fastfeature
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);
629 #ifdef CV_COL_ARRANGEMENT
630 CV_MAT_ELEM( *mat, float, j, idx ) = val;
632 CV_MAT_ELEM( *mat, float, idx, j ) = val;
638 #if 0 /*def CV_VERBOSE*/
639 if( first % 5000 == 0 )
641 fprintf( stderr, "%3d%%\r", (int) (100.0 * first /
642 haar_features->count) );
645 #endif /* CV_VERBOSE */
649 void icvPrecalculate( CvHaarTrainingData* data, CvIntHaarFeatures* haarFeatures,
650 int numprecalculated )
652 CV_FUNCNAME( "icvPrecalculate" );
656 icvReleaseHaarTrainingDataCache( &data );
658 numprecalculated -= numprecalculated % CV_STUMP_TRAIN_PORTION;
659 numprecalculated = MIN( numprecalculated, haarFeatures->count );
661 if( numprecalculated > 0 )
667 /* private variables */
673 int portion = CV_STUMP_TRAIN_PORTION;
674 #endif /* CV_OPENMP */
678 #ifdef CV_COL_ARRANGEMENT
679 CV_CALL( data->valcache = cvCreateMat( numprecalculated, m, CV_32FC1 ) );
681 CV_CALL( data->valcache = cvCreateMat( m, numprecalculated, CV_32FC1 ) );
683 CV_CALL( data->idxcache = cvCreateMat( numprecalculated, m, CV_IDX_MAT_TYPE ) );
685 userdata = cvUserdata( data, haarFeatures );
688 #pragma omp parallel for private(t_data, t_idx, first, t_portion)
689 for( first = 0; first < numprecalculated; first += portion )
691 t_data = *data->valcache;
692 t_idx = *data->idxcache;
693 t_portion = MIN( portion, (numprecalculated - first) );
696 t_idx.rows = t_portion;
697 t_idx.data.ptr = data->idxcache->data.ptr + first * ((size_t)t_idx.step);
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 );
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 ));
709 icvGetTrainingDataCallback( &t_data, NULL, NULL, first, t_portion,
711 #ifdef CV_COL_ARRANGEMENT
712 cvGetSortedIndices( &t_data, &t_idx, 0 );
714 cvGetSortedIndices( &t_data, &t_idx, 1 );
720 #endif /* CV_VERBOSE */
725 fprintf( stderr, "\n" );
727 #endif /* CV_VERBOSE */
730 icvGetTrainingDataCallback( data->valcache, NULL, NULL, 0, numprecalculated,
732 #ifdef CV_COL_ARRANGEMENT
733 cvGetSortedIndices( data->valcache, data->idxcache, 0 );
735 cvGetSortedIndices( data->valcache, data->idxcache, 1 );
737 #endif /* CV_OPENMP */
744 void icvSplitIndicesCallback( int compidx, float threshold,
745 CvMat* idx, CvMat** left, CvMat** right,
748 CvHaarTrainingData* data;
749 CvIntHaarFeatures* haar_features;
752 CvFastHaarFeature* fastfeature;
754 data = ((CvUserdata*) userdata)->trainingData;
755 haar_features = ((CvUserdata*) userdata)->haarFeatures;
756 fastfeature = &haar_features->fastfeature[compidx];
759 *left = cvCreateMat( 1, m, CV_32FC1 );
760 *right = cvCreateMat( 1, m, CV_32FC1 );
761 (*left)->cols = (*right)->cols = 0;
764 for( i = 0; i < m; i++ )
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] )
771 (*left)->data.fl[(*left)->cols++] = (float) i;
775 (*right)->data.fl[(*right)->cols++] = (float) i;
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++ )
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] )
797 (*left)->data.fl[(*left)->cols++] = (float) index;
801 (*right)->data.fl[(*right)->cols++] = (float) index;
808 * icvCreateCARTStageClassifier
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>.
825 CvIntHaarClassifier* icvCreateCARTStageClassifier( CvHaarTrainingData* data,
827 CvIntHaarFeatures* haarFeatures,
831 float weightfraction,
833 CvBoostType boosttype,
834 CvStumpError stumperror,
838 #ifdef CV_COL_ARRANGEMENT
839 int flags = CV_COL_SAMPLE;
841 int flags = CV_ROW_SAMPLE;
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;
857 float sum_stage = 0.0F;
858 float threshold = 0.0F;
859 float falsealarm = 0.0F;
861 //CvMat* sampleIdx = NULL;
863 //float* idxdata = NULL;
864 //float* tempweights = NULL;
874 CvCARTHaarClassifier* classifier;
876 CvMemStorage* storage = NULL;
877 CvMat* weakTrainVals;
880 int num_splits; /* total number of splits in all weak classifiers */
883 printf( "+----+----+-+---------+---------+---------+---------+\n" );
884 printf( "| N |%%SMP|F| ST.THR | HR | FA | EXP. ERR|\n" );
885 printf( "+----+----+-+---------+---------+---------+---------+\n" );
886 #endif /* CV_VERBOSE */
888 n = haarFeatures->count;
890 numsamples = (sampleIdx) ? MAX( sampleIdx->rows, sampleIdx->cols ) : m;
892 userdata = cvUserdata( data, haarFeatures );
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;
904 trainParams.count = numsplits;
905 trainParams.stumpTrainParams = (CvClassifierTrainParams*) &stumpTrainParams;
906 trainParams.stumpConstructor = cvCreateMTStumpClassifier;
907 trainParams.splitIdx = icvSplitIndicesCallback;
908 trainParams.userdata = &userdata;
910 eval = cvMat( 1, m, CV_32FC1, cvAlloc( sizeof( float ) * m ) );
912 storage = cvCreateMemStorage();
913 seq = cvCreateSeq( 0, sizeof( *seq ), sizeof( classifier ), storage );
915 weakTrainVals = cvCreateMat( 1, m, CV_32FC1 );
916 trainer = cvBoostStartTraining( &data->cls, weakTrainVals, &data->weights,
917 sampleIdx, boosttype );
926 #endif /* CV_VERBOSE */
928 trimmedIdx = cvTrimWeights( &data->weights, sampleIdx, weightfraction );
929 numtrimmed = (trimmedIdx) ? MAX( trimmedIdx->rows, trimmedIdx->cols ) : m;
932 v_wt = 100 * numtrimmed / numsamples;
935 #endif /* CV_VERBOSE */
937 cart = (CvCARTClassifier*) cvCreateCARTClassifier( data->valcache,
939 weakTrainVals, 0, 0, 0, trimmedIdx,
941 (CvClassifierTrainParams*) &trainParams );
943 classifier = (CvCARTHaarClassifier*) icvCreateCARTHaarClassifier( numsplits );
944 icvInitCARTHaarClassifier( classifier, cart, haarFeatures );
946 num_splits += classifier->count;
948 cart->release( (CvClassifier**) &cart );
950 if( symmetric && (seq->total % 2) )
952 float normfactor = 0.0F;
953 CvStumpClassifier* stump;
955 /* flip haar features */
956 for( i = 0; i < classifier->count; i++ )
958 if( classifier->feature[i].desc[0] == 'h' )
960 for( j = 0; j < CV_HAAR_FEATURE_MAX &&
961 classifier->feature[i].rect[j].weight != 0.0F; j++ )
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;
972 /* (x,y) -> (24-x,y) */
974 for( j = 0; j < CV_HAAR_FEATURE_MAX &&
975 classifier->feature[i].rect[j].weight != 0.0F; j++ )
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 );
984 icvConvertToFastHaarFeature( classifier->feature,
985 classifier->fastfeature,
986 classifier->count, data->winsize.width + 1 );
988 stumpTrainParams.getTrainData = NULL;
989 stumpTrainParams.numcomp = 1;
990 stumpTrainParams.userdata = NULL;
991 stumpTrainParams.sortedIdx = NULL;
993 for( i = 0; i < classifier->count; i++ )
995 for( j = 0; j < numtrimmed; j++ )
997 idx = icvGetIdxAt( trimmedIdx, j );
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);
1007 stump = (CvStumpClassifier*) trainParams.stumpConstructor( &eval,
1009 weakTrainVals, 0, 0, 0, trimmedIdx,
1011 trainParams.stumpTrainParams );
1013 classifier->threshold[i] = stump->threshold;
1014 if( classifier->left[i] <= 0 )
1016 classifier->val[-classifier->left[i]] = stump->left;
1018 if( classifier->right[i] <= 0 )
1020 classifier->val[-classifier->right[i]] = stump->right;
1023 stump->release( (CvClassifier**) &stump );
1027 stumpTrainParams.getTrainData = icvGetTrainingDataCallback;
1028 stumpTrainParams.numcomp = n;
1029 stumpTrainParams.userdata = &userdata;
1030 stumpTrainParams.sortedIdx = data->idxcache;
1034 #endif /* CV_VERBOSE */
1036 } /* if symmetric */
1037 if( trimmedIdx != sampleIdx )
1039 cvReleaseMat( &trimmedIdx );
1043 for( i = 0; i < numsamples; i++ )
1045 idx = icvGetIdxAt( sampleIdx, i );
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] );
1053 alpha = cvBoostNextWeakClassifier( &eval, &data->cls, weakTrainVals,
1054 &data->weights, trainer );
1057 for( i = 0; i <= classifier->count; i++ )
1059 if( boosttype == CV_RABCLASS )
1061 classifier->val[i] = cvLogRatio( classifier->val[i] );
1063 classifier->val[i] *= alpha;
1066 cvSeqPush( seq, (void*) &classifier );
1069 for( i = 0; i < numsamples; i++ )
1071 idx = icvGetIdxAt( sampleIdx, i );
1073 if( data->cls.data.fl[idx] == 1.0F )
1075 eval.data.fl[numpos] = 0.0F;
1076 for( j = 0; j < seq->total; j++ )
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] );
1085 /* eval.data.fl[numpos] = 2.0F * eval.data.fl[numpos] - seq->total; */
1089 icvSort_32f( eval.data.fl, numpos, 0 );
1090 threshold = eval.data.fl[(int) ((1.0F - minhitrate) * numpos)];
1094 for( i = 0; i < numsamples; i++ )
1096 idx = icvGetIdxAt( sampleIdx, i );
1098 if( data->cls.data.fl[idx] == 0.0F )
1102 for( j = 0; j < seq->total; j++ )
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] );
1110 /* sum_stage = 2.0F * sum_stage - seq->total; */
1111 if( sum_stage >= (threshold - CV_THRESHOLD_EPS) )
1117 falsealarm = ((float) numfalse) / ((float) numneg);
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;
1126 for( i = 0; i < numsamples; i++ )
1128 idx = icvGetIdxAt( sampleIdx, i );
1131 for( j = 0; j < seq->total; j++ )
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] );
1139 /* sum_stage = 2.0F * sum_stage - seq->total; */
1140 if( sum_stage >= (threshold - CV_THRESHOLD_EPS) )
1142 if( data->cls.data.fl[idx] == 1.0F )
1148 v_falsealarm += 1.0F;
1151 if( ( sum_stage >= 0.0F ) != (data->cls.data.fl[idx] == 1.0F) )
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,
1161 printf( "+----+----+-+---------+---------+---------+---------+\n" );
1164 #endif /* CV_VERBOSE */
1166 } while( falsealarm > maxfalsealarm && (!maxsplits || (num_splits < maxsplits) ) );
1167 cvBoostEndTraining( &trainer );
1169 if( falsealarm > maxfalsealarm )
1175 stage = (CvStageHaarClassifier*) icvCreateStageHaarClassifier( seq->total,
1177 cvCvtSeqToArray( seq, (CvArr*) stage->classifier );
1181 cvReleaseMemStorage( &storage );
1182 cvReleaseMat( &weakTrainVals );
1183 cvFree( &(eval.data.ptr) );
1185 return (CvIntHaarClassifier*) stage;
1190 CvBackgroundData* icvCreateBackgroundData( const char* filename, CvSize winsize )
1192 CvBackgroundData* data = NULL;
1194 const char* dir = NULL;
1195 char full[PATH_MAX];
1196 char* imgfilename = NULL;
1197 size_t datasize = 0;
1203 assert( filename != NULL );
1205 dir = strrchr( filename, '\\' );
1208 dir = strrchr( filename, '/' );
1212 imgfilename = &(full[0]);
1216 strncpy( &(full[0]), filename, (dir - filename + 1) );
1217 imgfilename = &(full[(dir - filename + 1)]);
1220 input = fopen( filename, "r" );
1227 while( !feof( input ) )
1229 *imgfilename = '\0';
1230 if( !fscanf( input, "%s", imgfilename ))
1232 len = (int)strlen( imgfilename );
1235 if( (*imgfilename) == '#' ) continue; /* comment */
1237 datasize += sizeof( char ) * (strlen( &(full[0]) ) + 1);
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);
1251 data->winsize = winsize;
1252 tmp = (char*) (data->filename + data->count);
1254 while( !feof( input ) )
1256 *imgfilename = '\0';
1257 if( !fscanf( input, "%s", imgfilename ))
1259 len = (int)strlen( imgfilename );
1262 if( (*imgfilename) == '#' ) continue; /* comment */
1263 data->filename[count++] = tmp;
1264 strcpy( tmp, &(full[0]) );
1265 tmp += strlen( &(full[0]) ) + 1;
1276 void icvReleaseBackgroundData( CvBackgroundData** data )
1278 assert( data != NULL && (*data) != NULL );
1284 CvBackgroundReader* icvCreateBackgroundReader()
1286 CvBackgroundReader* reader = NULL;
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;
1302 void icvReleaseBackgroundReader( CvBackgroundReader** reader )
1304 assert( reader != NULL && (*reader) != NULL );
1306 if( (*reader)->src.data.ptr != NULL )
1308 cvFree( &((*reader)->src.data.ptr) );
1310 if( (*reader)->img.data.ptr != NULL )
1312 cvFree( &((*reader)->img.data.ptr) );
1319 void icvGetNextFromBackgroundData( CvBackgroundData* data,
1320 CvBackgroundReader* reader )
1322 IplImage* img = NULL;
1323 size_t datasize = 0;
1326 CvPoint offset = cvPoint(0,0);
1328 assert( data != NULL && reader != NULL );
1330 if( reader->src.data.ptr != NULL )
1332 cvFree( &(reader->src.data.ptr) );
1333 reader->src.data.ptr = NULL;
1335 if( reader->img.data.ptr != NULL )
1337 cvFree( &(reader->img.data.ptr) );
1338 reader->img.data.ptr = NULL;
1342 #pragma omp critical(c_background_data)
1343 #endif /* CV_OPENMP */
1345 for( i = 0; i < data->count; i++ )
1347 round = data->round;
1350 // printf( "Open background image: %s\n", data->filename[data->last] );
1351 //#endif /* CV_VERBOSE */
1353 img = cvLoadImage( data->filename[data->last++], 0 );
1356 data->round += data->last / data->count;
1357 data->round = data->round % (data->winsize.width * data->winsize.height);
1358 data->last %= data->count;
1360 offset.x = round % data->winsize.width;
1361 offset.y = round / data->winsize.width;
1363 offset.x = MIN( offset.x, img->width - data->winsize.width );
1364 offset.y = MIN( offset.y, img->height - data->winsize.height );
1366 if( img != NULL && img->depth == IPL_DEPTH_8U && img->nChannels == 1 &&
1367 offset.x >= 0 && offset.y >= 0 )
1372 cvReleaseImage( &img );
1378 /* no appropriate image */
1381 printf( "Invalid background description file.\n" );
1382 #endif /* CV_VERBOSE */
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 );
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) );
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) );
1409 * icvGetBackgroundImage
1411 * Get an image from background
1412 * <img> must be allocated and have size, previously passed to icvInitBackgroundReaders
1415 * icvInitBackgroundReaders( "bg.txt", cvSize( 24, 24 ) );
1417 * #pragma omp parallel
1420 * icvGetBackgourndImage( cvbgdata, cvbgreader, img );
1424 * icvDestroyBackgroundReaders();
1427 void icvGetBackgroundImage( CvBackgroundData* data,
1428 CvBackgroundReader* reader,
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 );
1438 if( reader->img.data.ptr == NULL )
1440 icvGetNextFromBackgroundData( data, reader );
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 );
1447 cvCopy( &mat, img, 0 );
1448 if( (int) ( reader->point.x + (1.0F + reader->stepfactor ) * data->winsize.width )
1449 < reader->img.cols )
1451 reader->point.x += (int) (reader->stepfactor * data->winsize.width);
1455 reader->point.x = reader->offset.x;
1456 if( (int) ( reader->point.y + (1.0F + reader->stepfactor ) * data->winsize.height )
1457 < reader->img.rows )
1459 reader->point.y += (int) (reader->stepfactor * data->winsize.height);
1463 reader->point.y = reader->offset.y;
1464 reader->scale *= reader->scalefactor;
1465 if( reader->scale <= 1.0F )
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) );
1474 icvGetNextFromBackgroundData( data, reader );
1482 * icvInitBackgroundReaders
1484 * Initialize background reading process.
1485 * <cvbgreader> and <cvbgdata> are initialized.
1486 * Must be called before any usage of background
1488 * filename - name of background description file
1489 * winsize - size of images will be obtained from background
1491 * return 1 on success, 0 otherwise.
1494 int icvInitBackgroundReaders( const char* filename, CvSize winsize )
1496 if( cvbgdata == NULL && filename != NULL )
1498 cvbgdata = icvCreateBackgroundData( filename, winsize );
1505 #pragma omp parallel
1506 #endif /* CV_OPENMP */
1509 #pragma omp critical(c_create_bg_data)
1510 #endif /* CV_OPENMP */
1512 if( cvbgreader == NULL )
1514 cvbgreader = icvCreateBackgroundReader();
1521 return (cvbgdata != NULL);
1526 * icvDestroyBackgroundReaders
1528 * Finish backgournd reading process
1531 void icvDestroyBackgroundReaders()
1533 /* release background reader in each thread */
1535 #pragma omp parallel
1536 #endif /* CV_OPENMP */
1539 #pragma omp critical(c_release_bg_data)
1540 #endif /* CV_OPENMP */
1542 if( cvbgreader != NULL )
1544 icvReleaseBackgroundReader( &cvbgreader );
1550 if( cvbgdata != NULL )
1552 icvReleaseBackgroundData( &cvbgdata );
1561 * Get sum, tilted, sqsum images and calculate normalization factor
1562 * All images must be allocated.
1565 void icvGetAuxImages( CvMat* img, CvMat* sum, CvMat* tilted,
1566 CvMat* sqsum, float* normfactor )
1570 sum_type valsum = 0;
1571 sqsum_type valsqsum = 0;
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 )
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];
1586 /* sqrt( valsqsum / area - ( valsum / are )^2 ) * area */
1587 (*normfactor) = (float) sqrt( (double) (area * valsqsum - (double)valsum * valsum) );
1591 /* consumed counter */
1592 typedef uint64 ccounter_t;
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) ) )
1603 * icvGetHaarTrainingData
1605 * Unified method that can now be used for vec file, bg file and bg vec file
1607 * Fill <data> with samples, passed <cascade>
1610 int icvGetHaarTrainingData( CvHaarTrainingData* data, int first, int count,
1611 CvIntHaarClassifier* cascade,
1612 CvGetHaarTrainingDataCallback callback, void* userdata,
1613 int* consumed, double* acceptance_ratio )
1616 ccounter_t getcount = 0;
1617 ccounter_t thread_getcount = 0;
1618 ccounter_t consumed_count;
1619 ccounter_t thread_consumed_count;
1621 /* private variables */
1628 sum_type* tilteddata;
1631 /* end private variables */
1633 assert( data != NULL );
1634 assert( first + count <= data->maxnum );
1635 assert( cascade != NULL );
1636 assert( callback != NULL );
1638 // if( !cvbgdata ) return 0; this check needs to be done in the callback for BG
1640 CCOUNTER_SET_ZERO(getcount);
1641 CCOUNTER_SET_ZERO(thread_getcount);
1642 CCOUNTER_SET_ZERO(consumed_count);
1643 CCOUNTER_SET_ZERO(thread_consumed_count);
1646 #pragma omp parallel private(img, sum, tilted, sqsum, sumdata, tilteddata, \
1647 normfactor, thread_consumed_count, thread_getcount)
1648 #endif /* CV_OPENMP */
1654 CCOUNTER_SET_ZERO(thread_getcount);
1655 CCOUNTER_SET_ZERO(thread_consumed_count);
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) ) );
1669 #pragma omp for schedule(static, 1)
1670 #endif /* CV_OPENMP */
1671 for( i = first; (i < first + count); i++ )
1677 ok = callback( &img, userdata );
1681 CCOUNTER_INC(thread_consumed_count);
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 )
1691 CCOUNTER_INC(thread_getcount);
1697 if( (i - first) % 500 == 0 )
1699 fprintf( stderr, "%3d%%\r", (int) ( 100.0 * (i - first) / count ) );
1702 #endif /* CV_VERBOSE */
1705 cvFree( &(img.data.ptr) );
1706 cvFree( &(sqsum.data.ptr) );
1709 #pragma omp critical (c_consumed_count)
1710 #endif /* CV_OPENMP */
1712 /* consumed_count += thread_consumed_count; */
1713 CCOUNTER_ADD(getcount, thread_getcount);
1714 CCOUNTER_ADD(consumed_count, thread_consumed_count);
1716 } /* omp parallel */
1718 if( consumed != NULL )
1720 *consumed = (int)consumed_count;
1723 if( acceptance_ratio != NULL )
1725 /* *acceptance_ratio = ((double) count) / consumed_count; */
1726 *acceptance_ratio = CCOUNTER_DIV(count, consumed_count);
1729 return static_cast<int>(getcount);
1733 * icvGetHaarTrainingDataFromBG
1735 * Fill <data> with background samples, passed <cascade>
1736 * Background reading process must be initialized before call.
1739 //int icvGetHaarTrainingDataFromBG( CvHaarTrainingData* data, int first, int count,
1740 // CvIntHaarClassifier* cascade, double* acceptance_ratio )
1743 // ccounter_t consumed_count;
1744 // ccounter_t thread_consumed_count;
1746 // /* private variables */
1752 // sum_type* sumdata;
1753 // sum_type* tilteddata;
1754 // float* normfactor;
1756 // /* end private variables */
1758 // assert( data != NULL );
1759 // assert( first + count <= data->maxnum );
1760 // assert( cascade != NULL );
1762 // if( !cvbgdata ) return 0;
1764 // CCOUNTER_SET_ZERO(consumed_count);
1765 // CCOUNTER_SET_ZERO(thread_consumed_count);
1768 // #pragma omp parallel private(img, sum, tilted, sqsum, sumdata, tilteddata,
1769 // normfactor, thread_consumed_count)
1770 // #endif /* CV_OPENMP */
1773 // tilteddata = NULL;
1774 // normfactor = NULL;
1776 // CCOUNTER_SET_ZERO(thread_consumed_count);
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) ) );
1790 // #pragma omp for schedule(static, 1)
1791 // #endif /* CV_OPENMP */
1792 // for( i = first; i < first + count; i++ )
1796 // icvGetBackgroundImage( cvbgdata, cvbgreader, &img );
1798 // CCOUNTER_INC(thread_consumed_count);
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 )
1813 // if( (i - first) % 500 == 0 )
1815 // fprintf( stderr, "%3d%%\r", (int) ( 100.0 * (i - first) / count ) );
1816 // fflush( stderr );
1818 //#endif /* CV_VERBOSE */
1822 // cvFree( &(img.data.ptr) );
1823 // cvFree( &(sqsum.data.ptr) );
1826 // #pragma omp critical (c_consumed_count)
1827 // #endif /* CV_OPENMP */
1829 // /* consumed_count += thread_consumed_count; */
1830 // CCOUNTER_ADD(consumed_count, thread_consumed_count);
1832 // } /* omp parallel */
1834 // if( acceptance_ratio != NULL )
1836 // /* *acceptance_ratio = ((double) count) / consumed_count; */
1837 // *acceptance_ratio = CCOUNTER_DIV(count, consumed_count);
1843 int icvGetHaarTraininDataFromVecCallback( CvMat* img, void* userdata )
1849 assert( img->rows * img->cols == ((CvVecFile*) userdata)->vecsize );
1851 fread( &tmp, sizeof( tmp ), 1, ((CvVecFile*) userdata)->input );
1852 fread( ((CvVecFile*) userdata)->vector, sizeof( short ),
1853 ((CvVecFile*) userdata)->vecsize, ((CvVecFile*) userdata)->input );
1855 if( feof( ((CvVecFile*) userdata)->input ) ||
1856 (((CvVecFile*) userdata)->last)++ >= ((CvVecFile*) userdata)->count )
1861 for( r = 0; r < img->rows; r++ )
1863 for( c = 0; c < img->cols; c++ )
1865 CV_MAT_ELEM( *img, uchar, r, c ) =
1866 (uchar) ( ((CvVecFile*) userdata)->vector[r * img->cols + c] );
1873 int icvGetHaarTrainingDataFromBGCallback ( CvMat* img, void* /*userdata*/ )
1881 // just in case icvGetBackgroundImage is not thread-safe ...
1883 #pragma omp critical (get_background_image_callback)
1884 #endif /* CV_OPENMP */
1886 icvGetBackgroundImage( cvbgdata, cvbgreader, img );
1893 * icvGetHaarTrainingDataFromVec
1894 * Get training data from .vec file
1897 int icvGetHaarTrainingDataFromVec( CvHaarTrainingData* data, int first, int count,
1898 CvIntHaarClassifier* cascade,
1899 const char* filename,
1904 CV_FUNCNAME( "icvGetHaarTrainingDataFromVec" );
1912 if( filename ) file.input = fopen( filename, "rb" );
1914 if( file.input != NULL )
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 ) )
1922 if( file.vecsize != data->winsize.width * data->winsize.height )
1924 fclose( file.input );
1925 CV_ERROR( CV_StsError, "Vec file sample size mismatch" );
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 );
1934 fclose( file.input );
1943 * icvGetHaarTrainingDataFromBG
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
1950 int icvGetHaarTrainingDataFromBG( CvHaarTrainingData* data, int first, int count,
1951 CvIntHaarClassifier* cascade, double* acceptance_ratio, const char * filename = NULL )
1953 CV_FUNCNAME( "icvGetHaarTrainingDataFromBG" );
1963 if( filename ) file.input = fopen( filename, "rb" );
1965 if( file.input != NULL )
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 ) )
1973 if( file.vecsize != data->winsize.width * data->winsize.height )
1975 fclose( file.input );
1976 CV_ERROR( CV_StsError, "Vec file sample size mismatch" );
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 );
1985 fclose( file.input );
1990 icvGetHaarTrainingData( data, first, count, cascade,
1991 icvGetHaarTrainingDataFromBGCallback, NULL, NULL, acceptance_ratio);
1999 void cvCreateCascadeClassifier( const char* dirname,
2000 const char* vecfilename,
2001 const char* bgfilename,
2002 int npos, int nneg, int nstages,
2003 int numprecalculated,
2005 float minhitrate, float maxfalsealarm,
2006 float weightfraction,
2007 int mode, int symmetric,
2009 int winwidth, int winheight,
2010 int boosttype, int stumperror )
2012 CvCascadeHaarClassifier* cascade = NULL;
2013 CvHaarTrainingData* data = NULL;
2014 CvIntHaarFeatures* haar_features;
2021 double false_alarm = 0;
2022 char stagename[PATH_MAX];
2023 float posweight = 1.0F;
2024 float negweight = 1.0F;
2028 double proctime = 0.0F;
2029 #endif /* CV_VERBOSE */
2031 assert( dirname != NULL );
2032 assert( bgfilename != NULL );
2033 assert( vecfilename != NULL );
2034 assert( nstages > 0 );
2036 winsize = cvSize( winwidth, winheight );
2038 cascade = (CvCascadeHaarClassifier*) icvCreateCascadeHaarClassifier( nstages );
2041 if( icvInitBackgroundReaders( bgfilename, winsize ) )
2043 data = icvCreateHaarTrainingData( winsize, npos + nneg );
2044 haar_features = icvCreateIntHaarFeatures( winsize, mode, symmetric );
2047 printf("Number of features used : %d\n", haar_features->count);
2048 #endif /* CV_VERBOSE */
2050 for( i = 0; i < nstages; i++, cascade->count++ )
2052 sprintf( stagename, "%s%d/%s", dirname, i, CV_STAGE_CART_FILE_NAME );
2053 cascade->classifier[i] =
2054 icvLoadCARTStageHaarClassifier( stagename, winsize.width + 1 );
2056 if( !icvMkDir( stagename ) )
2060 printf( "UNABLE TO CREATE DIRECTORY: %s\n", stagename );
2061 #endif /* CV_VERBOSE */
2065 if( cascade->classifier[i] != NULL )
2069 printf( "STAGE: %d LOADED.\n", i );
2070 #endif /* CV_VERBOSE */
2076 printf( "STAGE: %d\n", i );
2077 #endif /* CV_VERBOSE */
2079 poscount = icvGetHaarTrainingDataFromVec( data, 0, npos,
2080 (CvIntHaarClassifier*) cascade, vecfilename, &consumed );
2082 printf( "POS: %d %d %f\n", poscount, consumed,
2083 ((float) poscount) / consumed );
2084 #endif /* CV_VERBOSE */
2090 printf( "UNABLE TO OBTAIN POS SAMPLES\n" );
2091 #endif /* CV_VERBOSE */
2097 proctime = -TIME( 0 );
2098 #endif /* CV_VERBOSE */
2100 negcount = icvGetHaarTrainingDataFromBG( data, poscount, nneg,
2101 (CvIntHaarClassifier*) cascade, &false_alarm );
2103 printf( "NEG: %d %g\n", negcount, false_alarm );
2104 printf( "BACKGROUND PROCESSING TIME: %.2f\n",
2105 (proctime + TIME( 0 )) );
2106 #endif /* CV_VERBOSE */
2112 printf( "UNABLE TO OBTAIN NEG SAMPLES\n" );
2113 #endif /* CV_VERBOSE */
2118 data->sum.rows = data->tilted.rows = poscount + negcount;
2119 data->normfactor.cols = data->weights.cols = data->cls.cols =
2120 poscount + negcount;
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++ )
2126 data->weights.data.fl[j] = posweight;
2127 data->cls.data.fl[j] = 1.0F;
2130 for( j = poscount; j < poscount + negcount; j++ )
2132 data->weights.data.fl[j] = negweight;
2133 data->cls.data.fl[j] = 0.0F;
2137 proctime = -TIME( 0 );
2138 #endif /* CV_VERBOSE */
2140 icvPrecalculate( data, haar_features, numprecalculated );
2143 printf( "PRECALCULATION TIME: %.2f\n", (proctime + TIME( 0 )) );
2144 #endif /* CV_VERBOSE */
2147 proctime = -TIME( 0 );
2148 #endif /* CV_VERBOSE */
2150 cascade->classifier[i] = icvCreateCARTStageClassifier( data, NULL,
2151 haar_features, minhitrate, maxfalsealarm, symmetric, weightfraction,
2152 numsplits, (CvBoostType) boosttype, (CvStumpError) stumperror, 0 );
2155 printf( "STAGE TRAINING TIME: %.2f\n", (proctime + TIME( 0 )) );
2156 #endif /* CV_VERBOSE */
2158 file = fopen( stagename, "w" );
2161 cascade->classifier[i]->save(
2162 (CvIntHaarClassifier*) cascade->classifier[i], file );
2169 printf( "FAILED TO SAVE STAGE CLASSIFIER IN FILE %s\n", stagename );
2170 #endif /* CV_VERBOSE */
2175 icvReleaseIntHaarFeatures( &haar_features );
2176 icvReleaseHaarTrainingData( &data );
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] == '/' )
2186 strcpy( xml_path + len, ".xml" );
2187 cascade = cvLoadHaarClassifierCascade( dirname, cvSize(winwidth,winheight) );
2189 cvSave( xml_path, cascade );
2190 cvReleaseHaarClassifierCascade( &cascade );
2196 printf( "FAILED TO INITIALIZE BACKGROUND READERS\n" );
2197 #endif /* CV_VERBOSE */
2201 icvDestroyBackgroundReaders();
2202 cascade->release( (CvIntHaarClassifier**) &cascade );
2205 /* tree cascade classifier */
2207 int icvNumSplits( CvStageHaarClassifier* stage )
2213 for( i = 0; i < stage->count; i++ )
2215 num += ((CvCARTHaarClassifier*) stage->classifier[i])->count;
2221 void icvSetNumSamples( CvHaarTrainingData* training_data, int num )
2223 assert( num <= training_data->maxnum );
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;
2230 void icvSetWeightsAndClasses( CvHaarTrainingData* training_data,
2231 int num1, float weight1, float cls1,
2232 int num2, float weight2, float cls2 )
2236 assert( num1 + num2 <= training_data->maxnum );
2238 for( j = 0; j < num1; j++ )
2240 training_data->weights.data.fl[j] = weight1;
2241 training_data->cls.data.fl[j] = cls1;
2243 for( j = num1; j < num1 + num2; j++ )
2245 training_data->weights.data.fl[j] = weight2;
2246 training_data->cls.data.fl[j] = cls2;
2250 CvMat* icvGetUsedValues( CvHaarTrainingData* training_data,
2252 CvIntHaarFeatures* haar_features,
2253 CvStageHaarClassifier* stage )
2256 CvMat* feature_idx = NULL;
2258 CV_FUNCNAME( "icvGetUsedValues" );
2267 num_splits = icvNumSplits( stage );
2269 CV_CALL( feature_idx = cvCreateMat( 1, num_splits, CV_32SC1 ) );
2272 for( i = 0; i < stage->count; i++ )
2274 CvCARTHaarClassifier* cart;
2276 cart = (CvCARTHaarClassifier*) stage->classifier[i];
2277 for( j = 0; j < cart->count; j++ )
2279 feature_idx->data.i[total++] = cart->compidx[j];
2282 icvSort_32s( feature_idx->data.i, total, 0 );
2285 for( i = 1; i < total; i++ )
2287 if( feature_idx->data.i[i] != feature_idx->data.i[last] )
2289 feature_idx->data.i[++last] = feature_idx->data.i[i];
2293 CV_CALL( ptr = cvCreateMat( num, total, CV_32FC1 ) );
2297 #pragma omp parallel for
2299 for( r = start; r < start + num; r++ )
2303 for( c = 0; c < total; c++ )
2305 float val, normfactor;
2308 fnum = feature_idx->data.i[c];
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;
2323 cvReleaseMat( &feature_idx );
2328 /* possible split in the tree */
2329 typedef struct CvSplit
2331 CvTreeCascadeNode* parent;
2332 CvTreeCascadeNode* single_cluster;
2333 CvTreeCascadeNode* multiple_clusters;
2335 float single_multiple_ratio;
2337 struct CvSplit* next;
2341 void cvCreateTreeCascadeClassifier( const char* dirname,
2342 const char* vecfilename,
2343 const char* bgfilename,
2344 int npos, int nneg, int nstages,
2345 int numprecalculated,
2347 float minhitrate, float maxfalsealarm,
2348 float weightfraction,
2349 int mode, int symmetric,
2351 int winwidth, int winheight,
2352 int boosttype, int stumperror,
2353 int maxtreesplits, int minpos, bool bg_vecfile )
2355 CvTreeCascadeClassifier* tcc = NULL;
2356 CvIntHaarFeatures* haar_features = NULL;
2357 CvHaarTrainingData* training_data = NULL;
2359 CvMat* cluster_idx = NULL;
2361 CvMat* features_idx = NULL;
2363 CV_FUNCNAME( "cvCreateTreeCascadeClassifier" );
2368 CvTreeCascadeNode* leaves;
2369 int best_num, cur_num;
2371 char stage_name[PATH_MAX];
2383 double required_leaf_fa_rate;
2388 max_clusters = CV_MAX_CLUSTERS;
2389 neg_ratio = (float) nneg / npos;
2391 nleaves = 1 + MAX( 0, maxtreesplits );
2392 required_leaf_fa_rate = pow( (double) maxfalsealarm, (double) nstages ) / nleaves;
2394 printf( "Required leaf false alarm rate: %g\n", required_leaf_fa_rate );
2398 winsize = cvSize( winwidth, winheight );
2400 CV_CALL( cluster_idx = cvCreateMat( 1, npos + nneg, CV_32SC1 ) );
2401 CV_CALL( idx = cvCreateMat( 1, npos + nneg, CV_32SC1 ) );
2403 CV_CALL( tcc = (CvTreeCascadeClassifier*)
2404 icvLoadTreeCascadeClassifier( dirname, winwidth + 1, &total_splits ) );
2405 CV_CALL( leaves = icvFindDeepestLeaves( tcc ) );
2407 CV_CALL( icvPrintTreeCascade( tcc->root ) );
2409 haar_features = icvCreateIntHaarFeatures( winsize, mode, symmetric );
2411 printf( "Number of features used : %d\n", haar_features->count );
2413 training_data = icvCreateHaarTrainingData( winsize, npos + nneg );
2415 sprintf( stage_name, "%s/", dirname );
2416 suffix = stage_name + strlen( stage_name );
2419 if( !icvInitBackgroundReaders( bgfilename, winsize ) && nstages > 0 )
2420 CV_ERROR( CV_StsError, "Unable to read negative images" );
2424 /* width-first search in the tree */
2427 CvSplit* first_split;
2428 CvSplit* last_split;
2431 CvTreeCascadeNode* parent;
2432 CvTreeCascadeNode* cur_node;
2433 CvTreeCascadeNode* last_node;
2435 first_split = last_split = cur_split = NULL;
2440 int best_clusters; /* best selected number of clusters */
2441 float posweight, negweight;
2442 double leaf_fa_rate;
2444 if( parent ) sprintf( buf, "%d", parent->idx );
2445 else sprintf( buf, "NULL" );
2446 printf( "\nParent node: %s\n\n", buf );
2448 printf( "*** 1 cluster ***\n" );
2450 tcc->eval = icvEvalTreeCascadeClassifierFilter;
2451 /* find path from the root to the node <parent> */
2452 icvSetLeafNode( tcc, parent );
2456 poscount = icvGetHaarTrainingDataFromVec( training_data, 0, npos,
2457 (CvIntHaarClassifier*) tcc, vecfilename, &consumed );
2459 printf( "POS: %d %d %f\n", poscount, consumed, ((double) poscount)/consumed );
2462 CV_ERROR( CV_StsError, "Unable to obtain positive samples" );
2466 proctime = -TIME( 0 );
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 );
2473 printf( "BACKGROUND PROCESSING TIME: %.2f\n", (proctime + TIME( 0 )) );
2476 CV_ERROR( CV_StsError, "Unable to obtain negative samples" );
2478 leaf_fa_rate = false_alarm;
2479 if( leaf_fa_rate <= required_leaf_fa_rate )
2481 printf( "Required leaf false alarm rate achieved. "
2482 "Branch training terminated.\n" );
2484 else if( nleaves == 1 && tcc->next_idx == nstages )
2486 printf( "Required number of stages achieved. "
2487 "Branch training terminated.\n" );
2491 CvTreeCascadeNode* single_cluster;
2492 CvTreeCascadeNode* multiple_clusters;
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 );
2504 /* precalculate feature values */
2505 proctime = -TIME( 0 );
2506 icvPrecalculate( training_data, haar_features, numprecalculated );
2507 printf( "Precalculation time: %.2f\n", (proctime + TIME( 0 )) );
2509 /* train stage classifier using all positive samples */
2510 CV_CALL( single_cluster = icvCreateTreeCascadeNode() );
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 )) );
2522 single_num = icvNumSplits( single_cluster->stage );
2523 best_num = single_num;
2525 multiple_clusters = NULL;
2527 printf( "Number of used features: %d\n", single_num );
2529 if( maxtreesplits >= 0 )
2531 max_clusters = MIN( max_clusters, maxtreesplits - total_splits + 1 );
2534 /* try clustering */
2536 for( k = 2; k <= max_clusters; k++ )
2539 int stop_clustering;
2541 printf( "*** %d clusters ***\n", k );
2543 /* check whether clusters are big enough */
2544 stop_clustering = ( k * minpos > poscount );
2545 if( !stop_clustering )
2547 int num[CV_MAX_CLUSTERS];
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 );
2558 cluster_idx->cols = vals->rows;
2559 for( i = 0; i < negcount; i++ ) idx->data.i[i] = poscount + i;
2562 proctime = -TIME( 0 );
2564 CV_CALL( cvKMeans2( vals, k, cluster_idx, CV_TERM_CRITERIA() ) );
2566 printf( "Clustering time: %.2f\n", (proctime + TIME( 0 )) );
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++ )
2573 if( num[cluster] < minpos )
2575 stop_clustering = 1;
2581 if( stop_clustering )
2583 printf( "Clusters are too small. Clustering aborted.\n" );
2588 cur_node = last_node = NULL;
2589 for( cluster = 0; (cluster < k) && (cur_num < best_num); cluster++ )
2591 CvTreeCascadeNode* new_node;
2597 printf( "Cluster: %d\n", cluster );
2599 last_pos = negcount;
2600 for( i = 0; i < cluster_idx->cols; i++ )
2602 if( cluster_idx->data.i[i] == cluster )
2604 idx->data.i[last_pos++] = i;
2607 idx->cols = last_pos;
2609 total_pos = idx->cols - negcount;
2610 printf( "# pos: %d of %d. (%d%%)\n", total_pos, poscount,
2611 100 * total_pos / poscount );
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;
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);
2623 icvSetWeightsAndClasses( training_data,
2624 poscount, posweight, 1.0F, negcount, negweight, 0.0F );
2626 /* CV_DEBUG_SAVE( idx ); */
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 )) );
2638 if( !(new_node->stage) )
2640 printf( "Stage training aborted.\n" );
2641 cur_num = best_num + 1;
2645 num_splits = icvNumSplits( new_node->stage );
2646 cur_num += num_splits;
2648 printf( "Number of used features: %d\n", num_splits );
2650 } /* for each cluster */
2652 if( cur_num < best_num )
2654 icvReleaseTreeCascadeNodes( &multiple_clusters );
2657 multiple_clusters = cur_node;
2661 icvReleaseTreeCascadeNodes( &cur_node );
2663 } /* try different number of clusters */
2664 cvReleaseMat( &vals );
2666 CV_CALL( cur_split = (CvSplit*) cvAlloc( sizeof( *cur_split ) ) );
2667 CV_ZERO_OBJ( cur_split );
2669 if( last_split ) last_split->next = cur_split;
2670 else first_split = cur_split;
2671 last_split = cur_split;
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;
2680 if( parent ) parent = parent->next_same_level;
2683 /* choose which nodes should be splitted */
2686 float max_single_multiple_ratio;
2689 max_single_multiple_ratio = 0.0F;
2690 last_split = first_split;
2693 if( last_split->single_cluster && last_split->multiple_clusters &&
2694 last_split->single_multiple_ratio > max_single_multiple_ratio )
2696 max_single_multiple_ratio = last_split->single_multiple_ratio;
2697 cur_split = last_split;
2699 last_split = last_split->next;
2703 if( maxtreesplits < 0 ||
2704 cur_split->num_clusters <= maxtreesplits - total_splits + 1 )
2706 cur_split->single_cluster = NULL;
2707 total_splits += cur_split->num_clusters - 1;
2711 icvReleaseTreeCascadeNodes( &(cur_split->multiple_clusters) );
2712 cur_split->multiple_clusters = NULL;
2715 } while( cur_split );
2717 /* attach new nodes to the tree */
2718 leaves = last_node = NULL;
2719 last_split = first_split;
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;
2727 /* connect leaves via next_same_level and save them */
2728 for( ; cur_node; cur_node = cur_node->next )
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;
2737 cur_node->idx = tcc->next_idx;
2739 sprintf( suffix, "%d/%s", cur_node->idx, CV_STAGE_CART_FILE_NAME );
2741 if( icvMkDir( stage_name ) && (file = fopen( stage_name, "w" )) != 0 )
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) );
2750 printf( "Failed to save classifier into %s\n", stage_name );
2752 if( file ) fclose( file );
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 );
2761 cur_split = last_split;
2762 last_split = last_split->next;
2763 cvFree( &cur_split );
2764 } /* for each split point */
2766 printf( "Total number of splits: %d\n", total_splits );
2768 if( !(tcc->root) ) tcc->root = leaves;
2769 CV_CALL( icvPrintTreeCascade( tcc->root ) );
2773 /* save the cascade to xml file */
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] == '/' )
2781 strcpy( xml_path + len, ".xml" );
2782 cascade = cvLoadHaarClassifierCascade( dirname, cvSize(winwidth,winheight) );
2784 cvSave( xml_path, cascade );
2785 cvReleaseHaarClassifierCascade( &cascade );
2788 } /* if( nstages > 0 ) */
2790 /* check cascade performance */
2791 printf( "\nCascade performance\n" );
2793 tcc->eval = icvEvalTreeCascadeClassifier;
2797 poscount = icvGetHaarTrainingDataFromVec( training_data, 0, npos,
2798 (CvIntHaarClassifier*) tcc, vecfilename, &consumed );
2800 printf( "POS: %d %d %f\n", poscount, consumed,
2801 (consumed > 0) ? (((float) poscount)/consumed) : 0 );
2804 fprintf( stderr, "Warning: unable to obtain positive samples\n" );
2806 proctime = -TIME( 0 );
2808 negcount = icvGetHaarTrainingDataFromBG( training_data, poscount, nneg,
2809 (CvIntHaarClassifier*) tcc, &false_alarm, bg_vecfile ? bgfilename : NULL );
2811 printf( "NEG: %d %g\n", negcount, false_alarm );
2813 printf( "BACKGROUND PROCESSING TIME: %.2f\n", (proctime + TIME( 0 )) );
2816 fprintf( stderr, "Warning: unable to obtain negative samples\n" );
2821 icvDestroyBackgroundReaders();
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 );
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,
2840 int winwidth, int winheight )
2842 CvSampleDistortionData data;
2844 assert( filename != NULL );
2845 assert( imgfilename != NULL );
2847 if( !icvMkDir( filename ) )
2849 fprintf( stderr, "Unable to create output file: %s\n", filename );
2852 if( icvStartSampleDistortion( imgfilename, bgcolor, bgthreshold, &data ) )
2854 FILE* output = NULL;
2856 output = fopen( filename, "wb" );
2857 if( output != NULL )
2865 hasbg = (bgfilename != NULL && icvInitBackgroundReaders( bgfilename,
2866 cvSize( winwidth,winheight ) ) );
2868 sample = cvMat( winheight, winwidth, CV_8UC1, cvAlloc( sizeof( uchar ) *
2869 winheight * winwidth ) );
2871 icvWriteVecHeader( output, count, sample.cols, sample.rows );
2875 cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
2879 for( i = 0; i < count; i++ )
2883 icvGetBackgroundImage( cvbgdata, cvbgreader, &sample );
2887 cvSet( &sample, cvScalar( bgcolor ) );
2890 if( invert == CV_RANDOM_INVERT )
2892 inverse = (rand() > (RAND_MAX/2));
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 */,
2903 cvShowImage( "Sample", &sample );
2904 if( cvWaitKey( 0 ) == 27 )
2910 icvWriteVecSample( output, &sample );
2915 printf( "\r%3d%%", 100 * i / count );
2917 #endif /* CV_VERBOSE */
2919 icvDestroyBackgroundReaders();
2920 cvFree( &(sample.data.ptr) );
2922 } /* if( output != NULL ) */
2924 icvEndSampleDistortion( &data );
2929 #endif /* CV_VERBOSE */
2933 #define CV_INFO_FILENAME "info.dat"
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,
2942 int winwidth, int winheight )
2944 CvSampleDistortionData data;
2946 assert( infoname != NULL );
2947 assert( imgfilename != NULL );
2948 assert( bgfilename != NULL );
2950 if( !icvMkDir( infoname ) )
2954 fprintf( stderr, "Unable to create directory hierarchy: %s\n", infoname );
2955 #endif /* CV_VERBOSE */
2959 if( icvStartSampleDistortion( imgfilename, bgcolor, bgthreshold, &data ) )
2961 char fullname[PATH_MAX];
2966 if( icvInitBackgroundReaders( bgfilename, cvSize( 10, 10 ) ) )
2969 int x, y, width, height;
2976 cvNamedWindow( "Image", CV_WINDOW_AUTOSIZE );
2979 info = fopen( infoname, "w" );
2980 strcpy( fullname, infoname );
2981 filename = strrchr( fullname, '\\' );
2982 if( filename == NULL )
2984 filename = strrchr( fullname, '/' );
2986 if( filename == NULL )
2988 filename = fullname;
2995 count = MIN( count, cvbgdata->count );
2997 for( i = 0; i < count; i++ )
2999 icvGetNextFromBackgroundData( cvbgdata, cvbgreader );
3001 maxscale = MIN( 0.7F * cvbgreader->src.cols / winwidth,
3002 0.7F * cvbgreader->src.rows / winheight );
3003 if( maxscale < 1.0F ) continue;
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));
3011 cvGetSubArr( &cvbgreader->src, &win, cvRect( x, y ,width, height ) );
3012 if( invert == CV_RANDOM_INVERT )
3014 inverse = (rand() > (RAND_MAX/2));
3016 icvPlaceDistortedSample( &win, inverse, maxintensitydev,
3017 maxxangle, maxyangle, maxzangle,
3018 1, 0.0, 0.0, &data );
3021 sprintf( filename, "%04d_%04d_%04d_%04d_%04d.jpg",
3022 (i + 1), x, y, width, height );
3026 fprintf( info, "%s %d %d %d %d %d\n",
3027 filename, 1, x, y, width, height );
3030 cvSaveImage( fullname, &cvbgreader->src );
3033 cvShowImage( "Image", &cvbgreader->src );
3034 if( cvWaitKey( 0 ) == 27 )
3040 if( info ) fclose( info );
3041 icvDestroyBackgroundReaders();
3043 icvEndSampleDistortion( &data );