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