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