Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project-sd-card by
haar.cpp
00001 /*M/////////////////////////////////////////////////////////////////////////////////////// 00002 // 00003 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 00004 // 00005 // By downloading, copying, installing or using the software you agree to this license. 00006 // If you do not agree to this license, do not download, install, 00007 // copy or use the software. 00008 // 00009 // 00010 // Intel License Agreement 00011 // For Open Source Computer Vision Library 00012 // 00013 // Copyright (C) 2000, Intel Corporation, all rights reserved. 00014 // Third party copyrights are property of their respective owners. 00015 // 00016 // Redistribution and use in source and binary forms, with or without modification, 00017 // are permitted provided that the following conditions are met: 00018 // 00019 // * Redistribution's of source code must retain the above copyright notice, 00020 // this list of conditions and the following disclaimer. 00021 // 00022 // * Redistribution's in binary form must reproduce the above copyright notice, 00023 // this list of conditions and the following disclaimer in the documentation 00024 // and/or other materials provided with the distribution. 00025 // 00026 // * The name of Intel Corporation may not be used to endorse or promote products 00027 // derived from this software without specific prior written permission. 00028 // 00029 // This software is provided by the copyright holders and contributors "as is" and 00030 // any express or implied warranties, including, but not limited to, the implied 00031 // warranties of merchantability and fitness for a particular purpose are disclaimed. 00032 // In no event shall the Intel Corporation or contributors be liable for any direct, 00033 // indirect, incidental, special, exemplary, or consequential damages 00034 // (including, but not limited to, procurement of substitute goods or services; 00035 // loss of use, data, or profits; or business interruption) however caused 00036 // and on any theory of liability, whether in contract, strict liability, 00037 // or tort (including negligence or otherwise) arising in any way out of 00038 // the use of this software, even if advised of the possibility of such damage. 00039 // 00040 //M*/ 00041 00042 /* Haar features calculation */ 00043 00044 #include "precomp.hpp" 00045 #include "opencv2/imgproc/imgproc_c.h" 00046 #include "opencv2/objdetect/objdetect_c.h" 00047 #include <stdio.h> 00048 00049 #if CV_SSE2 00050 # if 1 /*!CV_SSE4_1 && !CV_SSE4_2*/ 00051 # define _mm_blendv_pd(a, b, m) _mm_xor_pd(a, _mm_and_pd(_mm_xor_pd(b, a), m)) 00052 # define _mm_blendv_ps(a, b, m) _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(b, a), m)) 00053 # endif 00054 #endif 00055 00056 #if 0 /*CV_AVX*/ 00057 # define CV_HAAR_USE_AVX 1 00058 # if defined _MSC_VER 00059 # pragma warning( disable : 4752 ) 00060 # endif 00061 #else 00062 # if CV_SSE2 00063 # define CV_HAAR_USE_SSE 1 00064 # endif 00065 #endif 00066 00067 /* these settings affect the quality of detection: change with care */ 00068 #define CV_ADJUST_FEATURES 1 00069 #define CV_ADJUST_WEIGHTS 0 00070 00071 typedef int sumtype; 00072 typedef double sqsumtype; 00073 00074 typedef struct CvHidHaarFeature 00075 { 00076 struct 00077 { 00078 sumtype *p0, *p1, *p2, *p3; 00079 float weight; 00080 } 00081 rect[CV_HAAR_FEATURE_MAX]; 00082 } CvHidHaarFeature; 00083 00084 00085 typedef struct CvHidHaarTreeNode 00086 { 00087 CvHidHaarFeature feature; 00088 float threshold; 00089 int left; 00090 int right; 00091 } CvHidHaarTreeNode; 00092 00093 00094 typedef struct CvHidHaarClassifier 00095 { 00096 int count; 00097 //CvHaarFeature* orig_feature; 00098 CvHidHaarTreeNode* node; 00099 float* alpha; 00100 } CvHidHaarClassifier; 00101 00102 00103 typedef struct CvHidHaarStageClassifier 00104 { 00105 int count; 00106 float threshold; 00107 CvHidHaarClassifier* classifier; 00108 int two_rects; 00109 00110 struct CvHidHaarStageClassifier* next; 00111 struct CvHidHaarStageClassifier* child; 00112 struct CvHidHaarStageClassifier* parent; 00113 } CvHidHaarStageClassifier; 00114 00115 00116 typedef struct CvHidHaarClassifierCascade 00117 { 00118 int count; 00119 int isStumpBased; 00120 int has_tilted_features; 00121 int is_tree; 00122 double inv_window_area; 00123 CvMat sum, sqsum, tilted; 00124 CvHidHaarStageClassifier* stage_classifier; 00125 sqsumtype *pq0, *pq1, *pq2, *pq3; 00126 sumtype *p0, *p1, *p2, *p3; 00127 00128 void** ipp_stages; 00129 } CvHidHaarClassifierCascade; 00130 00131 00132 const int icv_object_win_border = 1; 00133 const float icv_stage_threshold_bias = 0.0001f; 00134 00135 static CvHaarClassifierCascade* 00136 icvCreateHaarClassifierCascade( int stage_count ) 00137 { 00138 CvHaarClassifierCascade* cascade = 0; 00139 00140 int block_size = sizeof(*cascade) + stage_count*sizeof(*cascade->stage_classifier); 00141 00142 if( stage_count <= 0 ) 00143 CV_Error( CV_StsOutOfRange, "Number of stages should be positive" ); 00144 00145 cascade = (CvHaarClassifierCascade*)cvAlloc( block_size ); 00146 memset( cascade, 0, block_size ); 00147 00148 cascade->stage_classifier = (CvHaarStageClassifier*)(cascade + 1); 00149 cascade->flags = CV_HAAR_MAGIC_VAL; 00150 cascade->count = stage_count; 00151 00152 return cascade; 00153 } 00154 00155 static void 00156 icvReleaseHidHaarClassifierCascade( CvHidHaarClassifierCascade** _cascade ) 00157 { 00158 if( _cascade && *_cascade ) 00159 { 00160 #ifdef HAVE_IPP 00161 CvHidHaarClassifierCascade* cascade = *_cascade; 00162 if( CV_IPP_CHECK_COND && cascade->ipp_stages ) 00163 { 00164 int i; 00165 for( i = 0; i < cascade->count; i++ ) 00166 { 00167 if( cascade->ipp_stages[i] ) 00168 #if IPP_VERSION_X100 < 900 00169 ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)cascade->ipp_stages[i] ); 00170 #else 00171 cvFree(&cascade->ipp_stages[i]); 00172 #endif 00173 } 00174 } 00175 cvFree( &cascade->ipp_stages ); 00176 #endif 00177 cvFree( _cascade ); 00178 } 00179 } 00180 00181 /* create more efficient internal representation of haar classifier cascade */ 00182 static CvHidHaarClassifierCascade* 00183 icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) 00184 { 00185 CvRect * ipp_features = 0; 00186 float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0; 00187 int* ipp_counts = 0; 00188 00189 CvHidHaarClassifierCascade* out = 0; 00190 00191 int i, j, k, l; 00192 int datasize; 00193 int total_classifiers = 0; 00194 int total_nodes = 0; 00195 char errorstr[1000]; 00196 CvHidHaarClassifier* haar_classifier_ptr; 00197 CvHidHaarTreeNode* haar_node_ptr; 00198 CvSize orig_window_size; 00199 int has_tilted_features = 0; 00200 int max_count = 0; 00201 00202 if( !CV_IS_HAAR_CLASSIFIER(cascade) ) 00203 CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" ); 00204 00205 if( cascade->hid_cascade ) 00206 CV_Error( CV_StsError, "hid_cascade has been already created" ); 00207 00208 if( !cascade->stage_classifier ) 00209 CV_Error( CV_StsNullPtr, "" ); 00210 00211 if( cascade->count <= 0 ) 00212 CV_Error( CV_StsOutOfRange, "Negative number of cascade stages" ); 00213 00214 orig_window_size = cascade->orig_window_size; 00215 00216 /* check input structure correctness and calculate total memory size needed for 00217 internal representation of the classifier cascade */ 00218 for( i = 0; i < cascade->count; i++ ) 00219 { 00220 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i; 00221 00222 if( !stage_classifier->classifier || 00223 stage_classifier->count <= 0 ) 00224 { 00225 sprintf( errorstr, "header of the stage classifier #%d is invalid " 00226 "(has null pointers or non-positive classfier count)", i ); 00227 CV_Error( CV_StsError, errorstr ); 00228 } 00229 00230 max_count = MAX( max_count, stage_classifier->count ); 00231 total_classifiers += stage_classifier->count; 00232 00233 for( j = 0; j < stage_classifier->count; j++ ) 00234 { 00235 CvHaarClassifier* classifier = stage_classifier->classifier + j; 00236 00237 total_nodes += classifier->count; 00238 for( l = 0; l < classifier->count; l++ ) 00239 { 00240 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ ) 00241 { 00242 if( classifier->haar_feature[l].rect[k].r.width ) 00243 { 00244 CvRect r = classifier->haar_feature[l].rect[k].r; 00245 int tilted = classifier->haar_feature[l].tilted; 00246 has_tilted_features |= tilted != 0; 00247 if( r.width < 0 || r.height < 0 || r.y < 0 || 00248 r.x + r.width > orig_window_size.width 00249 || 00250 (!tilted && 00251 (r.x < 0 || r.y + r.height > orig_window_size.height)) 00252 || 00253 (tilted && (r.x - r.height < 0 || 00254 r.y + r.width + r.height > orig_window_size.height))) 00255 { 00256 sprintf( errorstr, "rectangle #%d of the classifier #%d of " 00257 "the stage classifier #%d is not inside " 00258 "the reference (original) cascade window", k, j, i ); 00259 CV_Error( CV_StsNullPtr, errorstr ); 00260 } 00261 } 00262 } 00263 } 00264 } 00265 } 00266 00267 // this is an upper boundary for the whole hidden cascade size 00268 datasize = sizeof(CvHidHaarClassifierCascade) + 00269 sizeof(CvHidHaarStageClassifier)*cascade->count + 00270 sizeof(CvHidHaarClassifier) * total_classifiers + 00271 sizeof(CvHidHaarTreeNode) * total_nodes + 00272 sizeof(void*)*(total_nodes + total_classifiers); 00273 00274 out = (CvHidHaarClassifierCascade*)cvAlloc( datasize ); 00275 memset( out, 0, sizeof(*out) ); 00276 00277 /* init header */ 00278 out->count = cascade->count; 00279 out->stage_classifier = (CvHidHaarStageClassifier*)(out + 1); 00280 haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count); 00281 haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers); 00282 00283 out->isStumpBased = 1; 00284 out->has_tilted_features = has_tilted_features; 00285 out->is_tree = 0; 00286 00287 /* initialize internal representation */ 00288 for( i = 0; i < cascade->count; i++ ) 00289 { 00290 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i; 00291 CvHidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i; 00292 00293 hid_stage_classifier->count = stage_classifier->count; 00294 hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias; 00295 hid_stage_classifier->classifier = haar_classifier_ptr; 00296 hid_stage_classifier->two_rects = 1; 00297 haar_classifier_ptr += stage_classifier->count; 00298 00299 hid_stage_classifier->parent = (stage_classifier->parent == -1) 00300 ? NULL : out->stage_classifier + stage_classifier->parent; 00301 hid_stage_classifier->next = (stage_classifier->next == -1) 00302 ? NULL : out->stage_classifier + stage_classifier->next; 00303 hid_stage_classifier->child = (stage_classifier->child == -1) 00304 ? NULL : out->stage_classifier + stage_classifier->child; 00305 00306 out->is_tree |= hid_stage_classifier->next != NULL; 00307 00308 for( j = 0; j < stage_classifier->count; j++ ) 00309 { 00310 CvHaarClassifier* classifier = stage_classifier->classifier + j; 00311 CvHidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j; 00312 int node_count = classifier->count; 00313 float* alpha_ptr = (float*)(haar_node_ptr + node_count); 00314 00315 hid_classifier->count = node_count; 00316 hid_classifier->node = haar_node_ptr; 00317 hid_classifier->alpha = alpha_ptr; 00318 00319 for( l = 0; l < node_count; l++ ) 00320 { 00321 CvHidHaarTreeNode* node = hid_classifier->node + l; 00322 CvHaarFeature* feature = classifier->haar_feature + l; 00323 memset( node, -1, sizeof(*node) ); 00324 node->threshold = classifier->threshold[l]; 00325 node->left = classifier->left[l]; 00326 node->right = classifier->right[l]; 00327 00328 if( fabs(feature->rect[2].weight) < DBL_EPSILON || 00329 feature->rect[2].r.width == 0 || 00330 feature->rect[2].r.height == 0 ) 00331 memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) ); 00332 else 00333 hid_stage_classifier->two_rects = 0; 00334 } 00335 00336 memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0])); 00337 haar_node_ptr = 00338 (CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*)); 00339 00340 out->isStumpBased &= node_count == 1; 00341 } 00342 } 00343 /* 00344 #ifdef HAVE_IPP 00345 int can_use_ipp = CV_IPP_CHECK_COND && (!out->has_tilted_features && !out->is_tree && out->isStumpBased); 00346 00347 if( can_use_ipp ) 00348 { 00349 int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]); 00350 float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)* 00351 (orig_window_size.height-icv_object_win_border*2))); 00352 00353 out->ipp_stages = (void**)cvAlloc( ipp_datasize ); 00354 memset( out->ipp_stages, 0, ipp_datasize ); 00355 00356 ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) ); 00357 ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) ); 00358 ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) ); 00359 ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) ); 00360 ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) ); 00361 ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) ); 00362 00363 for( i = 0; i < cascade->count; i++ ) 00364 { 00365 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i; 00366 for( j = 0, k = 0; j < stage_classifier->count; j++ ) 00367 { 00368 CvHaarClassifier* classifier = stage_classifier->classifier + j; 00369 int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0); 00370 00371 ipp_thresholds[j] = classifier->threshold[0]; 00372 ipp_val1[j] = classifier->alpha[0]; 00373 ipp_val2[j] = classifier->alpha[1]; 00374 ipp_counts[j] = rect_count; 00375 00376 for( l = 0; l < rect_count; l++, k++ ) 00377 { 00378 ipp_features[k] = classifier->haar_feature->rect[l].r; 00379 //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height; 00380 ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale; 00381 } 00382 } 00383 00384 if( ippiHaarClassifierInitAlloc_32f( (IppiHaarClassifier_32f**)&out->ipp_stages[i], 00385 (const IppiRect*)ipp_features, ipp_weights, ipp_thresholds, 00386 ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 ) 00387 break; 00388 } 00389 00390 if( i < cascade->count ) 00391 { 00392 for( j = 0; j < i; j++ ) 00393 if( out->ipp_stages[i] ) 00394 ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)out->ipp_stages[i] ); 00395 cvFree( &out->ipp_stages ); 00396 } 00397 } 00398 #endif 00399 */ 00400 cascade->hid_cascade = out; 00401 assert( (char*)haar_node_ptr - (char*)out <= datasize ); 00402 00403 cvFree( &ipp_features ); 00404 cvFree( &ipp_weights ); 00405 cvFree( &ipp_thresholds ); 00406 cvFree( &ipp_val1 ); 00407 cvFree( &ipp_val2 ); 00408 cvFree( &ipp_counts ); 00409 00410 return out; 00411 } 00412 00413 00414 #define sum_elem_ptr(sum,row,col) \ 00415 ((sumtype*)CV_MAT_ELEM_PTR_FAST((sum),(row),(col),sizeof(sumtype))) 00416 00417 #define sqsum_elem_ptr(sqsum,row,col) \ 00418 ((sqsumtype*)CV_MAT_ELEM_PTR_FAST((sqsum),(row),(col),sizeof(sqsumtype))) 00419 00420 #define calc_sum(rect,offset) \ 00421 ((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset]) 00422 00423 #define calc_sumf(rect,offset) \ 00424 static_cast<float>((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset]) 00425 00426 00427 CV_IMPL void 00428 cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* _cascade, 00429 const CvArr* _sum, 00430 const CvArr* _sqsum, 00431 const CvArr* _tilted_sum, 00432 double scale ) 00433 { 00434 CvMat sum_stub, *sum = (CvMat*)_sum; 00435 CvMat sqsum_stub, *sqsum = (CvMat*)_sqsum; 00436 CvMat tilted_stub, *tilted = (CvMat*)_tilted_sum; 00437 CvHidHaarClassifierCascade* cascade; 00438 int coi0 = 0, coi1 = 0; 00439 int i; 00440 CvRect equRect; 00441 double weight_scale; 00442 00443 if( !CV_IS_HAAR_CLASSIFIER(_cascade) ) 00444 CV_Error( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" ); 00445 00446 if( scale <= 0 ) 00447 CV_Error( CV_StsOutOfRange, "Scale must be positive" ); 00448 00449 sum = cvGetMat( sum, &sum_stub, &coi0 ); 00450 sqsum = cvGetMat( sqsum, &sqsum_stub, &coi1 ); 00451 00452 if( coi0 || coi1 ) 00453 CV_Error( CV_BadCOI, "COI is not supported" ); 00454 00455 if( !CV_ARE_SIZES_EQ( sum, sqsum )) 00456 CV_Error( CV_StsUnmatchedSizes, "All integral images must have the same size" ); 00457 00458 if( CV_MAT_TYPE(sqsum->type) != CV_64FC1 || 00459 CV_MAT_TYPE(sum->type) != CV_32SC1 ) 00460 CV_Error( CV_StsUnsupportedFormat, 00461 "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" ); 00462 00463 if( !_cascade->hid_cascade ) 00464 icvCreateHidHaarClassifierCascade(_cascade); 00465 00466 cascade = _cascade->hid_cascade; 00467 00468 if( cascade->has_tilted_features ) 00469 { 00470 tilted = cvGetMat( tilted, &tilted_stub, &coi1 ); 00471 00472 if( CV_MAT_TYPE(tilted->type) != CV_32SC1 ) 00473 CV_Error( CV_StsUnsupportedFormat, 00474 "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" ); 00475 00476 if( sum->step != tilted->step ) 00477 CV_Error( CV_StsUnmatchedSizes, 00478 "Sum and tilted_sum must have the same stride (step, widthStep)" ); 00479 00480 if( !CV_ARE_SIZES_EQ( sum, tilted )) 00481 CV_Error( CV_StsUnmatchedSizes, "All integral images must have the same size" ); 00482 cascade->tilted = *tilted; 00483 } 00484 00485 _cascade->scale = scale; 00486 _cascade->real_window_size.width = cvRound( _cascade->orig_window_size.width * scale ); 00487 _cascade->real_window_size.height = cvRound( _cascade->orig_window_size.height * scale ); 00488 00489 cascade->sum = *sum; 00490 cascade->sqsum = *sqsum; 00491 00492 equRect.x = equRect.y = cvRound(scale); 00493 equRect.width = cvRound((_cascade->orig_window_size.width-2)*scale); 00494 equRect.height = cvRound((_cascade->orig_window_size.height-2)*scale); 00495 weight_scale = 1./(equRect.width*equRect.height); 00496 cascade->inv_window_area = weight_scale; 00497 00498 cascade->p0 = sum_elem_ptr(*sum, equRect.y, equRect.x); 00499 cascade->p1 = sum_elem_ptr(*sum, equRect.y, equRect.x + equRect.width ); 00500 cascade->p2 = sum_elem_ptr(*sum, equRect.y + equRect.height, equRect.x ); 00501 cascade->p3 = sum_elem_ptr(*sum, equRect.y + equRect.height, 00502 equRect.x + equRect.width ); 00503 00504 cascade->pq0 = sqsum_elem_ptr(*sqsum, equRect.y, equRect.x); 00505 cascade->pq1 = sqsum_elem_ptr(*sqsum, equRect.y, equRect.x + equRect.width ); 00506 cascade->pq2 = sqsum_elem_ptr(*sqsum, equRect.y + equRect.height, equRect.x ); 00507 cascade->pq3 = sqsum_elem_ptr(*sqsum, equRect.y + equRect.height, 00508 equRect.x + equRect.width ); 00509 00510 /* init pointers in haar features according to real window size and 00511 given image pointers */ 00512 for( i = 0; i < _cascade->count; i++ ) 00513 { 00514 int j, k, l; 00515 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 00516 { 00517 for( l = 0; l < cascade->stage_classifier[i].classifier[j].count; l++ ) 00518 { 00519 CvHaarFeature* feature = 00520 &_cascade->stage_classifier[i].classifier[j].haar_feature[l]; 00521 /* CvHidHaarClassifier* classifier = 00522 cascade->stage_classifier[i].classifier + j; */ 00523 CvHidHaarFeature* hidfeature = 00524 &cascade->stage_classifier[i].classifier[j].node[l].feature; 00525 double sum0 = 0, area0 = 0; 00526 CvRect r[3]; 00527 00528 int base_w = -1, base_h = -1; 00529 int new_base_w = 0, new_base_h = 0; 00530 int kx, ky; 00531 int flagx = 0, flagy = 0; 00532 int x0 = 0, y0 = 0; 00533 int nr; 00534 00535 /* align blocks */ 00536 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ ) 00537 { 00538 if( !hidfeature->rect[k].p0 ) 00539 break; 00540 r[k] = feature->rect[k].r; 00541 base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].width-1) ); 00542 base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].x - r[0].x-1) ); 00543 base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].height-1) ); 00544 base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].y - r[0].y-1) ); 00545 } 00546 00547 nr = k; 00548 00549 base_w += 1; 00550 base_h += 1; 00551 kx = r[0].width / base_w; 00552 ky = r[0].height / base_h; 00553 00554 if( kx <= 0 ) 00555 { 00556 flagx = 1; 00557 new_base_w = cvRound( r[0].width * scale ) / kx; 00558 x0 = cvRound( r[0].x * scale ); 00559 } 00560 00561 if( ky <= 0 ) 00562 { 00563 flagy = 1; 00564 new_base_h = cvRound( r[0].height * scale ) / ky; 00565 y0 = cvRound( r[0].y * scale ); 00566 } 00567 00568 for( k = 0; k < nr; k++ ) 00569 { 00570 CvRect tr; 00571 double correction_ratio; 00572 00573 if( flagx ) 00574 { 00575 tr.x = (r[k].x - r[0].x) * new_base_w / base_w + x0; 00576 tr.width = r[k].width * new_base_w / base_w; 00577 } 00578 else 00579 { 00580 tr.x = cvRound( r[k].x * scale ); 00581 tr.width = cvRound( r[k].width * scale ); 00582 } 00583 00584 if( flagy ) 00585 { 00586 tr.y = (r[k].y - r[0].y) * new_base_h / base_h + y0; 00587 tr.height = r[k].height * new_base_h / base_h; 00588 } 00589 else 00590 { 00591 tr.y = cvRound( r[k].y * scale ); 00592 tr.height = cvRound( r[k].height * scale ); 00593 } 00594 00595 #if CV_ADJUST_WEIGHTS 00596 { 00597 // RAINER START 00598 const float orig_feature_size = (float)(feature->rect[k].r.width)*feature->rect[k].r.height; 00599 const float orig_norm_size = (float)(_cascade->orig_window_size.width)*(_cascade->orig_window_size.height); 00600 const float feature_size = float(tr.width*tr.height); 00601 //const float normSize = float(equRect.width*equRect.height); 00602 float target_ratio = orig_feature_size / orig_norm_size; 00603 //float isRatio = featureSize / normSize; 00604 //correctionRatio = targetRatio / isRatio / normSize; 00605 correction_ratio = target_ratio / feature_size; 00606 // RAINER END 00607 } 00608 #else 00609 correction_ratio = weight_scale * (!feature->tilted ? 1 : 0.5); 00610 #endif 00611 00612 if( !feature->tilted ) 00613 { 00614 hidfeature->rect[k].p0 = sum_elem_ptr(*sum, tr.y, tr.x); 00615 hidfeature->rect[k].p1 = sum_elem_ptr(*sum, tr.y, tr.x + tr.width); 00616 hidfeature->rect[k].p2 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x); 00617 hidfeature->rect[k].p3 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x + tr.width); 00618 } 00619 else 00620 { 00621 hidfeature->rect[k].p2 = sum_elem_ptr(*tilted, tr.y + tr.width, tr.x + tr.width); 00622 hidfeature->rect[k].p3 = sum_elem_ptr(*tilted, tr.y + tr.width + tr.height, 00623 tr.x + tr.width - tr.height); 00624 hidfeature->rect[k].p0 = sum_elem_ptr(*tilted, tr.y, tr.x); 00625 hidfeature->rect[k].p1 = sum_elem_ptr(*tilted, tr.y + tr.height, tr.x - tr.height); 00626 } 00627 00628 hidfeature->rect[k].weight = (float)(feature->rect[k].weight * correction_ratio); 00629 00630 if( k == 0 ) 00631 area0 = tr.width * tr.height; 00632 else 00633 sum0 += hidfeature->rect[k].weight * tr.width * tr.height; 00634 } 00635 00636 hidfeature->rect[0].weight = (float)(-sum0/area0); 00637 } /* l */ 00638 } /* j */ 00639 } 00640 } 00641 00642 00643 // AVX version icvEvalHidHaarClassifier. Process 8 CvHidHaarClassifiers per call. Check AVX support before invocation!! 00644 #ifdef CV_HAAR_USE_AVX 00645 CV_INLINE 00646 double icvEvalHidHaarClassifierAVX( CvHidHaarClassifier* classifier, 00647 double variance_norm_factor, size_t p_offset ) 00648 { 00649 int CV_DECL_ALIGNED(32) idxV[8] = {0,0,0,0,0,0,0,0}; 00650 uchar flags[8] = {0,0,0,0,0,0,0,0}; 00651 CvHidHaarTreeNode* nodes[8]; 00652 double res = 0; 00653 uchar exitConditionFlag = 0; 00654 for(;;) 00655 { 00656 float CV_DECL_ALIGNED(32) tmp[8] = {0,0,0,0,0,0,0,0}; 00657 nodes[0] = (classifier+0)->node + idxV[0]; 00658 nodes[1] = (classifier+1)->node + idxV[1]; 00659 nodes[2] = (classifier+2)->node + idxV[2]; 00660 nodes[3] = (classifier+3)->node + idxV[3]; 00661 nodes[4] = (classifier+4)->node + idxV[4]; 00662 nodes[5] = (classifier+5)->node + idxV[5]; 00663 nodes[6] = (classifier+6)->node + idxV[6]; 00664 nodes[7] = (classifier+7)->node + idxV[7]; 00665 00666 __m256 t = _mm256_set1_ps(static_cast<float>(variance_norm_factor)); 00667 00668 t = _mm256_mul_ps(t, _mm256_set_ps(nodes[7]->threshold, 00669 nodes[6]->threshold, 00670 nodes[5]->threshold, 00671 nodes[4]->threshold, 00672 nodes[3]->threshold, 00673 nodes[2]->threshold, 00674 nodes[1]->threshold, 00675 nodes[0]->threshold)); 00676 00677 __m256 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[0], p_offset), 00678 calc_sumf(nodes[6]->feature.rect[0], p_offset), 00679 calc_sumf(nodes[5]->feature.rect[0], p_offset), 00680 calc_sumf(nodes[4]->feature.rect[0], p_offset), 00681 calc_sumf(nodes[3]->feature.rect[0], p_offset), 00682 calc_sumf(nodes[2]->feature.rect[0], p_offset), 00683 calc_sumf(nodes[1]->feature.rect[0], p_offset), 00684 calc_sumf(nodes[0]->feature.rect[0], p_offset)); 00685 00686 __m256 weight = _mm256_set_ps(nodes[7]->feature.rect[0].weight, 00687 nodes[6]->feature.rect[0].weight, 00688 nodes[5]->feature.rect[0].weight, 00689 nodes[4]->feature.rect[0].weight, 00690 nodes[3]->feature.rect[0].weight, 00691 nodes[2]->feature.rect[0].weight, 00692 nodes[1]->feature.rect[0].weight, 00693 nodes[0]->feature.rect[0].weight); 00694 00695 __m256 sum = _mm256_mul_ps(offset, weight); 00696 00697 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[1], p_offset), 00698 calc_sumf(nodes[6]->feature.rect[1], p_offset), 00699 calc_sumf(nodes[5]->feature.rect[1], p_offset), 00700 calc_sumf(nodes[4]->feature.rect[1], p_offset), 00701 calc_sumf(nodes[3]->feature.rect[1], p_offset), 00702 calc_sumf(nodes[2]->feature.rect[1], p_offset), 00703 calc_sumf(nodes[1]->feature.rect[1], p_offset), 00704 calc_sumf(nodes[0]->feature.rect[1], p_offset)); 00705 00706 weight = _mm256_set_ps(nodes[7]->feature.rect[1].weight, 00707 nodes[6]->feature.rect[1].weight, 00708 nodes[5]->feature.rect[1].weight, 00709 nodes[4]->feature.rect[1].weight, 00710 nodes[3]->feature.rect[1].weight, 00711 nodes[2]->feature.rect[1].weight, 00712 nodes[1]->feature.rect[1].weight, 00713 nodes[0]->feature.rect[1].weight); 00714 00715 sum = _mm256_add_ps(sum, _mm256_mul_ps(offset, weight)); 00716 00717 if( nodes[0]->feature.rect[2].p0 ) 00718 tmp[0] = calc_sumf(nodes[0]->feature.rect[2], p_offset) * nodes[0]->feature.rect[2].weight; 00719 if( nodes[1]->feature.rect[2].p0 ) 00720 tmp[1] = calc_sumf(nodes[1]->feature.rect[2], p_offset) * nodes[1]->feature.rect[2].weight; 00721 if( nodes[2]->feature.rect[2].p0 ) 00722 tmp[2] = calc_sumf(nodes[2]->feature.rect[2], p_offset) * nodes[2]->feature.rect[2].weight; 00723 if( nodes[3]->feature.rect[2].p0 ) 00724 tmp[3] = calc_sumf(nodes[3]->feature.rect[2], p_offset) * nodes[3]->feature.rect[2].weight; 00725 if( nodes[4]->feature.rect[2].p0 ) 00726 tmp[4] = calc_sumf(nodes[4]->feature.rect[2], p_offset) * nodes[4]->feature.rect[2].weight; 00727 if( nodes[5]->feature.rect[2].p0 ) 00728 tmp[5] = calc_sumf(nodes[5]->feature.rect[2], p_offset) * nodes[5]->feature.rect[2].weight; 00729 if( nodes[6]->feature.rect[2].p0 ) 00730 tmp[6] = calc_sumf(nodes[6]->feature.rect[2], p_offset) * nodes[6]->feature.rect[2].weight; 00731 if( nodes[7]->feature.rect[2].p0 ) 00732 tmp[7] = calc_sumf(nodes[7]->feature.rect[2], p_offset) * nodes[7]->feature.rect[2].weight; 00733 00734 sum = _mm256_add_ps(sum,_mm256_load_ps(tmp)); 00735 00736 __m256 left = _mm256_set_ps(static_cast<float>(nodes[7]->left), static_cast<float>(nodes[6]->left), 00737 static_cast<float>(nodes[5]->left), static_cast<float>(nodes[4]->left), 00738 static_cast<float>(nodes[3]->left), static_cast<float>(nodes[2]->left), 00739 static_cast<float>(nodes[1]->left), static_cast<float>(nodes[0]->left)); 00740 __m256 right = _mm256_set_ps(static_cast<float>(nodes[7]->right),static_cast<float>(nodes[6]->right), 00741 static_cast<float>(nodes[5]->right),static_cast<float>(nodes[4]->right), 00742 static_cast<float>(nodes[3]->right),static_cast<float>(nodes[2]->right), 00743 static_cast<float>(nodes[1]->right),static_cast<float>(nodes[0]->right)); 00744 00745 _mm256_store_si256((__m256i*)idxV, _mm256_cvttps_epi32(_mm256_blendv_ps(right, left, _mm256_cmp_ps(sum, t, _CMP_LT_OQ)))); 00746 00747 for(int i = 0; i < 8; i++) 00748 { 00749 if(idxV[i]<=0) 00750 { 00751 if(!flags[i]) 00752 { 00753 exitConditionFlag++; 00754 flags[i] = 1; 00755 res += (classifier+i)->alpha[-idxV[i]]; 00756 } 00757 idxV[i]=0; 00758 } 00759 } 00760 if(exitConditionFlag == 8) 00761 return res; 00762 } 00763 } 00764 #endif //CV_HAAR_USE_AVX 00765 00766 CV_INLINE 00767 double icvEvalHidHaarClassifier( CvHidHaarClassifier* classifier, 00768 double variance_norm_factor, 00769 size_t p_offset ) 00770 { 00771 int idx = 0; 00772 /*#if CV_HAAR_USE_SSE && !CV_HAAR_USE_AVX 00773 if(cv::checkHardwareSupport(CV_CPU_SSE2))//based on old SSE variant. Works slow 00774 { 00775 double CV_DECL_ALIGNED(16) temp[2]; 00776 __m128d zero = _mm_setzero_pd(); 00777 do 00778 { 00779 CvHidHaarTreeNode* node = classifier->node + idx; 00780 __m128d t = _mm_set1_pd((node->threshold)*variance_norm_factor); 00781 __m128d left = _mm_set1_pd(node->left); 00782 __m128d right = _mm_set1_pd(node->right); 00783 00784 double _sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 00785 _sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 00786 if( node->feature.rect[2].p0 ) 00787 _sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight; 00788 00789 __m128d sum = _mm_set1_pd(_sum); 00790 t = _mm_cmplt_sd(sum, t); 00791 sum = _mm_blendv_pd(right, left, t); 00792 00793 _mm_store_pd(temp, sum); 00794 idx = (int)temp[0]; 00795 } 00796 while(idx > 0 ); 00797 00798 } 00799 else 00800 #endif*/ 00801 { 00802 do 00803 { 00804 CvHidHaarTreeNode* node = classifier->node + idx; 00805 double t = node->threshold * variance_norm_factor; 00806 00807 double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 00808 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 00809 00810 if( node->feature.rect[2].p0 ) 00811 sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight; 00812 00813 idx = sum < t ? node->left : node->right; 00814 } 00815 while( idx > 0 ); 00816 } 00817 return classifier->alpha[-idx]; 00818 } 00819 00820 00821 00822 static int 00823 cvRunHaarClassifierCascadeSum( const CvHaarClassifierCascade* _cascade, 00824 CvPoint pt, double& stage_sum, int start_stage ) 00825 { 00826 #ifdef CV_HAAR_USE_AVX 00827 bool haveAVX = false; 00828 if(cv::checkHardwareSupport(CV_CPU_AVX)) 00829 if(__xgetbv()&0x6)// Check if the OS will save the YMM registers 00830 haveAVX = true; 00831 #else 00832 # ifdef CV_HAAR_USE_SSE 00833 bool haveSSE2 = cv::checkHardwareSupport(CV_CPU_SSE2); 00834 # endif 00835 #endif 00836 00837 int p_offset, pq_offset; 00838 int i, j; 00839 double mean, variance_norm_factor; 00840 CvHidHaarClassifierCascade* cascade; 00841 00842 if( !CV_IS_HAAR_CLASSIFIER(_cascade) ) 00843 CV_Error( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid cascade pointer" ); 00844 00845 cascade = _cascade->hid_cascade; 00846 if( !cascade ) 00847 CV_Error( CV_StsNullPtr, "Hidden cascade has not been created.\n" 00848 "Use cvSetImagesForHaarClassifierCascade" ); 00849 00850 if( pt.x < 0 || pt.y < 0 || 00851 pt.x + _cascade->real_window_size.width >= cascade->sum.width || 00852 pt.y + _cascade->real_window_size.height >= cascade->sum.height ) 00853 return -1; 00854 00855 p_offset = pt.y * (cascade->sum.step/sizeof(sumtype)) + pt.x; 00856 pq_offset = pt.y * (cascade->sqsum.step/sizeof(sqsumtype)) + pt.x; 00857 mean = calc_sum(*cascade,p_offset)*cascade->inv_window_area; 00858 variance_norm_factor = cascade->pq0[pq_offset] - cascade->pq1[pq_offset] - 00859 cascade->pq2[pq_offset] + cascade->pq3[pq_offset]; 00860 variance_norm_factor = variance_norm_factor*cascade->inv_window_area - mean*mean; 00861 if( variance_norm_factor >= 0. ) 00862 variance_norm_factor = std::sqrt(variance_norm_factor); 00863 else 00864 variance_norm_factor = 1.; 00865 00866 if( cascade->is_tree ) 00867 { 00868 CvHidHaarStageClassifier* ptr = cascade->stage_classifier; 00869 assert( start_stage == 0 ); 00870 00871 while( ptr ) 00872 { 00873 stage_sum = 0.0; 00874 j = 0; 00875 00876 #ifdef CV_HAAR_USE_AVX 00877 if(haveAVX) 00878 { 00879 for( ; j <= ptr->count - 8; j += 8 ) 00880 { 00881 stage_sum += icvEvalHidHaarClassifierAVX( 00882 ptr->classifier + j, 00883 variance_norm_factor, p_offset ); 00884 } 00885 } 00886 #endif 00887 for( ; j < ptr->count; j++ ) 00888 { 00889 stage_sum += icvEvalHidHaarClassifier( ptr->classifier + j, variance_norm_factor, p_offset ); 00890 } 00891 00892 if( stage_sum >= ptr->threshold ) 00893 { 00894 ptr = ptr->child; 00895 } 00896 else 00897 { 00898 while( ptr && ptr->next == NULL ) ptr = ptr->parent; 00899 if( ptr == NULL ) 00900 return 0; 00901 ptr = ptr->next; 00902 } 00903 } 00904 } 00905 else if( cascade->isStumpBased ) 00906 { 00907 #ifdef CV_HAAR_USE_AVX 00908 if(haveAVX) 00909 { 00910 CvHidHaarClassifier* classifiers[8]; 00911 CvHidHaarTreeNode* nodes[8]; 00912 for( i = start_stage; i < cascade->count; i++ ) 00913 { 00914 stage_sum = 0.0; 00915 j = 0; 00916 float CV_DECL_ALIGNED(32) buf[8]; 00917 if( cascade->stage_classifier[i].two_rects ) 00918 { 00919 for( ; j <= cascade->stage_classifier[i].count - 8; j += 8 ) 00920 { 00921 classifiers[0] = cascade->stage_classifier[i].classifier + j; 00922 nodes[0] = classifiers[0]->node; 00923 classifiers[1] = cascade->stage_classifier[i].classifier + j + 1; 00924 nodes[1] = classifiers[1]->node; 00925 classifiers[2] = cascade->stage_classifier[i].classifier + j + 2; 00926 nodes[2] = classifiers[2]->node; 00927 classifiers[3] = cascade->stage_classifier[i].classifier + j + 3; 00928 nodes[3] = classifiers[3]->node; 00929 classifiers[4] = cascade->stage_classifier[i].classifier + j + 4; 00930 nodes[4] = classifiers[4]->node; 00931 classifiers[5] = cascade->stage_classifier[i].classifier + j + 5; 00932 nodes[5] = classifiers[5]->node; 00933 classifiers[6] = cascade->stage_classifier[i].classifier + j + 6; 00934 nodes[6] = classifiers[6]->node; 00935 classifiers[7] = cascade->stage_classifier[i].classifier + j + 7; 00936 nodes[7] = classifiers[7]->node; 00937 00938 __m256 t = _mm256_set1_ps(static_cast<float>(variance_norm_factor)); 00939 t = _mm256_mul_ps(t, _mm256_set_ps(nodes[7]->threshold, 00940 nodes[6]->threshold, 00941 nodes[5]->threshold, 00942 nodes[4]->threshold, 00943 nodes[3]->threshold, 00944 nodes[2]->threshold, 00945 nodes[1]->threshold, 00946 nodes[0]->threshold)); 00947 00948 __m256 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[0], p_offset), 00949 calc_sumf(nodes[6]->feature.rect[0], p_offset), 00950 calc_sumf(nodes[5]->feature.rect[0], p_offset), 00951 calc_sumf(nodes[4]->feature.rect[0], p_offset), 00952 calc_sumf(nodes[3]->feature.rect[0], p_offset), 00953 calc_sumf(nodes[2]->feature.rect[0], p_offset), 00954 calc_sumf(nodes[1]->feature.rect[0], p_offset), 00955 calc_sumf(nodes[0]->feature.rect[0], p_offset)); 00956 00957 __m256 weight = _mm256_set_ps(nodes[7]->feature.rect[0].weight, 00958 nodes[6]->feature.rect[0].weight, 00959 nodes[5]->feature.rect[0].weight, 00960 nodes[4]->feature.rect[0].weight, 00961 nodes[3]->feature.rect[0].weight, 00962 nodes[2]->feature.rect[0].weight, 00963 nodes[1]->feature.rect[0].weight, 00964 nodes[0]->feature.rect[0].weight); 00965 00966 __m256 sum = _mm256_mul_ps(offset, weight); 00967 00968 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[1], p_offset), 00969 calc_sumf(nodes[6]->feature.rect[1], p_offset), 00970 calc_sumf(nodes[5]->feature.rect[1], p_offset), 00971 calc_sumf(nodes[4]->feature.rect[1], p_offset), 00972 calc_sumf(nodes[3]->feature.rect[1], p_offset), 00973 calc_sumf(nodes[2]->feature.rect[1], p_offset), 00974 calc_sumf(nodes[1]->feature.rect[1], p_offset), 00975 calc_sumf(nodes[0]->feature.rect[1], p_offset)); 00976 00977 weight = _mm256_set_ps(nodes[7]->feature.rect[1].weight, 00978 nodes[6]->feature.rect[1].weight, 00979 nodes[5]->feature.rect[1].weight, 00980 nodes[4]->feature.rect[1].weight, 00981 nodes[3]->feature.rect[1].weight, 00982 nodes[2]->feature.rect[1].weight, 00983 nodes[1]->feature.rect[1].weight, 00984 nodes[0]->feature.rect[1].weight); 00985 00986 sum = _mm256_add_ps(sum, _mm256_mul_ps(offset,weight)); 00987 00988 __m256 alpha0 = _mm256_set_ps(classifiers[7]->alpha[0], 00989 classifiers[6]->alpha[0], 00990 classifiers[5]->alpha[0], 00991 classifiers[4]->alpha[0], 00992 classifiers[3]->alpha[0], 00993 classifiers[2]->alpha[0], 00994 classifiers[1]->alpha[0], 00995 classifiers[0]->alpha[0]); 00996 __m256 alpha1 = _mm256_set_ps(classifiers[7]->alpha[1], 00997 classifiers[6]->alpha[1], 00998 classifiers[5]->alpha[1], 00999 classifiers[4]->alpha[1], 01000 classifiers[3]->alpha[1], 01001 classifiers[2]->alpha[1], 01002 classifiers[1]->alpha[1], 01003 classifiers[0]->alpha[1]); 01004 01005 _mm256_store_ps(buf, _mm256_blendv_ps(alpha0, alpha1, _mm256_cmp_ps(t, sum, _CMP_LE_OQ))); 01006 stage_sum += (buf[0]+buf[1]+buf[2]+buf[3]+buf[4]+buf[5]+buf[6]+buf[7]); 01007 } 01008 01009 for( ; j < cascade->stage_classifier[i].count; j++ ) 01010 { 01011 CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 01012 CvHidHaarTreeNode* node = classifier->node; 01013 01014 double t = node->threshold*variance_norm_factor; 01015 double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 01016 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 01017 stage_sum += classifier->alpha[sum >= t]; 01018 } 01019 } 01020 else 01021 { 01022 for( ; j <= (cascade->stage_classifier[i].count)-8; j+=8 ) 01023 { 01024 float CV_DECL_ALIGNED(32) tmp[8] = {0,0,0,0,0,0,0,0}; 01025 01026 classifiers[0] = cascade->stage_classifier[i].classifier + j; 01027 nodes[0] = classifiers[0]->node; 01028 classifiers[1] = cascade->stage_classifier[i].classifier + j + 1; 01029 nodes[1] = classifiers[1]->node; 01030 classifiers[2] = cascade->stage_classifier[i].classifier + j + 2; 01031 nodes[2] = classifiers[2]->node; 01032 classifiers[3] = cascade->stage_classifier[i].classifier + j + 3; 01033 nodes[3] = classifiers[3]->node; 01034 classifiers[4] = cascade->stage_classifier[i].classifier + j + 4; 01035 nodes[4] = classifiers[4]->node; 01036 classifiers[5] = cascade->stage_classifier[i].classifier + j + 5; 01037 nodes[5] = classifiers[5]->node; 01038 classifiers[6] = cascade->stage_classifier[i].classifier + j + 6; 01039 nodes[6] = classifiers[6]->node; 01040 classifiers[7] = cascade->stage_classifier[i].classifier + j + 7; 01041 nodes[7] = classifiers[7]->node; 01042 01043 __m256 t = _mm256_set1_ps(static_cast<float>(variance_norm_factor)); 01044 01045 t = _mm256_mul_ps(t, _mm256_set_ps(nodes[7]->threshold, 01046 nodes[6]->threshold, 01047 nodes[5]->threshold, 01048 nodes[4]->threshold, 01049 nodes[3]->threshold, 01050 nodes[2]->threshold, 01051 nodes[1]->threshold, 01052 nodes[0]->threshold)); 01053 01054 __m256 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[0], p_offset), 01055 calc_sumf(nodes[6]->feature.rect[0], p_offset), 01056 calc_sumf(nodes[5]->feature.rect[0], p_offset), 01057 calc_sumf(nodes[4]->feature.rect[0], p_offset), 01058 calc_sumf(nodes[3]->feature.rect[0], p_offset), 01059 calc_sumf(nodes[2]->feature.rect[0], p_offset), 01060 calc_sumf(nodes[1]->feature.rect[0], p_offset), 01061 calc_sumf(nodes[0]->feature.rect[0], p_offset)); 01062 01063 __m256 weight = _mm256_set_ps(nodes[7]->feature.rect[0].weight, 01064 nodes[6]->feature.rect[0].weight, 01065 nodes[5]->feature.rect[0].weight, 01066 nodes[4]->feature.rect[0].weight, 01067 nodes[3]->feature.rect[0].weight, 01068 nodes[2]->feature.rect[0].weight, 01069 nodes[1]->feature.rect[0].weight, 01070 nodes[0]->feature.rect[0].weight); 01071 01072 __m256 sum = _mm256_mul_ps(offset, weight); 01073 01074 offset = _mm256_set_ps(calc_sumf(nodes[7]->feature.rect[1], p_offset), 01075 calc_sumf(nodes[6]->feature.rect[1], p_offset), 01076 calc_sumf(nodes[5]->feature.rect[1], p_offset), 01077 calc_sumf(nodes[4]->feature.rect[1], p_offset), 01078 calc_sumf(nodes[3]->feature.rect[1], p_offset), 01079 calc_sumf(nodes[2]->feature.rect[1], p_offset), 01080 calc_sumf(nodes[1]->feature.rect[1], p_offset), 01081 calc_sumf(nodes[0]->feature.rect[1], p_offset)); 01082 01083 weight = _mm256_set_ps(nodes[7]->feature.rect[1].weight, 01084 nodes[6]->feature.rect[1].weight, 01085 nodes[5]->feature.rect[1].weight, 01086 nodes[4]->feature.rect[1].weight, 01087 nodes[3]->feature.rect[1].weight, 01088 nodes[2]->feature.rect[1].weight, 01089 nodes[1]->feature.rect[1].weight, 01090 nodes[0]->feature.rect[1].weight); 01091 01092 sum = _mm256_add_ps(sum, _mm256_mul_ps(offset, weight)); 01093 01094 if( nodes[0]->feature.rect[2].p0 ) 01095 tmp[0] = calc_sumf(nodes[0]->feature.rect[2],p_offset) * nodes[0]->feature.rect[2].weight; 01096 if( nodes[1]->feature.rect[2].p0 ) 01097 tmp[1] = calc_sumf(nodes[1]->feature.rect[2],p_offset) * nodes[1]->feature.rect[2].weight; 01098 if( nodes[2]->feature.rect[2].p0 ) 01099 tmp[2] = calc_sumf(nodes[2]->feature.rect[2],p_offset) * nodes[2]->feature.rect[2].weight; 01100 if( nodes[3]->feature.rect[2].p0 ) 01101 tmp[3] = calc_sumf(nodes[3]->feature.rect[2],p_offset) * nodes[3]->feature.rect[2].weight; 01102 if( nodes[4]->feature.rect[2].p0 ) 01103 tmp[4] = calc_sumf(nodes[4]->feature.rect[2],p_offset) * nodes[4]->feature.rect[2].weight; 01104 if( nodes[5]->feature.rect[2].p0 ) 01105 tmp[5] = calc_sumf(nodes[5]->feature.rect[2],p_offset) * nodes[5]->feature.rect[2].weight; 01106 if( nodes[6]->feature.rect[2].p0 ) 01107 tmp[6] = calc_sumf(nodes[6]->feature.rect[2],p_offset) * nodes[6]->feature.rect[2].weight; 01108 if( nodes[7]->feature.rect[2].p0 ) 01109 tmp[7] = calc_sumf(nodes[7]->feature.rect[2],p_offset) * nodes[7]->feature.rect[2].weight; 01110 01111 sum = _mm256_add_ps(sum, _mm256_load_ps(tmp)); 01112 01113 __m256 alpha0 = _mm256_set_ps(classifiers[7]->alpha[0], 01114 classifiers[6]->alpha[0], 01115 classifiers[5]->alpha[0], 01116 classifiers[4]->alpha[0], 01117 classifiers[3]->alpha[0], 01118 classifiers[2]->alpha[0], 01119 classifiers[1]->alpha[0], 01120 classifiers[0]->alpha[0]); 01121 __m256 alpha1 = _mm256_set_ps(classifiers[7]->alpha[1], 01122 classifiers[6]->alpha[1], 01123 classifiers[5]->alpha[1], 01124 classifiers[4]->alpha[1], 01125 classifiers[3]->alpha[1], 01126 classifiers[2]->alpha[1], 01127 classifiers[1]->alpha[1], 01128 classifiers[0]->alpha[1]); 01129 01130 __m256 outBuf = _mm256_blendv_ps(alpha0, alpha1, _mm256_cmp_ps(t, sum, _CMP_LE_OQ )); 01131 outBuf = _mm256_hadd_ps(outBuf, outBuf); 01132 outBuf = _mm256_hadd_ps(outBuf, outBuf); 01133 _mm256_store_ps(buf, outBuf); 01134 stage_sum += (buf[0] + buf[4]); 01135 } 01136 01137 for( ; j < cascade->stage_classifier[i].count; j++ ) 01138 { 01139 CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 01140 CvHidHaarTreeNode* node = classifier->node; 01141 01142 double t = node->threshold*variance_norm_factor; 01143 double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 01144 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 01145 if( node->feature.rect[2].p0 ) 01146 sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight; 01147 stage_sum += classifier->alpha[sum >= t]; 01148 } 01149 } 01150 if( stage_sum < cascade->stage_classifier[i].threshold ) 01151 return -i; 01152 } 01153 } 01154 else 01155 #elif defined CV_HAAR_USE_SSE //old SSE optimization 01156 if(haveSSE2) 01157 { 01158 for( i = start_stage; i < cascade->count; i++ ) 01159 { 01160 __m128d vstage_sum = _mm_setzero_pd(); 01161 if( cascade->stage_classifier[i].two_rects ) 01162 { 01163 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 01164 { 01165 CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 01166 CvHidHaarTreeNode* node = classifier->node; 01167 01168 // ayasin - NHM perf optim. Avoid use of costly flaky jcc 01169 __m128d t = _mm_set_sd(node->threshold*variance_norm_factor); 01170 __m128d a = _mm_set_sd(classifier->alpha[0]); 01171 __m128d b = _mm_set_sd(classifier->alpha[1]); 01172 __m128d sum = _mm_set_sd(calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight + 01173 calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight); 01174 t = _mm_cmpgt_sd(t, sum); 01175 vstage_sum = _mm_add_sd(vstage_sum, _mm_blendv_pd(b, a, t)); 01176 } 01177 } 01178 else 01179 { 01180 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 01181 { 01182 CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 01183 CvHidHaarTreeNode* node = classifier->node; 01184 // ayasin - NHM perf optim. Avoid use of costly flaky jcc 01185 __m128d t = _mm_set_sd(node->threshold*variance_norm_factor); 01186 __m128d a = _mm_set_sd(classifier->alpha[0]); 01187 __m128d b = _mm_set_sd(classifier->alpha[1]); 01188 double _sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 01189 _sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 01190 if( node->feature.rect[2].p0 ) 01191 _sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight; 01192 __m128d sum = _mm_set_sd(_sum); 01193 01194 t = _mm_cmpgt_sd(t, sum); 01195 vstage_sum = _mm_add_sd(vstage_sum, _mm_blendv_pd(b, a, t)); 01196 } 01197 } 01198 __m128d i_threshold = _mm_set1_pd(cascade->stage_classifier[i].threshold); 01199 if( _mm_comilt_sd(vstage_sum, i_threshold) ) 01200 return -i; 01201 } 01202 } 01203 else 01204 #endif // AVX or SSE 01205 { 01206 for( i = start_stage; i < cascade->count; i++ ) 01207 { 01208 stage_sum = 0.0; 01209 if( cascade->stage_classifier[i].two_rects ) 01210 { 01211 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 01212 { 01213 CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 01214 CvHidHaarTreeNode* node = classifier->node; 01215 double t = node->threshold*variance_norm_factor; 01216 double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 01217 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 01218 stage_sum += classifier->alpha[sum >= t]; 01219 } 01220 } 01221 else 01222 { 01223 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 01224 { 01225 CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 01226 CvHidHaarTreeNode* node = classifier->node; 01227 double t = node->threshold*variance_norm_factor; 01228 double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 01229 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 01230 if( node->feature.rect[2].p0 ) 01231 sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight; 01232 stage_sum += classifier->alpha[sum >= t]; 01233 } 01234 } 01235 if( stage_sum < cascade->stage_classifier[i].threshold ) 01236 return -i; 01237 } 01238 } 01239 } 01240 else 01241 { 01242 for( i = start_stage; i < cascade->count; i++ ) 01243 { 01244 stage_sum = 0.0; 01245 int k = 0; 01246 01247 #ifdef CV_HAAR_USE_AVX 01248 if(haveAVX) 01249 { 01250 for( ; k < cascade->stage_classifier[i].count - 8; k += 8 ) 01251 { 01252 stage_sum += icvEvalHidHaarClassifierAVX( 01253 cascade->stage_classifier[i].classifier + k, 01254 variance_norm_factor, p_offset ); 01255 } 01256 } 01257 #endif 01258 for(; k < cascade->stage_classifier[i].count; k++ ) 01259 { 01260 01261 stage_sum += icvEvalHidHaarClassifier( 01262 cascade->stage_classifier[i].classifier + k, 01263 variance_norm_factor, p_offset ); 01264 } 01265 01266 if( stage_sum < cascade->stage_classifier[i].threshold ) 01267 return -i; 01268 } 01269 } 01270 return 1; 01271 } 01272 01273 01274 CV_IMPL int 01275 cvRunHaarClassifierCascade( const CvHaarClassifierCascade* _cascade, 01276 CvPoint pt, int start_stage ) 01277 { 01278 double stage_sum; 01279 return cvRunHaarClassifierCascadeSum(_cascade, pt, stage_sum, start_stage); 01280 } 01281 01282 namespace cv 01283 { 01284 01285 class HaarDetectObjects_ScaleImage_Invoker : public ParallelLoopBody 01286 { 01287 public: 01288 HaarDetectObjects_ScaleImage_Invoker( const CvHaarClassifierCascade* _cascade, 01289 int _stripSize, double _factor, 01290 const Mat& _sum1, const Mat& _sqsum1, Mat* _norm1, 01291 Mat* _mask1, Rect _equRect, std::vector<Rect>& _vec, 01292 std::vector<int>& _levels, std::vector<double>& _weights, 01293 bool _outputLevels, Mutex *_mtx ) 01294 { 01295 cascade = _cascade; 01296 stripSize = _stripSize; 01297 factor = _factor; 01298 sum1 = _sum1; 01299 sqsum1 = _sqsum1; 01300 norm1 = _norm1; 01301 mask1 = _mask1; 01302 equRect = _equRect; 01303 vec = &_vec; 01304 rejectLevels = _outputLevels ? &_levels : 0; 01305 levelWeights = _outputLevels ? &_weights : 0; 01306 mtx = _mtx; 01307 } 01308 01309 void operator()( const Range& range ) const 01310 { 01311 Size winSize0 = cascade->orig_window_size; 01312 Size winSize(cvRound(winSize0.width*factor), cvRound(winSize0.height*factor)); 01313 int y1 = range.start*stripSize, y2 = std::min(range.end*stripSize, sum1.rows - 1 - winSize0.height); 01314 01315 if (y2 <= y1 || sum1.cols <= 1 + winSize0.width) 01316 return; 01317 01318 Size ssz(sum1.cols - 1 - winSize0.width, y2 - y1); 01319 int x, y, ystep = factor > 2 ? 1 : 2; 01320 01321 #ifdef HAVE_IPP 01322 if(CV_IPP_CHECK_COND && cascade->hid_cascade->ipp_stages ) 01323 { 01324 IppiRect iequRect = {equRect.x, equRect.y, equRect.width, equRect.height}; 01325 ippiRectStdDev_32f_C1R(sum1.ptr<float>(y1), (int)sum1.step, 01326 sqsum1.ptr<double>(y1), (int)sqsum1.step, 01327 norm1->ptr<float>(y1), (int)norm1->step, 01328 ippiSize(ssz.width, ssz.height), iequRect ); 01329 01330 int positive = (ssz.width/ystep)*((ssz.height + ystep-1)/ystep); 01331 01332 if( ystep == 1 ) 01333 (*mask1) = Scalar::all(1); 01334 else 01335 for( y = y1; y < y2; y++ ) 01336 { 01337 uchar* mask1row = mask1->ptr(y); 01338 memset( mask1row, 0, ssz.width ); 01339 01340 if( y % ystep == 0 ) 01341 for( x = 0; x < ssz.width; x += ystep ) 01342 mask1row[x] = (uchar)1; 01343 } 01344 01345 for( int j = 0; j < cascade->count; j++ ) 01346 { 01347 if( ippiApplyHaarClassifier_32f_C1R( 01348 sum1.ptr<float>(y1), (int)sum1.step, 01349 norm1->ptr<float>(y1), (int)norm1->step, 01350 mask1->ptr<uchar>(y1), (int)mask1->step, 01351 ippiSize(ssz.width, ssz.height), &positive, 01352 cascade->hid_cascade->stage_classifier[j].threshold, 01353 (IppiHaarClassifier_32f*)cascade->hid_cascade->ipp_stages[j]) < 0 ) 01354 positive = 0; 01355 if( positive <= 0 ) 01356 break; 01357 } 01358 CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); 01359 01360 if( positive > 0 ) 01361 for( y = y1; y < y2; y += ystep ) 01362 { 01363 uchar* mask1row = mask1->ptr(y); 01364 for( x = 0; x < ssz.width; x += ystep ) 01365 if( mask1row[x] != 0 ) 01366 { 01367 mtx->lock(); 01368 vec->push_back(Rect(cvRound(x*factor), cvRound(y*factor), 01369 winSize.width, winSize.height)); 01370 mtx->unlock(); 01371 if( --positive == 0 ) 01372 break; 01373 } 01374 if( positive == 0 ) 01375 break; 01376 } 01377 } 01378 else 01379 #endif // IPP 01380 for( y = y1; y < y2; y += ystep ) 01381 for( x = 0; x < ssz.width; x += ystep ) 01382 { 01383 double gypWeight; 01384 int result = cvRunHaarClassifierCascadeSum( cascade, cvPoint(x,y), gypWeight, 0 ); 01385 if( rejectLevels ) 01386 { 01387 if( result == 1 ) 01388 result = -1*cascade->count; 01389 if( cascade->count + result < 4 ) 01390 { 01391 mtx->lock(); 01392 vec->push_back(Rect(cvRound(x*factor), cvRound(y*factor), 01393 winSize.width, winSize.height)); 01394 rejectLevels->push_back(-result); 01395 levelWeights->push_back(gypWeight); 01396 mtx->unlock(); 01397 } 01398 } 01399 else 01400 { 01401 if( result > 0 ) 01402 { 01403 mtx->lock(); 01404 vec->push_back(Rect(cvRound(x*factor), cvRound(y*factor), 01405 winSize.width, winSize.height)); 01406 mtx->unlock(); 01407 } 01408 } 01409 } 01410 } 01411 01412 const CvHaarClassifierCascade* cascade; 01413 int stripSize; 01414 double factor; 01415 Mat sum1, sqsum1, *norm1, *mask1; 01416 Rect equRect; 01417 std::vector<Rect>* vec; 01418 std::vector<int>* rejectLevels; 01419 std::vector<double>* levelWeights; 01420 Mutex* mtx; 01421 }; 01422 01423 01424 class HaarDetectObjects_ScaleCascade_Invoker : public ParallelLoopBody 01425 { 01426 public: 01427 HaarDetectObjects_ScaleCascade_Invoker( const CvHaarClassifierCascade* _cascade, 01428 Size _winsize, const Range& _xrange, double _ystep, 01429 size_t _sumstep, const int** _p, const int** _pq, 01430 std::vector<Rect>& _vec, Mutex* _mtx ) 01431 { 01432 cascade = _cascade; 01433 winsize = _winsize; 01434 xrange = _xrange; 01435 ystep = _ystep; 01436 sumstep = _sumstep; 01437 p = _p; pq = _pq; 01438 vec = &_vec; 01439 mtx = _mtx; 01440 } 01441 01442 void operator()( const Range& range ) const 01443 { 01444 int iy, startY = range.start, endY = range.end; 01445 const int *p0 = p[0], *p1 = p[1], *p2 = p[2], *p3 = p[3]; 01446 const int *pq0 = pq[0], *pq1 = pq[1], *pq2 = pq[2], *pq3 = pq[3]; 01447 bool doCannyPruning = p0 != 0; 01448 int sstep = (int)(sumstep/sizeof(p0[0])); 01449 01450 for( iy = startY; iy < endY; iy++ ) 01451 { 01452 int ix, y = cvRound(iy*ystep), ixstep = 1; 01453 for( ix = xrange.start; ix < xrange.end; ix += ixstep ) 01454 { 01455 int x = cvRound(ix*ystep); // it should really be ystep, not ixstep 01456 01457 if( doCannyPruning ) 01458 { 01459 int offset = y*sstep + x; 01460 int s = p0[offset] - p1[offset] - p2[offset] + p3[offset]; 01461 int sq = pq0[offset] - pq1[offset] - pq2[offset] + pq3[offset]; 01462 if( s < 100 || sq < 20 ) 01463 { 01464 ixstep = 2; 01465 continue; 01466 } 01467 } 01468 01469 int result = cvRunHaarClassifierCascade( cascade, cvPoint(x, y), 0 ); 01470 if( result > 0 ) 01471 { 01472 mtx->lock(); 01473 vec->push_back(Rect(x, y, winsize.width, winsize.height)); 01474 mtx->unlock(); 01475 } 01476 ixstep = result != 0 ? 1 : 2; 01477 } 01478 } 01479 } 01480 01481 const CvHaarClassifierCascade* cascade; 01482 double ystep; 01483 size_t sumstep; 01484 Size winsize; 01485 Range xrange; 01486 const int** p; 01487 const int** pq; 01488 std::vector<Rect>* vec; 01489 Mutex* mtx; 01490 }; 01491 01492 01493 } 01494 01495 01496 CvSeq* 01497 cvHaarDetectObjectsForROC( const CvArr* _img, 01498 CvHaarClassifierCascade* cascade, CvMemStorage* storage, 01499 std::vector<int>& rejectLevels, std::vector<double>& levelWeights, 01500 double scaleFactor, int minNeighbors, int flags, 01501 CvSize minSize, CvSize maxSize, bool outputRejectLevels ) 01502 { 01503 const double GROUP_EPS = 0.2; 01504 CvMat stub, *img = (CvMat*)_img; 01505 cv::Ptr<CvMat> temp, sum, tilted, sqsum, normImg, sumcanny, imgSmall; 01506 CvSeq* result_seq = 0; 01507 cv::Ptr<CvMemStorage> temp_storage; 01508 01509 std::vector<cv::Rect> allCandidates; 01510 std::vector<cv::Rect> rectList; 01511 std::vector<int> rweights; 01512 double factor; 01513 int coi; 01514 bool doCannyPruning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0; 01515 bool findBiggestObject = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0; 01516 bool roughSearch = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0; 01517 cv::Mutex mtx; 01518 01519 if( !CV_IS_HAAR_CLASSIFIER(cascade) ) 01520 CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" ); 01521 01522 if( !storage ) 01523 CV_Error( CV_StsNullPtr, "Null storage pointer" ); 01524 01525 img = cvGetMat( img, &stub, &coi ); 01526 if( coi ) 01527 CV_Error( CV_BadCOI, "COI is not supported" ); 01528 01529 if( CV_MAT_DEPTH(img->type) != CV_8U ) 01530 CV_Error( CV_StsUnsupportedFormat, "Only 8-bit images are supported" ); 01531 01532 if( scaleFactor <= 1 ) 01533 CV_Error( CV_StsOutOfRange, "scale factor must be > 1" ); 01534 01535 if( findBiggestObject ) 01536 flags &= ~CV_HAAR_SCALE_IMAGE; 01537 01538 if( maxSize.height == 0 || maxSize.width == 0 ) 01539 { 01540 maxSize.height = img->rows; 01541 maxSize.width = img->cols; 01542 } 01543 01544 temp.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 )); 01545 sum.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 )); 01546 sqsum.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 )); 01547 01548 if( !cascade->hid_cascade ) 01549 icvCreateHidHaarClassifierCascade(cascade); 01550 01551 if( cascade->hid_cascade->has_tilted_features ) 01552 tilted.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 )); 01553 01554 result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage ); 01555 01556 if( CV_MAT_CN(img->type) > 1 ) 01557 { 01558 cvCvtColor( img, temp, CV_BGR2GRAY ); 01559 img = temp; 01560 } 01561 01562 if( findBiggestObject ) 01563 flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING); 01564 01565 if( flags & CV_HAAR_SCALE_IMAGE ) 01566 { 01567 CvSize winSize0 = cascade->orig_window_size; 01568 #ifdef HAVE_IPP 01569 int use_ipp = CV_IPP_CHECK_COND && (cascade->hid_cascade->ipp_stages != 0); 01570 01571 if( use_ipp ) 01572 normImg.reset(cvCreateMat( img->rows, img->cols, CV_32FC1)); 01573 #endif 01574 imgSmall.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 )); 01575 01576 for( factor = 1; ; factor *= scaleFactor ) 01577 { 01578 CvSize winSize(cvRound(winSize0.width*factor), 01579 cvRound(winSize0.height*factor)); 01580 CvSize sz(cvRound( img->cols/factor ), cvRound( img->rows/factor )); 01581 CvSize sz1(sz.width - winSize0.width + 1, sz.height - winSize0.height + 1); 01582 01583 CvRect equRect(icv_object_win_border, icv_object_win_border, 01584 winSize0.width - icv_object_win_border*2, 01585 winSize0.height - icv_object_win_border*2); 01586 01587 CvMat img1, sum1, sqsum1, norm1, tilted1, mask1; 01588 CvMat* _tilted = 0; 01589 01590 if( sz1.width <= 0 || sz1.height <= 0 ) 01591 break; 01592 if( winSize.width > maxSize.width || winSize.height > maxSize.height ) 01593 break; 01594 if( winSize.width < minSize.width || winSize.height < minSize.height ) 01595 continue; 01596 01597 img1 = cvMat( sz.height, sz.width, CV_8UC1, imgSmall->data.ptr ); 01598 sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr ); 01599 sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr ); 01600 if( tilted ) 01601 { 01602 tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr ); 01603 _tilted = &tilted1; 01604 } 01605 norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, normImg ? normImg->data.ptr : 0 ); 01606 mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr ); 01607 01608 cvResize( img, &img1, CV_INTER_LINEAR ); 01609 cvIntegral( &img1, &sum1, &sqsum1, _tilted ); 01610 01611 int ystep = factor > 2 ? 1 : 2; 01612 const int LOCS_PER_THREAD = 1000; 01613 int stripCount = ((sz1.width/ystep)*(sz1.height + ystep-1)/ystep + LOCS_PER_THREAD/2)/LOCS_PER_THREAD; 01614 stripCount = std::min(std::max(stripCount, 1), 100); 01615 01616 #ifdef HAVE_IPP 01617 if( use_ipp ) 01618 { 01619 cv::Mat fsum(sum1.rows, sum1.cols, CV_32F, sum1.data.ptr, sum1.step); 01620 cv::cvarrToMat(&sum1).convertTo(fsum, CV_32F, 1, -(1<<24)); 01621 } 01622 else 01623 #endif 01624 cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, _tilted, 1. ); 01625 01626 cv::Mat _norm1 = cv::cvarrToMat(&norm1), _mask1 = cv::cvarrToMat(&mask1); 01627 cv::parallel_for_(cv::Range(0, stripCount), 01628 cv::HaarDetectObjects_ScaleImage_Invoker(cascade, 01629 (((sz1.height + stripCount - 1)/stripCount + ystep-1)/ystep)*ystep, 01630 factor, cv::cvarrToMat(&sum1), cv::cvarrToMat(&sqsum1), &_norm1, &_mask1, 01631 cv::Rect(equRect), allCandidates, rejectLevels, levelWeights, outputRejectLevels, &mtx)); 01632 } 01633 } 01634 else 01635 { 01636 int n_factors = 0; 01637 cv::Rect scanROI; 01638 01639 cvIntegral( img, sum, sqsum, tilted ); 01640 01641 if( doCannyPruning ) 01642 { 01643 sumcanny.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 )); 01644 cvCanny( img, temp, 0, 50, 3 ); 01645 cvIntegral( temp, sumcanny ); 01646 } 01647 01648 for( n_factors = 0, factor = 1; 01649 factor*cascade->orig_window_size.width < img->cols - 10 && 01650 factor*cascade->orig_window_size.height < img->rows - 10; 01651 n_factors++, factor *= scaleFactor ) 01652 ; 01653 01654 if( findBiggestObject ) 01655 { 01656 scaleFactor = 1./scaleFactor; 01657 factor *= scaleFactor; 01658 } 01659 else 01660 factor = 1; 01661 01662 for( ; n_factors-- > 0; factor *= scaleFactor ) 01663 { 01664 const double ystep = std::max( 2., factor ); 01665 CvSize winSize(cvRound( cascade->orig_window_size.width * factor ), 01666 cvRound( cascade->orig_window_size.height * factor )); 01667 CvRect equRect; 01668 int *p[4] = {0,0,0,0}; 01669 int *pq[4] = {0,0,0,0}; 01670 int startX = 0, startY = 0; 01671 int endX = cvRound((img->cols - winSize.width) / ystep); 01672 int endY = cvRound((img->rows - winSize.height) / ystep); 01673 01674 if( winSize.width < minSize.width || winSize.height < minSize.height ) 01675 { 01676 if( findBiggestObject ) 01677 break; 01678 continue; 01679 } 01680 01681 if ( winSize.width > maxSize.width || winSize.height > maxSize.height ) 01682 { 01683 if( !findBiggestObject ) 01684 break; 01685 continue; 01686 } 01687 01688 cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor ); 01689 cvZero( temp ); 01690 01691 if( doCannyPruning ) 01692 { 01693 equRect.x = cvRound(winSize.width*0.15); 01694 equRect.y = cvRound(winSize.height*0.15); 01695 equRect.width = cvRound(winSize.width*0.7); 01696 equRect.height = cvRound(winSize.height*0.7); 01697 01698 p[0] = (int*)(sumcanny->data.ptr + equRect.y*sumcanny->step) + equRect.x; 01699 p[1] = (int*)(sumcanny->data.ptr + equRect.y*sumcanny->step) 01700 + equRect.x + equRect.width; 01701 p[2] = (int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step) + equRect.x; 01702 p[3] = (int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step) 01703 + equRect.x + equRect.width; 01704 01705 pq[0] = (int*)(sum->data.ptr + equRect.y*sum->step) + equRect.x; 01706 pq[1] = (int*)(sum->data.ptr + equRect.y*sum->step) 01707 + equRect.x + equRect.width; 01708 pq[2] = (int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step) + equRect.x; 01709 pq[3] = (int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step) 01710 + equRect.x + equRect.width; 01711 } 01712 01713 if( scanROI.area() > 0 ) 01714 { 01715 //adjust start_height and stop_height 01716 startY = cvRound(scanROI.y / ystep); 01717 endY = cvRound((scanROI.y + scanROI.height - winSize.height) / ystep); 01718 01719 startX = cvRound(scanROI.x / ystep); 01720 endX = cvRound((scanROI.x + scanROI.width - winSize.width) / ystep); 01721 } 01722 01723 cv::parallel_for_(cv::Range(startY, endY), 01724 cv::HaarDetectObjects_ScaleCascade_Invoker(cascade, winSize, cv::Range(startX, endX), 01725 ystep, sum->step, (const int**)p, 01726 (const int**)pq, allCandidates, &mtx )); 01727 01728 if( findBiggestObject && !allCandidates.empty() && scanROI.area() == 0 ) 01729 { 01730 rectList.resize(allCandidates.size()); 01731 std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin()); 01732 01733 groupRectangles (rectList, std::max(minNeighbors, 1), GROUP_EPS); 01734 01735 if( !rectList.empty() ) 01736 { 01737 size_t i, sz = rectList.size(); 01738 cv::Rect maxRect; 01739 01740 for( i = 0; i < sz; i++ ) 01741 { 01742 if( rectList[i].area() > maxRect.area() ) 01743 maxRect = rectList[i]; 01744 } 01745 01746 allCandidates.push_back(maxRect); 01747 01748 scanROI = maxRect; 01749 int dx = cvRound(maxRect.width*GROUP_EPS); 01750 int dy = cvRound(maxRect.height*GROUP_EPS); 01751 scanROI.x = std::max(scanROI.x - dx, 0); 01752 scanROI.y = std::max(scanROI.y - dy, 0); 01753 scanROI.width = std::min(scanROI.width + dx*2, img->cols-1-scanROI.x); 01754 scanROI.height = std::min(scanROI.height + dy*2, img->rows-1-scanROI.y); 01755 01756 double minScale = roughSearch ? 0.6 : 0.4; 01757 minSize.width = cvRound(maxRect.width*minScale); 01758 minSize.height = cvRound(maxRect.height*minScale); 01759 } 01760 } 01761 } 01762 } 01763 01764 rectList.resize(allCandidates.size()); 01765 if(!allCandidates.empty()) 01766 std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin()); 01767 01768 if( minNeighbors != 0 || findBiggestObject ) 01769 { 01770 if( outputRejectLevels ) 01771 { 01772 groupRectangles (rectList, rejectLevels, levelWeights, minNeighbors, GROUP_EPS ); 01773 } 01774 else 01775 { 01776 groupRectangles (rectList, rweights, std::max(minNeighbors, 1), GROUP_EPS); 01777 } 01778 } 01779 else 01780 rweights.resize(rectList.size(),0); 01781 01782 if( findBiggestObject && rectList.size() ) 01783 { 01784 CvAvgComp result_comp = {CvRect (),0}; 01785 01786 for( size_t i = 0; i < rectList.size(); i++ ) 01787 { 01788 cv::Rect r = rectList[i]; 01789 if( r.area() > cv::Rect(result_comp.rect).area() ) 01790 { 01791 result_comp.rect = r; 01792 result_comp.neighbors = rweights[i]; 01793 } 01794 } 01795 cvSeqPush( result_seq, &result_comp ); 01796 } 01797 else 01798 { 01799 for( size_t i = 0; i < rectList.size(); i++ ) 01800 { 01801 CvAvgComp c; 01802 c.rect = rectList[i]; 01803 c.neighbors = !rweights.empty() ? rweights[i] : 0; 01804 cvSeqPush( result_seq, &c ); 01805 } 01806 } 01807 01808 return result_seq; 01809 } 01810 01811 CV_IMPL CvSeq* 01812 cvHaarDetectObjects( const CvArr* _img, 01813 CvHaarClassifierCascade* cascade, CvMemStorage* storage, 01814 double scaleFactor, 01815 int minNeighbors, int flags, CvSize minSize, CvSize maxSize ) 01816 { 01817 std::vector<int> fakeLevels; 01818 std::vector<double> fakeWeights; 01819 return cvHaarDetectObjectsForROC( _img, cascade, storage, fakeLevels, fakeWeights, 01820 scaleFactor, minNeighbors, flags, minSize, maxSize, false ); 01821 01822 } 01823 01824 01825 static CvHaarClassifierCascade* 01826 icvLoadCascadeCART( const char** input_cascade, int n, CvSize orig_window_size ) 01827 { 01828 int i; 01829 CvHaarClassifierCascade* cascade = icvCreateHaarClassifierCascade(n); 01830 cascade->orig_window_size = orig_window_size; 01831 01832 for( i = 0; i < n; i++ ) 01833 { 01834 int j, count, l; 01835 float threshold = 0; 01836 const char* stage = input_cascade[i]; 01837 int dl = 0; 01838 01839 /* tree links */ 01840 int parent = -1; 01841 int next = -1; 01842 01843 sscanf( stage, "%d%n", &count, &dl ); 01844 stage += dl; 01845 01846 assert( count > 0 ); 01847 cascade->stage_classifier[i].count = count; 01848 cascade->stage_classifier[i].classifier = 01849 (CvHaarClassifier*)cvAlloc( count*sizeof(cascade->stage_classifier[i].classifier[0])); 01850 01851 for( j = 0; j < count; j++ ) 01852 { 01853 CvHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 01854 int k, rects = 0; 01855 char str[100]; 01856 01857 sscanf( stage, "%d%n", &classifier->count, &dl ); 01858 stage += dl; 01859 01860 classifier->haar_feature = (CvHaarFeature*) cvAlloc( 01861 classifier->count * ( sizeof( *classifier->haar_feature ) + 01862 sizeof( *classifier->threshold ) + 01863 sizeof( *classifier->left ) + 01864 sizeof( *classifier->right ) ) + 01865 (classifier->count + 1) * sizeof( *classifier->alpha ) ); 01866 classifier->threshold = (float*) (classifier->haar_feature+classifier->count); 01867 classifier->left = (int*) (classifier->threshold + classifier->count); 01868 classifier->right = (int*) (classifier->left + classifier->count); 01869 classifier->alpha = (float*) (classifier->right + classifier->count); 01870 01871 for( l = 0; l < classifier->count; l++ ) 01872 { 01873 sscanf( stage, "%d%n", &rects, &dl ); 01874 stage += dl; 01875 01876 assert( rects >= 2 && rects <= CV_HAAR_FEATURE_MAX ); 01877 01878 for( k = 0; k < rects; k++ ) 01879 { 01880 CvRect r; 01881 int band = 0; 01882 sscanf( stage, "%d%d%d%d%d%f%n", 01883 &r.x, &r.y, &r.width, &r.height, &band, 01884 &(classifier->haar_feature[l].rect[k].weight), &dl ); 01885 stage += dl; 01886 classifier->haar_feature[l].rect[k].r = r; 01887 } 01888 sscanf( stage, "%s%n", str, &dl ); 01889 stage += dl; 01890 01891 classifier->haar_feature[l].tilted = strncmp( str, "tilted", 6 ) == 0; 01892 01893 for( k = rects; k < CV_HAAR_FEATURE_MAX; k++ ) 01894 { 01895 memset( classifier->haar_feature[l].rect + k, 0, 01896 sizeof(classifier->haar_feature[l].rect[k]) ); 01897 } 01898 01899 sscanf( stage, "%f%d%d%n", &(classifier->threshold[l]), 01900 &(classifier->left[l]), 01901 &(classifier->right[l]), &dl ); 01902 stage += dl; 01903 } 01904 for( l = 0; l <= classifier->count; l++ ) 01905 { 01906 sscanf( stage, "%f%n", &(classifier->alpha[l]), &dl ); 01907 stage += dl; 01908 } 01909 } 01910 01911 sscanf( stage, "%f%n", &threshold, &dl ); 01912 stage += dl; 01913 01914 cascade->stage_classifier[i].threshold = threshold; 01915 01916 /* load tree links */ 01917 if( sscanf( stage, "%d%d%n", &parent, &next, &dl ) != 2 ) 01918 { 01919 parent = i - 1; 01920 next = -1; 01921 } 01922 stage += dl; 01923 01924 cascade->stage_classifier[i].parent = parent; 01925 cascade->stage_classifier[i].next = next; 01926 cascade->stage_classifier[i].child = -1; 01927 01928 if( parent != -1 && cascade->stage_classifier[parent].child == -1 ) 01929 { 01930 cascade->stage_classifier[parent].child = i; 01931 } 01932 } 01933 01934 return cascade; 01935 } 01936 01937 #ifndef _MAX_PATH 01938 #define _MAX_PATH 1024 01939 #endif 01940 01941 CV_IMPL CvHaarClassifierCascade* 01942 cvLoadHaarClassifierCascade( const char* directory, CvSize orig_window_size ) 01943 { 01944 if( !directory ) 01945 CV_Error( CV_StsNullPtr, "Null path is passed" ); 01946 01947 char name[_MAX_PATH]; 01948 01949 int n = (int)strlen(directory)-1; 01950 const char* slash = directory[n] == '\\' || directory[n] == '/' ? "" : "/"; 01951 int size = 0; 01952 01953 /* try to read the classifier from directory */ 01954 for( n = 0; ; n++ ) 01955 { 01956 sprintf( name, "%s%s%d/AdaBoostCARTHaarClassifier.txt", directory, slash, n ); 01957 FILE* f = fopen( name, "rb" ); 01958 if( !f ) 01959 break; 01960 fseek( f, 0, SEEK_END ); 01961 size += ftell( f ) + 1; 01962 fclose(f); 01963 } 01964 01965 if( n == 0 && slash[0] ) 01966 return (CvHaarClassifierCascade*)cvLoad( directory ); 01967 01968 if( n == 0 ) 01969 CV_Error( CV_StsBadArg, "Invalid path" ); 01970 01971 size += (n+1)*sizeof(char*); 01972 const char** input_cascade = (const char**)cvAlloc( size ); 01973 01974 if( !input_cascade ) 01975 CV_Error( CV_StsNoMem, "Could not allocate memory for input_cascade" ); 01976 01977 char* ptr = (char*)(input_cascade + n + 1); 01978 01979 for( int i = 0; i < n; i++ ) 01980 { 01981 sprintf( name, "%s/%d/AdaBoostCARTHaarClassifier.txt", directory, i ); 01982 FILE* f = fopen( name, "rb" ); 01983 if( !f ) 01984 CV_Error( CV_StsError, "" ); 01985 fseek( f, 0, SEEK_END ); 01986 size = (int)ftell( f ); 01987 fseek( f, 0, SEEK_SET ); 01988 size_t elements_read = fread( ptr, 1, size, f ); 01989 CV_Assert(elements_read == (size_t)(size)); 01990 fclose(f); 01991 input_cascade[i] = ptr; 01992 ptr += size; 01993 *ptr++ = '\0'; 01994 } 01995 01996 input_cascade[n] = 0; 01997 01998 CvHaarClassifierCascade* cascade = icvLoadCascadeCART( input_cascade, n, orig_window_size ); 01999 02000 if( input_cascade ) 02001 cvFree( &input_cascade ); 02002 02003 return cascade; 02004 } 02005 02006 02007 CV_IMPL void 02008 cvReleaseHaarClassifierCascade( CvHaarClassifierCascade** _cascade ) 02009 { 02010 if( _cascade && *_cascade ) 02011 { 02012 int i, j; 02013 CvHaarClassifierCascade* cascade = *_cascade; 02014 02015 for( i = 0; i < cascade->count; i++ ) 02016 { 02017 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 02018 cvFree( &cascade->stage_classifier[i].classifier[j].haar_feature ); 02019 cvFree( &cascade->stage_classifier[i].classifier ); 02020 } 02021 icvReleaseHidHaarClassifierCascade( &cascade->hid_cascade ); 02022 cvFree( _cascade ); 02023 } 02024 } 02025 02026 02027 /****************************************************************************************\ 02028 * Persistence functions * 02029 \****************************************************************************************/ 02030 02031 /* field names */ 02032 02033 #define ICV_HAAR_SIZE_NAME "size" 02034 #define ICV_HAAR_STAGES_NAME "stages" 02035 #define ICV_HAAR_TREES_NAME "trees" 02036 #define ICV_HAAR_FEATURE_NAME "feature" 02037 #define ICV_HAAR_RECTS_NAME "rects" 02038 #define ICV_HAAR_TILTED_NAME "tilted" 02039 #define ICV_HAAR_THRESHOLD_NAME "threshold" 02040 #define ICV_HAAR_LEFT_NODE_NAME "left_node" 02041 #define ICV_HAAR_LEFT_VAL_NAME "left_val" 02042 #define ICV_HAAR_RIGHT_NODE_NAME "right_node" 02043 #define ICV_HAAR_RIGHT_VAL_NAME "right_val" 02044 #define ICV_HAAR_STAGE_THRESHOLD_NAME "stage_threshold" 02045 #define ICV_HAAR_PARENT_NAME "parent" 02046 #define ICV_HAAR_NEXT_NAME "next" 02047 02048 static int 02049 icvIsHaarClassifier( const void* struct_ptr ) 02050 { 02051 return CV_IS_HAAR_CLASSIFIER( struct_ptr ); 02052 } 02053 02054 static void* 02055 icvReadHaarClassifier( CvFileStorage* fs, CvFileNode* node ) 02056 { 02057 CvHaarClassifierCascade* cascade = NULL; 02058 02059 char buf[256]; 02060 CvFileNode* seq_fn = NULL; /* sequence */ 02061 CvFileNode* fn = NULL; 02062 CvFileNode* stages_fn = NULL; 02063 CvSeqReader stages_reader; 02064 int n; 02065 int i, j, k, l; 02066 int parent, next; 02067 02068 stages_fn = cvGetFileNodeByName( fs, node, ICV_HAAR_STAGES_NAME ); 02069 if( !stages_fn || !CV_NODE_IS_SEQ( stages_fn->tag) ) 02070 CV_Error( CV_StsError, "Invalid stages node" ); 02071 02072 n = stages_fn->data.seq->total; 02073 cascade = icvCreateHaarClassifierCascade(n); 02074 02075 /* read size */ 02076 seq_fn = cvGetFileNodeByName( fs, node, ICV_HAAR_SIZE_NAME ); 02077 if( !seq_fn || !CV_NODE_IS_SEQ( seq_fn->tag ) || seq_fn->data.seq->total != 2 ) 02078 CV_Error( CV_StsError, "size node is not a valid sequence." ); 02079 fn = (CvFileNode*) cvGetSeqElem( seq_fn->data.seq, 0 ); 02080 if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 ) 02081 CV_Error( CV_StsError, "Invalid size node: width must be positive integer" ); 02082 cascade->orig_window_size.width = fn->data.i; 02083 fn = (CvFileNode*) cvGetSeqElem( seq_fn->data.seq, 1 ); 02084 if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 ) 02085 CV_Error( CV_StsError, "Invalid size node: height must be positive integer" ); 02086 cascade->orig_window_size.height = fn->data.i; 02087 02088 cvStartReadSeq( stages_fn->data.seq, &stages_reader ); 02089 for( i = 0; i < n; ++i ) 02090 { 02091 CvFileNode* stage_fn; 02092 CvFileNode* trees_fn; 02093 CvSeqReader trees_reader; 02094 02095 stage_fn = (CvFileNode*) stages_reader.ptr; 02096 if( !CV_NODE_IS_MAP( stage_fn->tag ) ) 02097 { 02098 sprintf( buf, "Invalid stage %d", i ); 02099 CV_Error( CV_StsError, buf ); 02100 } 02101 02102 trees_fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_TREES_NAME ); 02103 if( !trees_fn || !CV_NODE_IS_SEQ( trees_fn->tag ) 02104 || trees_fn->data.seq->total <= 0 ) 02105 { 02106 sprintf( buf, "Trees node is not a valid sequence. (stage %d)", i ); 02107 CV_Error( CV_StsError, buf ); 02108 } 02109 02110 cascade->stage_classifier[i].classifier = 02111 (CvHaarClassifier*) cvAlloc( trees_fn->data.seq->total 02112 * sizeof( cascade->stage_classifier[i].classifier[0] ) ); 02113 for( j = 0; j < trees_fn->data.seq->total; ++j ) 02114 { 02115 cascade->stage_classifier[i].classifier[j].haar_feature = NULL; 02116 } 02117 cascade->stage_classifier[i].count = trees_fn->data.seq->total; 02118 02119 cvStartReadSeq( trees_fn->data.seq, &trees_reader ); 02120 for( j = 0; j < trees_fn->data.seq->total; ++j ) 02121 { 02122 CvFileNode* tree_fn; 02123 CvSeqReader tree_reader; 02124 CvHaarClassifier* classifier; 02125 int last_idx; 02126 02127 classifier = &cascade->stage_classifier[i].classifier[j]; 02128 tree_fn = (CvFileNode*) trees_reader.ptr; 02129 if( !CV_NODE_IS_SEQ( tree_fn->tag ) || tree_fn->data.seq->total <= 0 ) 02130 { 02131 sprintf( buf, "Tree node is not a valid sequence." 02132 " (stage %d, tree %d)", i, j ); 02133 CV_Error( CV_StsError, buf ); 02134 } 02135 02136 classifier->count = tree_fn->data.seq->total; 02137 classifier->haar_feature = (CvHaarFeature*) cvAlloc( 02138 classifier->count * ( sizeof( *classifier->haar_feature ) + 02139 sizeof( *classifier->threshold ) + 02140 sizeof( *classifier->left ) + 02141 sizeof( *classifier->right ) ) + 02142 (classifier->count + 1) * sizeof( *classifier->alpha ) ); 02143 classifier->threshold = (float*) (classifier->haar_feature+classifier->count); 02144 classifier->left = (int*) (classifier->threshold + classifier->count); 02145 classifier->right = (int*) (classifier->left + classifier->count); 02146 classifier->alpha = (float*) (classifier->right + classifier->count); 02147 02148 cvStartReadSeq( tree_fn->data.seq, &tree_reader ); 02149 for( k = 0, last_idx = 0; k < tree_fn->data.seq->total; ++k ) 02150 { 02151 CvFileNode* node_fn; 02152 CvFileNode* feature_fn; 02153 CvFileNode* rects_fn; 02154 CvSeqReader rects_reader; 02155 02156 node_fn = (CvFileNode*) tree_reader.ptr; 02157 if( !CV_NODE_IS_MAP( node_fn->tag ) ) 02158 { 02159 sprintf( buf, "Tree node %d is not a valid map. (stage %d, tree %d)", 02160 k, i, j ); 02161 CV_Error( CV_StsError, buf ); 02162 } 02163 feature_fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_FEATURE_NAME ); 02164 if( !feature_fn || !CV_NODE_IS_MAP( feature_fn->tag ) ) 02165 { 02166 sprintf( buf, "Feature node is not a valid map. " 02167 "(stage %d, tree %d, node %d)", i, j, k ); 02168 CV_Error( CV_StsError, buf ); 02169 } 02170 rects_fn = cvGetFileNodeByName( fs, feature_fn, ICV_HAAR_RECTS_NAME ); 02171 if( !rects_fn || !CV_NODE_IS_SEQ( rects_fn->tag ) 02172 || rects_fn->data.seq->total < 1 02173 || rects_fn->data.seq->total > CV_HAAR_FEATURE_MAX ) 02174 { 02175 sprintf( buf, "Rects node is not a valid sequence. " 02176 "(stage %d, tree %d, node %d)", i, j, k ); 02177 CV_Error( CV_StsError, buf ); 02178 } 02179 cvStartReadSeq( rects_fn->data.seq, &rects_reader ); 02180 for( l = 0; l < rects_fn->data.seq->total; ++l ) 02181 { 02182 CvFileNode* rect_fn; 02183 CvRect r; 02184 02185 rect_fn = (CvFileNode*) rects_reader.ptr; 02186 if( !CV_NODE_IS_SEQ( rect_fn->tag ) || rect_fn->data.seq->total != 5 ) 02187 { 02188 sprintf( buf, "Rect %d is not a valid sequence. " 02189 "(stage %d, tree %d, node %d)", l, i, j, k ); 02190 CV_Error( CV_StsError, buf ); 02191 } 02192 02193 fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 0 ); 02194 if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i < 0 ) 02195 { 02196 sprintf( buf, "x coordinate must be non-negative integer. " 02197 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l ); 02198 CV_Error( CV_StsError, buf ); 02199 } 02200 r.x = fn->data.i; 02201 fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 1 ); 02202 if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i < 0 ) 02203 { 02204 sprintf( buf, "y coordinate must be non-negative integer. " 02205 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l ); 02206 CV_Error( CV_StsError, buf ); 02207 } 02208 r.y = fn->data.i; 02209 fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 2 ); 02210 if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 02211 || r.x + fn->data.i > cascade->orig_window_size.width ) 02212 { 02213 sprintf( buf, "width must be positive integer and " 02214 "(x + width) must not exceed window width. " 02215 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l ); 02216 CV_Error( CV_StsError, buf ); 02217 } 02218 r.width = fn->data.i; 02219 fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 3 ); 02220 if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 02221 || r.y + fn->data.i > cascade->orig_window_size.height ) 02222 { 02223 sprintf( buf, "height must be positive integer and " 02224 "(y + height) must not exceed window height. " 02225 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l ); 02226 CV_Error( CV_StsError, buf ); 02227 } 02228 r.height = fn->data.i; 02229 fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 4 ); 02230 if( !CV_NODE_IS_REAL( fn->tag ) ) 02231 { 02232 sprintf( buf, "weight must be real number. " 02233 "(stage %d, tree %d, node %d, rect %d)", i, j, k, l ); 02234 CV_Error( CV_StsError, buf ); 02235 } 02236 02237 classifier->haar_feature[k].rect[l].weight = (float) fn->data.f; 02238 classifier->haar_feature[k].rect[l].r = r; 02239 02240 CV_NEXT_SEQ_ELEM( sizeof( *rect_fn ), rects_reader ); 02241 } /* for each rect */ 02242 for( l = rects_fn->data.seq->total; l < CV_HAAR_FEATURE_MAX; ++l ) 02243 { 02244 classifier->haar_feature[k].rect[l].weight = 0; 02245 classifier->haar_feature[k].rect[l].r = cvRect( 0, 0, 0, 0 ); 02246 } 02247 02248 fn = cvGetFileNodeByName( fs, feature_fn, ICV_HAAR_TILTED_NAME); 02249 if( !fn || !CV_NODE_IS_INT( fn->tag ) ) 02250 { 02251 sprintf( buf, "tilted must be 0 or 1. " 02252 "(stage %d, tree %d, node %d)", i, j, k ); 02253 CV_Error( CV_StsError, buf ); 02254 } 02255 classifier->haar_feature[k].tilted = ( fn->data.i != 0 ); 02256 fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_THRESHOLD_NAME); 02257 if( !fn || !CV_NODE_IS_REAL( fn->tag ) ) 02258 { 02259 sprintf( buf, "threshold must be real number. " 02260 "(stage %d, tree %d, node %d)", i, j, k ); 02261 CV_Error( CV_StsError, buf ); 02262 } 02263 classifier->threshold[k] = (float) fn->data.f; 02264 fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_LEFT_NODE_NAME); 02265 if( fn ) 02266 { 02267 if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= k 02268 || fn->data.i >= tree_fn->data.seq->total ) 02269 { 02270 sprintf( buf, "left node must be valid node number. " 02271 "(stage %d, tree %d, node %d)", i, j, k ); 02272 CV_Error( CV_StsError, buf ); 02273 } 02274 /* left node */ 02275 classifier->left[k] = fn->data.i; 02276 } 02277 else 02278 { 02279 fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_LEFT_VAL_NAME ); 02280 if( !fn ) 02281 { 02282 sprintf( buf, "left node or left value must be specified. " 02283 "(stage %d, tree %d, node %d)", i, j, k ); 02284 CV_Error( CV_StsError, buf ); 02285 } 02286 if( !CV_NODE_IS_REAL( fn->tag ) ) 02287 { 02288 sprintf( buf, "left value must be real number. " 02289 "(stage %d, tree %d, node %d)", i, j, k ); 02290 CV_Error( CV_StsError, buf ); 02291 } 02292 /* left value */ 02293 if( last_idx >= classifier->count + 1 ) 02294 { 02295 sprintf( buf, "Tree structure is broken: too many values. " 02296 "(stage %d, tree %d, node %d)", i, j, k ); 02297 CV_Error( CV_StsError, buf ); 02298 } 02299 classifier->left[k] = -last_idx; 02300 classifier->alpha[last_idx++] = (float) fn->data.f; 02301 } 02302 fn = cvGetFileNodeByName( fs, node_fn,ICV_HAAR_RIGHT_NODE_NAME); 02303 if( fn ) 02304 { 02305 if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= k 02306 || fn->data.i >= tree_fn->data.seq->total ) 02307 { 02308 sprintf( buf, "right node must be valid node number. " 02309 "(stage %d, tree %d, node %d)", i, j, k ); 02310 CV_Error( CV_StsError, buf ); 02311 } 02312 /* right node */ 02313 classifier->right[k] = fn->data.i; 02314 } 02315 else 02316 { 02317 fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_RIGHT_VAL_NAME ); 02318 if( !fn ) 02319 { 02320 sprintf( buf, "right node or right value must be specified. " 02321 "(stage %d, tree %d, node %d)", i, j, k ); 02322 CV_Error( CV_StsError, buf ); 02323 } 02324 if( !CV_NODE_IS_REAL( fn->tag ) ) 02325 { 02326 sprintf( buf, "right value must be real number. " 02327 "(stage %d, tree %d, node %d)", i, j, k ); 02328 CV_Error( CV_StsError, buf ); 02329 } 02330 /* right value */ 02331 if( last_idx >= classifier->count + 1 ) 02332 { 02333 sprintf( buf, "Tree structure is broken: too many values. " 02334 "(stage %d, tree %d, node %d)", i, j, k ); 02335 CV_Error( CV_StsError, buf ); 02336 } 02337 classifier->right[k] = -last_idx; 02338 classifier->alpha[last_idx++] = (float) fn->data.f; 02339 } 02340 02341 CV_NEXT_SEQ_ELEM( sizeof( *node_fn ), tree_reader ); 02342 } /* for each node */ 02343 if( last_idx != classifier->count + 1 ) 02344 { 02345 sprintf( buf, "Tree structure is broken: too few values. " 02346 "(stage %d, tree %d)", i, j ); 02347 CV_Error( CV_StsError, buf ); 02348 } 02349 02350 CV_NEXT_SEQ_ELEM( sizeof( *tree_fn ), trees_reader ); 02351 } /* for each tree */ 02352 02353 fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_STAGE_THRESHOLD_NAME); 02354 if( !fn || !CV_NODE_IS_REAL( fn->tag ) ) 02355 { 02356 sprintf( buf, "stage threshold must be real number. (stage %d)", i ); 02357 CV_Error( CV_StsError, buf ); 02358 } 02359 cascade->stage_classifier[i].threshold = (float) fn->data.f; 02360 02361 parent = i - 1; 02362 next = -1; 02363 02364 fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_PARENT_NAME ); 02365 if( !fn || !CV_NODE_IS_INT( fn->tag ) 02366 || fn->data.i < -1 || fn->data.i >= cascade->count ) 02367 { 02368 sprintf( buf, "parent must be integer number. (stage %d)", i ); 02369 CV_Error( CV_StsError, buf ); 02370 } 02371 parent = fn->data.i; 02372 fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_NEXT_NAME ); 02373 if( !fn || !CV_NODE_IS_INT( fn->tag ) 02374 || fn->data.i < -1 || fn->data.i >= cascade->count ) 02375 { 02376 sprintf( buf, "next must be integer number. (stage %d)", i ); 02377 CV_Error( CV_StsError, buf ); 02378 } 02379 next = fn->data.i; 02380 02381 cascade->stage_classifier[i].parent = parent; 02382 cascade->stage_classifier[i].next = next; 02383 cascade->stage_classifier[i].child = -1; 02384 02385 if( parent != -1 && cascade->stage_classifier[parent].child == -1 ) 02386 { 02387 cascade->stage_classifier[parent].child = i; 02388 } 02389 02390 CV_NEXT_SEQ_ELEM( sizeof( *stage_fn ), stages_reader ); 02391 } /* for each stage */ 02392 02393 return cascade; 02394 } 02395 02396 static void 02397 icvWriteHaarClassifier( CvFileStorage* fs, const char* name, const void* struct_ptr, 02398 CvAttrList attributes ) 02399 { 02400 int i, j, k, l; 02401 char buf[256]; 02402 const CvHaarClassifierCascade* cascade = (const CvHaarClassifierCascade*) struct_ptr; 02403 02404 /* TODO: parameters check */ 02405 02406 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_HAAR, attributes ); 02407 02408 cvStartWriteStruct( fs, ICV_HAAR_SIZE_NAME, CV_NODE_SEQ | CV_NODE_FLOW ); 02409 cvWriteInt( fs, NULL, cascade->orig_window_size.width ); 02410 cvWriteInt( fs, NULL, cascade->orig_window_size.height ); 02411 cvEndWriteStruct( fs ); /* size */ 02412 02413 cvStartWriteStruct( fs, ICV_HAAR_STAGES_NAME, CV_NODE_SEQ ); 02414 for( i = 0; i < cascade->count; ++i ) 02415 { 02416 cvStartWriteStruct( fs, NULL, CV_NODE_MAP ); 02417 sprintf( buf, "stage %d", i ); 02418 cvWriteComment( fs, buf, 1 ); 02419 02420 cvStartWriteStruct( fs, ICV_HAAR_TREES_NAME, CV_NODE_SEQ ); 02421 02422 for( j = 0; j < cascade->stage_classifier[i].count; ++j ) 02423 { 02424 CvHaarClassifier* tree = &cascade->stage_classifier[i].classifier[j]; 02425 02426 cvStartWriteStruct( fs, NULL, CV_NODE_SEQ ); 02427 sprintf( buf, "tree %d", j ); 02428 cvWriteComment( fs, buf, 1 ); 02429 02430 for( k = 0; k < tree->count; ++k ) 02431 { 02432 CvHaarFeature* feature = &tree->haar_feature[k]; 02433 02434 cvStartWriteStruct( fs, NULL, CV_NODE_MAP ); 02435 if( k ) 02436 { 02437 sprintf( buf, "node %d", k ); 02438 } 02439 else 02440 { 02441 sprintf( buf, "root node" ); 02442 } 02443 cvWriteComment( fs, buf, 1 ); 02444 02445 cvStartWriteStruct( fs, ICV_HAAR_FEATURE_NAME, CV_NODE_MAP ); 02446 02447 cvStartWriteStruct( fs, ICV_HAAR_RECTS_NAME, CV_NODE_SEQ ); 02448 for( l = 0; l < CV_HAAR_FEATURE_MAX && feature->rect[l].r.width != 0; ++l ) 02449 { 02450 cvStartWriteStruct( fs, NULL, CV_NODE_SEQ | CV_NODE_FLOW ); 02451 cvWriteInt( fs, NULL, feature->rect[l].r.x ); 02452 cvWriteInt( fs, NULL, feature->rect[l].r.y ); 02453 cvWriteInt( fs, NULL, feature->rect[l].r.width ); 02454 cvWriteInt( fs, NULL, feature->rect[l].r.height ); 02455 cvWriteReal( fs, NULL, feature->rect[l].weight ); 02456 cvEndWriteStruct( fs ); /* rect */ 02457 } 02458 cvEndWriteStruct( fs ); /* rects */ 02459 cvWriteInt( fs, ICV_HAAR_TILTED_NAME, feature->tilted ); 02460 cvEndWriteStruct( fs ); /* feature */ 02461 02462 cvWriteReal( fs, ICV_HAAR_THRESHOLD_NAME, tree->threshold[k]); 02463 02464 if( tree->left[k] > 0 ) 02465 { 02466 cvWriteInt( fs, ICV_HAAR_LEFT_NODE_NAME, tree->left[k] ); 02467 } 02468 else 02469 { 02470 cvWriteReal( fs, ICV_HAAR_LEFT_VAL_NAME, 02471 tree->alpha[-tree->left[k]] ); 02472 } 02473 02474 if( tree->right[k] > 0 ) 02475 { 02476 cvWriteInt( fs, ICV_HAAR_RIGHT_NODE_NAME, tree->right[k] ); 02477 } 02478 else 02479 { 02480 cvWriteReal( fs, ICV_HAAR_RIGHT_VAL_NAME, 02481 tree->alpha[-tree->right[k]] ); 02482 } 02483 02484 cvEndWriteStruct( fs ); /* split */ 02485 } 02486 02487 cvEndWriteStruct( fs ); /* tree */ 02488 } 02489 02490 cvEndWriteStruct( fs ); /* trees */ 02491 02492 cvWriteReal( fs, ICV_HAAR_STAGE_THRESHOLD_NAME, cascade->stage_classifier[i].threshold); 02493 cvWriteInt( fs, ICV_HAAR_PARENT_NAME, cascade->stage_classifier[i].parent ); 02494 cvWriteInt( fs, ICV_HAAR_NEXT_NAME, cascade->stage_classifier[i].next ); 02495 02496 cvEndWriteStruct( fs ); /* stage */ 02497 } /* for each stage */ 02498 02499 cvEndWriteStruct( fs ); /* stages */ 02500 cvEndWriteStruct( fs ); /* root */ 02501 } 02502 02503 static void* 02504 icvCloneHaarClassifier( const void* struct_ptr ) 02505 { 02506 CvHaarClassifierCascade* cascade = NULL; 02507 02508 int i, j, k, n; 02509 const CvHaarClassifierCascade* cascade_src = 02510 (const CvHaarClassifierCascade*) struct_ptr; 02511 02512 n = cascade_src->count; 02513 cascade = icvCreateHaarClassifierCascade(n); 02514 cascade->orig_window_size = cascade_src->orig_window_size; 02515 02516 for( i = 0; i < n; ++i ) 02517 { 02518 cascade->stage_classifier[i].parent = cascade_src->stage_classifier[i].parent; 02519 cascade->stage_classifier[i].next = cascade_src->stage_classifier[i].next; 02520 cascade->stage_classifier[i].child = cascade_src->stage_classifier[i].child; 02521 cascade->stage_classifier[i].threshold = cascade_src->stage_classifier[i].threshold; 02522 02523 cascade->stage_classifier[i].count = 0; 02524 cascade->stage_classifier[i].classifier = 02525 (CvHaarClassifier*) cvAlloc( cascade_src->stage_classifier[i].count 02526 * sizeof( cascade->stage_classifier[i].classifier[0] ) ); 02527 02528 cascade->stage_classifier[i].count = cascade_src->stage_classifier[i].count; 02529 02530 for( j = 0; j < cascade->stage_classifier[i].count; ++j ) 02531 cascade->stage_classifier[i].classifier[j].haar_feature = NULL; 02532 02533 for( j = 0; j < cascade->stage_classifier[i].count; ++j ) 02534 { 02535 const CvHaarClassifier* classifier_src = 02536 &cascade_src->stage_classifier[i].classifier[j]; 02537 CvHaarClassifier* classifier = 02538 &cascade->stage_classifier[i].classifier[j]; 02539 02540 classifier->count = classifier_src->count; 02541 classifier->haar_feature = (CvHaarFeature*) cvAlloc( 02542 classifier->count * ( sizeof( *classifier->haar_feature ) + 02543 sizeof( *classifier->threshold ) + 02544 sizeof( *classifier->left ) + 02545 sizeof( *classifier->right ) ) + 02546 (classifier->count + 1) * sizeof( *classifier->alpha ) ); 02547 classifier->threshold = (float*) (classifier->haar_feature+classifier->count); 02548 classifier->left = (int*) (classifier->threshold + classifier->count); 02549 classifier->right = (int*) (classifier->left + classifier->count); 02550 classifier->alpha = (float*) (classifier->right + classifier->count); 02551 for( k = 0; k < classifier->count; ++k ) 02552 { 02553 classifier->haar_feature[k] = classifier_src->haar_feature[k]; 02554 classifier->threshold[k] = classifier_src->threshold[k]; 02555 classifier->left[k] = classifier_src->left[k]; 02556 classifier->right[k] = classifier_src->right[k]; 02557 classifier->alpha[k] = classifier_src->alpha[k]; 02558 } 02559 classifier->alpha[classifier->count] = 02560 classifier_src->alpha[classifier->count]; 02561 } 02562 } 02563 02564 return cascade; 02565 } 02566 02567 02568 CvType haar_type( CV_TYPE_NAME_HAAR, icvIsHaarClassifier, 02569 (CvReleaseFunc)cvReleaseHaarClassifierCascade, 02570 icvReadHaarClassifier, icvWriteHaarClassifier, 02571 icvCloneHaarClassifier ); 02572 02573 /* End of file. */ 02574
Generated on Tue Jul 12 2022 14:46:47 by
1.7.2
