1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/*M///////////////////////////////////////////////////////////////////////////////////////
2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//  By downloading, copying, installing or using the software you agree to this license.
6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//  If you do not agree to this license, do not download, install,
7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//  copy or use the software.
8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//                        Intel License Agreement
11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//                For Open Source Computer Vision Library
12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Copyright (C) 2000, Intel Corporation, all rights reserved.
14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Third party copyrights are property of their respective owners.
15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Redistribution and use in source and binary forms, with or without modification,
17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// are permitted provided that the following conditions are met:
18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//   * Redistribution's of source code must retain the above copyright notice,
20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//     this list of conditions and the following disclaimer.
21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//   * Redistribution's in binary form must reproduce the above copyright notice,
23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//     this list of conditions and the following disclaimer in the documentation
24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//     and/or other materials provided with the distribution.
25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
26793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//   * The name of Intel Corporation may not be used to endorse or promote products
27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//     derived from this software without specific prior written permission.
28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// This software is provided by the copyright holders and contributors "as is" and
30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// any express or implied warranties, including, but not limited to, the implied
31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// warranties of merchantability and fitness for a particular purpose are disclaimed.
32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// In no event shall the Intel Corporation or contributors be liable for any direct,
33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// indirect, incidental, special, exemplary, or consequential damages
34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// (including, but not limited to, procurement of substitute goods or services;
35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// loss of use, data, or profits; or business interruption) however caused
36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// and on any theory of liability, whether in contract, strict liability,
37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// or tort (including negligence or otherwise) arising in any way out of
38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// the use of this software, even if advised of the possibility of such damage.
39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//M*/
41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/* Haar features calculation */
43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "precomp.hpp"
45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/imgproc/imgproc_c.h"
46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/objdetect/objdetect_c.h"
47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <stdio.h>
48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#if CV_SSE2
50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#   if 1 /*!CV_SSE4_1 && !CV_SSE4_2*/
51793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#       define _mm_blendv_pd(a, b, m) _mm_xor_pd(a, _mm_and_pd(_mm_xor_pd(b, a), m))
52793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#       define _mm_blendv_ps(a, b, m) _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(b, a), m))
53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#   endif
54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#if 0 /*CV_AVX*/
57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#  define CV_HAAR_USE_AVX 1
58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#  if defined _MSC_VER
59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#    pragma warning( disable : 4752 )
60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#  endif
61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#else
62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#  if CV_SSE2
63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#    define CV_HAAR_USE_SSE 1
64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#  endif
65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/* these settings affect the quality of detection: change with care */
68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define CV_ADJUST_FEATURES 1
69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define CV_ADJUST_WEIGHTS  0
70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslertypedef int sumtype;
72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslertypedef double sqsumtype;
73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslertypedef struct CvHidHaarFeature
75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    struct
77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sumtype *p0, *p1, *p2, *p3;
79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        float weight;
80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    rect[CV_HAAR_FEATURE_MAX];
82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} CvHidHaarFeature;
83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslertypedef struct CvHidHaarTreeNode
86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarFeature feature;
88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    float threshold;
89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int left;
90793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int right;
91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} CvHidHaarTreeNode;
92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslertypedef struct CvHidHaarClassifier
95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int count;
97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    //CvHaarFeature* orig_feature;
98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarTreeNode* node;
99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    float* alpha;
100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} CvHidHaarClassifier;
101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslertypedef struct CvHidHaarStageClassifier
104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int  count;
106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    float threshold;
107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarClassifier* classifier;
108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int two_rects;
109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    struct CvHidHaarStageClassifier* next;
111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    struct CvHidHaarStageClassifier* child;
112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    struct CvHidHaarStageClassifier* parent;
113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} CvHidHaarStageClassifier;
114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslertypedef struct CvHidHaarClassifierCascade
117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int  count;
119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int  isStumpBased;
120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int  has_tilted_features;
121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int  is_tree;
122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    double inv_window_area;
123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvMat sum, sqsum, tilted;
124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarStageClassifier* stage_classifier;
125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    sqsumtype *pq0, *pq1, *pq2, *pq3;
126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    sumtype *p0, *p1, *p2, *p3;
127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    void** ipp_stages;
129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} CvHidHaarClassifierCascade;
130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerconst int icv_object_win_border = 1;
133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerconst float icv_stage_threshold_bias = 0.0001f;
134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic CvHaarClassifierCascade*
136793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslericvCreateHaarClassifierCascade( int stage_count )
137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHaarClassifierCascade* cascade = 0;
139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int block_size = sizeof(*cascade) + stage_count*sizeof(*cascade->stage_classifier);
141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( stage_count <= 0 )
143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsOutOfRange, "Number of stages should be positive" );
144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade = (CvHaarClassifierCascade*)cvAlloc( block_size );
146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    memset( cascade, 0, block_size );
147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->stage_classifier = (CvHaarStageClassifier*)(cascade + 1);
149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->flags = CV_HAAR_MAGIC_VAL;
150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->count = stage_count;
151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return cascade;
153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void
156793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslericvReleaseHidHaarClassifierCascade( CvHidHaarClassifierCascade** _cascade )
157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( _cascade && *_cascade )
159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef HAVE_IPP
161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvHidHaarClassifierCascade* cascade = *_cascade;
162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( CV_IPP_CHECK_COND && cascade->ipp_stages )
163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int i;
165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( i = 0; i < cascade->count; i++ )
166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( cascade->ipp_stages[i] )
168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)cascade->ipp_stages[i] );
169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvFree( &cascade->ipp_stages );
172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvFree( _cascade );
174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
176793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
177793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/* create more efficient internal representation of haar classifier cascade */
178793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic CvHidHaarClassifierCascade*
179793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslericvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
180793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
181793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvRect* ipp_features = 0;
182793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0;
183793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int* ipp_counts = 0;
184793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
185793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarClassifierCascade* out = 0;
186793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
187793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int i, j, k, l;
188793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int datasize;
189793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int total_classifiers = 0;
190793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int total_nodes = 0;
191793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    char errorstr[1000];
192793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarClassifier* haar_classifier_ptr;
193793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarTreeNode* haar_node_ptr;
194793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvSize orig_window_size;
195793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int has_tilted_features = 0;
196793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int max_count = 0;
197793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
198793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !CV_IS_HAAR_CLASSIFIER(cascade) )
199793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
200793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
201793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( cascade->hid_cascade )
202793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsError, "hid_cascade has been already created" );
203793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
204793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !cascade->stage_classifier )
205793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsNullPtr, "" );
206793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
207793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( cascade->count <= 0 )
208793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsOutOfRange, "Negative number of cascade stages" );
209793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
210793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    orig_window_size = cascade->orig_window_size;
211793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
212793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    /* check input structure correctness and calculate total memory size needed for
213793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler       internal representation of the classifier cascade */
214793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( i = 0; i < cascade->count; i++ )
215793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
216793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
217793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
218793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !stage_classifier->classifier ||
219793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            stage_classifier->count <= 0 )
220793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
221793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sprintf( errorstr, "header of the stage classifier #%d is invalid "
222793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                     "(has null pointers or non-positive classfier count)", i );
223793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsError, errorstr );
224793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
225793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
226793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        max_count = MAX( max_count, stage_classifier->count );
227793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        total_classifiers += stage_classifier->count;
228793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
229793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < stage_classifier->count; j++ )
230793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
231793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHaarClassifier* classifier = stage_classifier->classifier + j;
232793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
233793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            total_nodes += classifier->count;
234793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( l = 0; l < classifier->count; l++ )
235793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
236793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
237793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
238793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( classifier->haar_feature[l].rect[k].r.width )
239793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
240793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvRect r = classifier->haar_feature[l].rect[k].r;
241793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        int tilted = classifier->haar_feature[l].tilted;
242793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        has_tilted_features |= tilted != 0;
243793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( r.width < 0 || r.height < 0 || r.y < 0 ||
244793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            r.x + r.width > orig_window_size.width
245793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            ||
246793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            (!tilted &&
247793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            (r.x < 0 || r.y + r.height > orig_window_size.height))
248793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            ||
249793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            (tilted && (r.x - r.height < 0 ||
250793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            r.y + r.width + r.height > orig_window_size.height)))
251793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        {
252793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            sprintf( errorstr, "rectangle #%d of the classifier #%d of "
253793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     "the stage classifier #%d is not inside "
254793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     "the reference (original) cascade window", k, j, i );
255793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            CV_Error( CV_StsNullPtr, errorstr );
256793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        }
257793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
258793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
259793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
260793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
261793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
262793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
263793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    // this is an upper boundary for the whole hidden cascade size
264793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    datasize = sizeof(CvHidHaarClassifierCascade) +
265793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler               sizeof(CvHidHaarStageClassifier)*cascade->count +
266793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler               sizeof(CvHidHaarClassifier) * total_classifiers +
267793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler               sizeof(CvHidHaarTreeNode) * total_nodes +
268793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler               sizeof(void*)*(total_nodes + total_classifiers);
269793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
270793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    out = (CvHidHaarClassifierCascade*)cvAlloc( datasize );
271793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    memset( out, 0, sizeof(*out) );
272793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
273793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    /* init header */
274793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    out->count = cascade->count;
275793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    out->stage_classifier = (CvHidHaarStageClassifier*)(out + 1);
276793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count);
277793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);
278793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
279793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    out->isStumpBased = 1;
280793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    out->has_tilted_features = has_tilted_features;
281793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    out->is_tree = 0;
282793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
283793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    /* initialize internal representation */
284793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( i = 0; i < cascade->count; i++ )
285793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
286793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
287793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvHidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i;
288793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
289793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        hid_stage_classifier->count = stage_classifier->count;
290793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias;
291793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        hid_stage_classifier->classifier = haar_classifier_ptr;
292793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        hid_stage_classifier->two_rects = 1;
293793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        haar_classifier_ptr += stage_classifier->count;
294793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
295793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        hid_stage_classifier->parent = (stage_classifier->parent == -1)
296793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            ? NULL : out->stage_classifier + stage_classifier->parent;
297793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        hid_stage_classifier->next = (stage_classifier->next == -1)
298793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            ? NULL : out->stage_classifier + stage_classifier->next;
299793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        hid_stage_classifier->child = (stage_classifier->child == -1)
300793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            ? NULL : out->stage_classifier + stage_classifier->child;
301793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
302793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        out->is_tree |= hid_stage_classifier->next != NULL;
303793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
304793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < stage_classifier->count; j++ )
305793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
306793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHaarClassifier* classifier = stage_classifier->classifier + j;
307793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j;
308793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int node_count = classifier->count;
309793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            float* alpha_ptr = (float*)(haar_node_ptr + node_count);
310793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
311793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            hid_classifier->count = node_count;
312793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            hid_classifier->node = haar_node_ptr;
313793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            hid_classifier->alpha = alpha_ptr;
314793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
315793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( l = 0; l < node_count; l++ )
316793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
317793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvHidHaarTreeNode* node = hid_classifier->node + l;
318793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvHaarFeature* feature = classifier->haar_feature + l;
319793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                memset( node, -1, sizeof(*node) );
320793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                node->threshold = classifier->threshold[l];
321793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                node->left = classifier->left[l];
322793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                node->right = classifier->right[l];
323793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
324793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( fabs(feature->rect[2].weight) < DBL_EPSILON ||
325793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    feature->rect[2].r.width == 0 ||
326793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    feature->rect[2].r.height == 0 )
327793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) );
328793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
329793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    hid_stage_classifier->two_rects = 0;
330793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
331793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
332793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0]));
333793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            haar_node_ptr =
334793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                (CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*));
335793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
336793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            out->isStumpBased &= node_count == 1;
337793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
338793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
339793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/*
340793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef HAVE_IPP
341793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int can_use_ipp = CV_IPP_CHECK_COND && (!out->has_tilted_features && !out->is_tree && out->isStumpBased);
342793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
343793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( can_use_ipp )
344793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
345793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]);
346793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)*
347793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            (orig_window_size.height-icv_object_win_border*2)));
348793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
349793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        out->ipp_stages = (void**)cvAlloc( ipp_datasize );
350793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        memset( out->ipp_stages, 0, ipp_datasize );
351793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
352793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) );
353793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) );
354793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) );
355793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) );
356793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) );
357793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) );
358793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
359793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( i = 0; i < cascade->count; i++ )
360793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
361793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
362793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( j = 0, k = 0; j < stage_classifier->count; j++ )
363793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
364793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvHaarClassifier* classifier = stage_classifier->classifier + j;
365793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0);
366793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
367793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ipp_thresholds[j] = classifier->threshold[0];
368793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ipp_val1[j] = classifier->alpha[0];
369793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ipp_val2[j] = classifier->alpha[1];
370793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ipp_counts[j] = rect_count;
371793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
372793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( l = 0; l < rect_count; l++, k++ )
373793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
374793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    ipp_features[k] = classifier->haar_feature->rect[l].r;
375793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height;
376793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale;
377793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
378793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
379793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
380793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( ippiHaarClassifierInitAlloc_32f( (IppiHaarClassifier_32f**)&out->ipp_stages[i],
381793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                (const IppiRect*)ipp_features, ipp_weights, ipp_thresholds,
382793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 )
383793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                break;
384793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
385793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
386793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( i < cascade->count )
387793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
388793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( j = 0; j < i; j++ )
389793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( out->ipp_stages[i] )
390793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)out->ipp_stages[i] );
391793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvFree( &out->ipp_stages );
392793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
393793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
394793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
395793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler*/
396793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->hid_cascade = out;
397793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    assert( (char*)haar_node_ptr - (char*)out <= datasize );
398793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
399793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvFree( &ipp_features );
400793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvFree( &ipp_weights );
401793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvFree( &ipp_thresholds );
402793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvFree( &ipp_val1 );
403793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvFree( &ipp_val2 );
404793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvFree( &ipp_counts );
405793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
406793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return out;
407793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
408793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
409793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
410793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define sum_elem_ptr(sum,row,col)  \
411793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    ((sumtype*)CV_MAT_ELEM_PTR_FAST((sum),(row),(col),sizeof(sumtype)))
412793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
413793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define sqsum_elem_ptr(sqsum,row,col)  \
414793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    ((sqsumtype*)CV_MAT_ELEM_PTR_FAST((sqsum),(row),(col),sizeof(sqsumtype)))
415793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
416793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define calc_sum(rect,offset) \
417793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    ((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset])
418793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
419793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define calc_sumf(rect,offset) \
420793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    static_cast<float>((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset])
421793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
422793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
423793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCV_IMPL void
424793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslercvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* _cascade,
425793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     const CvArr* _sum,
426793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     const CvArr* _sqsum,
427793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     const CvArr* _tilted_sum,
428793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     double scale )
429793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
430793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvMat sum_stub, *sum = (CvMat*)_sum;
431793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvMat sqsum_stub, *sqsum = (CvMat*)_sqsum;
432793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvMat tilted_stub, *tilted = (CvMat*)_tilted_sum;
433793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarClassifierCascade* cascade;
434793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int coi0 = 0, coi1 = 0;
435793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int i;
436793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvRect equRect;
437793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    double weight_scale;
438793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
439793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
440793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
441793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
442793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( scale <= 0 )
443793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsOutOfRange, "Scale must be positive" );
444793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
445793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    sum = cvGetMat( sum, &sum_stub, &coi0 );
446793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    sqsum = cvGetMat( sqsum, &sqsum_stub, &coi1 );
447793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
448793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( coi0 || coi1 )
449793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_BadCOI, "COI is not supported" );
450793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
451793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !CV_ARE_SIZES_EQ( sum, sqsum ))
452793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsUnmatchedSizes, "All integral images must have the same size" );
453793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
454793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( CV_MAT_TYPE(sqsum->type) != CV_64FC1 ||
455793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_MAT_TYPE(sum->type) != CV_32SC1 )
456793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsUnsupportedFormat,
457793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
458793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
459793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !_cascade->hid_cascade )
460793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        icvCreateHidHaarClassifierCascade(_cascade);
461793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
462793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade = _cascade->hid_cascade;
463793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
464793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( cascade->has_tilted_features )
465793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
466793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        tilted = cvGetMat( tilted, &tilted_stub, &coi1 );
467793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
468793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( CV_MAT_TYPE(tilted->type) != CV_32SC1 )
469793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsUnsupportedFormat,
470793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
471793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
472793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( sum->step != tilted->step )
473793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsUnmatchedSizes,
474793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "Sum and tilted_sum must have the same stride (step, widthStep)" );
475793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
476793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !CV_ARE_SIZES_EQ( sum, tilted ))
477793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsUnmatchedSizes, "All integral images must have the same size" );
478793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->tilted = *tilted;
479793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
480793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
481793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    _cascade->scale = scale;
482793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    _cascade->real_window_size.width = cvRound( _cascade->orig_window_size.width * scale );
483793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    _cascade->real_window_size.height = cvRound( _cascade->orig_window_size.height * scale );
484793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
485793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->sum = *sum;
486793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->sqsum = *sqsum;
487793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
488793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    equRect.x = equRect.y = cvRound(scale);
489793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    equRect.width = cvRound((_cascade->orig_window_size.width-2)*scale);
490793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    equRect.height = cvRound((_cascade->orig_window_size.height-2)*scale);
491793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    weight_scale = 1./(equRect.width*equRect.height);
492793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->inv_window_area = weight_scale;
493793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
494793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->p0 = sum_elem_ptr(*sum, equRect.y, equRect.x);
495793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->p1 = sum_elem_ptr(*sum, equRect.y, equRect.x + equRect.width );
496793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->p2 = sum_elem_ptr(*sum, equRect.y + equRect.height, equRect.x );
497793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->p3 = sum_elem_ptr(*sum, equRect.y + equRect.height,
498793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     equRect.x + equRect.width );
499793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
500793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->pq0 = sqsum_elem_ptr(*sqsum, equRect.y, equRect.x);
501793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->pq1 = sqsum_elem_ptr(*sqsum, equRect.y, equRect.x + equRect.width );
502793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->pq2 = sqsum_elem_ptr(*sqsum, equRect.y + equRect.height, equRect.x );
503793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->pq3 = sqsum_elem_ptr(*sqsum, equRect.y + equRect.height,
504793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                          equRect.x + equRect.width );
505793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
506793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    /* init pointers in haar features according to real window size and
507793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler       given image pointers */
508793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( i = 0; i < _cascade->count; i++ )
509793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
510793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int j, k, l;
511793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < cascade->stage_classifier[i].count; j++ )
512793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
513793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( l = 0; l < cascade->stage_classifier[i].classifier[j].count; l++ )
514793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
515793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvHaarFeature* feature =
516793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    &_cascade->stage_classifier[i].classifier[j].haar_feature[l];
517793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                /* CvHidHaarClassifier* classifier =
518793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cascade->stage_classifier[i].classifier + j; */
519793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvHidHaarFeature* hidfeature =
520793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    &cascade->stage_classifier[i].classifier[j].node[l].feature;
521793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                double sum0 = 0, area0 = 0;
522793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvRect r[3];
523793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
524793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int base_w = -1, base_h = -1;
525793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int new_base_w = 0, new_base_h = 0;
526793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int kx, ky;
527793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int flagx = 0, flagy = 0;
528793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int x0 = 0, y0 = 0;
529793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int nr;
530793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
531793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                /* align blocks */
532793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
533793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
534793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !hidfeature->rect[k].p0 )
535793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        break;
536793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    r[k] = feature->rect[k].r;
537793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].width-1) );
538793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].x - r[0].x-1) );
539793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].height-1) );
540793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].y - r[0].y-1) );
541793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
542793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
543793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                nr = k;
544793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
545793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                base_w += 1;
546793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                base_h += 1;
547793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                kx = r[0].width / base_w;
548793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ky = r[0].height / base_h;
549793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
550793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( kx <= 0 )
551793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
552793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    flagx = 1;
553793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    new_base_w = cvRound( r[0].width * scale ) / kx;
554793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    x0 = cvRound( r[0].x * scale );
555793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
556793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
557793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( ky <= 0 )
558793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
559793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    flagy = 1;
560793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    new_base_h = cvRound( r[0].height * scale ) / ky;
561793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    y0 = cvRound( r[0].y * scale );
562793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
563793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
564793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( k = 0; k < nr; k++ )
565793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
566793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CvRect tr;
567793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    double correction_ratio;
568793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
569793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( flagx )
570793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
571793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tr.x = (r[k].x - r[0].x) * new_base_w / base_w + x0;
572793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tr.width = r[k].width * new_base_w / base_w;
573793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
574793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    else
575793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
576793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tr.x = cvRound( r[k].x * scale );
577793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tr.width = cvRound( r[k].width * scale );
578793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
579793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
580793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( flagy )
581793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
582793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tr.y = (r[k].y - r[0].y) * new_base_h / base_h + y0;
583793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tr.height = r[k].height * new_base_h / base_h;
584793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
585793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    else
586793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
587793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tr.y = cvRound( r[k].y * scale );
588793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tr.height = cvRound( r[k].height * scale );
589793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
590793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
591793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#if CV_ADJUST_WEIGHTS
592793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
593793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    // RAINER START
594793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    const float orig_feature_size =  (float)(feature->rect[k].r.width)*feature->rect[k].r.height;
595793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    const float orig_norm_size = (float)(_cascade->orig_window_size.width)*(_cascade->orig_window_size.height);
596793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    const float feature_size = float(tr.width*tr.height);
597793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    //const float normSize    = float(equRect.width*equRect.height);
598793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    float target_ratio = orig_feature_size / orig_norm_size;
599793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    //float isRatio = featureSize / normSize;
600793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    //correctionRatio = targetRatio / isRatio / normSize;
601793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    correction_ratio = target_ratio / feature_size;
602793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    // RAINER END
603793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
604793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#else
605793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    correction_ratio = weight_scale * (!feature->tilted ? 1 : 0.5);
606793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
607793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
608793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !feature->tilted )
609793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
610793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        hidfeature->rect[k].p0 = sum_elem_ptr(*sum, tr.y, tr.x);
611793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        hidfeature->rect[k].p1 = sum_elem_ptr(*sum, tr.y, tr.x + tr.width);
612793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        hidfeature->rect[k].p2 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x);
613793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        hidfeature->rect[k].p3 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x + tr.width);
614793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
615793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    else
616793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
617793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        hidfeature->rect[k].p2 = sum_elem_ptr(*tilted, tr.y + tr.width, tr.x + tr.width);
618793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        hidfeature->rect[k].p3 = sum_elem_ptr(*tilted, tr.y + tr.width + tr.height,
619793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                              tr.x + tr.width - tr.height);
620793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        hidfeature->rect[k].p0 = sum_elem_ptr(*tilted, tr.y, tr.x);
621793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        hidfeature->rect[k].p1 = sum_elem_ptr(*tilted, tr.y + tr.height, tr.x - tr.height);
622793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
623793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
624793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    hidfeature->rect[k].weight = (float)(feature->rect[k].weight * correction_ratio);
625793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
626793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( k == 0 )
627793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        area0 = tr.width * tr.height;
628793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    else
629793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sum0 += hidfeature->rect[k].weight * tr.width * tr.height;
630793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
631793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
632793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                hidfeature->rect[0].weight = (float)(-sum0/area0);
633793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            } /* l */
634793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        } /* j */
635793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
636793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
637793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
638793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
639793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// AVX version icvEvalHidHaarClassifier.  Process 8 CvHidHaarClassifiers per call. Check AVX support before invocation!!
640793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef CV_HAAR_USE_AVX
641793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCV_INLINE
642793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerdouble icvEvalHidHaarClassifierAVX( CvHidHaarClassifier* classifier,
643793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                    double variance_norm_factor, size_t p_offset )
644793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
645793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int  CV_DECL_ALIGNED(32) idxV[8] = {0,0,0,0,0,0,0,0};
646793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    uchar flags[8] = {0,0,0,0,0,0,0,0};
647793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarTreeNode* nodes[8];
648793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    double res = 0;
649793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    uchar exitConditionFlag = 0;
650793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for(;;)
651793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
652793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        float CV_DECL_ALIGNED(32) tmp[8] = {0,0,0,0,0,0,0,0};
653793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        nodes[0] = (classifier+0)->node + idxV[0];
654793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        nodes[1] = (classifier+1)->node + idxV[1];
655793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        nodes[2] = (classifier+2)->node + idxV[2];
656793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        nodes[3] = (classifier+3)->node + idxV[3];
657793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        nodes[4] = (classifier+4)->node + idxV[4];
658793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        nodes[5] = (classifier+5)->node + idxV[5];
659793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        nodes[6] = (classifier+6)->node + idxV[6];
660793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        nodes[7] = (classifier+7)->node + idxV[7];
661793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
662793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        __m256 t = _mm256_set1_ps(static_cast<float>(variance_norm_factor));
663793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
664793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        t = _mm256_mul_ps(t, _mm256_set_ps(nodes[7]->threshold,
665793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           nodes[6]->threshold,
666793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           nodes[5]->threshold,
667793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           nodes[4]->threshold,
668793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           nodes[3]->threshold,
669793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           nodes[2]->threshold,
670793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           nodes[1]->threshold,
671793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           nodes[0]->threshold));
672793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
673793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        __m256 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[0], p_offset),
674793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      calc_sumf(nodes[6]->feature.rect[0], p_offset),
675793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      calc_sumf(nodes[5]->feature.rect[0], p_offset),
676793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      calc_sumf(nodes[4]->feature.rect[0], p_offset),
677793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      calc_sumf(nodes[3]->feature.rect[0], p_offset),
678793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      calc_sumf(nodes[2]->feature.rect[0], p_offset),
679793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      calc_sumf(nodes[1]->feature.rect[0], p_offset),
680793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      calc_sumf(nodes[0]->feature.rect[0], p_offset));
681793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
682793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        __m256 weight = _mm256_set_ps(nodes[7]->feature.rect[0].weight,
683793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      nodes[6]->feature.rect[0].weight,
684793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      nodes[5]->feature.rect[0].weight,
685793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      nodes[4]->feature.rect[0].weight,
686793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      nodes[3]->feature.rect[0].weight,
687793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      nodes[2]->feature.rect[0].weight,
688793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      nodes[1]->feature.rect[0].weight,
689793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      nodes[0]->feature.rect[0].weight);
690793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
691793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        __m256 sum = _mm256_mul_ps(offset, weight);
692793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
693793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[1], p_offset),
694793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               calc_sumf(nodes[6]->feature.rect[1], p_offset),
695793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               calc_sumf(nodes[5]->feature.rect[1], p_offset),
696793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               calc_sumf(nodes[4]->feature.rect[1], p_offset),
697793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               calc_sumf(nodes[3]->feature.rect[1], p_offset),
698793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               calc_sumf(nodes[2]->feature.rect[1], p_offset),
699793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               calc_sumf(nodes[1]->feature.rect[1], p_offset),
700793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               calc_sumf(nodes[0]->feature.rect[1], p_offset));
701793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
702793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        weight = _mm256_set_ps(nodes[7]->feature.rect[1].weight,
703793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               nodes[6]->feature.rect[1].weight,
704793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               nodes[5]->feature.rect[1].weight,
705793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               nodes[4]->feature.rect[1].weight,
706793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               nodes[3]->feature.rect[1].weight,
707793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               nodes[2]->feature.rect[1].weight,
708793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               nodes[1]->feature.rect[1].weight,
709793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               nodes[0]->feature.rect[1].weight);
710793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
711793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sum = _mm256_add_ps(sum, _mm256_mul_ps(offset, weight));
712793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
713793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nodes[0]->feature.rect[2].p0 )
714793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp[0] = calc_sumf(nodes[0]->feature.rect[2], p_offset) * nodes[0]->feature.rect[2].weight;
715793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nodes[1]->feature.rect[2].p0 )
716793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp[1] = calc_sumf(nodes[1]->feature.rect[2], p_offset) * nodes[1]->feature.rect[2].weight;
717793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nodes[2]->feature.rect[2].p0 )
718793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp[2] = calc_sumf(nodes[2]->feature.rect[2], p_offset) * nodes[2]->feature.rect[2].weight;
719793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nodes[3]->feature.rect[2].p0 )
720793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp[3] = calc_sumf(nodes[3]->feature.rect[2], p_offset) * nodes[3]->feature.rect[2].weight;
721793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nodes[4]->feature.rect[2].p0 )
722793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp[4] = calc_sumf(nodes[4]->feature.rect[2], p_offset) * nodes[4]->feature.rect[2].weight;
723793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nodes[5]->feature.rect[2].p0 )
724793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp[5] = calc_sumf(nodes[5]->feature.rect[2], p_offset) * nodes[5]->feature.rect[2].weight;
725793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nodes[6]->feature.rect[2].p0 )
726793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp[6] = calc_sumf(nodes[6]->feature.rect[2], p_offset) * nodes[6]->feature.rect[2].weight;
727793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nodes[7]->feature.rect[2].p0 )
728793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp[7] = calc_sumf(nodes[7]->feature.rect[2], p_offset) * nodes[7]->feature.rect[2].weight;
729793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
730793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sum = _mm256_add_ps(sum,_mm256_load_ps(tmp));
731793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
732793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        __m256 left  = _mm256_set_ps(static_cast<float>(nodes[7]->left), static_cast<float>(nodes[6]->left),
733793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     static_cast<float>(nodes[5]->left), static_cast<float>(nodes[4]->left),
734793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     static_cast<float>(nodes[3]->left), static_cast<float>(nodes[2]->left),
735793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     static_cast<float>(nodes[1]->left), static_cast<float>(nodes[0]->left));
736793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        __m256 right = _mm256_set_ps(static_cast<float>(nodes[7]->right),static_cast<float>(nodes[6]->right),
737793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     static_cast<float>(nodes[5]->right),static_cast<float>(nodes[4]->right),
738793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     static_cast<float>(nodes[3]->right),static_cast<float>(nodes[2]->right),
739793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                     static_cast<float>(nodes[1]->right),static_cast<float>(nodes[0]->right));
740793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
741793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        _mm256_store_si256((__m256i*)idxV, _mm256_cvttps_epi32(_mm256_blendv_ps(right, left, _mm256_cmp_ps(sum, t, _CMP_LT_OQ))));
742793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
743793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for(int i = 0; i < 8; i++)
744793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
745793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if(idxV[i]<=0)
746793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
747793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if(!flags[i])
748793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
749793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    exitConditionFlag++;
750793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    flags[i] = 1;
751793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    res += (classifier+i)->alpha[-idxV[i]];
752793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
753793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                idxV[i]=0;
754793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
755793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
756793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if(exitConditionFlag == 8)
757793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            return res;
758793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
759793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
760793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif //CV_HAAR_USE_AVX
761793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
762793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCV_INLINE
763793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerdouble icvEvalHidHaarClassifier( CvHidHaarClassifier* classifier,
764793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 double variance_norm_factor,
765793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 size_t p_offset )
766793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
767793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int idx = 0;
768793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    /*#if CV_HAAR_USE_SSE && !CV_HAAR_USE_AVX
769793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if(cv::checkHardwareSupport(CV_CPU_SSE2))//based on old SSE variant. Works slow
770793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
771793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            double CV_DECL_ALIGNED(16) temp[2];
772793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            __m128d zero = _mm_setzero_pd();
773793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            do
774793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
775793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvHidHaarTreeNode* node = classifier->node + idx;
776793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                __m128d t = _mm_set1_pd((node->threshold)*variance_norm_factor);
777793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                __m128d left = _mm_set1_pd(node->left);
778793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                __m128d right = _mm_set1_pd(node->right);
779793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
780793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                double _sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
781793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                _sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
782793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( node->feature.rect[2].p0 )
783793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    _sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
784793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
785793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                __m128d sum = _mm_set1_pd(_sum);
786793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                t = _mm_cmplt_sd(sum, t);
787793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                sum = _mm_blendv_pd(right, left, t);
788793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
789793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                _mm_store_pd(temp, sum);
790793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                idx = (int)temp[0];
791793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
792793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            while(idx > 0 );
793793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
794793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
795793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        else
796793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    #endif*/
797793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
798793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        do
799793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
800793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHidHaarTreeNode* node = classifier->node + idx;
801793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            double t = node->threshold * variance_norm_factor;
802793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
803793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
804793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
805793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
806793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( node->feature.rect[2].p0 )
807793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
808793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
809793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            idx = sum < t ? node->left : node->right;
810793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
811793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        while( idx > 0 );
812793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
813793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return classifier->alpha[-idx];
814793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
815793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
816793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
817793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
818793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int
819793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslercvRunHaarClassifierCascadeSum( const CvHaarClassifierCascade* _cascade,
820793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                               CvPoint pt, double& stage_sum, int start_stage )
821793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
822793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef CV_HAAR_USE_AVX
823793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool haveAVX = false;
824793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if(cv::checkHardwareSupport(CV_CPU_AVX))
825793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if(__xgetbv()&0x6)// Check if the OS will save the YMM registers
826793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler       haveAVX = true;
827793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#else
828793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#  ifdef CV_HAAR_USE_SSE
829793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool haveSSE2 = cv::checkHardwareSupport(CV_CPU_SSE2);
830793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#  endif
831793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
832793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
833793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int p_offset, pq_offset;
834793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int i, j;
835793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    double mean, variance_norm_factor;
836793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHidHaarClassifierCascade* cascade;
837793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
838793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
839793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid cascade pointer" );
840793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
841793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade = _cascade->hid_cascade;
842793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !cascade )
843793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsNullPtr, "Hidden cascade has not been created.\n"
844793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "Use cvSetImagesForHaarClassifierCascade" );
845793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
846793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( pt.x < 0 || pt.y < 0 ||
847793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        pt.x + _cascade->real_window_size.width >= cascade->sum.width ||
848793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        pt.y + _cascade->real_window_size.height >= cascade->sum.height )
849793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return -1;
850793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
851793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    p_offset = pt.y * (cascade->sum.step/sizeof(sumtype)) + pt.x;
852793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    pq_offset = pt.y * (cascade->sqsum.step/sizeof(sqsumtype)) + pt.x;
853793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    mean = calc_sum(*cascade,p_offset)*cascade->inv_window_area;
854793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    variance_norm_factor = cascade->pq0[pq_offset] - cascade->pq1[pq_offset] -
855793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                           cascade->pq2[pq_offset] + cascade->pq3[pq_offset];
856793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    variance_norm_factor = variance_norm_factor*cascade->inv_window_area - mean*mean;
857793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( variance_norm_factor >= 0. )
858793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        variance_norm_factor = std::sqrt(variance_norm_factor);
859793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    else
860793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        variance_norm_factor = 1.;
861793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
862793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( cascade->is_tree )
863793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
864793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvHidHaarStageClassifier* ptr = cascade->stage_classifier;
865793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        assert( start_stage == 0 );
866793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
867793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        while( ptr )
868793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
869793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            stage_sum = 0.0;
870793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            j = 0;
871793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
872793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef CV_HAAR_USE_AVX
873793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if(haveAVX)
874793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
875793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( ; j <= ptr->count - 8; j += 8 )
876793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
877793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    stage_sum += icvEvalHidHaarClassifierAVX(
878793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        ptr->classifier + j,
879793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        variance_norm_factor, p_offset );
880793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
881793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
882793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
883793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( ; j < ptr->count; j++ )
884793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
885793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                stage_sum += icvEvalHidHaarClassifier( ptr->classifier + j, variance_norm_factor, p_offset );
886793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
887793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
888793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( stage_sum >= ptr->threshold )
889793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
890793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ptr = ptr->child;
891793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
892793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            else
893793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
894793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                while( ptr && ptr->next == NULL ) ptr = ptr->parent;
895793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( ptr == NULL )
896793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    return 0;
897793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ptr = ptr->next;
898793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
899793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
900793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
901793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    else if( cascade->isStumpBased )
902793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
903793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef CV_HAAR_USE_AVX
904793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if(haveAVX)
905793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
906793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHidHaarClassifier* classifiers[8];
907793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHidHaarTreeNode* nodes[8];
908793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( i = start_stage; i < cascade->count; i++ )
909793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
910793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                stage_sum = 0.0;
911793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                j = 0;
912793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                float CV_DECL_ALIGNED(32) buf[8];
913793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( cascade->stage_classifier[i].two_rects )
914793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
915793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( ; j <= cascade->stage_classifier[i].count - 8; j += 8 )
916793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
917793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[0] = cascade->stage_classifier[i].classifier + j;
918793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[0] = classifiers[0]->node;
919793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[1] = cascade->stage_classifier[i].classifier + j + 1;
920793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[1] = classifiers[1]->node;
921793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[2] = cascade->stage_classifier[i].classifier + j + 2;
922793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[2] = classifiers[2]->node;
923793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[3] = cascade->stage_classifier[i].classifier + j + 3;
924793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[3] = classifiers[3]->node;
925793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[4] = cascade->stage_classifier[i].classifier + j + 4;
926793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[4] = classifiers[4]->node;
927793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[5] = cascade->stage_classifier[i].classifier + j + 5;
928793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[5] = classifiers[5]->node;
929793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[6] = cascade->stage_classifier[i].classifier + j + 6;
930793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[6] = classifiers[6]->node;
931793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[7] = cascade->stage_classifier[i].classifier + j + 7;
932793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[7] = classifiers[7]->node;
933793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
934793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 t = _mm256_set1_ps(static_cast<float>(variance_norm_factor));
935793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        t = _mm256_mul_ps(t, _mm256_set_ps(nodes[7]->threshold,
936793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[6]->threshold,
937793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[5]->threshold,
938793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[4]->threshold,
939793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[3]->threshold,
940793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[2]->threshold,
941793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[1]->threshold,
942793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[0]->threshold));
943793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
944793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[0], p_offset),
945793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[6]->feature.rect[0], p_offset),
946793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[5]->feature.rect[0], p_offset),
947793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[4]->feature.rect[0], p_offset),
948793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[3]->feature.rect[0], p_offset),
949793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[2]->feature.rect[0], p_offset),
950793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[1]->feature.rect[0], p_offset),
951793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[0]->feature.rect[0], p_offset));
952793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
953793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 weight = _mm256_set_ps(nodes[7]->feature.rect[0].weight,
954793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[6]->feature.rect[0].weight,
955793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[5]->feature.rect[0].weight,
956793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[4]->feature.rect[0].weight,
957793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[3]->feature.rect[0].weight,
958793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[2]->feature.rect[0].weight,
959793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[1]->feature.rect[0].weight,
960793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[0]->feature.rect[0].weight);
961793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
962793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 sum = _mm256_mul_ps(offset, weight);
963793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
964793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[1], p_offset),
965793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[6]->feature.rect[1], p_offset),
966793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[5]->feature.rect[1], p_offset),
967793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[4]->feature.rect[1], p_offset),
968793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[3]->feature.rect[1], p_offset),
969793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[2]->feature.rect[1], p_offset),
970793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[1]->feature.rect[1], p_offset),
971793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[0]->feature.rect[1], p_offset));
972793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
973793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        weight = _mm256_set_ps(nodes[7]->feature.rect[1].weight,
974793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[6]->feature.rect[1].weight,
975793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[5]->feature.rect[1].weight,
976793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[4]->feature.rect[1].weight,
977793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[3]->feature.rect[1].weight,
978793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[2]->feature.rect[1].weight,
979793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[1]->feature.rect[1].weight,
980793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[0]->feature.rect[1].weight);
981793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
982793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sum = _mm256_add_ps(sum, _mm256_mul_ps(offset,weight));
983793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
984793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 alpha0 = _mm256_set_ps(classifiers[7]->alpha[0],
985793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[6]->alpha[0],
986793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[5]->alpha[0],
987793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[4]->alpha[0],
988793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[3]->alpha[0],
989793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[2]->alpha[0],
990793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[1]->alpha[0],
991793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[0]->alpha[0]);
992793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 alpha1 = _mm256_set_ps(classifiers[7]->alpha[1],
993793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[6]->alpha[1],
994793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[5]->alpha[1],
995793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[4]->alpha[1],
996793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[3]->alpha[1],
997793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[2]->alpha[1],
998793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[1]->alpha[1],
999793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[0]->alpha[1]);
1000793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1001793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        _mm256_store_ps(buf, _mm256_blendv_ps(alpha0, alpha1, _mm256_cmp_ps(t, sum, _CMP_LE_OQ)));
1002793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        stage_sum += (buf[0]+buf[1]+buf[2]+buf[3]+buf[4]+buf[5]+buf[6]+buf[7]);
1003793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1004793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1005793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( ; j < cascade->stage_classifier[i].count; j++ )
1006793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1007793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
1008793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarTreeNode* node = classifier->node;
1009793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1010793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double t = node->threshold*variance_norm_factor;
1011793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
1012793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
1013793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        stage_sum += classifier->alpha[sum >= t];
1014793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1015793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1016793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
1017793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1018793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( ; j <= (cascade->stage_classifier[i].count)-8; j+=8 )
1019793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1020793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        float  CV_DECL_ALIGNED(32) tmp[8] = {0,0,0,0,0,0,0,0};
1021793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1022793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[0] = cascade->stage_classifier[i].classifier + j;
1023793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[0] = classifiers[0]->node;
1024793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[1] = cascade->stage_classifier[i].classifier + j + 1;
1025793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[1] = classifiers[1]->node;
1026793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[2] = cascade->stage_classifier[i].classifier + j + 2;
1027793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[2] = classifiers[2]->node;
1028793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[3] = cascade->stage_classifier[i].classifier + j + 3;
1029793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[3] = classifiers[3]->node;
1030793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[4] = cascade->stage_classifier[i].classifier + j + 4;
1031793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[4] = classifiers[4]->node;
1032793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[5] = cascade->stage_classifier[i].classifier + j + 5;
1033793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[5] = classifiers[5]->node;
1034793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[6] = cascade->stage_classifier[i].classifier + j + 6;
1035793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[6] = classifiers[6]->node;
1036793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        classifiers[7] = cascade->stage_classifier[i].classifier + j + 7;
1037793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        nodes[7] = classifiers[7]->node;
1038793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1039793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 t = _mm256_set1_ps(static_cast<float>(variance_norm_factor));
1040793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1041793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        t = _mm256_mul_ps(t, _mm256_set_ps(nodes[7]->threshold,
1042793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[6]->threshold,
1043793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[5]->threshold,
1044793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[4]->threshold,
1045793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[3]->threshold,
1046793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[2]->threshold,
1047793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[1]->threshold,
1048793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           nodes[0]->threshold));
1049793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1050793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[0], p_offset),
1051793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[6]->feature.rect[0], p_offset),
1052793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[5]->feature.rect[0], p_offset),
1053793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[4]->feature.rect[0], p_offset),
1054793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[3]->feature.rect[0], p_offset),
1055793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[2]->feature.rect[0], p_offset),
1056793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[1]->feature.rect[0], p_offset),
1057793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      calc_sumf(nodes[0]->feature.rect[0], p_offset));
1058793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1059793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 weight = _mm256_set_ps(nodes[7]->feature.rect[0].weight,
1060793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[6]->feature.rect[0].weight,
1061793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[5]->feature.rect[0].weight,
1062793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[4]->feature.rect[0].weight,
1063793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[3]->feature.rect[0].weight,
1064793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[2]->feature.rect[0].weight,
1065793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[1]->feature.rect[0].weight,
1066793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      nodes[0]->feature.rect[0].weight);
1067793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1068793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 sum = _mm256_mul_ps(offset, weight);
1069793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1070793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[1], p_offset),
1071793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[6]->feature.rect[1], p_offset),
1072793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[5]->feature.rect[1], p_offset),
1073793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[4]->feature.rect[1], p_offset),
1074793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[3]->feature.rect[1], p_offset),
1075793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[2]->feature.rect[1], p_offset),
1076793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[1]->feature.rect[1], p_offset),
1077793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               calc_sumf(nodes[0]->feature.rect[1], p_offset));
1078793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1079793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        weight = _mm256_set_ps(nodes[7]->feature.rect[1].weight,
1080793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[6]->feature.rect[1].weight,
1081793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[5]->feature.rect[1].weight,
1082793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[4]->feature.rect[1].weight,
1083793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[3]->feature.rect[1].weight,
1084793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[2]->feature.rect[1].weight,
1085793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[1]->feature.rect[1].weight,
1086793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                               nodes[0]->feature.rect[1].weight);
1087793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1088793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sum = _mm256_add_ps(sum, _mm256_mul_ps(offset, weight));
1089793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1090793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( nodes[0]->feature.rect[2].p0 )
1091793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            tmp[0] = calc_sumf(nodes[0]->feature.rect[2],p_offset) * nodes[0]->feature.rect[2].weight;
1092793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( nodes[1]->feature.rect[2].p0 )
1093793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            tmp[1] = calc_sumf(nodes[1]->feature.rect[2],p_offset) * nodes[1]->feature.rect[2].weight;
1094793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( nodes[2]->feature.rect[2].p0 )
1095793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            tmp[2] = calc_sumf(nodes[2]->feature.rect[2],p_offset) * nodes[2]->feature.rect[2].weight;
1096793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( nodes[3]->feature.rect[2].p0 )
1097793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            tmp[3] = calc_sumf(nodes[3]->feature.rect[2],p_offset) * nodes[3]->feature.rect[2].weight;
1098793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( nodes[4]->feature.rect[2].p0 )
1099793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            tmp[4] = calc_sumf(nodes[4]->feature.rect[2],p_offset) * nodes[4]->feature.rect[2].weight;
1100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( nodes[5]->feature.rect[2].p0 )
1101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            tmp[5] = calc_sumf(nodes[5]->feature.rect[2],p_offset) * nodes[5]->feature.rect[2].weight;
1102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( nodes[6]->feature.rect[2].p0 )
1103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            tmp[6] = calc_sumf(nodes[6]->feature.rect[2],p_offset) * nodes[6]->feature.rect[2].weight;
1104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( nodes[7]->feature.rect[2].p0 )
1105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            tmp[7] = calc_sumf(nodes[7]->feature.rect[2],p_offset) * nodes[7]->feature.rect[2].weight;
1106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sum = _mm256_add_ps(sum, _mm256_load_ps(tmp));
1108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 alpha0 = _mm256_set_ps(classifiers[7]->alpha[0],
1110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[6]->alpha[0],
1111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[5]->alpha[0],
1112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[4]->alpha[0],
1113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[3]->alpha[0],
1114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[2]->alpha[0],
1115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[1]->alpha[0],
1116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[0]->alpha[0]);
1117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 alpha1 = _mm256_set_ps(classifiers[7]->alpha[1],
1118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[6]->alpha[1],
1119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[5]->alpha[1],
1120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[4]->alpha[1],
1121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[3]->alpha[1],
1122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[2]->alpha[1],
1123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[1]->alpha[1],
1124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                      classifiers[0]->alpha[1]);
1125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m256 outBuf = _mm256_blendv_ps(alpha0, alpha1, _mm256_cmp_ps(t, sum, _CMP_LE_OQ ));
1127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        outBuf = _mm256_hadd_ps(outBuf, outBuf);
1128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        outBuf = _mm256_hadd_ps(outBuf, outBuf);
1129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        _mm256_store_ps(buf, outBuf);
1130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        stage_sum += (buf[0] + buf[4]);
1131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( ; j < cascade->stage_classifier[i].count; j++ )
1134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
1136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarTreeNode* node = classifier->node;
1137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double t = node->threshold*variance_norm_factor;
1139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
1140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
1141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( node->feature.rect[2].p0 )
1142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
1143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        stage_sum += classifier->alpha[sum >= t];
1144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( stage_sum < cascade->stage_classifier[i].threshold )
1147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    return -i;
1148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        else
1151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#elif defined CV_HAAR_USE_SSE //old SSE optimization
1152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if(haveSSE2)
1153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( i = start_stage; i < cascade->count; i++ )
1155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1156793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                __m128d vstage_sum = _mm_setzero_pd();
1157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( cascade->stage_classifier[i].two_rects )
1158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( j = 0; j < cascade->stage_classifier[i].count; j++ )
1160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
1162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarTreeNode* node = classifier->node;
1163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        // ayasin - NHM perf optim. Avoid use of costly flaky jcc
1165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m128d t = _mm_set_sd(node->threshold*variance_norm_factor);
1166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m128d a = _mm_set_sd(classifier->alpha[0]);
1167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m128d b = _mm_set_sd(classifier->alpha[1]);
1168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m128d sum = _mm_set_sd(calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight +
1169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                 calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight);
1170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        t = _mm_cmpgt_sd(t, sum);
1171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        vstage_sum = _mm_add_sd(vstage_sum, _mm_blendv_pd(b, a, t));
1172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
1175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1176793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( j = 0; j < cascade->stage_classifier[i].count; j++ )
1177793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1178793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
1179793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarTreeNode* node = classifier->node;
1180793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        // ayasin - NHM perf optim. Avoid use of costly flaky jcc
1181793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m128d t = _mm_set_sd(node->threshold*variance_norm_factor);
1182793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m128d a = _mm_set_sd(classifier->alpha[0]);
1183793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m128d b = _mm_set_sd(classifier->alpha[1]);
1184793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double _sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
1185793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        _sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
1186793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( node->feature.rect[2].p0 )
1187793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            _sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
1188793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        __m128d sum = _mm_set_sd(_sum);
1189793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1190793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        t = _mm_cmpgt_sd(t, sum);
1191793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        vstage_sum = _mm_add_sd(vstage_sum, _mm_blendv_pd(b, a, t));
1192793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1193793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1194793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                __m128d i_threshold = _mm_set1_pd(cascade->stage_classifier[i].threshold);
1195793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( _mm_comilt_sd(vstage_sum, i_threshold) )
1196793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    return -i;
1197793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1198793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1199793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        else
1200793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif // AVX or SSE
1201793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1202793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( i = start_stage; i < cascade->count; i++ )
1203793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1204793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                stage_sum = 0.0;
1205793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( cascade->stage_classifier[i].two_rects )
1206793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1207793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( j = 0; j < cascade->stage_classifier[i].count; j++ )
1208793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1209793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
1210793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarTreeNode* node = classifier->node;
1211793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double t = node->threshold*variance_norm_factor;
1212793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
1213793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
1214793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        stage_sum += classifier->alpha[sum >= t];
1215793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1216793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1217793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
1218793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1219793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( j = 0; j < cascade->stage_classifier[i].count; j++ )
1220793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1221793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
1222793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvHidHaarTreeNode* node = classifier->node;
1223793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double t = node->threshold*variance_norm_factor;
1224793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
1225793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
1226793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( node->feature.rect[2].p0 )
1227793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
1228793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        stage_sum += classifier->alpha[sum >= t];
1229793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1230793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1231793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( stage_sum < cascade->stage_classifier[i].threshold )
1232793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    return -i;
1233793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1234793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1235793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1236793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    else
1237793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1238793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( i = start_stage; i < cascade->count; i++ )
1239793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1240793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            stage_sum = 0.0;
1241793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int k = 0;
1242793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1243793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef CV_HAAR_USE_AVX
1244793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if(haveAVX)
1245793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1246793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( ; k < cascade->stage_classifier[i].count - 8; k += 8 )
1247793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1248793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    stage_sum += icvEvalHidHaarClassifierAVX(
1249793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        cascade->stage_classifier[i].classifier + k,
1250793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        variance_norm_factor, p_offset );
1251793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1252793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1253793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
1254793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for(; k < cascade->stage_classifier[i].count; k++ )
1255793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1256793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1257793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                stage_sum += icvEvalHidHaarClassifier(
1258793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cascade->stage_classifier[i].classifier + k,
1259793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    variance_norm_factor, p_offset );
1260793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1261793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1262793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( stage_sum < cascade->stage_classifier[i].threshold )
1263793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                return -i;
1264793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1265793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1266793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return 1;
1267793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
1268793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1269793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1270793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCV_IMPL int
1271793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslercvRunHaarClassifierCascade( const CvHaarClassifierCascade* _cascade,
1272793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            CvPoint pt, int start_stage )
1273793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
1274793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    double stage_sum;
1275793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return cvRunHaarClassifierCascadeSum(_cascade, pt, stage_sum, start_stage);
1276793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
1277793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1278793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslernamespace cv
1279793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
1280793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1281793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerclass HaarDetectObjects_ScaleImage_Invoker : public ParallelLoopBody
1282793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
1283793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerpublic:
1284793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    HaarDetectObjects_ScaleImage_Invoker( const CvHaarClassifierCascade* _cascade,
1285793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                          int _stripSize, double _factor,
1286793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                          const Mat& _sum1, const Mat& _sqsum1, Mat* _norm1,
1287793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                          Mat* _mask1, Rect _equRect, std::vector<Rect>& _vec,
1288793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                          std::vector<int>& _levels, std::vector<double>& _weights,
1289793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                          bool _outputLevels, Mutex *_mtx )
1290793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1291793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade = _cascade;
1292793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stripSize = _stripSize;
1293793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        factor = _factor;
1294793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sum1 = _sum1;
1295793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sqsum1 = _sqsum1;
1296793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        norm1 = _norm1;
1297793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        mask1 = _mask1;
1298793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        equRect = _equRect;
1299793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        vec = &_vec;
1300793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        rejectLevels = _outputLevels ? &_levels : 0;
1301793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        levelWeights = _outputLevels ? &_weights : 0;
1302793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        mtx = _mtx;
1303793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1304793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1305793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    void operator()( const Range& range ) const
1306793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1307793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Size winSize0 = cascade->orig_window_size;
1308793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Size winSize(cvRound(winSize0.width*factor), cvRound(winSize0.height*factor));
1309793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int y1 = range.start*stripSize, y2 = std::min(range.end*stripSize, sum1.rows - 1 - winSize0.height);
1310793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1311793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if (y2 <= y1 || sum1.cols <= 1 + winSize0.width)
1312793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            return;
1313793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1314793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Size ssz(sum1.cols - 1 - winSize0.width, y2 - y1);
1315793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int x, y, ystep = factor > 2 ? 1 : 2;
1316793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1317793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef HAVE_IPP
1318793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if(CV_IPP_CHECK_COND && cascade->hid_cascade->ipp_stages )
1319793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1320793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            IppiRect iequRect = {equRect.x, equRect.y, equRect.width, equRect.height};
1321793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            ippiRectStdDev_32f_C1R(sum1.ptr<float>(y1), (int)sum1.step,
1322793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                   sqsum1.ptr<double>(y1), (int)sqsum1.step,
1323793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                   norm1->ptr<float>(y1), (int)norm1->step,
1324793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                   ippiSize(ssz.width, ssz.height), iequRect );
1325793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1326793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int positive = (ssz.width/ystep)*((ssz.height + ystep-1)/ystep);
1327793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1328793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( ystep == 1 )
1329793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                (*mask1) = Scalar::all(1);
1330793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            else
1331793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( y = y1; y < y2; y++ )
1332793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1333793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    uchar* mask1row = mask1->ptr(y);
1334793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    memset( mask1row, 0, ssz.width );
1335793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1336793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( y % ystep == 0 )
1337793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        for( x = 0; x < ssz.width; x += ystep )
1338793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            mask1row[x] = (uchar)1;
1339793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1340793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1341793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( int j = 0; j < cascade->count; j++ )
1342793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1343793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( ippiApplyHaarClassifier_32f_C1R(
1344793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            sum1.ptr<float>(y1), (int)sum1.step,
1345793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            norm1->ptr<float>(y1), (int)norm1->step,
1346793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            mask1->ptr<uchar>(y1), (int)mask1->step,
1347793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            ippiSize(ssz.width, ssz.height), &positive,
1348793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            cascade->hid_cascade->stage_classifier[j].threshold,
1349793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            (IppiHaarClassifier_32f*)cascade->hid_cascade->ipp_stages[j]) < 0 )
1350793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    positive = 0;
1351793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( positive <= 0 )
1352793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    break;
1353793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1354793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT);
1355793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1356793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( positive > 0 )
1357793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( y = y1; y < y2; y += ystep )
1358793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1359793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    uchar* mask1row = mask1->ptr(y);
1360793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( x = 0; x < ssz.width; x += ystep )
1361793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( mask1row[x] != 0 )
1362793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        {
1363793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            mtx->lock();
1364793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            vec->push_back(Rect(cvRound(x*factor), cvRound(y*factor),
1365793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                winSize.width, winSize.height));
1366793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            mtx->unlock();
1367793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            if( --positive == 0 )
1368793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                break;
1369793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        }
1370793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( positive == 0 )
1371793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        break;
1372793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1373793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1374793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        else
1375793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif // IPP
1376793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( y = y1; y < y2; y += ystep )
1377793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( x = 0; x < ssz.width; x += ystep )
1378793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1379793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    double gypWeight;
1380793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    int result = cvRunHaarClassifierCascadeSum( cascade, cvPoint(x,y), gypWeight, 0 );
1381793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( rejectLevels )
1382793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1383793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( result == 1 )
1384793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            result = -1*cascade->count;
1385793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( cascade->count + result < 4 )
1386793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        {
1387793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            mtx->lock();
1388793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            vec->push_back(Rect(cvRound(x*factor), cvRound(y*factor),
1389793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           winSize.width, winSize.height));
1390793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            rejectLevels->push_back(-result);
1391793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            levelWeights->push_back(gypWeight);
1392793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            mtx->unlock();
1393793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        }
1394793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1395793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    else
1396793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1397793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( result > 0 )
1398793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        {
1399793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            mtx->lock();
1400793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            vec->push_back(Rect(cvRound(x*factor), cvRound(y*factor),
1401793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                           winSize.width, winSize.height));
1402793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            mtx->unlock();
1403793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        }
1404793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1405793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1406793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1407793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1408793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const CvHaarClassifierCascade* cascade;
1409793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int stripSize;
1410793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    double factor;
1411793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Mat sum1, sqsum1, *norm1, *mask1;
1412793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Rect equRect;
1413793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<Rect>* vec;
1414793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<int>* rejectLevels;
1415793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<double>* levelWeights;
1416793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Mutex* mtx;
1417793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler};
1418793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1419793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1420793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerclass HaarDetectObjects_ScaleCascade_Invoker : public ParallelLoopBody
1421793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
1422793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerpublic:
1423793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    HaarDetectObjects_ScaleCascade_Invoker( const CvHaarClassifierCascade* _cascade,
1424793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                            Size _winsize, const Range& _xrange, double _ystep,
1425793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                            size_t _sumstep, const int** _p, const int** _pq,
1426793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                            std::vector<Rect>& _vec, Mutex* _mtx )
1427793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1428793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade = _cascade;
1429793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        winsize = _winsize;
1430793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        xrange = _xrange;
1431793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ystep = _ystep;
1432793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sumstep = _sumstep;
1433793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        p = _p; pq = _pq;
1434793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        vec = &_vec;
1435793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        mtx = _mtx;
1436793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1437793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1438793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    void operator()( const Range& range ) const
1439793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1440793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int iy, startY = range.start, endY = range.end;
1441793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        const int *p0 = p[0], *p1 = p[1], *p2 = p[2], *p3 = p[3];
1442793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        const int *pq0 = pq[0], *pq1 = pq[1], *pq2 = pq[2], *pq3 = pq[3];
1443793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        bool doCannyPruning = p0 != 0;
1444793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int sstep = (int)(sumstep/sizeof(p0[0]));
1445793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1446793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( iy = startY; iy < endY; iy++ )
1447793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1448793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int ix, y = cvRound(iy*ystep), ixstep = 1;
1449793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( ix = xrange.start; ix < xrange.end; ix += ixstep )
1450793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1451793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int x = cvRound(ix*ystep); // it should really be ystep, not ixstep
1452793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1453793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( doCannyPruning )
1454793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1455793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    int offset = y*sstep + x;
1456793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    int s = p0[offset] - p1[offset] - p2[offset] + p3[offset];
1457793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    int sq = pq0[offset] - pq1[offset] - pq2[offset] + pq3[offset];
1458793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( s < 100 || sq < 20 )
1459793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1460793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        ixstep = 2;
1461793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        continue;
1462793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1463793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1464793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1465793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                int result = cvRunHaarClassifierCascade( cascade, cvPoint(x, y), 0 );
1466793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( result > 0 )
1467793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1468793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    mtx->lock();
1469793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    vec->push_back(Rect(x, y, winsize.width, winsize.height));
1470793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    mtx->unlock();
1471793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1472793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                ixstep = result != 0 ? 1 : 2;
1473793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1474793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1475793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1476793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1477793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const CvHaarClassifierCascade* cascade;
1478793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    double ystep;
1479793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    size_t sumstep;
1480793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Size winsize;
1481793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Range xrange;
1482793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const int** p;
1483793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const int** pq;
1484793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<Rect>* vec;
1485793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Mutex* mtx;
1486793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler};
1487793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1488793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1489793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
1490793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1491793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1492793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCvSeq*
1493793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslercvHaarDetectObjectsForROC( const CvArr* _img,
1494793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                     CvHaarClassifierCascade* cascade, CvMemStorage* storage,
1495793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                     std::vector<int>& rejectLevels, std::vector<double>& levelWeights,
1496793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                     double scaleFactor, int minNeighbors, int flags,
1497793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                     CvSize minSize, CvSize maxSize, bool outputRejectLevels )
1498793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
1499793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const double GROUP_EPS = 0.2;
1500793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvMat stub, *img = (CvMat*)_img;
1501793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::Ptr<CvMat> temp, sum, tilted, sqsum, normImg, sumcanny, imgSmall;
1502793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvSeq* result_seq = 0;
1503793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::Ptr<CvMemStorage> temp_storage;
1504793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1505793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<cv::Rect> allCandidates;
1506793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<cv::Rect> rectList;
1507793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<int> rweights;
1508793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    double factor;
1509793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int coi;
1510793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool doCannyPruning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0;
1511793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool findBiggestObject = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0;
1512793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool roughSearch = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0;
1513793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cv::Mutex mtx;
1514793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1515793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !CV_IS_HAAR_CLASSIFIER(cascade) )
1516793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" );
1517793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1518793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !storage )
1519793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsNullPtr, "Null storage pointer" );
1520793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1521793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    img = cvGetMat( img, &stub, &coi );
1522793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( coi )
1523793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_BadCOI, "COI is not supported" );
1524793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1525793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( CV_MAT_DEPTH(img->type) != CV_8U )
1526793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsUnsupportedFormat, "Only 8-bit images are supported" );
1527793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1528793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( scaleFactor <= 1 )
1529793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsOutOfRange, "scale factor must be > 1" );
1530793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1531793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( findBiggestObject )
1532793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        flags &= ~CV_HAAR_SCALE_IMAGE;
1533793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1534793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( maxSize.height == 0 || maxSize.width == 0 )
1535793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1536793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        maxSize.height = img->rows;
1537793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        maxSize.width = img->cols;
1538793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1539793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1540793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    temp.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
1541793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    sum.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ));
1542793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    sqsum.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 ));
1543793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1544793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !cascade->hid_cascade )
1545793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        icvCreateHidHaarClassifierCascade(cascade);
1546793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1547793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( cascade->hid_cascade->has_tilted_features )
1548793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        tilted.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ));
1549793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1550793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage );
1551793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1552793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( CV_MAT_CN(img->type) > 1 )
1553793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1554793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvCvtColor( img, temp, CV_BGR2GRAY );
1555793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        img = temp;
1556793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1557793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1558793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( findBiggestObject )
1559793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);
1560793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1561793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( flags & CV_HAAR_SCALE_IMAGE )
1562793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1563793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvSize winSize0 = cascade->orig_window_size;
1564793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef HAVE_IPP
1565793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int use_ipp = CV_IPP_CHECK_COND && (cascade->hid_cascade->ipp_stages != 0);
1566793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1567793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( use_ipp )
1568793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            normImg.reset(cvCreateMat( img->rows, img->cols, CV_32FC1));
1569793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
1570793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        imgSmall.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 ));
1571793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1572793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( factor = 1; ; factor *= scaleFactor )
1573793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1574793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvSize winSize(cvRound(winSize0.width*factor),
1575793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                cvRound(winSize0.height*factor));
1576793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvSize sz(cvRound( img->cols/factor ), cvRound( img->rows/factor ));
1577793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvSize sz1(sz.width - winSize0.width + 1, sz.height - winSize0.height + 1);
1578793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1579793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvRect equRect(icv_object_win_border, icv_object_win_border,
1580793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                winSize0.width - icv_object_win_border*2,
1581793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                winSize0.height - icv_object_win_border*2);
1582793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1583793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;
1584793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvMat* _tilted = 0;
1585793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1586793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( sz1.width <= 0 || sz1.height <= 0 )
1587793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                break;
1588793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( winSize.width > maxSize.width || winSize.height > maxSize.height )
1589793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                break;
1590793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( winSize.width < minSize.width || winSize.height < minSize.height )
1591793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                continue;
1592793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1593793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            img1 = cvMat( sz.height, sz.width, CV_8UC1, imgSmall->data.ptr );
1594793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );
1595793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );
1596793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( tilted )
1597793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1598793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );
1599793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                _tilted = &tilted1;
1600793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1601793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, normImg ? normImg->data.ptr : 0 );
1602793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );
1603793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1604793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvResize( img, &img1, CV_INTER_LINEAR );
1605793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvIntegral( &img1, &sum1, &sqsum1, _tilted );
1606793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1607793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int ystep = factor > 2 ? 1 : 2;
1608793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            const int LOCS_PER_THREAD = 1000;
1609793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int stripCount = ((sz1.width/ystep)*(sz1.height + ystep-1)/ystep + LOCS_PER_THREAD/2)/LOCS_PER_THREAD;
1610793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            stripCount = std::min(std::max(stripCount, 1), 100);
1611793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1612793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifdef HAVE_IPP
1613793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( use_ipp )
1614793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1615793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cv::Mat fsum(sum1.rows, sum1.cols, CV_32F, sum1.data.ptr, sum1.step);
1616793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cv::cvarrToMat(&sum1).convertTo(fsum, CV_32F, 1, -(1<<24));
1617793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1618793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            else
1619793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
1620793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, _tilted, 1. );
1621793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1622793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cv::Mat _norm1 = cv::cvarrToMat(&norm1), _mask1 = cv::cvarrToMat(&mask1);
1623793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cv::parallel_for_(cv::Range(0, stripCount),
1624793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                         cv::HaarDetectObjects_ScaleImage_Invoker(cascade,
1625793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                (((sz1.height + stripCount - 1)/stripCount + ystep-1)/ystep)*ystep,
1626793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                factor, cv::cvarrToMat(&sum1), cv::cvarrToMat(&sqsum1), &_norm1, &_mask1,
1627793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                cv::Rect(equRect), allCandidates, rejectLevels, levelWeights, outputRejectLevels, &mtx));
1628793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1629793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1630793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    else
1631793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1632793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int n_factors = 0;
1633793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cv::Rect scanROI;
1634793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1635793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvIntegral( img, sum, sqsum, tilted );
1636793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1637793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( doCannyPruning )
1638793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1639793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sumcanny.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ));
1640793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvCanny( img, temp, 0, 50, 3 );
1641793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvIntegral( temp, sumcanny );
1642793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1643793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1644793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( n_factors = 0, factor = 1;
1645793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler             factor*cascade->orig_window_size.width < img->cols - 10 &&
1646793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler             factor*cascade->orig_window_size.height < img->rows - 10;
1647793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler             n_factors++, factor *= scaleFactor )
1648793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            ;
1649793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1650793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( findBiggestObject )
1651793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1652793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            scaleFactor = 1./scaleFactor;
1653793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            factor *= scaleFactor;
1654793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1655793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        else
1656793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            factor = 1;
1657793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1658793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( ; n_factors-- > 0; factor *= scaleFactor )
1659793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1660793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            const double ystep = std::max( 2., factor );
1661793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvSize winSize(cvRound( cascade->orig_window_size.width * factor ),
1662793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                cvRound( cascade->orig_window_size.height * factor ));
1663793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvRect equRect;
1664793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int *p[4] = {0,0,0,0};
1665793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int *pq[4] = {0,0,0,0};
1666793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int startX = 0, startY = 0;
1667793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int endX = cvRound((img->cols - winSize.width) / ystep);
1668793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int endY = cvRound((img->rows - winSize.height) / ystep);
1669793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1670793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( winSize.width < minSize.width || winSize.height < minSize.height )
1671793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1672793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( findBiggestObject )
1673793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    break;
1674793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                continue;
1675793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1676793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1677793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if ( winSize.width > maxSize.width || winSize.height > maxSize.height )
1678793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1679793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( !findBiggestObject )
1680793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    break;
1681793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                continue;
1682793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1683793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1684793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );
1685793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvZero( temp );
1686793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1687793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( doCannyPruning )
1688793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1689793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                equRect.x = cvRound(winSize.width*0.15);
1690793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                equRect.y = cvRound(winSize.height*0.15);
1691793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                equRect.width = cvRound(winSize.width*0.7);
1692793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                equRect.height = cvRound(winSize.height*0.7);
1693793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1694793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                p[0] = (int*)(sumcanny->data.ptr + equRect.y*sumcanny->step) + equRect.x;
1695793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                p[1] = (int*)(sumcanny->data.ptr + equRect.y*sumcanny->step)
1696793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            + equRect.x + equRect.width;
1697793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                p[2] = (int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step) + equRect.x;
1698793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                p[3] = (int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step)
1699793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            + equRect.x + equRect.width;
1700793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1701793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                pq[0] = (int*)(sum->data.ptr + equRect.y*sum->step) + equRect.x;
1702793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                pq[1] = (int*)(sum->data.ptr + equRect.y*sum->step)
1703793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            + equRect.x + equRect.width;
1704793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                pq[2] = (int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step) + equRect.x;
1705793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                pq[3] = (int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step)
1706793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            + equRect.x + equRect.width;
1707793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1708793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1709793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( scanROI.area() > 0 )
1710793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1711793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                //adjust start_height and stop_height
1712793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                startY = cvRound(scanROI.y / ystep);
1713793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                endY = cvRound((scanROI.y + scanROI.height - winSize.height) / ystep);
1714793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1715793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                startX = cvRound(scanROI.x / ystep);
1716793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                endX = cvRound((scanROI.x + scanROI.width - winSize.width) / ystep);
1717793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1718793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1719793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cv::parallel_for_(cv::Range(startY, endY),
1720793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cv::HaarDetectObjects_ScaleCascade_Invoker(cascade, winSize, cv::Range(startX, endX),
1721793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           ystep, sum->step, (const int**)p,
1722793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                                           (const int**)pq, allCandidates, &mtx ));
1723793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1724793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( findBiggestObject && !allCandidates.empty() && scanROI.area() == 0 )
1725793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1726793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                rectList.resize(allCandidates.size());
1727793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin());
1728793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1729793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                groupRectangles(rectList, std::max(minNeighbors, 1), GROUP_EPS);
1730793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1731793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( !rectList.empty() )
1732793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1733793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    size_t i, sz = rectList.size();
1734793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cv::Rect maxRect;
1735793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1736793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    for( i = 0; i < sz; i++ )
1737793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
1738793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        if( rectList[i].area() > maxRect.area() )
1739793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            maxRect = rectList[i];
1740793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
1741793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1742793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    allCandidates.push_back(maxRect);
1743793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1744793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    scanROI = maxRect;
1745793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    int dx = cvRound(maxRect.width*GROUP_EPS);
1746793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    int dy = cvRound(maxRect.height*GROUP_EPS);
1747793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    scanROI.x = std::max(scanROI.x - dx, 0);
1748793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    scanROI.y = std::max(scanROI.y - dy, 0);
1749793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    scanROI.width = std::min(scanROI.width + dx*2, img->cols-1-scanROI.x);
1750793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    scanROI.height = std::min(scanROI.height + dy*2, img->rows-1-scanROI.y);
1751793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1752793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    double minScale = roughSearch ? 0.6 : 0.4;
1753793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    minSize.width = cvRound(maxRect.width*minScale);
1754793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    minSize.height = cvRound(maxRect.height*minScale);
1755793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1756793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1757793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1758793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1759793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1760793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    rectList.resize(allCandidates.size());
1761793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if(!allCandidates.empty())
1762793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin());
1763793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1764793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( minNeighbors != 0 || findBiggestObject )
1765793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1766793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( outputRejectLevels )
1767793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1768793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            groupRectangles(rectList, rejectLevels, levelWeights, minNeighbors, GROUP_EPS );
1769793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1770793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        else
1771793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1772793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            groupRectangles(rectList, rweights, std::max(minNeighbors, 1), GROUP_EPS);
1773793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1774793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1775793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    else
1776793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        rweights.resize(rectList.size(),0);
1777793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1778793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( findBiggestObject && rectList.size() )
1779793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1780793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvAvgComp result_comp = {CvRect(),0};
1781793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1782793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( size_t i = 0; i < rectList.size(); i++ )
1783793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1784793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cv::Rect r = rectList[i];
1785793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( r.area() > cv::Rect(result_comp.rect).area() )
1786793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1787793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                result_comp.rect = r;
1788793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                result_comp.neighbors = rweights[i];
1789793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1790793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1791793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvSeqPush( result_seq, &result_comp );
1792793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1793793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    else
1794793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1795793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( size_t i = 0; i < rectList.size(); i++ )
1796793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1797793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvAvgComp c;
1798793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            c.rect = rectList[i];
1799793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            c.neighbors = !rweights.empty() ? rweights[i] : 0;
1800793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvSeqPush( result_seq, &c );
1801793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1802793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1803793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1804793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return result_seq;
1805793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
1806793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1807793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCV_IMPL CvSeq*
1808793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslercvHaarDetectObjects( const CvArr* _img,
1809793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                     CvHaarClassifierCascade* cascade, CvMemStorage* storage,
1810793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                     double scaleFactor,
1811793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                     int minNeighbors, int flags, CvSize minSize, CvSize maxSize )
1812793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
1813793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<int> fakeLevels;
1814793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    std::vector<double> fakeWeights;
1815793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return cvHaarDetectObjectsForROC( _img, cascade, storage, fakeLevels, fakeWeights,
1816793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                scaleFactor, minNeighbors, flags, minSize, maxSize, false );
1817793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1818793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
1819793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1820793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1821793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic CvHaarClassifierCascade*
1822793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslericvLoadCascadeCART( const char** input_cascade, int n, CvSize orig_window_size )
1823793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
1824793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int i;
1825793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHaarClassifierCascade* cascade = icvCreateHaarClassifierCascade(n);
1826793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->orig_window_size = orig_window_size;
1827793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1828793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( i = 0; i < n; i++ )
1829793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1830793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int j, count, l;
1831793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        float threshold = 0;
1832793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        const char* stage = input_cascade[i];
1833793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int dl = 0;
1834793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1835793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        /* tree links */
1836793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int parent = -1;
1837793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int next = -1;
1838793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1839793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sscanf( stage, "%d%n", &count, &dl );
1840793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stage += dl;
1841793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1842793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        assert( count > 0 );
1843793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].count = count;
1844793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].classifier =
1845793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            (CvHaarClassifier*)cvAlloc( count*sizeof(cascade->stage_classifier[i].classifier[0]));
1846793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1847793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < count; j++ )
1848793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1849793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
1850793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int k, rects = 0;
1851793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            char str[100];
1852793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1853793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sscanf( stage, "%d%n", &classifier->count, &dl );
1854793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            stage += dl;
1855793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1856793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->haar_feature = (CvHaarFeature*) cvAlloc(
1857793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->count * ( sizeof( *classifier->haar_feature ) +
1858793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->threshold ) +
1859793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->left ) +
1860793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->right ) ) +
1861793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                (classifier->count + 1) * sizeof( *classifier->alpha ) );
1862793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
1863793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->left = (int*) (classifier->threshold + classifier->count);
1864793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->right = (int*) (classifier->left + classifier->count);
1865793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->alpha = (float*) (classifier->right + classifier->count);
1866793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1867793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( l = 0; l < classifier->count; l++ )
1868793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1869793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                sscanf( stage, "%d%n", &rects, &dl );
1870793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                stage += dl;
1871793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1872793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                assert( rects >= 2 && rects <= CV_HAAR_FEATURE_MAX );
1873793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1874793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( k = 0; k < rects; k++ )
1875793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1876793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CvRect r;
1877793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    int band = 0;
1878793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    sscanf( stage, "%d%d%d%d%d%f%n",
1879793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            &r.x, &r.y, &r.width, &r.height, &band,
1880793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            &(classifier->haar_feature[l].rect[k].weight), &dl );
1881793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    stage += dl;
1882793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->haar_feature[l].rect[k].r = r;
1883793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1884793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                sscanf( stage, "%s%n", str, &dl );
1885793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                stage += dl;
1886793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1887793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->haar_feature[l].tilted = strncmp( str, "tilted", 6 ) == 0;
1888793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1889793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( k = rects; k < CV_HAAR_FEATURE_MAX; k++ )
1890793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
1891793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    memset( classifier->haar_feature[l].rect + k, 0,
1892793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                            sizeof(classifier->haar_feature[l].rect[k]) );
1893793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
1894793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1895793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                sscanf( stage, "%f%d%d%n", &(classifier->threshold[l]),
1896793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                       &(classifier->left[l]),
1897793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                       &(classifier->right[l]), &dl );
1898793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                stage += dl;
1899793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1900793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( l = 0; l <= classifier->count; l++ )
1901793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
1902793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                sscanf( stage, "%f%n", &(classifier->alpha[l]), &dl );
1903793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                stage += dl;
1904793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
1905793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1906793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1907793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sscanf( stage, "%f%n", &threshold, &dl );
1908793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stage += dl;
1909793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1910793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].threshold = threshold;
1911793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1912793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        /* load tree links */
1913793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( sscanf( stage, "%d%d%n", &parent, &next, &dl ) != 2 )
1914793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1915793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            parent = i - 1;
1916793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            next = -1;
1917793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1918793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stage += dl;
1919793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1920793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].parent = parent;
1921793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].next = next;
1922793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].child = -1;
1923793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1924793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( parent != -1 && cascade->stage_classifier[parent].child == -1 )
1925793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
1926793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cascade->stage_classifier[parent].child = i;
1927793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
1928793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1929793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1930793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return cascade;
1931793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
1932793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1933793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifndef _MAX_PATH
1934793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define _MAX_PATH 1024
1935793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif
1936793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1937793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCV_IMPL CvHaarClassifierCascade*
1938793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslercvLoadHaarClassifierCascade( const char* directory, CvSize orig_window_size )
1939793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
1940793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !directory )
1941793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsNullPtr, "Null path is passed" );
1942793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1943793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    char name[_MAX_PATH];
1944793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1945793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int n = (int)strlen(directory)-1;
1946793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const char* slash = directory[n] == '\\' || directory[n] == '/' ? "" : "/";
1947793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int size = 0;
1948793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1949793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    /* try to read the classifier from directory */
1950793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( n = 0; ; n++ )
1951793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1952793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sprintf( name, "%s%s%d/AdaBoostCARTHaarClassifier.txt", directory, slash, n );
1953793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        FILE* f = fopen( name, "rb" );
1954793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !f )
1955793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            break;
1956793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        fseek( f, 0, SEEK_END );
1957793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        size += ftell( f ) + 1;
1958793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        fclose(f);
1959793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1960793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1961793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( n == 0 && slash[0] )
1962793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return (CvHaarClassifierCascade*)cvLoad( directory );
1963793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1964793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( n == 0 )
1965793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsBadArg, "Invalid path" );
1966793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1967793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    size += (n+1)*sizeof(char*);
1968793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const char** input_cascade = (const char**)cvAlloc( size );
1969793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1970793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !input_cascade )
1971793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler      CV_Error( CV_StsNoMem, "Could not allocate memory for input_cascade" );
1972793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1973793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    char* ptr = (char*)(input_cascade + n + 1);
1974793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1975793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( int i = 0; i < n; i++ )
1976793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
1977793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sprintf( name, "%s/%d/AdaBoostCARTHaarClassifier.txt", directory, i );
1978793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        FILE* f = fopen( name, "rb" );
1979793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !f )
1980793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsError, "" );
1981793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        fseek( f, 0, SEEK_END );
1982793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        size = (int)ftell( f );
1983793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        fseek( f, 0, SEEK_SET );
1984793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        size_t elements_read = fread( ptr, 1, size, f );
1985793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Assert(elements_read == (size_t)(size));
1986793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        fclose(f);
1987793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        input_cascade[i] = ptr;
1988793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ptr += size;
1989793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        *ptr++ = '\0';
1990793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
1991793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1992793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    input_cascade[n] = 0;
1993793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1994793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHaarClassifierCascade* cascade = icvLoadCascadeCART( input_cascade, n, orig_window_size );
1995793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1996793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( input_cascade )
1997793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvFree( &input_cascade );
1998793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
1999793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return cascade;
2000793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
2001793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2002793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2003793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCV_IMPL void
2004793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslercvReleaseHaarClassifierCascade( CvHaarClassifierCascade** _cascade )
2005793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
2006793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( _cascade && *_cascade )
2007793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
2008793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        int i, j;
2009793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvHaarClassifierCascade* cascade = *_cascade;
2010793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2011793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( i = 0; i < cascade->count; i++ )
2012793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2013793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( j = 0; j < cascade->stage_classifier[i].count; j++ )
2014793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvFree( &cascade->stage_classifier[i].classifier[j].haar_feature );
2015793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvFree( &cascade->stage_classifier[i].classifier );
2016793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2017793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        icvReleaseHidHaarClassifierCascade( &cascade->hid_cascade );
2018793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvFree( _cascade );
2019793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
2020793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
2021793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2022793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2023793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/****************************************************************************************\
2024793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler*                                  Persistence functions                                 *
2025793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler\****************************************************************************************/
2026793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2027793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/* field names */
2028793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2029793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_SIZE_NAME            "size"
2030793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_STAGES_NAME          "stages"
2031793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_TREES_NAME           "trees"
2032793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_FEATURE_NAME         "feature"
2033793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_RECTS_NAME           "rects"
2034793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_TILTED_NAME          "tilted"
2035793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_THRESHOLD_NAME       "threshold"
2036793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_LEFT_NODE_NAME       "left_node"
2037793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_LEFT_VAL_NAME        "left_val"
2038793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_RIGHT_NODE_NAME      "right_node"
2039793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_RIGHT_VAL_NAME       "right_val"
2040793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_STAGE_THRESHOLD_NAME "stage_threshold"
2041793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_PARENT_NAME          "parent"
2042793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#define ICV_HAAR_NEXT_NAME            "next"
2043793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2044793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int
2045793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslericvIsHaarClassifier( const void* struct_ptr )
2046793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
2047793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return CV_IS_HAAR_CLASSIFIER( struct_ptr );
2048793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
2049793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2050793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void*
2051793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslericvReadHaarClassifier( CvFileStorage* fs, CvFileNode* node )
2052793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
2053793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHaarClassifierCascade* cascade = NULL;
2054793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2055793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    char buf[256];
2056793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvFileNode* seq_fn = NULL; /* sequence */
2057793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvFileNode* fn = NULL;
2058793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvFileNode* stages_fn = NULL;
2059793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvSeqReader stages_reader;
2060793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int n;
2061793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int i, j, k, l;
2062793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int parent, next;
2063793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2064793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    stages_fn = cvGetFileNodeByName( fs, node, ICV_HAAR_STAGES_NAME );
2065793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !stages_fn || !CV_NODE_IS_SEQ( stages_fn->tag) )
2066793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsError, "Invalid stages node" );
2067793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2068793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    n = stages_fn->data.seq->total;
2069793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade = icvCreateHaarClassifierCascade(n);
2070793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2071793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    /* read size */
2072793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    seq_fn = cvGetFileNodeByName( fs, node, ICV_HAAR_SIZE_NAME );
2073793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !seq_fn || !CV_NODE_IS_SEQ( seq_fn->tag ) || seq_fn->data.seq->total != 2 )
2074793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsError, "size node is not a valid sequence." );
2075793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    fn = (CvFileNode*) cvGetSeqElem( seq_fn->data.seq, 0 );
2076793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 )
2077793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsError, "Invalid size node: width must be positive integer" );
2078793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->orig_window_size.width = fn->data.i;
2079793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    fn = (CvFileNode*) cvGetSeqElem( seq_fn->data.seq, 1 );
2080793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 )
2081793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_Error( CV_StsError, "Invalid size node: height must be positive integer" );
2082793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->orig_window_size.height = fn->data.i;
2083793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2084793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvStartReadSeq( stages_fn->data.seq, &stages_reader );
2085793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( i = 0; i < n; ++i )
2086793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
2087793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvFileNode* stage_fn;
2088793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvFileNode* trees_fn;
2089793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CvSeqReader trees_reader;
2090793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2091793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        stage_fn = (CvFileNode*) stages_reader.ptr;
2092793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !CV_NODE_IS_MAP( stage_fn->tag ) )
2093793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2094793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sprintf( buf, "Invalid stage %d", i );
2095793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsError, buf );
2096793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2097793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2098793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        trees_fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_TREES_NAME );
2099793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !trees_fn || !CV_NODE_IS_SEQ( trees_fn->tag )
2100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            || trees_fn->data.seq->total <= 0 )
2101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sprintf( buf, "Trees node is not a valid sequence. (stage %d)", i );
2103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsError, buf );
2104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].classifier =
2107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            (CvHaarClassifier*) cvAlloc( trees_fn->data.seq->total
2108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                * sizeof( cascade->stage_classifier[i].classifier[0] ) );
2109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < trees_fn->data.seq->total; ++j )
2110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cascade->stage_classifier[i].classifier[j].haar_feature = NULL;
2112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].count = trees_fn->data.seq->total;
2114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvStartReadSeq( trees_fn->data.seq, &trees_reader );
2116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < trees_fn->data.seq->total; ++j )
2117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvFileNode* tree_fn;
2119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvSeqReader tree_reader;
2120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHaarClassifier* classifier;
2121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            int last_idx;
2122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier = &cascade->stage_classifier[i].classifier[j];
2124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tree_fn = (CvFileNode*) trees_reader.ptr;
2125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( !CV_NODE_IS_SEQ( tree_fn->tag ) || tree_fn->data.seq->total <= 0 )
2126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
2127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                sprintf( buf, "Tree node is not a valid sequence."
2128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                         " (stage %d, tree %d)", i, j );
2129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CV_Error( CV_StsError, buf );
2130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
2131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->count = tree_fn->data.seq->total;
2133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->haar_feature = (CvHaarFeature*) cvAlloc(
2134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->count * ( sizeof( *classifier->haar_feature ) +
2135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->threshold ) +
2136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->left ) +
2137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->right ) ) +
2138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                (classifier->count + 1) * sizeof( *classifier->alpha ) );
2139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
2140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->left = (int*) (classifier->threshold + classifier->count);
2141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->right = (int*) (classifier->left + classifier->count);
2142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->alpha = (float*) (classifier->right + classifier->count);
2143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvStartReadSeq( tree_fn->data.seq, &tree_reader );
2145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( k = 0, last_idx = 0; k < tree_fn->data.seq->total; ++k )
2146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
2147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvFileNode* node_fn;
2148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvFileNode* feature_fn;
2149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvFileNode* rects_fn;
2150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvSeqReader rects_reader;
2151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                node_fn = (CvFileNode*) tree_reader.ptr;
2153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( !CV_NODE_IS_MAP( node_fn->tag ) )
2154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    sprintf( buf, "Tree node %d is not a valid map. (stage %d, tree %d)",
2156793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                             k, i, j );
2157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CV_Error( CV_StsError, buf );
2158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                feature_fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_FEATURE_NAME );
2160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( !feature_fn || !CV_NODE_IS_MAP( feature_fn->tag ) )
2161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    sprintf( buf, "Feature node is not a valid map. "
2163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                             "(stage %d, tree %d, node %d)", i, j, k );
2164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CV_Error( CV_StsError, buf );
2165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                rects_fn = cvGetFileNodeByName( fs, feature_fn, ICV_HAAR_RECTS_NAME );
2167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( !rects_fn || !CV_NODE_IS_SEQ( rects_fn->tag )
2168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    || rects_fn->data.seq->total < 1
2169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    || rects_fn->data.seq->total > CV_HAAR_FEATURE_MAX )
2170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    sprintf( buf, "Rects node is not a valid sequence. "
2172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                             "(stage %d, tree %d, node %d)", i, j, k );
2173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CV_Error( CV_StsError, buf );
2174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvStartReadSeq( rects_fn->data.seq, &rects_reader );
2176793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( l = 0; l < rects_fn->data.seq->total; ++l )
2177793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2178793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CvFileNode* rect_fn;
2179793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CvRect r;
2180793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2181793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    rect_fn = (CvFileNode*) rects_reader.ptr;
2182793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_SEQ( rect_fn->tag ) || rect_fn->data.seq->total != 5 )
2183793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2184793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "Rect %d is not a valid sequence. "
2185793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", l, i, j, k );
2186793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2187793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2188793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2189793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 0 );
2190793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i < 0 )
2191793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2192793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "x coordinate must be non-negative integer. "
2193793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
2194793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2195793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2196793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    r.x = fn->data.i;
2197793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 1 );
2198793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i < 0 )
2199793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2200793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "y coordinate must be non-negative integer. "
2201793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
2202793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2203793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2204793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    r.y = fn->data.i;
2205793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 2 );
2206793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0
2207793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        || r.x + fn->data.i > cascade->orig_window_size.width )
2208793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2209793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "width must be positive integer and "
2210793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(x + width) must not exceed window width. "
2211793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
2212793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2213793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2214793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    r.width = fn->data.i;
2215793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 3 );
2216793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0
2217793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        || r.y + fn->data.i > cascade->orig_window_size.height )
2218793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2219793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "height must be positive integer and "
2220793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(y + height) must not exceed window height. "
2221793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
2222793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2223793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2224793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    r.height = fn->data.i;
2225793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 4 );
2226793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_REAL( fn->tag ) )
2227793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2228793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "weight must be real number. "
2229793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
2230793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2231793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2232793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2233793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->haar_feature[k].rect[l].weight = (float) fn->data.f;
2234793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->haar_feature[k].rect[l].r = r;
2235793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2236793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CV_NEXT_SEQ_ELEM( sizeof( *rect_fn ), rects_reader );
2237793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                } /* for each rect */
2238793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( l = rects_fn->data.seq->total; l < CV_HAAR_FEATURE_MAX; ++l )
2239793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2240793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->haar_feature[k].rect[l].weight = 0;
2241793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->haar_feature[k].rect[l].r = cvRect( 0, 0, 0, 0 );
2242793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2243793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2244793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                fn = cvGetFileNodeByName( fs, feature_fn, ICV_HAAR_TILTED_NAME);
2245793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( !fn || !CV_NODE_IS_INT( fn->tag ) )
2246793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2247793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    sprintf( buf, "tilted must be 0 or 1. "
2248793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                             "(stage %d, tree %d, node %d)", i, j, k );
2249793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CV_Error( CV_StsError, buf );
2250793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2251793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->haar_feature[k].tilted = ( fn->data.i != 0 );
2252793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_THRESHOLD_NAME);
2253793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( !fn || !CV_NODE_IS_REAL( fn->tag ) )
2254793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2255793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    sprintf( buf, "threshold must be real number. "
2256793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                             "(stage %d, tree %d, node %d)", i, j, k );
2257793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CV_Error( CV_StsError, buf );
2258793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2259793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->threshold[k] = (float) fn->data.f;
2260793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_LEFT_NODE_NAME);
2261793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( fn )
2262793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2263793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= k
2264793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        || fn->data.i >= tree_fn->data.seq->total )
2265793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2266793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "left node must be valid node number. "
2267793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", i, j, k );
2268793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2269793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2270793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    /* left node */
2271793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->left[k] = fn->data.i;
2272793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2273793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
2274793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2275793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_LEFT_VAL_NAME );
2276793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !fn )
2277793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2278793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "left node or left value must be specified. "
2279793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", i, j, k );
2280793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2281793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2282793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_REAL( fn->tag ) )
2283793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2284793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "left value must be real number. "
2285793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", i, j, k );
2286793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2287793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2288793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    /* left value */
2289793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( last_idx >= classifier->count + 1 )
2290793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2291793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "Tree structure is broken: too many values. "
2292793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", i, j, k );
2293793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2294793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2295793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->left[k] = -last_idx;
2296793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->alpha[last_idx++] = (float) fn->data.f;
2297793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2298793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                fn = cvGetFileNodeByName( fs, node_fn,ICV_HAAR_RIGHT_NODE_NAME);
2299793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( fn )
2300793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2301793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= k
2302793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        || fn->data.i >= tree_fn->data.seq->total )
2303793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2304793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "right node must be valid node number. "
2305793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", i, j, k );
2306793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2307793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2308793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    /* right node */
2309793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->right[k] = fn->data.i;
2310793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2311793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
2312793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2313793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_RIGHT_VAL_NAME );
2314793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !fn )
2315793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2316793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "right node or right value must be specified. "
2317793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", i, j, k );
2318793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2319793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2320793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( !CV_NODE_IS_REAL( fn->tag ) )
2321793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2322793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "right value must be real number. "
2323793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", i, j, k );
2324793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2325793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2326793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    /* right value */
2327793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( last_idx >= classifier->count + 1 )
2328793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
2329793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        sprintf( buf, "Tree structure is broken: too many values. "
2330793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 "(stage %d, tree %d, node %d)", i, j, k );
2331793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CV_Error( CV_StsError, buf );
2332793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
2333793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->right[k] = -last_idx;
2334793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    classifier->alpha[last_idx++] = (float) fn->data.f;
2335793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2336793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2337793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CV_NEXT_SEQ_ELEM( sizeof( *node_fn ), tree_reader );
2338793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            } /* for each node */
2339793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if( last_idx != classifier->count + 1 )
2340793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
2341793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                sprintf( buf, "Tree structure is broken: too few values. "
2342793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                         "(stage %d, tree %d)", i, j );
2343793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CV_Error( CV_StsError, buf );
2344793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
2345793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2346793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_NEXT_SEQ_ELEM( sizeof( *tree_fn ), trees_reader );
2347793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        } /* for each tree */
2348793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2349793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_STAGE_THRESHOLD_NAME);
2350793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !fn || !CV_NODE_IS_REAL( fn->tag ) )
2351793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2352793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sprintf( buf, "stage threshold must be real number. (stage %d)", i );
2353793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsError, buf );
2354793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2355793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].threshold = (float) fn->data.f;
2356793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2357793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        parent = i - 1;
2358793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        next = -1;
2359793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2360793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_PARENT_NAME );
2361793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !fn || !CV_NODE_IS_INT( fn->tag )
2362793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            || fn->data.i < -1 || fn->data.i >= cascade->count )
2363793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2364793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sprintf( buf, "parent must be integer number. (stage %d)", i );
2365793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsError, buf );
2366793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2367793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        parent = fn->data.i;
2368793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_NEXT_NAME );
2369793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( !fn || !CV_NODE_IS_INT( fn->tag )
2370793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            || fn->data.i < -1 || fn->data.i >= cascade->count )
2371793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2372793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sprintf( buf, "next must be integer number. (stage %d)", i );
2373793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error( CV_StsError, buf );
2374793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2375793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        next = fn->data.i;
2376793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2377793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].parent = parent;
2378793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].next = next;
2379793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].child = -1;
2380793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2381793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( parent != -1 && cascade->stage_classifier[parent].child == -1 )
2382793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2383793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cascade->stage_classifier[parent].child = i;
2384793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2385793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2386793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CV_NEXT_SEQ_ELEM( sizeof( *stage_fn ), stages_reader );
2387793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    } /* for each stage */
2388793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2389793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return cascade;
2390793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
2391793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2392793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void
2393793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslericvWriteHaarClassifier( CvFileStorage* fs, const char* name, const void* struct_ptr,
2394793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        CvAttrList attributes )
2395793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
2396793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int i, j, k, l;
2397793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    char buf[256];
2398793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const CvHaarClassifierCascade* cascade = (const CvHaarClassifierCascade*) struct_ptr;
2399793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2400793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    /* TODO: parameters check */
2401793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2402793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_HAAR, attributes );
2403793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2404793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvStartWriteStruct( fs, ICV_HAAR_SIZE_NAME, CV_NODE_SEQ | CV_NODE_FLOW );
2405793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvWriteInt( fs, NULL, cascade->orig_window_size.width );
2406793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvWriteInt( fs, NULL, cascade->orig_window_size.height );
2407793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvEndWriteStruct( fs ); /* size */
2408793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2409793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvStartWriteStruct( fs, ICV_HAAR_STAGES_NAME, CV_NODE_SEQ );
2410793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( i = 0; i < cascade->count; ++i )
2411793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
2412793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvStartWriteStruct( fs, NULL, CV_NODE_MAP );
2413793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        sprintf( buf, "stage %d", i );
2414793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvWriteComment( fs, buf, 1 );
2415793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2416793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvStartWriteStruct( fs, ICV_HAAR_TREES_NAME, CV_NODE_SEQ );
2417793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2418793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < cascade->stage_classifier[i].count; ++j )
2419793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2420793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHaarClassifier* tree = &cascade->stage_classifier[i].classifier[j];
2421793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2422793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvStartWriteStruct( fs, NULL, CV_NODE_SEQ );
2423793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            sprintf( buf, "tree %d", j );
2424793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvWriteComment( fs, buf, 1 );
2425793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2426793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( k = 0; k < tree->count; ++k )
2427793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
2428793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CvHaarFeature* feature = &tree->haar_feature[k];
2429793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2430793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvStartWriteStruct( fs, NULL, CV_NODE_MAP );
2431793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( k )
2432793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2433793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    sprintf( buf, "node %d", k );
2434793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2435793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
2436793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2437793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    sprintf( buf, "root node" );
2438793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2439793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvWriteComment( fs, buf, 1 );
2440793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2441793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvStartWriteStruct( fs, ICV_HAAR_FEATURE_NAME, CV_NODE_MAP );
2442793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2443793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvStartWriteStruct( fs, ICV_HAAR_RECTS_NAME, CV_NODE_SEQ );
2444793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                for( l = 0; l < CV_HAAR_FEATURE_MAX && feature->rect[l].r.width != 0; ++l )
2445793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2446793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvStartWriteStruct( fs, NULL, CV_NODE_SEQ | CV_NODE_FLOW );
2447793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteInt(  fs, NULL, feature->rect[l].r.x );
2448793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteInt(  fs, NULL, feature->rect[l].r.y );
2449793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteInt(  fs, NULL, feature->rect[l].r.width );
2450793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteInt(  fs, NULL, feature->rect[l].r.height );
2451793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteReal( fs, NULL, feature->rect[l].weight );
2452793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvEndWriteStruct( fs ); /* rect */
2453793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2454793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvEndWriteStruct( fs ); /* rects */
2455793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvWriteInt( fs, ICV_HAAR_TILTED_NAME, feature->tilted );
2456793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvEndWriteStruct( fs ); /* feature */
2457793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2458793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvWriteReal( fs, ICV_HAAR_THRESHOLD_NAME, tree->threshold[k]);
2459793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2460793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( tree->left[k] > 0 )
2461793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2462793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteInt( fs, ICV_HAAR_LEFT_NODE_NAME, tree->left[k] );
2463793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2464793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
2465793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2466793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteReal( fs, ICV_HAAR_LEFT_VAL_NAME,
2467793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tree->alpha[-tree->left[k]] );
2468793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2469793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2470793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( tree->right[k] > 0 )
2471793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2472793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteInt( fs, ICV_HAAR_RIGHT_NODE_NAME, tree->right[k] );
2473793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2474793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                else
2475793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
2476793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    cvWriteReal( fs, ICV_HAAR_RIGHT_VAL_NAME,
2477793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        tree->alpha[-tree->right[k]] );
2478793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
2479793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2480793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                cvEndWriteStruct( fs ); /* split */
2481793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
2482793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2483793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cvEndWriteStruct( fs ); /* tree */
2484793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2485793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2486793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvEndWriteStruct( fs ); /* trees */
2487793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2488793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvWriteReal( fs, ICV_HAAR_STAGE_THRESHOLD_NAME, cascade->stage_classifier[i].threshold);
2489793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvWriteInt( fs, ICV_HAAR_PARENT_NAME, cascade->stage_classifier[i].parent );
2490793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvWriteInt( fs, ICV_HAAR_NEXT_NAME, cascade->stage_classifier[i].next );
2491793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2492793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvEndWriteStruct( fs ); /* stage */
2493793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    } /* for each stage */
2494793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2495793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvEndWriteStruct( fs ); /* stages */
2496793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cvEndWriteStruct( fs ); /* root */
2497793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
2498793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2499793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void*
2500793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslericvCloneHaarClassifier( const void* struct_ptr )
2501793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
2502793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CvHaarClassifierCascade* cascade = NULL;
2503793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2504793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    int i, j, k, n;
2505793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const CvHaarClassifierCascade* cascade_src =
2506793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        (const CvHaarClassifierCascade*) struct_ptr;
2507793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2508793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    n = cascade_src->count;
2509793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade = icvCreateHaarClassifierCascade(n);
2510793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cascade->orig_window_size = cascade_src->orig_window_size;
2511793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2512793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for( i = 0; i < n; ++i )
2513793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
2514793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].parent = cascade_src->stage_classifier[i].parent;
2515793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].next = cascade_src->stage_classifier[i].next;
2516793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].child = cascade_src->stage_classifier[i].child;
2517793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].threshold = cascade_src->stage_classifier[i].threshold;
2518793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2519793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].count = 0;
2520793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].classifier =
2521793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            (CvHaarClassifier*) cvAlloc( cascade_src->stage_classifier[i].count
2522793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                * sizeof( cascade->stage_classifier[i].classifier[0] ) );
2523793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2524793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cascade->stage_classifier[i].count = cascade_src->stage_classifier[i].count;
2525793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2526793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < cascade->stage_classifier[i].count; ++j )
2527793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cascade->stage_classifier[i].classifier[j].haar_feature = NULL;
2528793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2529793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        for( j = 0; j < cascade->stage_classifier[i].count; ++j )
2530793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
2531793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            const CvHaarClassifier* classifier_src =
2532793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                &cascade_src->stage_classifier[i].classifier[j];
2533793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CvHaarClassifier* classifier =
2534793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                &cascade->stage_classifier[i].classifier[j];
2535793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2536793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->count = classifier_src->count;
2537793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->haar_feature = (CvHaarFeature*) cvAlloc(
2538793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->count * ( sizeof( *classifier->haar_feature ) +
2539793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->threshold ) +
2540793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->left ) +
2541793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                      sizeof( *classifier->right ) ) +
2542793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                (classifier->count + 1) * sizeof( *classifier->alpha ) );
2543793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
2544793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->left = (int*) (classifier->threshold + classifier->count);
2545793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->right = (int*) (classifier->left + classifier->count);
2546793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->alpha = (float*) (classifier->right + classifier->count);
2547793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( k = 0; k < classifier->count; ++k )
2548793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
2549793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->haar_feature[k] = classifier_src->haar_feature[k];
2550793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->threshold[k] = classifier_src->threshold[k];
2551793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->left[k] = classifier_src->left[k];
2552793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->right[k] = classifier_src->right[k];
2553793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier->alpha[k] = classifier_src->alpha[k];
2554793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
2555793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            classifier->alpha[classifier->count] =
2556793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                classifier_src->alpha[classifier->count];
2557793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
2558793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
2559793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2560793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return cascade;
2561793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
2562793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2563793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2564793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerCvType haar_type( CV_TYPE_NAME_HAAR, icvIsHaarClassifier,
2565793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                  (CvReleaseFunc)cvReleaseHaarClassifierCascade,
2566793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                  icvReadHaarClassifier, icvWriteHaarClassifier,
2567793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                  icvCloneHaarClassifier );
2568793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
2569793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/* End of file. */
2570