Update to 2.0.0 tree from current Fremantle build
[opencv] / src / cv / cvhaar.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 /* Haar features calculation */
43
44 #include "_cv.h"
45 #include <stdio.h>
46
47 #if CV_SSE2
48 #   if CV_SSE4 || defined __SSE4__
49 #       include <smmintrin.h>
50 #   else
51 #       define _mm_blendv_pd(a, b, m) _mm_xor_pd(a, _mm_and_pd(_mm_xor_pd(b, a), m))
52 #       define _mm_blendv_ps(a, b, m) _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(b, a), m))
53 #   endif
54 #if defined CV_ICC
55 #   define CV_HAAR_USE_SSE 1
56 #endif
57 #endif
58
59 /* these settings affect the quality of detection: change with care */
60 #define CV_ADJUST_FEATURES 1
61 #define CV_ADJUST_WEIGHTS  0
62
63 typedef int sumtype;
64 typedef double sqsumtype;
65
66 typedef struct CvHidHaarFeature
67 {
68     struct
69     {
70         sumtype *p0, *p1, *p2, *p3;
71         float weight;
72     }
73     rect[CV_HAAR_FEATURE_MAX];
74 }
75 CvHidHaarFeature;
76
77
78 typedef struct CvHidHaarTreeNode
79 {
80     CvHidHaarFeature feature;
81     float threshold;
82     int left;
83     int right;
84 }
85 CvHidHaarTreeNode;
86
87
88 typedef struct CvHidHaarClassifier
89 {
90     int count;
91     //CvHaarFeature* orig_feature;
92     CvHidHaarTreeNode* node;
93     float* alpha;
94 }
95 CvHidHaarClassifier;
96
97
98 typedef struct CvHidHaarStageClassifier
99 {
100     int  count;
101     float threshold;
102     CvHidHaarClassifier* classifier;
103     int two_rects;
104
105     struct CvHidHaarStageClassifier* next;
106     struct CvHidHaarStageClassifier* child;
107     struct CvHidHaarStageClassifier* parent;
108 }
109 CvHidHaarStageClassifier;
110
111
112 struct CvHidHaarClassifierCascade
113 {
114     int  count;
115     int  is_stump_based;
116     int  has_tilted_features;
117     int  is_tree;
118     double inv_window_area;
119     CvMat sum, sqsum, tilted;
120     CvHidHaarStageClassifier* stage_classifier;
121     sqsumtype *pq0, *pq1, *pq2, *pq3;
122     sumtype *p0, *p1, *p2, *p3;
123
124     void** ipp_stages;
125 };
126
127
128 const int icv_object_win_border = 1;
129 const float icv_stage_threshold_bias = 0.0001f;
130
131 static CvHaarClassifierCascade*
132 icvCreateHaarClassifierCascade( int stage_count )
133 {
134     CvHaarClassifierCascade* cascade = 0;
135
136     CV_FUNCNAME( "icvCreateHaarClassifierCascade" );
137
138     __BEGIN__;
139
140     int block_size = sizeof(*cascade) + stage_count*sizeof(*cascade->stage_classifier);
141
142     if( stage_count <= 0 )
143         CV_ERROR( CV_StsOutOfRange, "Number of stages should be positive" );
144
145     CV_CALL( cascade = (CvHaarClassifierCascade*)cvAlloc( block_size ));
146     memset( cascade, 0, block_size );
147
148     cascade->stage_classifier = (CvHaarStageClassifier*)(cascade + 1);
149     cascade->flags = CV_HAAR_MAGIC_VAL;
150     cascade->count = stage_count;
151
152     __END__;
153
154     return cascade;
155 }
156
157 static void
158 icvReleaseHidHaarClassifierCascade( CvHidHaarClassifierCascade** _cascade )
159 {
160     if( _cascade && *_cascade )
161     {
162 #ifdef HAVE_IPP
163         CvHidHaarClassifierCascade* cascade = *_cascade;
164         if( cascade->ipp_stages )
165         {
166             int i;
167             for( i = 0; i < cascade->count; i++ )
168             {
169                 if( cascade->ipp_stages[i] )
170                     ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)cascade->ipp_stages[i] );
171             }
172         }
173         cvFree( &cascade->ipp_stages );
174 #endif
175         cvFree( _cascade );
176     }
177 }
178
179 /* create more efficient internal representation of haar classifier cascade */
180 static CvHidHaarClassifierCascade*
181 icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
182 {
183     CvRect* ipp_features = 0;
184     float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0;
185     int* ipp_counts = 0;
186
187     CvHidHaarClassifierCascade* out = 0;
188
189     CV_FUNCNAME( "icvCreateHidHaarClassifierCascade" );
190
191     __BEGIN__;
192
193     int i, j, k, l;
194     int datasize;
195     int total_classifiers = 0;
196     int total_nodes = 0;
197     char errorstr[100];
198     CvHidHaarClassifier* haar_classifier_ptr;
199     CvHidHaarTreeNode* haar_node_ptr;
200     CvSize orig_window_size;
201     int has_tilted_features = 0;
202     int max_count = 0;
203
204     if( !CV_IS_HAAR_CLASSIFIER(cascade) )
205         CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
206
207     if( cascade->hid_cascade )
208         CV_ERROR( CV_StsError, "hid_cascade has been already created" );
209
210     if( !cascade->stage_classifier )
211         CV_ERROR( CV_StsNullPtr, "" );
212
213     if( cascade->count <= 0 )
214         CV_ERROR( CV_StsOutOfRange, "Negative number of cascade stages" );
215
216     orig_window_size = cascade->orig_window_size;
217
218     /* check input structure correctness and calculate total memory size needed for
219        internal representation of the classifier cascade */
220     for( i = 0; i < cascade->count; i++ )
221     {
222         CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
223
224         if( !stage_classifier->classifier ||
225             stage_classifier->count <= 0 )
226         {
227             sprintf( errorstr, "header of the stage classifier #%d is invalid "
228                      "(has null pointers or non-positive classfier count)", i );
229             CV_ERROR( CV_StsError, errorstr );
230         }
231
232         max_count = MAX( max_count, stage_classifier->count );
233         total_classifiers += stage_classifier->count;
234
235         for( j = 0; j < stage_classifier->count; j++ )
236         {
237             CvHaarClassifier* classifier = stage_classifier->classifier + j;
238
239             total_nodes += classifier->count;
240             for( l = 0; l < classifier->count; l++ )
241             {
242                 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
243                 {
244                     if( classifier->haar_feature[l].rect[k].r.width )
245                     {
246                         CvRect r = classifier->haar_feature[l].rect[k].r;
247                         int tilted = classifier->haar_feature[l].tilted;
248                         has_tilted_features |= tilted != 0;
249                         if( r.width < 0 || r.height < 0 || r.y < 0 ||
250                             r.x + r.width > orig_window_size.width
251                             ||
252                             (!tilted &&
253                             (r.x < 0 || r.y + r.height > orig_window_size.height))
254                             ||
255                             (tilted && (r.x - r.height < 0 ||
256                             r.y + r.width + r.height > orig_window_size.height)))
257                         {
258                             sprintf( errorstr, "rectangle #%d of the classifier #%d of "
259                                      "the stage classifier #%d is not inside "
260                                      "the reference (original) cascade window", k, j, i );
261                             CV_ERROR( CV_StsNullPtr, errorstr );
262                         }
263                     }
264                 }
265             }
266         }
267     }
268
269     // this is an upper boundary for the whole hidden cascade size
270     datasize = sizeof(CvHidHaarClassifierCascade) +
271                sizeof(CvHidHaarStageClassifier)*cascade->count +
272                sizeof(CvHidHaarClassifier) * total_classifiers +
273                sizeof(CvHidHaarTreeNode) * total_nodes +
274                sizeof(void*)*(total_nodes + total_classifiers);
275
276     CV_CALL( out = (CvHidHaarClassifierCascade*)cvAlloc( datasize ));
277     memset( out, 0, sizeof(*out) );
278
279     /* init header */
280     out->count = cascade->count;
281     out->stage_classifier = (CvHidHaarStageClassifier*)(out + 1);
282     haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count);
283     haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);
284
285     out->is_stump_based = 1;
286     out->has_tilted_features = has_tilted_features;
287     out->is_tree = 0;
288
289     /* initialize internal representation */
290     for( i = 0; i < cascade->count; i++ )
291     {
292         CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
293         CvHidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i;
294
295         hid_stage_classifier->count = stage_classifier->count;
296         hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias;
297         hid_stage_classifier->classifier = haar_classifier_ptr;
298         hid_stage_classifier->two_rects = 1;
299         haar_classifier_ptr += stage_classifier->count;
300
301         hid_stage_classifier->parent = (stage_classifier->parent == -1)
302             ? NULL : out->stage_classifier + stage_classifier->parent;
303         hid_stage_classifier->next = (stage_classifier->next == -1)
304             ? NULL : out->stage_classifier + stage_classifier->next;
305         hid_stage_classifier->child = (stage_classifier->child == -1)
306             ? NULL : out->stage_classifier + stage_classifier->child;
307
308         out->is_tree |= hid_stage_classifier->next != NULL;
309
310         for( j = 0; j < stage_classifier->count; j++ )
311         {
312             CvHaarClassifier* classifier = stage_classifier->classifier + j;
313             CvHidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j;
314             int node_count = classifier->count;
315             float* alpha_ptr = (float*)(haar_node_ptr + node_count);
316
317             hid_classifier->count = node_count;
318             hid_classifier->node = haar_node_ptr;
319             hid_classifier->alpha = alpha_ptr;
320
321             for( l = 0; l < node_count; l++ )
322             {
323                 CvHidHaarTreeNode* node = hid_classifier->node + l;
324                 CvHaarFeature* feature = classifier->haar_feature + l;
325                 memset( node, -1, sizeof(*node) );
326                 node->threshold = classifier->threshold[l];
327                 node->left = classifier->left[l];
328                 node->right = classifier->right[l];
329
330                 if( fabs(feature->rect[2].weight) < DBL_EPSILON ||
331                     feature->rect[2].r.width == 0 ||
332                     feature->rect[2].r.height == 0 )
333                     memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) );
334                 else
335                     hid_stage_classifier->two_rects = 0;
336             }
337
338             memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0]));
339             haar_node_ptr =
340                 (CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*));
341
342             out->is_stump_based &= node_count == 1;
343         }
344     }
345
346 #ifdef HAVE_IPP
347     {
348     int can_use_ipp = !out->has_tilted_features && !out->is_tree && out->is_stump_based;
349
350     if( can_use_ipp )
351     {
352         int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]);
353         float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)*
354             (orig_window_size.height-icv_object_win_border*2)));
355
356         CV_CALL( out->ipp_stages = (void**)cvAlloc( ipp_datasize ));
357         memset( out->ipp_stages, 0, ipp_datasize );
358
359         CV_CALL( ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) ));
360         CV_CALL( ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) ));
361         CV_CALL( ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) ));
362         CV_CALL( ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) ));
363         CV_CALL( ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) ));
364         CV_CALL( ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) ));
365
366         for( i = 0; i < cascade->count; i++ )
367         {
368             CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
369             for( j = 0, k = 0; j < stage_classifier->count; j++ )
370             {
371                 CvHaarClassifier* classifier = stage_classifier->classifier + j;
372                 int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0);
373
374                 ipp_thresholds[j] = classifier->threshold[0];
375                 ipp_val1[j] = classifier->alpha[0];
376                 ipp_val2[j] = classifier->alpha[1];
377                 ipp_counts[j] = rect_count;
378
379                 for( l = 0; l < rect_count; l++, k++ )
380                 {
381                     ipp_features[k] = classifier->haar_feature->rect[l].r;
382                     //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height;
383                     ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale;
384                 }
385             }
386
387             if( ippiHaarClassifierInitAlloc_32f( (IppiHaarClassifier_32f**)&out->ipp_stages[i],
388                 (const IppiRect*)ipp_features, ipp_weights, ipp_thresholds,
389                 ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 )
390                 break;
391         }
392
393         if( i < cascade->count )
394         {
395             for( j = 0; j < i; j++ )
396                 if( out->ipp_stages[i] )
397                     ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)out->ipp_stages[i] );
398             cvFree( &out->ipp_stages );
399         }
400     }
401     }
402 #endif
403
404     cascade->hid_cascade = out;
405     assert( (char*)haar_node_ptr - (char*)out <= datasize );
406
407     __END__;
408
409     if( cvGetErrStatus() < 0 )
410         icvReleaseHidHaarClassifierCascade( &out );
411
412     cvFree( &ipp_features );
413     cvFree( &ipp_weights );
414     cvFree( &ipp_thresholds );
415     cvFree( &ipp_val1 );
416     cvFree( &ipp_val2 );
417     cvFree( &ipp_counts );
418
419     return out;
420 }
421
422
423 #define sum_elem_ptr(sum,row,col)  \
424     ((sumtype*)CV_MAT_ELEM_PTR_FAST((sum),(row),(col),sizeof(sumtype)))
425
426 #define sqsum_elem_ptr(sqsum,row,col)  \
427     ((sqsumtype*)CV_MAT_ELEM_PTR_FAST((sqsum),(row),(col),sizeof(sqsumtype)))
428
429 #define calc_sum(rect,offset) \
430     ((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset])
431
432
433 CV_IMPL void
434 cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* _cascade,
435                                      const CvArr* _sum,
436                                      const CvArr* _sqsum,
437                                      const CvArr* _tilted_sum,
438                                      double scale )
439 {
440     CV_FUNCNAME("cvSetImagesForHaarClassifierCascade");
441
442     __BEGIN__;
443
444     CvMat sum_stub, *sum = (CvMat*)_sum;
445     CvMat sqsum_stub, *sqsum = (CvMat*)_sqsum;
446     CvMat tilted_stub, *tilted = (CvMat*)_tilted_sum;
447     CvHidHaarClassifierCascade* cascade;
448     int coi0 = 0, coi1 = 0;
449     int i;
450     CvRect equ_rect;
451     double weight_scale;
452
453     if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
454         CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
455
456     if( scale <= 0 )
457         CV_ERROR( CV_StsOutOfRange, "Scale must be positive" );
458
459     CV_CALL( sum = cvGetMat( sum, &sum_stub, &coi0 ));
460     CV_CALL( sqsum = cvGetMat( sqsum, &sqsum_stub, &coi1 ));
461
462     if( coi0 || coi1 )
463         CV_ERROR( CV_BadCOI, "COI is not supported" );
464
465     if( !CV_ARE_SIZES_EQ( sum, sqsum ))
466         CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" );
467
468     if( CV_MAT_TYPE(sqsum->type) != CV_64FC1 ||
469         CV_MAT_TYPE(sum->type) != CV_32SC1 )
470         CV_ERROR( CV_StsUnsupportedFormat,
471         "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
472
473     if( !_cascade->hid_cascade )
474         CV_CALL( icvCreateHidHaarClassifierCascade(_cascade) );
475
476     cascade = _cascade->hid_cascade;
477
478     if( cascade->has_tilted_features )
479     {
480         CV_CALL( tilted = cvGetMat( tilted, &tilted_stub, &coi1 ));
481
482         if( CV_MAT_TYPE(tilted->type) != CV_32SC1 )
483             CV_ERROR( CV_StsUnsupportedFormat,
484             "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
485
486         if( sum->step != tilted->step )
487             CV_ERROR( CV_StsUnmatchedSizes,
488             "Sum and tilted_sum must have the same stride (step, widthStep)" );
489
490         if( !CV_ARE_SIZES_EQ( sum, tilted ))
491             CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" );
492         cascade->tilted = *tilted;
493     }
494
495     _cascade->scale = scale;
496     _cascade->real_window_size.width = cvRound( _cascade->orig_window_size.width * scale );
497     _cascade->real_window_size.height = cvRound( _cascade->orig_window_size.height * scale );
498
499     cascade->sum = *sum;
500     cascade->sqsum = *sqsum;
501
502     equ_rect.x = equ_rect.y = cvRound(scale);
503     equ_rect.width = cvRound((_cascade->orig_window_size.width-2)*scale);
504     equ_rect.height = cvRound((_cascade->orig_window_size.height-2)*scale);
505     weight_scale = 1./(equ_rect.width*equ_rect.height);
506     cascade->inv_window_area = weight_scale;
507
508     cascade->p0 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x);
509     cascade->p1 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x + equ_rect.width );
510     cascade->p2 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height, equ_rect.x );
511     cascade->p3 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height,
512                                      equ_rect.x + equ_rect.width );
513
514     cascade->pq0 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x);
515     cascade->pq1 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x + equ_rect.width );
516     cascade->pq2 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height, equ_rect.x );
517     cascade->pq3 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height,
518                                           equ_rect.x + equ_rect.width );
519
520     /* init pointers in haar features according to real window size and
521        given image pointers */
522     {
523 #ifdef _OPENMP
524     int max_threads = cvGetNumThreads();
525     #pragma omp parallel for num_threads(max_threads) schedule(dynamic)
526 #endif // _OPENMP
527     for( i = 0; i < _cascade->count; i++ )
528     {
529         int j, k, l;
530         for( j = 0; j < cascade->stage_classifier[i].count; j++ )
531         {
532             for( l = 0; l < cascade->stage_classifier[i].classifier[j].count; l++ )
533             {
534                 CvHaarFeature* feature =
535                     &_cascade->stage_classifier[i].classifier[j].haar_feature[l];
536                 /* CvHidHaarClassifier* classifier =
537                     cascade->stage_classifier[i].classifier + j; */
538                 CvHidHaarFeature* hidfeature =
539                     &cascade->stage_classifier[i].classifier[j].node[l].feature;
540                 double sum0 = 0, area0 = 0;
541                 CvRect r[3];
542 #if CV_ADJUST_FEATURES
543                 int base_w = -1, base_h = -1;
544                 int new_base_w = 0, new_base_h = 0;
545                 int kx, ky;
546                 int flagx = 0, flagy = 0;
547                 int x0 = 0, y0 = 0;
548 #endif
549                 int nr;
550
551                 /* align blocks */
552                 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
553                 {
554                     if( !hidfeature->rect[k].p0 )
555                         break;
556 #if CV_ADJUST_FEATURES
557                     r[k] = feature->rect[k].r;
558                     base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].width-1) );
559                     base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].x - r[0].x-1) );
560                     base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].height-1) );
561                     base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].y - r[0].y-1) );
562 #endif
563                 }
564
565                 nr = k;
566
567 #if CV_ADJUST_FEATURES
568                 base_w += 1;
569                 base_h += 1;
570                 kx = r[0].width / base_w;
571                 ky = r[0].height / base_h;
572
573                 if( kx <= 0 )
574                 {
575                     flagx = 1;
576                     new_base_w = cvRound( r[0].width * scale ) / kx;
577                     x0 = cvRound( r[0].x * scale );
578                 }
579
580                 if( ky <= 0 )
581                 {
582                     flagy = 1;
583                     new_base_h = cvRound( r[0].height * scale ) / ky;
584                     y0 = cvRound( r[0].y * scale );
585                 }
586 #endif
587
588                 for( k = 0; k < nr; k++ )
589                 {
590                     CvRect tr;
591                     double correction_ratio;
592
593 #if CV_ADJUST_FEATURES
594                     if( flagx )
595                     {
596                         tr.x = (r[k].x - r[0].x) * new_base_w / base_w + x0;
597                         tr.width = r[k].width * new_base_w / base_w;
598                     }
599                     else
600 #endif
601                     {
602                         tr.x = cvRound( r[k].x * scale );
603                         tr.width = cvRound( r[k].width * scale );
604                     }
605
606 #if CV_ADJUST_FEATURES
607                     if( flagy )
608                     {
609                         tr.y = (r[k].y - r[0].y) * new_base_h / base_h + y0;
610                         tr.height = r[k].height * new_base_h / base_h;
611                     }
612                     else
613 #endif
614                     {
615                         tr.y = cvRound( r[k].y * scale );
616                         tr.height = cvRound( r[k].height * scale );
617                     }
618
619 #if CV_ADJUST_WEIGHTS
620                     {
621                     // RAINER START
622                     const float orig_feature_size =  (float)(feature->rect[k].r.width)*feature->rect[k].r.height;
623                     const float orig_norm_size = (float)(_cascade->orig_window_size.width)*(_cascade->orig_window_size.height);
624                     const float feature_size = float(tr.width*tr.height);
625                     //const float normSize    = float(equ_rect.width*equ_rect.height);
626                     float target_ratio = orig_feature_size / orig_norm_size;
627                     //float isRatio = featureSize / normSize;
628                     //correctionRatio = targetRatio / isRatio / normSize;
629                     correction_ratio = target_ratio / feature_size;
630                     // RAINER END
631                     }
632 #else
633                     correction_ratio = weight_scale * (!feature->tilted ? 1 : 0.5);
634 #endif
635
636                     if( !feature->tilted )
637                     {
638                         hidfeature->rect[k].p0 = sum_elem_ptr(*sum, tr.y, tr.x);
639                         hidfeature->rect[k].p1 = sum_elem_ptr(*sum, tr.y, tr.x + tr.width);
640                         hidfeature->rect[k].p2 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x);
641                         hidfeature->rect[k].p3 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x + tr.width);
642                     }
643                     else
644                     {
645                         hidfeature->rect[k].p2 = sum_elem_ptr(*tilted, tr.y + tr.width, tr.x + tr.width);
646                         hidfeature->rect[k].p3 = sum_elem_ptr(*tilted, tr.y + tr.width + tr.height,
647                                                               tr.x + tr.width - tr.height);
648                         hidfeature->rect[k].p0 = sum_elem_ptr(*tilted, tr.y, tr.x);
649                         hidfeature->rect[k].p1 = sum_elem_ptr(*tilted, tr.y + tr.height, tr.x - tr.height);
650                     }
651
652                     hidfeature->rect[k].weight = (float)(feature->rect[k].weight * correction_ratio);
653
654                     if( k == 0 )
655                         area0 = tr.width * tr.height;
656                     else
657                         sum0 += hidfeature->rect[k].weight * tr.width * tr.height;
658                 }
659
660                 hidfeature->rect[0].weight = (float)(-sum0/area0);
661             } /* l */
662         } /* j */
663     }
664     }
665
666     __END__;
667 }
668
669
670 CV_INLINE
671 double icvEvalHidHaarClassifier( CvHidHaarClassifier* classifier,
672                                  double variance_norm_factor,
673                                  size_t p_offset )
674 {
675     int idx = 0;
676     do
677     {
678         CvHidHaarTreeNode* node = classifier->node + idx;
679         double t = node->threshold * variance_norm_factor;
680
681         double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
682         sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
683
684         if( node->feature.rect[2].p0 )
685             sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
686
687         idx = sum < t ? node->left : node->right;
688     }
689     while( idx > 0 );
690     return classifier->alpha[-idx];
691 }
692
693
694 CV_IMPL int
695 cvRunHaarClassifierCascade( const CvHaarClassifierCascade* _cascade,
696                             CvPoint pt, int start_stage )
697 {
698     int result = -1;
699     CV_FUNCNAME("cvRunHaarClassifierCascade");
700
701     __BEGIN__;
702
703     int p_offset, pq_offset;
704     int i, j;
705     double mean, variance_norm_factor;
706     CvHidHaarClassifierCascade* cascade;
707
708     if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
709         CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid cascade pointer" );
710
711     cascade = _cascade->hid_cascade;
712     if( !cascade )
713         CV_ERROR( CV_StsNullPtr, "Hidden cascade has not been created.\n"
714             "Use cvSetImagesForHaarClassifierCascade" );
715
716     if( pt.x < 0 || pt.y < 0 ||
717         pt.x + _cascade->real_window_size.width >= cascade->sum.width-2 ||
718         pt.y + _cascade->real_window_size.height >= cascade->sum.height-2 )
719         EXIT;
720
721     p_offset = pt.y * (cascade->sum.step/sizeof(sumtype)) + pt.x;
722     pq_offset = pt.y * (cascade->sqsum.step/sizeof(sqsumtype)) + pt.x;
723     mean = calc_sum(*cascade,p_offset)*cascade->inv_window_area;
724     variance_norm_factor = cascade->pq0[pq_offset] - cascade->pq1[pq_offset] -
725                            cascade->pq2[pq_offset] + cascade->pq3[pq_offset];
726     variance_norm_factor = variance_norm_factor*cascade->inv_window_area - mean*mean;
727     if( variance_norm_factor >= 0. )
728         variance_norm_factor = sqrt(variance_norm_factor);
729     else
730         variance_norm_factor = 1.;
731
732     if( cascade->is_tree )
733     {
734         CvHidHaarStageClassifier* ptr;
735         assert( start_stage == 0 );
736
737         result = 1;
738         ptr = cascade->stage_classifier;
739
740         while( ptr )
741         {
742             double stage_sum = 0;
743
744             for( j = 0; j < ptr->count; j++ )
745             {
746                 stage_sum += icvEvalHidHaarClassifier( ptr->classifier + j,
747                     variance_norm_factor, p_offset );
748             }
749
750             if( stage_sum >= ptr->threshold )
751             {
752                 ptr = ptr->child;
753             }
754             else
755             {
756                 while( ptr && ptr->next == NULL ) ptr = ptr->parent;
757                 if( ptr == NULL )
758                 {
759                     result = 0;
760                     EXIT;
761                 }
762                 ptr = ptr->next;
763             }
764         }
765     }
766     else if( cascade->is_stump_based )
767     {
768         for( i = start_stage; i < cascade->count; i++ )
769         {
770 #ifndef CV_HAAR_USE_SSE
771             double stage_sum = 0;
772 #else
773             __m128d stage_sum = _mm_setzero_pd();
774 #endif
775
776             if( cascade->stage_classifier[i].two_rects )
777             {
778                 for( j = 0; j < cascade->stage_classifier[i].count; j++ )
779                 {
780                     CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
781                     CvHidHaarTreeNode* node = classifier->node;
782 #ifndef CV_HAAR_USE_SSE
783                     double t = node->threshold*variance_norm_factor;
784                     double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
785                     sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
786                     stage_sum += classifier->alpha[sum >= t];
787 #else
788                     // ayasin - NHM perf optim. Avoid use of costly flaky jcc
789                     __m128d t = _mm_set_sd(node->threshold*variance_norm_factor);
790                     __m128d a = _mm_set_sd(classifier->alpha[0]);
791                     __m128d b = _mm_set_sd(classifier->alpha[1]);
792                     __m128d sum = _mm_set_sd(calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight +
793                                              calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight);
794                     t = _mm_cmpgt_sd(t, sum);
795                     stage_sum = _mm_add_sd(stage_sum, _mm_blendv_pd(b, a, t));
796 #endif
797                 }
798             }
799             else
800             {
801                 for( j = 0; j < cascade->stage_classifier[i].count; j++ )
802                 {
803                     CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
804                     CvHidHaarTreeNode* node = classifier->node;
805 #ifndef CV_HAAR_USE_SSE
806                     double t = node->threshold*variance_norm_factor;
807                     double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
808                     sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
809                     if( node->feature.rect[2].p0 )
810                         sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
811                     
812                     stage_sum += classifier->alpha[sum >= t];
813 #else
814                     // ayasin - NHM perf optim. Avoid use of costly flaky jcc
815                     __m128d t = _mm_set_sd(node->threshold*variance_norm_factor);
816                     __m128d a = _mm_set_sd(classifier->alpha[0]);
817                     __m128d b = _mm_set_sd(classifier->alpha[1]);
818                     double _sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
819                     _sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
820                     if( node->feature.rect[2].p0 )
821                         _sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
822                     __m128d sum = _mm_set_sd(_sum);
823                     
824                     t = _mm_cmpgt_sd(t, sum);
825                     stage_sum = _mm_add_sd(stage_sum, _mm_blendv_pd(b, a, t));
826 #endif
827                 }
828             }
829
830 #ifndef CV_HAAR_USE_SSE
831             if( stage_sum < cascade->stage_classifier[i].threshold )
832 #else
833             __m128d i_threshold = _mm_set_sd(cascade->stage_classifier[i].threshold);
834             if( _mm_comilt_sd(stage_sum, i_threshold) )
835 #endif
836             {
837                 result = -i;
838                 EXIT;
839             }
840         }
841     }
842     else
843     {
844         for( i = start_stage; i < cascade->count; i++ )
845         {
846             double stage_sum = 0;
847
848             for( j = 0; j < cascade->stage_classifier[i].count; j++ )
849             {
850                 stage_sum += icvEvalHidHaarClassifier(
851                     cascade->stage_classifier[i].classifier + j,
852                     variance_norm_factor, p_offset );
853             }
854
855             if( stage_sum < cascade->stage_classifier[i].threshold )
856             {
857                 result = -i;
858                 EXIT;
859             }
860         }
861     }
862
863     result = 1;
864
865     __END__;
866
867     return result;
868 }
869
870
871 static int is_equal( const void* _r1, const void* _r2, void* )
872 {
873     const CvRect* r1 = (const CvRect*)_r1;
874     const CvRect* r2 = (const CvRect*)_r2;
875     int distance = cvRound(r1->width*0.2);
876
877     return r2->x <= r1->x + distance &&
878            r2->x >= r1->x - distance &&
879            r2->y <= r1->y + distance &&
880            r2->y >= r1->y - distance &&
881            r2->width <= cvRound( r1->width * 1.2 ) &&
882            cvRound( r2->width * 1.2 ) >= r1->width;
883 }
884
885
886 #define VERY_ROUGH_SEARCH 0
887
888 CV_IMPL CvSeq*
889 cvHaarDetectObjects( const CvArr* _img,
890                      CvHaarClassifierCascade* cascade,
891                      CvMemStorage* storage, double scale_factor,
892                      int min_neighbors, int flags, CvSize min_size )
893 {
894     int split_stage = 2;
895
896     CvMat stub, *img = (CvMat*)_img;
897     CvMat *temp = 0, *sum = 0, *tilted = 0, *sqsum = 0, *norm_img = 0, *sumcanny = 0, *img_small = 0;
898     CvSeq* result_seq = 0;
899     CvMemStorage* temp_storage = 0;
900     CvAvgComp* comps = 0;
901     CvSeq* seq_thread[CV_MAX_THREADS] = {0};
902     int i, max_threads = 0;
903
904     CV_FUNCNAME( "cvHaarDetectObjects" );
905
906     __BEGIN__;
907
908     CvSeq *seq = 0, *seq2 = 0, *idx_seq = 0, *big_seq = 0;
909     CvAvgComp result_comp = {{0,0,0,0},0};
910     double factor;
911     int npass = 2, coi;
912     bool do_canny_pruning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0;
913     bool find_biggest_object = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0;
914     bool rough_search = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0;
915
916     if( !CV_IS_HAAR_CLASSIFIER(cascade) )
917         CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" );
918
919     if( !storage )
920         CV_ERROR( CV_StsNullPtr, "Null storage pointer" );
921
922     CV_CALL( img = cvGetMat( img, &stub, &coi ));
923     if( coi )
924         CV_ERROR( CV_BadCOI, "COI is not supported" );
925
926     if( CV_MAT_DEPTH(img->type) != CV_8U )
927         CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit images are supported" );
928     
929     if( scale_factor <= 1 )
930         CV_ERROR( CV_StsOutOfRange, "scale factor must be > 1" );
931
932     if( find_biggest_object )
933         flags &= ~CV_HAAR_SCALE_IMAGE;
934
935     CV_CALL( temp = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
936     CV_CALL( sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ));
937     CV_CALL( sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 ));
938     CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));
939
940     if( !cascade->hid_cascade )
941         CV_CALL( icvCreateHidHaarClassifierCascade(cascade) );
942
943     if( cascade->hid_cascade->has_tilted_features )
944         tilted = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
945
946     seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );
947     seq2 = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), temp_storage );
948     result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage );
949
950     max_threads = cvGetNumThreads();
951     if( max_threads > 1 )
952         for( i = 0; i < max_threads; i++ )
953         {
954             CvMemStorage* temp_storage_thread;
955             CV_CALL( temp_storage_thread = cvCreateMemStorage(0));
956             CV_CALL( seq_thread[i] = cvCreateSeq( 0, sizeof(CvSeq),
957                 sizeof(CvRect), temp_storage_thread ));
958         }
959     else
960         seq_thread[0] = seq;
961
962     if( CV_MAT_CN(img->type) > 1 )
963     {
964         cvCvtColor( img, temp, CV_BGR2GRAY );
965         img = temp;
966     }
967
968     if( flags & CV_HAAR_FIND_BIGGEST_OBJECT )
969         flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);
970
971     if( flags & CV_HAAR_SCALE_IMAGE )
972     {
973         CvSize win_size0 = cascade->orig_window_size;
974 #ifdef HAVE_IPP
975         int use_ipp = cascade->hid_cascade->ipp_stages != 0;
976
977         if( use_ipp )
978             CV_CALL( norm_img = cvCreateMat( img->rows, img->cols, CV_32FC1 ));
979 #endif
980         CV_CALL( img_small = cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 ));
981
982         for( factor = 1; ; factor *= scale_factor )
983         {
984             int strip_count, strip_size;
985             int ystep = factor > 2. ? 1 : 2;
986             CvSize win_size = { cvRound(win_size0.width*factor),
987                                 cvRound(win_size0.height*factor) };
988             CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) };
989             CvSize sz1 = { sz.width - win_size0.width, sz.height - win_size0.height };
990 #ifdef HAVE_IPP
991             IppiRect equ_rect = { icv_object_win_border, icv_object_win_border,
992                 win_size0.width - icv_object_win_border*2,
993                 win_size0.height - icv_object_win_border*2 };
994 #endif
995             CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;
996             CvMat* _tilted = 0;
997
998             if( sz1.width <= 0 || sz1.height <= 0 )
999                 break;
1000             if( win_size.width < min_size.width || win_size.height < min_size.height )
1001                 continue;
1002
1003             img1 = cvMat( sz.height, sz.width, CV_8UC1, img_small->data.ptr );
1004             sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );
1005             sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );
1006             if( tilted )
1007             {
1008                 tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );
1009                 _tilted = &tilted1;
1010             }
1011             norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, norm_img ? norm_img->data.ptr : 0 );
1012             mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );
1013
1014             cvResize( img, &img1, CV_INTER_LINEAR );
1015             cvIntegral( &img1, &sum1, &sqsum1, _tilted );
1016
1017             if( max_threads > 1 )
1018             {
1019                 strip_count = MAX(MIN(sz1.height/ystep, max_threads*3), 1);
1020                 strip_size = (sz1.height + strip_count - 1)/strip_count;
1021                 strip_size = (strip_size / ystep)*ystep;
1022             }
1023             else
1024             {
1025                 strip_count = 1;
1026                 strip_size = sz1.height;
1027             }
1028
1029 #ifdef HAVE_IPP
1030             if( use_ipp )
1031             {
1032                 for( i = 0; i <= sz.height; i++ )
1033                 {
1034                     const int* isum = (int*)(sum1.data.ptr + sum1.step*i);
1035                     float* fsum = (float*)isum;
1036                     const int FLT_DELTA = -(1 << 24);
1037                     int j;
1038                     for( j = 0; j <= sz.width; j++ )
1039                         fsum[j] = (float)(isum[j] + FLT_DELTA);
1040                 }
1041             }
1042             else
1043 #endif
1044                 cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, _tilted, 1. );
1045
1046         #ifdef _OPENMP
1047             #pragma omp parallel for num_threads(max_threads) schedule(dynamic)
1048         #endif
1049             for( i = 0; i < strip_count; i++ )
1050             {
1051                 int thread_id = cvGetThreadNum();
1052                 int positive = 0;
1053                 int y1 = i*strip_size, y2 = (i+1)*strip_size/* - ystep + 1*/;
1054                 CvSize ssz;
1055                 int x, y;
1056                 if( i == strip_count - 1 || y2 > sz1.height )
1057                     y2 = sz1.height;
1058                 ssz = cvSize(sz1.width, y2 - y1);
1059
1060 #ifdef HAVE_IPP
1061                 if( use_ipp )
1062                 {
1063                     ippiRectStdDev_32f_C1R(
1064                         (float*)(sum1.data.ptr + y1*sum1.step), sum1.step,
1065                         (double*)(sqsum1.data.ptr + y1*sqsum1.step), sqsum1.step,
1066                         (float*)(norm1.data.ptr + y1*norm1.step), norm1.step,
1067                         ippiSize(ssz.width, ssz.height), equ_rect );
1068
1069                     positive = (ssz.width/ystep)*((ssz.height + ystep-1)/ystep);
1070                     memset( mask1.data.ptr + y1*mask1.step, ystep == 1, mask1.height*mask1.step);
1071                     
1072                     if( ystep > 1 )
1073                     {
1074                         for( y = y1, positive = 0; y < y2; y += ystep )
1075                             for( x = 0; x < ssz.width; x += ystep )
1076                                 mask1.data.ptr[mask1.step*y + x] = (uchar)1;
1077                     }
1078
1079                     for( int j = 0; j < cascade->count; j++ )
1080                     {
1081                         if( ippiApplyHaarClassifier_32f_C1R(
1082                             (float*)(sum1.data.ptr + y1*sum1.step), sum1.step,
1083                             (float*)(norm1.data.ptr + y1*norm1.step), norm1.step,
1084                             mask1.data.ptr + y1*mask1.step, mask1.step,
1085                             ippiSize(ssz.width, ssz.height), &positive,
1086                             cascade->hid_cascade->stage_classifier[j].threshold,
1087                             (IppiHaarClassifier_32f*)cascade->hid_cascade->ipp_stages[j]) < 0 )
1088                         {
1089                             positive = 0;
1090                             break;
1091                         }
1092                         if( positive <= 0 )
1093                             break;
1094                     }
1095                 }
1096                 else
1097 #endif
1098                 {
1099                     for( y = y1, positive = 0; y < y2; y += ystep )
1100                         for( x = 0; x < ssz.width; x += ystep )
1101                         {
1102                             mask1.data.ptr[mask1.step*y + x] =
1103                                 cvRunHaarClassifierCascade( cascade, cvPoint(x,y), 0 ) > 0;
1104                             positive += mask1.data.ptr[mask1.step*y + x];
1105                         }
1106                 }
1107
1108                 if( positive > 0 )
1109                 {
1110                     for( y = y1; y < y2; y += ystep )
1111                         for( x = 0; x < ssz.width; x += ystep )
1112                             if( mask1.data.ptr[mask1.step*y + x] != 0 )
1113                             {
1114                                 CvRect obj_rect = { cvRound(x*factor), cvRound(y*factor),
1115                                                     win_size.width, win_size.height };
1116                                 cvSeqPush( seq_thread[thread_id], &obj_rect );
1117                             }
1118                 }
1119             }
1120
1121             // gather the results
1122             if( max_threads > 1 )
1123                 for( i = 0; i < max_threads; i++ )
1124                 {
1125                     CvSeq* s = seq_thread[i];
1126                     int j, total = s->total;
1127                     CvSeqBlock* b = s->first;
1128                     for( j = 0; j < total; j += b->count, b = b->next )
1129                         cvSeqPushMulti( seq, b->data, b->count );
1130                 }
1131         }
1132     }
1133     else
1134     {
1135         int n_factors = 0;
1136         CvRect scan_roi_rect = {0,0,0,0};
1137         bool is_found = false, scan_roi = false;
1138
1139         cvIntegral( img, sum, sqsum, tilted );
1140
1141         if( do_canny_pruning )
1142         {
1143             sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
1144             cvCanny( img, temp, 0, 50, 3 );
1145             cvIntegral( temp, sumcanny );
1146         }
1147
1148         if( (unsigned)split_stage >= (unsigned)cascade->count ||
1149             cascade->hid_cascade->is_tree )
1150         {
1151             split_stage = cascade->count;
1152             npass = 1;
1153         }
1154
1155         for( n_factors = 0, factor = 1;
1156              factor*cascade->orig_window_size.width < img->cols - 10 &&
1157              factor*cascade->orig_window_size.height < img->rows - 10;
1158              n_factors++, factor *= scale_factor )
1159             ;
1160
1161         if( find_biggest_object )
1162         {
1163             scale_factor = 1./scale_factor;
1164             factor *= scale_factor;
1165             big_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );
1166         }
1167         else
1168             factor = 1;
1169
1170         for( ; n_factors-- > 0 && !is_found; factor *= scale_factor )
1171         {
1172             const double ystep = MAX( 2, factor );
1173             CvSize win_size = { cvRound( cascade->orig_window_size.width * factor ),
1174                                 cvRound( cascade->orig_window_size.height * factor )};
1175             CvRect equ_rect = { 0, 0, 0, 0 };
1176             int *p0 = 0, *p1 = 0, *p2 = 0, *p3 = 0;
1177             int *pq0 = 0, *pq1 = 0, *pq2 = 0, *pq3 = 0;
1178             int pass, stage_offset = 0;
1179             int start_x = 0, start_y = 0;
1180             int end_x = cvRound((img->cols - win_size.width) / ystep);
1181             int end_y = cvRound((img->rows - win_size.height) / ystep);
1182
1183             if( win_size.width < min_size.width || win_size.height < min_size.height )
1184             {
1185                 if( find_biggest_object )
1186                     break;
1187                 continue;
1188             }
1189
1190             cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );
1191             cvZero( temp );
1192
1193             if( do_canny_pruning )
1194             {
1195                 equ_rect.x = cvRound(win_size.width*0.15);
1196                 equ_rect.y = cvRound(win_size.height*0.15);
1197                 equ_rect.width = cvRound(win_size.width*0.7);
1198                 equ_rect.height = cvRound(win_size.height*0.7);
1199
1200                 p0 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step) + equ_rect.x;
1201                 p1 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step)
1202                             + equ_rect.x + equ_rect.width;
1203                 p2 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step) + equ_rect.x;
1204                 p3 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step)
1205                             + equ_rect.x + equ_rect.width;
1206
1207                 pq0 = (int*)(sum->data.ptr + equ_rect.y*sum->step) + equ_rect.x;
1208                 pq1 = (int*)(sum->data.ptr + equ_rect.y*sum->step)
1209                             + equ_rect.x + equ_rect.width;
1210                 pq2 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step) + equ_rect.x;
1211                 pq3 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step)
1212                             + equ_rect.x + equ_rect.width;
1213             }
1214
1215             if( scan_roi )
1216             {
1217                 //adjust start_height and stop_height
1218                 start_y = cvRound(scan_roi_rect.y / ystep);
1219                 end_y = cvRound((scan_roi_rect.y + scan_roi_rect.height - win_size.height) / ystep);
1220
1221                 start_x = cvRound(scan_roi_rect.x / ystep);
1222                 end_x = cvRound((scan_roi_rect.x + scan_roi_rect.width - win_size.width) / ystep);
1223             }
1224
1225             cascade->hid_cascade->count = split_stage;
1226
1227             for( pass = 0; pass < npass; pass++ )
1228             {
1229             #ifdef _OPENMP
1230                 #pragma omp parallel for num_threads(max_threads) schedule(dynamic)
1231             #endif
1232                 for( int _iy = start_y; _iy < end_y; _iy++ )
1233                 {
1234                     int thread_id = cvGetThreadNum();
1235                     int iy = cvRound(_iy*ystep);
1236                     int _ix, _xstep = 1;
1237                     uchar* mask_row = temp->data.ptr + temp->step * iy;
1238
1239                     for( _ix = start_x; _ix < end_x; _ix += _xstep )
1240                     {
1241                         int ix = cvRound(_ix*ystep); // it really should be ystep
1242
1243                         if( pass == 0 )
1244                         {
1245                             int result;
1246                             _xstep = 2;
1247
1248                             if( do_canny_pruning )
1249                             {
1250                                 int offset;
1251                                 int s, sq;
1252
1253                                 offset = iy*(sum->step/sizeof(p0[0])) + ix;
1254                                 s = p0[offset] - p1[offset] - p2[offset] + p3[offset];
1255                                 sq = pq0[offset] - pq1[offset] - pq2[offset] + pq3[offset];
1256                                 if( s < 100 || sq < 20 )
1257                                     continue;
1258                             }
1259
1260                             result = cvRunHaarClassifierCascade( cascade, cvPoint(ix,iy), 0 );
1261                             if( result > 0 )
1262                             {
1263                                 if( pass < npass - 1 )
1264                                     mask_row[ix] = 1;
1265                                 else
1266                                 {
1267                                     CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);
1268                                     cvSeqPush( seq_thread[thread_id], &rect );
1269                                 }
1270                             }
1271                             if( result < 0 )
1272                                 _xstep = 1;
1273                         }
1274                         else if( mask_row[ix] )
1275                         {
1276                             int result = cvRunHaarClassifierCascade( cascade, cvPoint(ix,iy),
1277                                                                      stage_offset );
1278                             if( result > 0 )
1279                             {
1280                                 if( pass == npass - 1 )
1281                                 {
1282                                     CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);
1283                                     cvSeqPush( seq_thread[thread_id], &rect );
1284                                 }
1285                             }
1286                             else
1287                                 mask_row[ix] = 0;
1288                         }
1289                     }
1290                 }
1291                 stage_offset = cascade->hid_cascade->count;
1292                 cascade->hid_cascade->count = cascade->count;
1293             }
1294
1295             // gather the results
1296             if( max_threads > 1 )
1297                     for( i = 0; i < max_threads; i++ )
1298                     {
1299                             CvSeq* s = seq_thread[i];
1300                     int j, total = s->total;
1301                     CvSeqBlock* b = s->first;
1302                     for( j = 0; j < total; j += b->count, b = b->next )
1303                         cvSeqPushMulti( seq, b->data, b->count );
1304                     }
1305
1306             if( find_biggest_object )
1307             {
1308                 CvSeq* bseq = min_neighbors > 0 ? big_seq : seq;
1309                 
1310                 if( min_neighbors > 0 && !scan_roi )
1311                 {
1312                     // group retrieved rectangles in order to filter out noise
1313                     int ncomp = cvSeqPartition( seq, 0, &idx_seq, is_equal, 0 );
1314                     CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));
1315                     memset( comps, 0, (ncomp+1)*sizeof(comps[0]));
1316
1317                 #if VERY_ROUGH_SEARCH
1318                     if( rough_search )
1319                     {
1320                         for( i = 0; i < seq->total; i++ )
1321                         {
1322                             CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
1323                             int idx = *(int*)cvGetSeqElem( idx_seq, i );
1324                             assert( (unsigned)idx < (unsigned)ncomp );
1325
1326                             comps[idx].neighbors++;
1327                             comps[idx].rect.x += r1.x;
1328                             comps[idx].rect.y += r1.y;
1329                             comps[idx].rect.width += r1.width;
1330                             comps[idx].rect.height += r1.height;
1331                         }
1332
1333                         // calculate average bounding box
1334                         for( i = 0; i < ncomp; i++ )
1335                         {
1336                             int n = comps[i].neighbors;
1337                             if( n >= min_neighbors )
1338                             {
1339                                 CvAvgComp comp;
1340                                 comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);
1341                                 comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);
1342                                 comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);
1343                                 comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);
1344                                 comp.neighbors = n;
1345                                 cvSeqPush( bseq, &comp );
1346                             }
1347                         }
1348                     }
1349                     else
1350                 #endif
1351                     {
1352                         for( i = 0 ; i <= ncomp; i++ )
1353                             comps[i].rect.x = comps[i].rect.y = INT_MAX;
1354
1355                         // count number of neighbors
1356                         for( i = 0; i < seq->total; i++ )
1357                         {
1358                             CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
1359                             int idx = *(int*)cvGetSeqElem( idx_seq, i );
1360                             assert( (unsigned)idx < (unsigned)ncomp );
1361
1362                             comps[idx].neighbors++;
1363
1364                             // rect.width and rect.height will store coordinate of right-bottom corner
1365                             comps[idx].rect.x = MIN(comps[idx].rect.x, r1.x);
1366                             comps[idx].rect.y = MIN(comps[idx].rect.y, r1.y);
1367                             comps[idx].rect.width = MAX(comps[idx].rect.width, r1.x+r1.width-1);
1368                             comps[idx].rect.height = MAX(comps[idx].rect.height, r1.y+r1.height-1);
1369                         }
1370
1371                         // calculate enclosing box
1372                         for( i = 0; i < ncomp; i++ )
1373                         {
1374                             int n = comps[i].neighbors;
1375                             if( n >= min_neighbors )
1376                             {
1377                                 CvAvgComp comp;
1378                                 int t;
1379                                 double min_scale = rough_search ? 0.6 : 0.4;
1380                                 comp.rect.x = comps[i].rect.x;
1381                                 comp.rect.y = comps[i].rect.y;
1382                                 comp.rect.width = comps[i].rect.width - comps[i].rect.x + 1;
1383                                 comp.rect.height = comps[i].rect.height - comps[i].rect.y + 1;
1384
1385                                 // update min_size
1386                                 t = cvRound( comp.rect.width*min_scale );
1387                                 min_size.width = MAX( min_size.width, t );
1388
1389                                 t = cvRound( comp.rect.height*min_scale );
1390                                 min_size.height = MAX( min_size.height, t );
1391
1392                                 //expand the box by 20% because we could miss some neighbours
1393                                 //see 'is_equal' function
1394                             #if 1
1395                                 int offset = cvRound(comp.rect.width * 0.2);
1396                                 int right = MIN( img->cols-1, comp.rect.x+comp.rect.width-1 + offset );
1397                                 int bottom = MIN( img->rows-1, comp.rect.y+comp.rect.height-1 + offset);
1398                                 comp.rect.x = MAX( comp.rect.x - offset, 0 );
1399                                 comp.rect.y = MAX( comp.rect.y - offset, 0 );
1400                                 comp.rect.width = right - comp.rect.x + 1;
1401                                 comp.rect.height = bottom - comp.rect.y + 1;
1402                             #endif
1403
1404                                 comp.neighbors = n;
1405                                 cvSeqPush( bseq, &comp );
1406                             }
1407                         }
1408                     }
1409
1410                     cvFree( &comps );
1411                 }
1412
1413                 // extract the biggest rect
1414                 if( bseq->total > 0 )
1415                 {
1416                     int max_area = 0;
1417                     for( i = 0; i < bseq->total; i++ )
1418                     {
1419                         CvAvgComp* comp = (CvAvgComp*)cvGetSeqElem( bseq, i );
1420                         int area = comp->rect.width * comp->rect.height;
1421                         if( max_area < area )
1422                         {
1423                             max_area = area;
1424                             result_comp.rect = comp->rect;
1425                             result_comp.neighbors = bseq == seq ? 1 : comp->neighbors;
1426                         }
1427                     }
1428
1429                     //Prepare information for further scanning inside the biggest rectangle
1430
1431                 #if VERY_ROUGH_SEARCH
1432                     // change scan ranges to roi in case of required
1433                     if( !rough_search && !scan_roi )
1434                     {
1435                         scan_roi = true;
1436                         scan_roi_rect = result_comp.rect;
1437                         cvClearSeq(bseq);
1438                     }
1439                     else if( rough_search )
1440                         is_found = true;
1441                 #else
1442                     if( !scan_roi )
1443                     {
1444                         scan_roi = true;
1445                         scan_roi_rect = result_comp.rect;
1446                         cvClearSeq(bseq);
1447                     }
1448                 #endif
1449                 }
1450             }
1451         }
1452     }
1453
1454     if( min_neighbors == 0 && !find_biggest_object )
1455     {
1456         for( i = 0; i < seq->total; i++ )
1457         {
1458             CvRect* rect = (CvRect*)cvGetSeqElem( seq, i );
1459             CvAvgComp comp;
1460             comp.rect = *rect;
1461             comp.neighbors = 1;
1462             cvSeqPush( result_seq, &comp );
1463         }
1464     }
1465
1466     if( min_neighbors != 0
1467 #if VERY_ROUGH_SEARCH        
1468         && (!find_biggest_object || !rough_search)
1469 #endif        
1470         )
1471     {
1472         // group retrieved rectangles in order to filter out noise
1473         int ncomp = cvSeqPartition( seq, 0, &idx_seq, is_equal, 0 );
1474         CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));
1475         memset( comps, 0, (ncomp+1)*sizeof(comps[0]));
1476
1477         // count number of neighbors
1478         for( i = 0; i < seq->total; i++ )
1479         {
1480             CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
1481             int idx = *(int*)cvGetSeqElem( idx_seq, i );
1482             assert( (unsigned)idx < (unsigned)ncomp );
1483
1484             comps[idx].neighbors++;
1485
1486             comps[idx].rect.x += r1.x;
1487             comps[idx].rect.y += r1.y;
1488             comps[idx].rect.width += r1.width;
1489             comps[idx].rect.height += r1.height;
1490         }
1491
1492         // calculate average bounding box
1493         for( i = 0; i < ncomp; i++ )
1494         {
1495             int n = comps[i].neighbors;
1496             if( n >= min_neighbors )
1497             {
1498                 CvAvgComp comp;
1499                 comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);
1500                 comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);
1501                 comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);
1502                 comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);
1503                 comp.neighbors = comps[i].neighbors;
1504
1505                 cvSeqPush( seq2, &comp );
1506             }
1507         }
1508
1509         if( !find_biggest_object )
1510         {
1511             // filter out small face rectangles inside large face rectangles
1512             for( i = 0; i < seq2->total; i++ )
1513             {
1514                 CvAvgComp r1 = *(CvAvgComp*)cvGetSeqElem( seq2, i );
1515                 int j, flag = 1;
1516
1517                 for( j = 0; j < seq2->total; j++ )
1518                 {
1519                     CvAvgComp r2 = *(CvAvgComp*)cvGetSeqElem( seq2, j );
1520                     int distance = cvRound( r2.rect.width * 0.2 );
1521
1522                     if( i != j &&
1523                         r1.rect.x >= r2.rect.x - distance &&
1524                         r1.rect.y >= r2.rect.y - distance &&
1525                         r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&
1526                         r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance &&
1527                         (r2.neighbors > MAX( 3, r1.neighbors ) || r1.neighbors < 3) )
1528                     {
1529                         flag = 0;
1530                         break;
1531                     }
1532                 }
1533
1534                 if( flag )
1535                     cvSeqPush( result_seq, &r1 );
1536             }
1537         }
1538         else
1539         {
1540             int max_area = 0;
1541             for( i = 0; i < seq2->total; i++ )
1542             {
1543                 CvAvgComp* comp = (CvAvgComp*)cvGetSeqElem( seq2, i );
1544                 int area = comp->rect.width * comp->rect.height;
1545                 if( max_area < area )
1546                 {
1547                     max_area = area;
1548                     result_comp = *comp;
1549                 }                
1550             }
1551         }
1552     }
1553
1554     if( find_biggest_object && result_comp.rect.width > 0 )
1555         cvSeqPush( result_seq, &result_comp );
1556
1557     __END__;
1558
1559     if( max_threads > 1 )
1560             for( i = 0; i < max_threads; i++ )
1561             {
1562                     if( seq_thread[i] )
1563                 cvReleaseMemStorage( &seq_thread[i]->storage );
1564             }
1565
1566     cvReleaseMemStorage( &temp_storage );
1567     cvReleaseMat( &sum );
1568     cvReleaseMat( &sqsum );
1569     cvReleaseMat( &tilted );
1570     cvReleaseMat( &temp );
1571     cvReleaseMat( &sumcanny );
1572     cvReleaseMat( &norm_img );
1573     cvReleaseMat( &img_small );
1574     cvFree( &comps );
1575
1576     return result_seq;
1577 }
1578
1579
1580 static CvHaarClassifierCascade*
1581 icvLoadCascadeCART( const char** input_cascade, int n, CvSize orig_window_size )
1582 {
1583     int i;
1584     CvHaarClassifierCascade* cascade = icvCreateHaarClassifierCascade(n);
1585     cascade->orig_window_size = orig_window_size;
1586
1587     for( i = 0; i < n; i++ )
1588     {
1589         int j, count, l;
1590         float threshold = 0;
1591         const char* stage = input_cascade[i];
1592         int dl = 0;
1593
1594         /* tree links */
1595         int parent = -1;
1596         int next = -1;
1597
1598         sscanf( stage, "%d%n", &count, &dl );
1599         stage += dl;
1600
1601         assert( count > 0 );
1602         cascade->stage_classifier[i].count = count;
1603         cascade->stage_classifier[i].classifier =
1604             (CvHaarClassifier*)cvAlloc( count*sizeof(cascade->stage_classifier[i].classifier[0]));
1605
1606         for( j = 0; j < count; j++ )
1607         {
1608             CvHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
1609             int k, rects = 0;
1610             char str[100];
1611
1612             sscanf( stage, "%d%n", &classifier->count, &dl );
1613             stage += dl;
1614
1615             classifier->haar_feature = (CvHaarFeature*) cvAlloc(
1616                 classifier->count * ( sizeof( *classifier->haar_feature ) +
1617                                       sizeof( *classifier->threshold ) +
1618                                       sizeof( *classifier->left ) +
1619                                       sizeof( *classifier->right ) ) +
1620                 (classifier->count + 1) * sizeof( *classifier->alpha ) );
1621             classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
1622             classifier->left = (int*) (classifier->threshold + classifier->count);
1623             classifier->right = (int*) (classifier->left + classifier->count);
1624             classifier->alpha = (float*) (classifier->right + classifier->count);
1625
1626             for( l = 0; l < classifier->count; l++ )
1627             {
1628                 sscanf( stage, "%d%n", &rects, &dl );
1629                 stage += dl;
1630
1631                 assert( rects >= 2 && rects <= CV_HAAR_FEATURE_MAX );
1632
1633                 for( k = 0; k < rects; k++ )
1634                 {
1635                     CvRect r;
1636                     int band = 0;
1637                     sscanf( stage, "%d%d%d%d%d%f%n",
1638                             &r.x, &r.y, &r.width, &r.height, &band,
1639                             &(classifier->haar_feature[l].rect[k].weight), &dl );
1640                     stage += dl;
1641                     classifier->haar_feature[l].rect[k].r = r;
1642                 }
1643                 sscanf( stage, "%s%n", str, &dl );
1644                 stage += dl;
1645
1646                 classifier->haar_feature[l].tilted = strncmp( str, "tilted", 6 ) == 0;
1647
1648                 for( k = rects; k < CV_HAAR_FEATURE_MAX; k++ )
1649                 {
1650                     memset( classifier->haar_feature[l].rect + k, 0,
1651                             sizeof(classifier->haar_feature[l].rect[k]) );
1652                 }
1653
1654                 sscanf( stage, "%f%d%d%n", &(classifier->threshold[l]),
1655                                        &(classifier->left[l]),
1656                                        &(classifier->right[l]), &dl );
1657                 stage += dl;
1658             }
1659             for( l = 0; l <= classifier->count; l++ )
1660             {
1661                 sscanf( stage, "%f%n", &(classifier->alpha[l]), &dl );
1662                 stage += dl;
1663             }
1664         }
1665
1666         sscanf( stage, "%f%n", &threshold, &dl );
1667         stage += dl;
1668
1669         cascade->stage_classifier[i].threshold = threshold;
1670
1671         /* load tree links */
1672         if( sscanf( stage, "%d%d%n", &parent, &next, &dl ) != 2 )
1673         {
1674             parent = i - 1;
1675             next = -1;
1676         }
1677         stage += dl;
1678
1679         cascade->stage_classifier[i].parent = parent;
1680         cascade->stage_classifier[i].next = next;
1681         cascade->stage_classifier[i].child = -1;
1682
1683         if( parent != -1 && cascade->stage_classifier[parent].child == -1 )
1684         {
1685             cascade->stage_classifier[parent].child = i;
1686         }
1687     }
1688
1689     return cascade;
1690 }
1691
1692 #ifndef _MAX_PATH
1693 #define _MAX_PATH 1024
1694 #endif
1695
1696 CV_IMPL CvHaarClassifierCascade*
1697 cvLoadHaarClassifierCascade( const char* directory, CvSize orig_window_size )
1698 {
1699     const char** input_cascade = 0;
1700     CvHaarClassifierCascade *cascade = 0;
1701
1702     CV_FUNCNAME( "cvLoadHaarClassifierCascade" );
1703
1704     __BEGIN__;
1705
1706     int i, n;
1707     const char* slash;
1708     char name[_MAX_PATH];
1709     int size = 0;
1710     char* ptr = 0;
1711
1712     if( !directory )
1713         CV_ERROR( CV_StsNullPtr, "Null path is passed" );
1714
1715     n = (int)strlen(directory)-1;
1716     slash = directory[n] == '\\' || directory[n] == '/' ? "" : "/";
1717
1718     /* try to read the classifier from directory */
1719     for( n = 0; ; n++ )
1720     {
1721         sprintf( name, "%s%s%d/AdaBoostCARTHaarClassifier.txt", directory, slash, n );
1722         FILE* f = fopen( name, "rb" );
1723         if( !f )
1724             break;
1725         fseek( f, 0, SEEK_END );
1726         size += ftell( f ) + 1;
1727         fclose(f);
1728     }
1729
1730     if( n == 0 && slash[0] )
1731     {
1732         CV_CALL( cascade = (CvHaarClassifierCascade*)cvLoad( directory ));
1733         EXIT;
1734     }
1735     else if( n == 0 )
1736         CV_ERROR( CV_StsBadArg, "Invalid path" );
1737
1738     size += (n+1)*sizeof(char*);
1739     CV_CALL( input_cascade = (const char**)cvAlloc( size ));
1740     ptr = (char*)(input_cascade + n + 1);
1741
1742     for( i = 0; i < n; i++ )
1743     {
1744         sprintf( name, "%s/%d/AdaBoostCARTHaarClassifier.txt", directory, i );
1745         FILE* f = fopen( name, "rb" );
1746         if( !f )
1747             CV_ERROR( CV_StsError, "" );
1748         fseek( f, 0, SEEK_END );
1749         size = ftell( f );
1750         fseek( f, 0, SEEK_SET );
1751         fread( ptr, 1, size, f );
1752         fclose(f);
1753         input_cascade[i] = ptr;
1754         ptr += size;
1755         *ptr++ = '\0';
1756     }
1757
1758     input_cascade[n] = 0;
1759     cascade = icvLoadCascadeCART( input_cascade, n, orig_window_size );
1760
1761     __END__;
1762
1763     if( input_cascade )
1764         cvFree( &input_cascade );
1765
1766     if( cvGetErrStatus() < 0 )
1767         cvReleaseHaarClassifierCascade( &cascade );
1768
1769     return cascade;
1770 }
1771
1772
1773 CV_IMPL void
1774 cvReleaseHaarClassifierCascade( CvHaarClassifierCascade** _cascade )
1775 {
1776     if( _cascade && *_cascade )
1777     {
1778         int i, j;
1779         CvHaarClassifierCascade* cascade = *_cascade;
1780
1781         for( i = 0; i < cascade->count; i++ )
1782         {
1783             for( j = 0; j < cascade->stage_classifier[i].count; j++ )
1784                 cvFree( &cascade->stage_classifier[i].classifier[j].haar_feature );
1785             cvFree( &cascade->stage_classifier[i].classifier );
1786         }
1787         icvReleaseHidHaarClassifierCascade( &cascade->hid_cascade );
1788         cvFree( _cascade );
1789     }
1790 }
1791
1792
1793 /****************************************************************************************\
1794 *                                  Persistence functions                                 *
1795 \****************************************************************************************/
1796
1797 /* field names */
1798
1799 #define ICV_HAAR_SIZE_NAME            "size"
1800 #define ICV_HAAR_STAGES_NAME          "stages"
1801 #define ICV_HAAR_TREES_NAME             "trees"
1802 #define ICV_HAAR_FEATURE_NAME             "feature"
1803 #define ICV_HAAR_RECTS_NAME                 "rects"
1804 #define ICV_HAAR_TILTED_NAME                "tilted"
1805 #define ICV_HAAR_THRESHOLD_NAME           "threshold"
1806 #define ICV_HAAR_LEFT_NODE_NAME           "left_node"
1807 #define ICV_HAAR_LEFT_VAL_NAME            "left_val"
1808 #define ICV_HAAR_RIGHT_NODE_NAME          "right_node"
1809 #define ICV_HAAR_RIGHT_VAL_NAME           "right_val"
1810 #define ICV_HAAR_STAGE_THRESHOLD_NAME   "stage_threshold"
1811 #define ICV_HAAR_PARENT_NAME            "parent"
1812 #define ICV_HAAR_NEXT_NAME              "next"
1813
1814 static int
1815 icvIsHaarClassifier( const void* struct_ptr )
1816 {
1817     return CV_IS_HAAR_CLASSIFIER( struct_ptr );
1818 }
1819
1820 static void*
1821 icvReadHaarClassifier( CvFileStorage* fs, CvFileNode* node )
1822 {
1823     CvHaarClassifierCascade* cascade = NULL;
1824
1825     CV_FUNCNAME( "cvReadHaarClassifier" );
1826
1827     __BEGIN__;
1828
1829     char buf[256];
1830     CvFileNode* seq_fn = NULL; /* sequence */
1831     CvFileNode* fn = NULL;
1832     CvFileNode* stages_fn = NULL;
1833     CvSeqReader stages_reader;
1834     int n;
1835     int i, j, k, l;
1836     int parent, next;
1837
1838     CV_CALL( stages_fn = cvGetFileNodeByName( fs, node, ICV_HAAR_STAGES_NAME ) );
1839     if( !stages_fn || !CV_NODE_IS_SEQ( stages_fn->tag) )
1840         CV_ERROR( CV_StsError, "Invalid stages node" );
1841
1842     n = stages_fn->data.seq->total;
1843     CV_CALL( cascade = icvCreateHaarClassifierCascade(n) );
1844
1845     /* read size */
1846     CV_CALL( seq_fn = cvGetFileNodeByName( fs, node, ICV_HAAR_SIZE_NAME ) );
1847     if( !seq_fn || !CV_NODE_IS_SEQ( seq_fn->tag ) || seq_fn->data.seq->total != 2 )
1848         CV_ERROR( CV_StsError, "size node is not a valid sequence." );
1849     CV_CALL( fn = (CvFileNode*) cvGetSeqElem( seq_fn->data.seq, 0 ) );
1850     if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 )
1851         CV_ERROR( CV_StsError, "Invalid size node: width must be positive integer" );
1852     cascade->orig_window_size.width = fn->data.i;
1853     CV_CALL( fn = (CvFileNode*) cvGetSeqElem( seq_fn->data.seq, 1 ) );
1854     if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 )
1855         CV_ERROR( CV_StsError, "Invalid size node: height must be positive integer" );
1856     cascade->orig_window_size.height = fn->data.i;
1857
1858     CV_CALL( cvStartReadSeq( stages_fn->data.seq, &stages_reader ) );
1859     for( i = 0; i < n; ++i )
1860     {
1861         CvFileNode* stage_fn;
1862         CvFileNode* trees_fn;
1863         CvSeqReader trees_reader;
1864
1865         stage_fn = (CvFileNode*) stages_reader.ptr;
1866         if( !CV_NODE_IS_MAP( stage_fn->tag ) )
1867         {
1868             sprintf( buf, "Invalid stage %d", i );
1869             CV_ERROR( CV_StsError, buf );
1870         }
1871
1872         CV_CALL( trees_fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_TREES_NAME ) );
1873         if( !trees_fn || !CV_NODE_IS_SEQ( trees_fn->tag )
1874             || trees_fn->data.seq->total <= 0 )
1875         {
1876             sprintf( buf, "Trees node is not a valid sequence. (stage %d)", i );
1877             CV_ERROR( CV_StsError, buf );
1878         }
1879
1880         CV_CALL( cascade->stage_classifier[i].classifier =
1881             (CvHaarClassifier*) cvAlloc( trees_fn->data.seq->total
1882                 * sizeof( cascade->stage_classifier[i].classifier[0] ) ) );
1883         for( j = 0; j < trees_fn->data.seq->total; ++j )
1884         {
1885             cascade->stage_classifier[i].classifier[j].haar_feature = NULL;
1886         }
1887         cascade->stage_classifier[i].count = trees_fn->data.seq->total;
1888
1889         CV_CALL( cvStartReadSeq( trees_fn->data.seq, &trees_reader ) );
1890         for( j = 0; j < trees_fn->data.seq->total; ++j )
1891         {
1892             CvFileNode* tree_fn;
1893             CvSeqReader tree_reader;
1894             CvHaarClassifier* classifier;
1895             int last_idx;
1896
1897             classifier = &cascade->stage_classifier[i].classifier[j];
1898             tree_fn = (CvFileNode*) trees_reader.ptr;
1899             if( !CV_NODE_IS_SEQ( tree_fn->tag ) || tree_fn->data.seq->total <= 0 )
1900             {
1901                 sprintf( buf, "Tree node is not a valid sequence."
1902                          " (stage %d, tree %d)", i, j );
1903                 CV_ERROR( CV_StsError, buf );
1904             }
1905
1906             classifier->count = tree_fn->data.seq->total;
1907             CV_CALL( classifier->haar_feature = (CvHaarFeature*) cvAlloc(
1908                 classifier->count * ( sizeof( *classifier->haar_feature ) +
1909                                       sizeof( *classifier->threshold ) +
1910                                       sizeof( *classifier->left ) +
1911                                       sizeof( *classifier->right ) ) +
1912                 (classifier->count + 1) * sizeof( *classifier->alpha ) ) );
1913             classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
1914             classifier->left = (int*) (classifier->threshold + classifier->count);
1915             classifier->right = (int*) (classifier->left + classifier->count);
1916             classifier->alpha = (float*) (classifier->right + classifier->count);
1917
1918             CV_CALL( cvStartReadSeq( tree_fn->data.seq, &tree_reader ) );
1919             for( k = 0, last_idx = 0; k < tree_fn->data.seq->total; ++k )
1920             {
1921                 CvFileNode* node_fn;
1922                 CvFileNode* feature_fn;
1923                 CvFileNode* rects_fn;
1924                 CvSeqReader rects_reader;
1925
1926                 node_fn = (CvFileNode*) tree_reader.ptr;
1927                 if( !CV_NODE_IS_MAP( node_fn->tag ) )
1928                 {
1929                     sprintf( buf, "Tree node %d is not a valid map. (stage %d, tree %d)",
1930                              k, i, j );
1931                     CV_ERROR( CV_StsError, buf );
1932                 }
1933                 CV_CALL( feature_fn = cvGetFileNodeByName( fs, node_fn,
1934                     ICV_HAAR_FEATURE_NAME ) );
1935                 if( !feature_fn || !CV_NODE_IS_MAP( feature_fn->tag ) )
1936                 {
1937                     sprintf( buf, "Feature node is not a valid map. "
1938                              "(stage %d, tree %d, node %d)", i, j, k );
1939                     CV_ERROR( CV_StsError, buf );
1940                 }
1941                 CV_CALL( rects_fn = cvGetFileNodeByName( fs, feature_fn,
1942                     ICV_HAAR_RECTS_NAME ) );
1943                 if( !rects_fn || !CV_NODE_IS_SEQ( rects_fn->tag )
1944                     || rects_fn->data.seq->total < 1
1945                     || rects_fn->data.seq->total > CV_HAAR_FEATURE_MAX )
1946                 {
1947                     sprintf( buf, "Rects node is not a valid sequence. "
1948                              "(stage %d, tree %d, node %d)", i, j, k );
1949                     CV_ERROR( CV_StsError, buf );
1950                 }
1951                 CV_CALL( cvStartReadSeq( rects_fn->data.seq, &rects_reader ) );
1952                 for( l = 0; l < rects_fn->data.seq->total; ++l )
1953                 {
1954                     CvFileNode* rect_fn;
1955                     CvRect r;
1956
1957                     rect_fn = (CvFileNode*) rects_reader.ptr;
1958                     if( !CV_NODE_IS_SEQ( rect_fn->tag ) || rect_fn->data.seq->total != 5 )
1959                     {
1960                         sprintf( buf, "Rect %d is not a valid sequence. "
1961                                  "(stage %d, tree %d, node %d)", l, i, j, k );
1962                         CV_ERROR( CV_StsError, buf );
1963                     }
1964
1965                     fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 0 );
1966                     if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i < 0 )
1967                     {
1968                         sprintf( buf, "x coordinate must be non-negative integer. "
1969                                  "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
1970                         CV_ERROR( CV_StsError, buf );
1971                     }
1972                     r.x = fn->data.i;
1973                     fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 1 );
1974                     if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i < 0 )
1975                     {
1976                         sprintf( buf, "y coordinate must be non-negative integer. "
1977                                  "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
1978                         CV_ERROR( CV_StsError, buf );
1979                     }
1980                     r.y = fn->data.i;
1981                     fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 2 );
1982                     if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0
1983                         || r.x + fn->data.i > cascade->orig_window_size.width )
1984                     {
1985                         sprintf( buf, "width must be positive integer and "
1986                                  "(x + width) must not exceed window width. "
1987                                  "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
1988                         CV_ERROR( CV_StsError, buf );
1989                     }
1990                     r.width = fn->data.i;
1991                     fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 3 );
1992                     if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0
1993                         || r.y + fn->data.i > cascade->orig_window_size.height )
1994                     {
1995                         sprintf( buf, "height must be positive integer and "
1996                                  "(y + height) must not exceed window height. "
1997                                  "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
1998                         CV_ERROR( CV_StsError, buf );
1999                     }
2000                     r.height = fn->data.i;
2001                     fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 4 );
2002                     if( !CV_NODE_IS_REAL( fn->tag ) )
2003                     {
2004                         sprintf( buf, "weight must be real number. "
2005                                  "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
2006                         CV_ERROR( CV_StsError, buf );
2007                     }
2008
2009                     classifier->haar_feature[k].rect[l].weight = (float) fn->data.f;
2010                     classifier->haar_feature[k].rect[l].r = r;
2011
2012                     CV_NEXT_SEQ_ELEM( sizeof( *rect_fn ), rects_reader );
2013                 } /* for each rect */
2014                 for( l = rects_fn->data.seq->total; l < CV_HAAR_FEATURE_MAX; ++l )
2015                 {
2016                     classifier->haar_feature[k].rect[l].weight = 0;
2017                     classifier->haar_feature[k].rect[l].r = cvRect( 0, 0, 0, 0 );
2018                 }
2019
2020                 CV_CALL( fn = cvGetFileNodeByName( fs, feature_fn, ICV_HAAR_TILTED_NAME));
2021                 if( !fn || !CV_NODE_IS_INT( fn->tag ) )
2022                 {
2023                     sprintf( buf, "tilted must be 0 or 1. "
2024                              "(stage %d, tree %d, node %d)", i, j, k );
2025                     CV_ERROR( CV_StsError, buf );
2026                 }
2027                 classifier->haar_feature[k].tilted = ( fn->data.i != 0 );
2028                 CV_CALL( fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_THRESHOLD_NAME));
2029                 if( !fn || !CV_NODE_IS_REAL( fn->tag ) )
2030                 {
2031                     sprintf( buf, "threshold must be real number. "
2032                              "(stage %d, tree %d, node %d)", i, j, k );
2033                     CV_ERROR( CV_StsError, buf );
2034                 }
2035                 classifier->threshold[k] = (float) fn->data.f;
2036                 CV_CALL( fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_LEFT_NODE_NAME));
2037                 if( fn )
2038                 {
2039                     if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= k
2040                         || fn->data.i >= tree_fn->data.seq->total )
2041                     {
2042                         sprintf( buf, "left node must be valid node number. "
2043                                  "(stage %d, tree %d, node %d)", i, j, k );
2044                         CV_ERROR( CV_StsError, buf );
2045                     }
2046                     /* left node */
2047                     classifier->left[k] = fn->data.i;
2048                 }
2049                 else
2050                 {
2051                     CV_CALL( fn = cvGetFileNodeByName( fs, node_fn,
2052                         ICV_HAAR_LEFT_VAL_NAME ) );
2053                     if( !fn )
2054                     {
2055                         sprintf( buf, "left node or left value must be specified. "
2056                                  "(stage %d, tree %d, node %d)", i, j, k );
2057                         CV_ERROR( CV_StsError, buf );
2058                     }
2059                     if( !CV_NODE_IS_REAL( fn->tag ) )
2060                     {
2061                         sprintf( buf, "left value must be real number. "
2062                                  "(stage %d, tree %d, node %d)", i, j, k );
2063                         CV_ERROR( CV_StsError, buf );
2064                     }
2065                     /* left value */
2066                     if( last_idx >= classifier->count + 1 )
2067                     {
2068                         sprintf( buf, "Tree structure is broken: too many values. "
2069                                  "(stage %d, tree %d, node %d)", i, j, k );
2070                         CV_ERROR( CV_StsError, buf );
2071                     }
2072                     classifier->left[k] = -last_idx;
2073                     classifier->alpha[last_idx++] = (float) fn->data.f;
2074                 }
2075                 CV_CALL( fn = cvGetFileNodeByName( fs, node_fn,ICV_HAAR_RIGHT_NODE_NAME));
2076                 if( fn )
2077                 {
2078                     if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= k
2079                         || fn->data.i >= tree_fn->data.seq->total )
2080                     {
2081                         sprintf( buf, "right node must be valid node number. "
2082                                  "(stage %d, tree %d, node %d)", i, j, k );
2083                         CV_ERROR( CV_StsError, buf );
2084                     }
2085                     /* right node */
2086                     classifier->right[k] = fn->data.i;
2087                 }
2088                 else
2089                 {
2090                     CV_CALL( fn = cvGetFileNodeByName( fs, node_fn,
2091                         ICV_HAAR_RIGHT_VAL_NAME ) );
2092                     if( !fn )
2093                     {
2094                         sprintf( buf, "right node or right value must be specified. "
2095                                  "(stage %d, tree %d, node %d)", i, j, k );
2096                         CV_ERROR( CV_StsError, buf );
2097                     }
2098                     if( !CV_NODE_IS_REAL( fn->tag ) )
2099                     {
2100                         sprintf( buf, "right value must be real number. "
2101                                  "(stage %d, tree %d, node %d)", i, j, k );
2102                         CV_ERROR( CV_StsError, buf );
2103                     }
2104                     /* right value */
2105                     if( last_idx >= classifier->count + 1 )
2106                     {
2107                         sprintf( buf, "Tree structure is broken: too many values. "
2108                                  "(stage %d, tree %d, node %d)", i, j, k );
2109                         CV_ERROR( CV_StsError, buf );
2110                     }
2111                     classifier->right[k] = -last_idx;
2112                     classifier->alpha[last_idx++] = (float) fn->data.f;
2113                 }
2114
2115                 CV_NEXT_SEQ_ELEM( sizeof( *node_fn ), tree_reader );
2116             } /* for each node */
2117             if( last_idx != classifier->count + 1 )
2118             {
2119                 sprintf( buf, "Tree structure is broken: too few values. "
2120                          "(stage %d, tree %d)", i, j );
2121                 CV_ERROR( CV_StsError, buf );
2122             }
2123
2124             CV_NEXT_SEQ_ELEM( sizeof( *tree_fn ), trees_reader );
2125         } /* for each tree */
2126
2127         CV_CALL( fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_STAGE_THRESHOLD_NAME));
2128         if( !fn || !CV_NODE_IS_REAL( fn->tag ) )
2129         {
2130             sprintf( buf, "stage threshold must be real number. (stage %d)", i );
2131             CV_ERROR( CV_StsError, buf );
2132         }
2133         cascade->stage_classifier[i].threshold = (float) fn->data.f;
2134
2135         parent = i - 1;
2136         next = -1;
2137
2138         CV_CALL( fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_PARENT_NAME ) );
2139         if( !fn || !CV_NODE_IS_INT( fn->tag )
2140             || fn->data.i < -1 || fn->data.i >= cascade->count )
2141         {
2142             sprintf( buf, "parent must be integer number. (stage %d)", i );
2143             CV_ERROR( CV_StsError, buf );
2144         }
2145         parent = fn->data.i;
2146         CV_CALL( fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_NEXT_NAME ) );
2147         if( !fn || !CV_NODE_IS_INT( fn->tag )
2148             || fn->data.i < -1 || fn->data.i >= cascade->count )
2149         {
2150             sprintf( buf, "next must be integer number. (stage %d)", i );
2151             CV_ERROR( CV_StsError, buf );
2152         }
2153         next = fn->data.i;
2154
2155         cascade->stage_classifier[i].parent = parent;
2156         cascade->stage_classifier[i].next = next;
2157         cascade->stage_classifier[i].child = -1;
2158
2159         if( parent != -1 && cascade->stage_classifier[parent].child == -1 )
2160         {
2161             cascade->stage_classifier[parent].child = i;
2162         }
2163
2164         CV_NEXT_SEQ_ELEM( sizeof( *stage_fn ), stages_reader );
2165     } /* for each stage */
2166
2167     __END__;
2168
2169     if( cvGetErrStatus() < 0 )
2170     {
2171         cvReleaseHaarClassifierCascade( &cascade );
2172         cascade = NULL;
2173     }
2174
2175     return cascade;
2176 }
2177
2178 static void
2179 icvWriteHaarClassifier( CvFileStorage* fs, const char* name, const void* struct_ptr,
2180                         CvAttrList attributes )
2181 {
2182     CV_FUNCNAME( "cvWriteHaarClassifier" );
2183
2184     __BEGIN__;
2185
2186     int i, j, k, l;
2187     char buf[256];
2188     const CvHaarClassifierCascade* cascade = (const CvHaarClassifierCascade*) struct_ptr;
2189
2190     /* TODO: parameters check */
2191
2192     CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_HAAR, attributes ) );
2193
2194     CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_SIZE_NAME, CV_NODE_SEQ | CV_NODE_FLOW ) );
2195     CV_CALL( cvWriteInt( fs, NULL, cascade->orig_window_size.width ) );
2196     CV_CALL( cvWriteInt( fs, NULL, cascade->orig_window_size.height ) );
2197     CV_CALL( cvEndWriteStruct( fs ) ); /* size */
2198
2199     CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_STAGES_NAME, CV_NODE_SEQ ) );
2200     for( i = 0; i < cascade->count; ++i )
2201     {
2202         CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_MAP ) );
2203         sprintf( buf, "stage %d", i );
2204         CV_CALL( cvWriteComment( fs, buf, 1 ) );
2205
2206         CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_TREES_NAME, CV_NODE_SEQ ) );
2207
2208         for( j = 0; j < cascade->stage_classifier[i].count; ++j )
2209         {
2210             CvHaarClassifier* tree = &cascade->stage_classifier[i].classifier[j];
2211
2212             CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_SEQ ) );
2213             sprintf( buf, "tree %d", j );
2214             CV_CALL( cvWriteComment( fs, buf, 1 ) );
2215
2216             for( k = 0; k < tree->count; ++k )
2217             {
2218                 CvHaarFeature* feature = &tree->haar_feature[k];
2219
2220                 CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_MAP ) );
2221                 if( k )
2222                 {
2223                     sprintf( buf, "node %d", k );
2224                 }
2225                 else
2226                 {
2227                     sprintf( buf, "root node" );
2228                 }
2229                 CV_CALL( cvWriteComment( fs, buf, 1 ) );
2230
2231                 CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_FEATURE_NAME, CV_NODE_MAP ) );
2232
2233                 CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_RECTS_NAME, CV_NODE_SEQ ) );
2234                 for( l = 0; l < CV_HAAR_FEATURE_MAX && feature->rect[l].r.width != 0; ++l )
2235                 {
2236                     CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_SEQ | CV_NODE_FLOW ) );
2237                     CV_CALL( cvWriteInt(  fs, NULL, feature->rect[l].r.x ) );
2238                     CV_CALL( cvWriteInt(  fs, NULL, feature->rect[l].r.y ) );
2239                     CV_CALL( cvWriteInt(  fs, NULL, feature->rect[l].r.width ) );
2240                     CV_CALL( cvWriteInt(  fs, NULL, feature->rect[l].r.height ) );
2241                     CV_CALL( cvWriteReal( fs, NULL, feature->rect[l].weight ) );
2242                     CV_CALL( cvEndWriteStruct( fs ) ); /* rect */
2243                 }
2244                 CV_CALL( cvEndWriteStruct( fs ) ); /* rects */
2245                 CV_CALL( cvWriteInt( fs, ICV_HAAR_TILTED_NAME, feature->tilted ) );
2246                 CV_CALL( cvEndWriteStruct( fs ) ); /* feature */
2247
2248                 CV_CALL( cvWriteReal( fs, ICV_HAAR_THRESHOLD_NAME, tree->threshold[k]) );
2249
2250                 if( tree->left[k] > 0 )
2251                 {
2252                     CV_CALL( cvWriteInt( fs, ICV_HAAR_LEFT_NODE_NAME, tree->left[k] ) );
2253                 }
2254                 else
2255                 {
2256                     CV_CALL( cvWriteReal( fs, ICV_HAAR_LEFT_VAL_NAME,
2257                         tree->alpha[-tree->left[k]] ) );
2258                 }
2259
2260                 if( tree->right[k] > 0 )
2261                 {
2262                     CV_CALL( cvWriteInt( fs, ICV_HAAR_RIGHT_NODE_NAME, tree->right[k] ) );
2263                 }
2264                 else
2265                 {
2266                     CV_CALL( cvWriteReal( fs, ICV_HAAR_RIGHT_VAL_NAME,
2267                         tree->alpha[-tree->right[k]] ) );
2268                 }
2269
2270                 CV_CALL( cvEndWriteStruct( fs ) ); /* split */
2271             }
2272
2273             CV_CALL( cvEndWriteStruct( fs ) ); /* tree */
2274         }
2275
2276         CV_CALL( cvEndWriteStruct( fs ) ); /* trees */
2277
2278         CV_CALL( cvWriteReal( fs, ICV_HAAR_STAGE_THRESHOLD_NAME,
2279                               cascade->stage_classifier[i].threshold) );
2280
2281         CV_CALL( cvWriteInt( fs, ICV_HAAR_PARENT_NAME,
2282                               cascade->stage_classifier[i].parent ) );
2283         CV_CALL( cvWriteInt( fs, ICV_HAAR_NEXT_NAME,
2284                               cascade->stage_classifier[i].next ) );
2285
2286         CV_CALL( cvEndWriteStruct( fs ) ); /* stage */
2287     } /* for each stage */
2288
2289     CV_CALL( cvEndWriteStruct( fs ) ); /* stages */
2290     CV_CALL( cvEndWriteStruct( fs ) ); /* root */
2291
2292     __END__;
2293 }
2294
2295 static void*
2296 icvCloneHaarClassifier( const void* struct_ptr )
2297 {
2298     CvHaarClassifierCascade* cascade = NULL;
2299
2300     CV_FUNCNAME( "cvCloneHaarClassifier" );
2301
2302     __BEGIN__;
2303
2304     int i, j, k, n;
2305     const CvHaarClassifierCascade* cascade_src =
2306         (const CvHaarClassifierCascade*) struct_ptr;
2307
2308     n = cascade_src->count;
2309     CV_CALL( cascade = icvCreateHaarClassifierCascade(n) );
2310     cascade->orig_window_size = cascade_src->orig_window_size;
2311
2312     for( i = 0; i < n; ++i )
2313     {
2314         cascade->stage_classifier[i].parent = cascade_src->stage_classifier[i].parent;
2315         cascade->stage_classifier[i].next = cascade_src->stage_classifier[i].next;
2316         cascade->stage_classifier[i].child = cascade_src->stage_classifier[i].child;
2317         cascade->stage_classifier[i].threshold = cascade_src->stage_classifier[i].threshold;
2318
2319         cascade->stage_classifier[i].count = 0;
2320         CV_CALL( cascade->stage_classifier[i].classifier =
2321             (CvHaarClassifier*) cvAlloc( cascade_src->stage_classifier[i].count
2322                 * sizeof( cascade->stage_classifier[i].classifier[0] ) ) );
2323
2324         cascade->stage_classifier[i].count = cascade_src->stage_classifier[i].count;
2325
2326         for( j = 0; j < cascade->stage_classifier[i].count; ++j )
2327         {
2328             cascade->stage_classifier[i].classifier[j].haar_feature = NULL;
2329         }
2330
2331         for( j = 0; j < cascade->stage_classifier[i].count; ++j )
2332         {
2333             const CvHaarClassifier* classifier_src =
2334                 &cascade_src->stage_classifier[i].classifier[j];
2335             CvHaarClassifier* classifier =
2336                 &cascade->stage_classifier[i].classifier[j];
2337
2338             classifier->count = classifier_src->count;
2339             CV_CALL( classifier->haar_feature = (CvHaarFeature*) cvAlloc(
2340                 classifier->count * ( sizeof( *classifier->haar_feature ) +
2341                                       sizeof( *classifier->threshold ) +
2342                                       sizeof( *classifier->left ) +
2343                                       sizeof( *classifier->right ) ) +
2344                 (classifier->count + 1) * sizeof( *classifier->alpha ) ) );
2345             classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
2346             classifier->left = (int*) (classifier->threshold + classifier->count);
2347             classifier->right = (int*) (classifier->left + classifier->count);
2348             classifier->alpha = (float*) (classifier->right + classifier->count);
2349             for( k = 0; k < classifier->count; ++k )
2350             {
2351                 classifier->haar_feature[k] = classifier_src->haar_feature[k];
2352                 classifier->threshold[k] = classifier_src->threshold[k];
2353                 classifier->left[k] = classifier_src->left[k];
2354                 classifier->right[k] = classifier_src->right[k];
2355                 classifier->alpha[k] = classifier_src->alpha[k];
2356             }
2357             classifier->alpha[classifier->count] =
2358                 classifier_src->alpha[classifier->count];
2359         }
2360     }
2361
2362     __END__;
2363
2364     return cascade;
2365 }
2366
2367
2368 CvType haar_type( CV_TYPE_NAME_HAAR, icvIsHaarClassifier,
2369                   (CvReleaseFunc)cvReleaseHaarClassifierCascade,
2370                   icvReadHaarClassifier, icvWriteHaarClassifier,
2371                   icvCloneHaarClassifier );
2372
2373 #if 0
2374 namespace cv
2375 {
2376
2377 HaarClassifierCascade::HaarClassifierCascade() {}
2378 HaarClassifierCascade::HaarClassifierCascade(const String& filename)
2379 { load(filename); }
2380     
2381 bool HaarClassifierCascade::load(const String& filename)
2382 {
2383     cascade = Ptr<CvHaarClassifierCascade>((CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0));
2384     return (CvHaarClassifierCascade*)cascade != 0;
2385 }
2386
2387 void HaarClassifierCascade::detectMultiScale( const Mat& image,
2388                        Vector<Rect>& objects, double scaleFactor,
2389                        int minNeighbors, int flags,
2390                        Size minSize )
2391 {
2392     MemStorage storage(cvCreateMemStorage(0));
2393     CvMat _image = image;
2394     CvSeq* _objects = cvHaarDetectObjects( &_image, cascade, storage, scaleFactor,
2395                                            minNeighbors, flags, minSize );
2396     Seq<Rect>(_objects).copyTo(objects);
2397 }
2398
2399 int HaarClassifierCascade::runAt(Point pt, int startStage, int) const
2400 {
2401     return cvRunHaarClassifierCascade(cascade, pt, startStage);
2402 }
2403
2404 void HaarClassifierCascade::setImages( const Mat& sum, const Mat& sqsum,
2405                                        const Mat& tilted, double scale )
2406 {
2407     CvMat _sum = sum, _sqsum = sqsum, _tilted = tilted;
2408     cvSetImagesForHaarClassifierCascade( cascade, &_sum, &_sqsum, &_tilted, scale );
2409 }
2410
2411 }
2412 #endif
2413
2414 /* End of file. */