Home | History | Annotate | Download | only in src
      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*
    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
    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*
    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
    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
    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
    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
    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
   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:
   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 
   1305     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:
   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 
   1438     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*
   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*
   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*
   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*
   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
   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
   2045 icvIsHaarClassifier( const void* struct_ptr )
   2046 {
   2047     return CV_IS_HAAR_CLASSIFIER( struct_ptr );
   2048 }
   2049 
   2050 static void*
   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
   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*
   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