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