00001 /*! @file ObjRec/test-faceDet.C test face detection */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/ObjRec/test-faceDet.C $ 00035 // $Id: test-faceDet.C 13716 2010-07-28 22:07:03Z itti $ 00036 // 00037 00038 00039 #include "Image/OpenCVUtil.H" 00040 #include "Component/ModelManager.H" 00041 #include "Image/Image.H" 00042 #include "Image/Transforms.H" 00043 #include "Image/DrawOps.H" 00044 #include "Image/Rectangle.H" 00045 #include "Image/MathOps.H" 00046 #include "Media/FrameSeries.H" 00047 #include "Transport/FrameInfo.H" 00048 #include "Raster/GenericFrame.H" 00049 #include "Raster/Raster.H" 00050 #include "GUI/DebugWin.H" 00051 #include "Neuro/BeoHeadBrain.H" 00052 #include "Util/Timer.H" 00053 00054 static CvMemStorage* storage = 0; 00055 static CvHaarClassifierCascade* cascade = 0; 00056 00057 #include <stdio.h> 00058 00059 00060 //these settings affect the quality of detection: change with care 00061 #define CV_ADJUST_FEATURES 1 00062 #define CV_ADJUST_WEIGHTS 0 00063 00064 typedef int sumtype; 00065 typedef double sqsumtype; 00066 00067 void* cvAlignPtr( const void* ptr, int align=32 ) 00068 { 00069 assert( (align & (align-1)) == 0 ); 00070 return (void*)( ((size_t)ptr + align - 1) & ~(size_t)(align-1) ); 00071 } 00072 00073 typedef struct CvHidHaarFeature 00074 { 00075 struct 00076 { 00077 sumtype *p0, *p1, *p2, *p3; 00078 float weight; 00079 } 00080 rect[CV_HAAR_FEATURE_MAX]; 00081 } 00082 CvHidHaarFeature; 00083 00084 00085 typedef struct CvHidHaarTreeNode 00086 { 00087 CvHidHaarFeature feature; 00088 float threshold; 00089 int left; 00090 int right; 00091 } 00092 CvHidHaarTreeNode; 00093 00094 00095 typedef struct CvHidHaarClassifier 00096 { 00097 int count; 00098 //CvHaarFeature* orig_feature; 00099 CvHidHaarTreeNode* node; 00100 float* alpha; 00101 } 00102 CvHidHaarClassifier; 00103 00104 00105 typedef struct CvHidHaarStageClassifier 00106 { 00107 int count; 00108 float threshold; 00109 CvHidHaarClassifier* classifier; 00110 int two_rects; 00111 00112 struct CvHidHaarStageClassifier* next; 00113 struct CvHidHaarStageClassifier* child; 00114 struct CvHidHaarStageClassifier* parent; 00115 } 00116 CvHidHaarStageClassifier; 00117 00118 00119 struct CvHidHaarClassifierCascade 00120 { 00121 int count; 00122 int is_stump_based; 00123 int has_tilted_features; 00124 int is_tree; 00125 double inv_window_area; 00126 CvMat sum, sqsum, tilted; 00127 CvHidHaarStageClassifier* stage_classifier; 00128 sqsumtype *pq0, *pq1, *pq2, *pq3; 00129 sumtype *p0, *p1, *p2, *p3; 00130 00131 void** ipp_stages; 00132 }; 00133 00134 00135 // IPP functions for object detection 00136 int icvHaarClassifierInitAlloc_32f_p = 0; 00137 int icvHaarClassifierFree_32f_p = 0; 00138 int icvApplyHaarClassifier_32s32f_C1R_p = 0; 00139 int icvRectStdDev_32s32f_C1R_p = 0; 00140 00141 const int icv_object_win_border = 1; 00142 const float icv_stage_threshold_bias = 0.0001f; 00143 00144 //static CvHaarClassifierCascade* 00145 //icvCreateHaarClassifierCascade( int stage_count ) 00146 //{ 00147 // CvHaarClassifierCascade* cascade = 0; 00148 // 00149 // CV_FUNCNAME( "icvCreateHaarClassifierCascade" ); 00150 // 00151 // __BEGIN__; 00152 // 00153 // int block_size = sizeof(*cascade) + stage_count*sizeof(*cascade->stage_classifier); 00154 // 00155 // if( stage_count <= 0 ) 00156 // CV_ERROR( CV_StsOutOfRange, "Number of stages should be positive" ); 00157 // 00158 // CV_CALL( cascade = (CvHaarClassifierCascade*)cvAlloc( block_size )); 00159 // memset( cascade, 0, block_size ); 00160 // 00161 // cascade->stage_classifier = (CvHaarStageClassifier*)(cascade + 1); 00162 // cascade->flags = CV_HAAR_MAGIC_VAL; 00163 // cascade->count = stage_count; 00164 // 00165 // __END__; 00166 // 00167 // return cascade; 00168 //} 00169 00170 static void 00171 icvReleaseHidHaarClassifierCascade( CvHidHaarClassifierCascade** _cascade ) 00172 { 00173 if( _cascade && *_cascade ) 00174 { 00175 CvHidHaarClassifierCascade* cascade = *_cascade; 00176 if( cascade->ipp_stages && icvHaarClassifierFree_32f_p ) 00177 { 00178 int i; 00179 for( i = 0; i < cascade->count; i++ ) 00180 { 00181 //if( cascade->ipp_stages[i] ) 00182 // icvHaarClassifierFree_32f_p( cascade->ipp_stages[i] ); 00183 } 00184 } 00185 //cvFree( &cascade->ipp_stages ); 00186 //cvFree((void**) _cascade ); 00187 } 00188 } 00189 00190 // create more efficient internal representation of haar classifier cascade 00191 static CvHidHaarClassifierCascade* 00192 icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) 00193 { 00194 CvRect* ipp_features = 0; 00195 float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0; 00196 int* ipp_counts = 0; 00197 00198 CvHidHaarClassifierCascade* out = 0; 00199 00200 CV_FUNCNAME( "icvCreateHidHaarClassifierCascade" ); 00201 00202 __BEGIN__; 00203 00204 int i, j, k, l; 00205 int datasize; 00206 int total_classifiers = 0; 00207 int total_nodes = 0; 00208 char errorstr[100]; 00209 CvHidHaarClassifier* haar_classifier_ptr; 00210 CvHidHaarTreeNode* haar_node_ptr; 00211 CvSize orig_window_size; 00212 int has_tilted_features = 0; 00213 int max_count = 0; 00214 00215 if( !CV_IS_HAAR_CLASSIFIER(cascade) ) 00216 CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" ); 00217 00218 if( cascade->hid_cascade ) 00219 CV_ERROR( CV_StsError, "hid_cascade has been already created" ); 00220 00221 if( !cascade->stage_classifier ) 00222 CV_ERROR( CV_StsNullPtr, "" ); 00223 00224 if( cascade->count <= 0 ) 00225 CV_ERROR( CV_StsOutOfRange, "Negative number of cascade stages" ); 00226 00227 orig_window_size = cascade->orig_window_size; 00228 00229 // check input structure correctness and calculate total memory size needed for 00230 // internal representation of the classifier cascade 00231 for( i = 0; i < cascade->count; i++ ) 00232 { 00233 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i; 00234 00235 if( !stage_classifier->classifier || 00236 stage_classifier->count <= 0 ) 00237 { 00238 sprintf( errorstr, "header of the stage classifier #%d is invalid " 00239 "(has null pointers or non-positive classfier count)", i ); 00240 CV_ERROR( CV_StsError, errorstr ); 00241 } 00242 00243 max_count = MAX( max_count, stage_classifier->count ); 00244 total_classifiers += stage_classifier->count; 00245 00246 for( j = 0; j < stage_classifier->count; j++ ) 00247 { 00248 CvHaarClassifier* classifier = stage_classifier->classifier + j; 00249 00250 total_nodes += classifier->count; 00251 for( l = 0; l < classifier->count; l++ ) 00252 { 00253 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ ) 00254 { 00255 if( classifier->haar_feature[l].rect[k].r.width ) 00256 { 00257 CvRect r = classifier->haar_feature[l].rect[k].r; 00258 int tilted = classifier->haar_feature[l].tilted; 00259 has_tilted_features |= tilted != 0; 00260 if( r.width < 0 || r.height < 0 || r.y < 0 || 00261 r.x + r.width > orig_window_size.width 00262 || 00263 (!tilted && 00264 (r.x < 0 || r.y + r.height > orig_window_size.height)) 00265 || 00266 (tilted && (r.x - r.height < 0 || 00267 r.y + r.width + r.height > orig_window_size.height))) 00268 { 00269 sprintf( errorstr, "rectangle #%d of the classifier #%d of " 00270 "the stage classifier #%d is not inside " 00271 "the reference (original) cascade window", k, j, i ); 00272 CV_ERROR( CV_StsNullPtr, errorstr ); 00273 } 00274 } 00275 } 00276 } 00277 } 00278 } 00279 00280 // this is an upper boundary for the whole hidden cascade size 00281 datasize = sizeof(CvHidHaarClassifierCascade) + 00282 sizeof(CvHidHaarStageClassifier)*cascade->count + 00283 sizeof(CvHidHaarClassifier) * total_classifiers + 00284 sizeof(CvHidHaarTreeNode) * total_nodes + 00285 sizeof(void*)*(total_nodes + total_classifiers); 00286 00287 CV_CALL( out = (CvHidHaarClassifierCascade*)cvAlloc( datasize )); 00288 memset( out, 0, sizeof(*out) ); 00289 00290 // init header 00291 out->count = cascade->count; 00292 out->stage_classifier = (CvHidHaarStageClassifier*)(out + 1); 00293 haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count); 00294 haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers); 00295 00296 out->is_stump_based = 1; 00297 out->has_tilted_features = has_tilted_features; 00298 out->is_tree = 0; 00299 00300 // initialize internal representation 00301 for( i = 0; i < cascade->count; i++ ) 00302 { 00303 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i; 00304 CvHidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i; 00305 00306 hid_stage_classifier->count = stage_classifier->count; 00307 hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias; 00308 hid_stage_classifier->classifier = haar_classifier_ptr; 00309 hid_stage_classifier->two_rects = 1; 00310 haar_classifier_ptr += stage_classifier->count; 00311 00312 hid_stage_classifier->parent = (stage_classifier->parent == -1) 00313 ? NULL : out->stage_classifier + stage_classifier->parent; 00314 hid_stage_classifier->next = (stage_classifier->next == -1) 00315 ? NULL : out->stage_classifier + stage_classifier->next; 00316 hid_stage_classifier->child = (stage_classifier->child == -1) 00317 ? NULL : out->stage_classifier + stage_classifier->child; 00318 00319 out->is_tree |= hid_stage_classifier->next != NULL; 00320 00321 for( j = 0; j < stage_classifier->count; j++ ) 00322 { 00323 CvHaarClassifier* classifier = stage_classifier->classifier + j; 00324 CvHidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j; 00325 int node_count = classifier->count; 00326 float* alpha_ptr = (float*)(haar_node_ptr + node_count); 00327 00328 hid_classifier->count = node_count; 00329 hid_classifier->node = haar_node_ptr; 00330 hid_classifier->alpha = alpha_ptr; 00331 00332 for( l = 0; l < node_count; l++ ) 00333 { 00334 CvHidHaarTreeNode* node = hid_classifier->node + l; 00335 CvHaarFeature* feature = classifier->haar_feature + l; 00336 memset( node, -1, sizeof(*node) ); 00337 node->threshold = classifier->threshold[l]; 00338 node->left = classifier->left[l]; 00339 node->right = classifier->right[l]; 00340 00341 if( fabs(feature->rect[2].weight) < DBL_EPSILON || 00342 feature->rect[2].r.width == 0 || 00343 feature->rect[2].r.height == 0 ) 00344 memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) ); 00345 else 00346 hid_stage_classifier->two_rects = 0; 00347 } 00348 00349 memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0])); 00350 haar_node_ptr = 00351 (CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*)); 00352 00353 out->is_stump_based &= node_count == 1; 00354 } 00355 } 00356 00357 // 00358 // NOTE: Currently, OpenMP is implemented and IPP modes are incompatible. 00359 // 00360 #ifndef _OPENMP 00361 { 00362 int can_use_ipp = icvHaarClassifierInitAlloc_32f_p != 0 && 00363 icvHaarClassifierFree_32f_p != 0 && 00364 icvApplyHaarClassifier_32s32f_C1R_p != 0 && 00365 icvRectStdDev_32s32f_C1R_p != 0 && 00366 !out->has_tilted_features && !out->is_tree && out->is_stump_based; 00367 00368 if( can_use_ipp ) 00369 { 00370 int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]); 00371 float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)* 00372 (orig_window_size.height-icv_object_win_border*2))); 00373 00374 CV_CALL( out->ipp_stages = (void**)cvAlloc( ipp_datasize )); 00375 memset( out->ipp_stages, 0, ipp_datasize ); 00376 00377 CV_CALL( ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) )); 00378 CV_CALL( ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) )); 00379 CV_CALL( ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) )); 00380 CV_CALL( ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) )); 00381 CV_CALL( ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) )); 00382 CV_CALL( ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) )); 00383 00384 for( i = 0; i < cascade->count; i++ ) 00385 { 00386 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i; 00387 for( j = 0, k = 0; j < stage_classifier->count; j++ ) 00388 { 00389 CvHaarClassifier* classifier = stage_classifier->classifier + j; 00390 int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0); 00391 00392 ipp_thresholds[j] = classifier->threshold[0]; 00393 ipp_val1[j] = classifier->alpha[0]; 00394 ipp_val2[j] = classifier->alpha[1]; 00395 ipp_counts[j] = rect_count; 00396 00397 for( l = 0; l < rect_count; l++, k++ ) 00398 { 00399 ipp_features[k] = classifier->haar_feature->rect[l].r; 00400 //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height; 00401 ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale; 00402 } 00403 } 00404 00405 //if( icvHaarClassifierInitAlloc_32f_p( &out->ipp_stages[i], 00406 // ipp_features, ipp_weights, ipp_thresholds, 00407 // ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 ) 00408 // break; 00409 } 00410 00411 if( i < cascade->count ) 00412 { 00413 //for( j = 0; j < i; j++ ) 00414 // // if( icvHaarClassifierFree_32f_p && out->ipp_stages[i] ) 00415 // // icvHaarClassifierFree_32f_p( out->ipp_stages[i] ); 00416 //cvFree( &out->ipp_stages ); 00417 } 00418 } 00419 } 00420 #endif 00421 00422 cascade->hid_cascade = out; 00423 assert( (char*)haar_node_ptr - (char*)out <= datasize ); 00424 00425 __END__; 00426 00427 if( cvGetErrStatus() < 0 ) 00428 icvReleaseHidHaarClassifierCascade( &out ); 00429 00430 //cvFree( &ipp_features ); 00431 //cvFree( &ipp_weights ); 00432 //cvFree( &ipp_thresholds ); 00433 //cvFree( &ipp_val1 ); 00434 //cvFree( &ipp_val2 ); 00435 //cvFree( &ipp_counts ); 00436 00437 return out; 00438 } 00439 00440 00441 #define sum_elem_ptr(sum,row,col) \ 00442 ((sumtype*)CV_MAT_ELEM_PTR_FAST((sum),(row),(col),sizeof(sumtype))) 00443 00444 #define sqsum_elem_ptr(sqsum,row,col) \ 00445 ((sqsumtype*)CV_MAT_ELEM_PTR_FAST((sqsum),(row),(col),sizeof(sqsumtype))) 00446 00447 #define calc_sum(rect,offset) \ 00448 ((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset]) 00449 00450 00451 void 00452 cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* _cascade, 00453 const CvArr* _sum, 00454 const CvArr* _sqsum, 00455 const CvArr* _tilted_sum, 00456 double scale ) 00457 { 00458 CV_FUNCNAME("cvSetImagesForHaarClassifierCascade"); 00459 00460 __BEGIN__; 00461 00462 CvMat sum_stub, *sum = (CvMat*)_sum; 00463 CvMat sqsum_stub, *sqsum = (CvMat*)_sqsum; 00464 CvMat tilted_stub, *tilted = (CvMat*)_tilted_sum; 00465 CvHidHaarClassifierCascade* cascade; 00466 int coi0 = 0, coi1 = 0; 00467 int i; 00468 CvRect equ_rect; 00469 double weight_scale; 00470 00471 if( !CV_IS_HAAR_CLASSIFIER(_cascade) ) 00472 CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" ); 00473 00474 if( scale <= 0 ) 00475 CV_ERROR( CV_StsOutOfRange, "Scale must be positive" ); 00476 00477 CV_CALL( sum = cvGetMat( sum, &sum_stub, &coi0 )); 00478 CV_CALL( sqsum = cvGetMat( sqsum, &sqsum_stub, &coi1 )); 00479 00480 if( coi0 || coi1 ) 00481 CV_ERROR( CV_BadCOI, "COI is not supported" ); 00482 00483 if( !CV_ARE_SIZES_EQ( sum, sqsum )) 00484 CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" ); 00485 00486 if( CV_MAT_TYPE(sqsum->type) != CV_64FC1 || 00487 CV_MAT_TYPE(sum->type) != CV_32SC1 ) 00488 CV_ERROR( CV_StsUnsupportedFormat, 00489 "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" ); 00490 00491 if( !_cascade->hid_cascade ) 00492 CV_CALL( icvCreateHidHaarClassifierCascade(_cascade) ); 00493 00494 cascade = _cascade->hid_cascade; 00495 00496 if( cascade->has_tilted_features ) 00497 { 00498 CV_CALL( tilted = cvGetMat( tilted, &tilted_stub, &coi1 )); 00499 00500 if( CV_MAT_TYPE(tilted->type) != CV_32SC1 ) 00501 CV_ERROR( CV_StsUnsupportedFormat, 00502 "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" ); 00503 00504 if( sum->step != tilted->step ) 00505 CV_ERROR( CV_StsUnmatchedSizes, 00506 "Sum and tilted_sum must have the same stride (step, widthStep)" ); 00507 00508 if( !CV_ARE_SIZES_EQ( sum, tilted )) 00509 CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" ); 00510 cascade->tilted = *tilted; 00511 } 00512 00513 _cascade->scale = scale; 00514 _cascade->real_window_size.width = cvRound( _cascade->orig_window_size.width * scale ); 00515 _cascade->real_window_size.height = cvRound( _cascade->orig_window_size.height * scale ); 00516 00517 cascade->sum = *sum; 00518 cascade->sqsum = *sqsum; 00519 00520 equ_rect.x = equ_rect.y = cvRound(scale); 00521 equ_rect.width = cvRound((_cascade->orig_window_size.width-2)*scale); 00522 equ_rect.height = cvRound((_cascade->orig_window_size.height-2)*scale); 00523 weight_scale = 1./(equ_rect.width*equ_rect.height); 00524 cascade->inv_window_area = weight_scale; 00525 00526 cascade->p0 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x); 00527 cascade->p1 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x + equ_rect.width ); 00528 cascade->p2 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height, equ_rect.x ); 00529 cascade->p3 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height, 00530 equ_rect.x + equ_rect.width ); 00531 00532 cascade->pq0 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x); 00533 cascade->pq1 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x + equ_rect.width ); 00534 cascade->pq2 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height, equ_rect.x ); 00535 cascade->pq3 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height, 00536 equ_rect.x + equ_rect.width ); 00537 00538 // init pointers in haar features according to real window size and 00539 // given image pointers 00540 { 00541 #ifdef _OPENMP 00542 int max_threads = cvGetNumThreads(); 00543 #pragma omp parallel for num_threads(max_threads), schedule(dynamic) 00544 #endif // _OPENMP 00545 for( i = 0; i < _cascade->count; i++ ) 00546 { 00547 int j, k, l; 00548 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 00549 { 00550 for( l = 0; l < cascade->stage_classifier[i].classifier[j].count; l++ ) 00551 { 00552 CvHaarFeature* feature = 00553 &_cascade->stage_classifier[i].classifier[j].haar_feature[l]; 00554 // CvHidHaarClassifier* classifier = 00555 // cascade->stage_classifier[i].classifier + j; 00556 CvHidHaarFeature* hidfeature = 00557 &cascade->stage_classifier[i].classifier[j].node[l].feature; 00558 double sum0 = 0, area0 = 0; 00559 CvRect r[3]; 00560 #if CV_ADJUST_FEATURES 00561 int base_w = -1, base_h = -1; 00562 int new_base_w = 0, new_base_h = 0; 00563 int kx, ky; 00564 int flagx = 0, flagy = 0; 00565 int x0 = 0, y0 = 0; 00566 #endif 00567 int nr; 00568 00569 // align blocks 00570 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ ) 00571 { 00572 if( !hidfeature->rect[k].p0 ) 00573 break; 00574 #if CV_ADJUST_FEATURES 00575 r[k] = feature->rect[k].r; 00576 base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].width-1) ); 00577 base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].x - r[0].x-1) ); 00578 base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].height-1) ); 00579 base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].y - r[0].y-1) ); 00580 #endif 00581 } 00582 00583 nr = k; 00584 00585 #if CV_ADJUST_FEATURES 00586 base_w += 1; 00587 base_h += 1; 00588 kx = r[0].width / base_w; 00589 ky = r[0].height / base_h; 00590 00591 if( kx <= 0 ) 00592 { 00593 flagx = 1; 00594 new_base_w = cvRound( r[0].width * scale ) / kx; 00595 x0 = cvRound( r[0].x * scale ); 00596 } 00597 00598 if( ky <= 0 ) 00599 { 00600 flagy = 1; 00601 new_base_h = cvRound( r[0].height * scale ) / ky; 00602 y0 = cvRound( r[0].y * scale ); 00603 } 00604 #endif 00605 00606 for( k = 0; k < nr; k++ ) 00607 { 00608 CvRect tr; 00609 double correction_ratio; 00610 00611 #if CV_ADJUST_FEATURES 00612 if( flagx ) 00613 { 00614 tr.x = (r[k].x - r[0].x) * new_base_w / base_w + x0; 00615 tr.width = r[k].width * new_base_w / base_w; 00616 } 00617 else 00618 #endif 00619 { 00620 tr.x = cvRound( r[k].x * scale ); 00621 tr.width = cvRound( r[k].width * scale ); 00622 } 00623 00624 #if CV_ADJUST_FEATURES 00625 if( flagy ) 00626 { 00627 tr.y = (r[k].y - r[0].y) * new_base_h / base_h + y0; 00628 tr.height = r[k].height * new_base_h / base_h; 00629 } 00630 else 00631 #endif 00632 { 00633 tr.y = cvRound( r[k].y * scale ); 00634 tr.height = cvRound( r[k].height * scale ); 00635 } 00636 00637 #if CV_ADJUST_WEIGHTS 00638 { 00639 // RAINER START 00640 const float orig_feature_size = (float)(feature->rect[k].r.width)*feature->rect[k].r.height; 00641 const float orig_norm_size = (float)(_cascade->orig_window_size.width)*(_cascade->orig_window_size.height); 00642 const float feature_size = float(tr.width*tr.height); 00643 //const float normSize = float(equ_rect.width*equ_rect.height); 00644 float target_ratio = orig_feature_size / orig_norm_size; 00645 //float isRatio = featureSize / normSize; 00646 //correctionRatio = targetRatio / isRatio / normSize; 00647 correction_ratio = target_ratio / feature_size; 00648 // RAINER END 00649 } 00650 #else 00651 correction_ratio = weight_scale * (!feature->tilted ? 1 : 0.5); 00652 #endif 00653 00654 if( !feature->tilted ) 00655 { 00656 hidfeature->rect[k].p0 = sum_elem_ptr(*sum, tr.y, tr.x); 00657 hidfeature->rect[k].p1 = sum_elem_ptr(*sum, tr.y, tr.x + tr.width); 00658 hidfeature->rect[k].p2 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x); 00659 hidfeature->rect[k].p3 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x + tr.width); 00660 } 00661 else 00662 { 00663 hidfeature->rect[k].p2 = sum_elem_ptr(*tilted, tr.y + tr.width, tr.x + tr.width); 00664 hidfeature->rect[k].p3 = sum_elem_ptr(*tilted, tr.y + tr.width + tr.height, 00665 tr.x + tr.width - tr.height); 00666 hidfeature->rect[k].p0 = sum_elem_ptr(*tilted, tr.y, tr.x); 00667 hidfeature->rect[k].p1 = sum_elem_ptr(*tilted, tr.y + tr.height, tr.x - tr.height); 00668 } 00669 00670 hidfeature->rect[k].weight = (float)(feature->rect[k].weight * correction_ratio); 00671 00672 if( k == 0 ) 00673 area0 = tr.width * tr.height; 00674 else 00675 sum0 += hidfeature->rect[k].weight * tr.width * tr.height; 00676 } 00677 00678 hidfeature->rect[0].weight = (float)(-sum0/area0); 00679 } // l 00680 } // j 00681 } 00682 } 00683 00684 __END__; 00685 } 00686 00687 00688 CV_INLINE 00689 double icvEvalHidHaarClassifier( CvHidHaarClassifier* classifier, 00690 double variance_norm_factor, 00691 size_t p_offset ) 00692 { 00693 int idx = 0; 00694 do 00695 { 00696 CvHidHaarTreeNode* node = classifier->node + idx; 00697 double t = node->threshold * variance_norm_factor; 00698 00699 double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 00700 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 00701 00702 if( node->feature.rect[2].p0 ) 00703 sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight; 00704 00705 idx = sum < t ? node->left : node->right; 00706 } 00707 while( idx > 0 ); 00708 return classifier->alpha[-idx]; 00709 } 00710 00711 00712 int 00713 cvRunHaarClassifierCascade( CvHaarClassifierCascade* _cascade, 00714 CvPoint pt, int start_stage ) 00715 { 00716 int result = -1; 00717 CV_FUNCNAME("cvRunHaarClassifierCascade"); 00718 00719 __BEGIN__; 00720 00721 int p_offset, pq_offset; 00722 int i, j; 00723 double mean, variance_norm_factor; 00724 CvHidHaarClassifierCascade* cascade; 00725 00726 if( !CV_IS_HAAR_CLASSIFIER(_cascade) ) 00727 CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid cascade pointer" ); 00728 00729 cascade = _cascade->hid_cascade; 00730 if( !cascade ) 00731 CV_ERROR( CV_StsNullPtr, "Hidden cascade has not been created.\n" 00732 "Use cvSetImagesForHaarClassifierCascade" ); 00733 00734 if( pt.x < 0 || pt.y < 0 || 00735 pt.x + _cascade->real_window_size.width >= cascade->sum.width-2 || 00736 pt.y + _cascade->real_window_size.height >= cascade->sum.height-2 ) 00737 EXIT; 00738 00739 p_offset = pt.y * (cascade->sum.step/sizeof(sumtype)) + pt.x; 00740 pq_offset = pt.y * (cascade->sqsum.step/sizeof(sqsumtype)) + pt.x; 00741 mean = calc_sum(*cascade,p_offset)*cascade->inv_window_area; 00742 variance_norm_factor = cascade->pq0[pq_offset] - cascade->pq1[pq_offset] - 00743 cascade->pq2[pq_offset] + cascade->pq3[pq_offset]; 00744 variance_norm_factor = variance_norm_factor*cascade->inv_window_area - mean*mean; 00745 if( variance_norm_factor >= 0. ) 00746 variance_norm_factor = sqrt(variance_norm_factor); 00747 else 00748 variance_norm_factor = 1.; 00749 00750 if( cascade->is_tree ) 00751 { 00752 CvHidHaarStageClassifier* ptr; 00753 assert( start_stage == 0 ); 00754 00755 result = 1; 00756 ptr = cascade->stage_classifier; 00757 00758 while( ptr ) 00759 { 00760 double stage_sum = 0; 00761 00762 for( j = 0; j < ptr->count; j++ ) 00763 { 00764 stage_sum += icvEvalHidHaarClassifier( ptr->classifier + j, 00765 variance_norm_factor, p_offset ); 00766 } 00767 00768 if( stage_sum >= ptr->threshold ) 00769 { 00770 ptr = ptr->child; 00771 } 00772 else 00773 { 00774 while( ptr && ptr->next == NULL ) ptr = ptr->parent; 00775 if( ptr == NULL ) 00776 { 00777 result = 0; 00778 EXIT; 00779 } 00780 ptr = ptr->next; 00781 } 00782 } 00783 } 00784 else if( cascade->is_stump_based ) 00785 { 00786 for( i = start_stage; i < cascade->count; i++ ) 00787 { 00788 double stage_sum = 0; 00789 00790 if( cascade->stage_classifier[i].two_rects ) 00791 { 00792 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 00793 { 00794 CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 00795 CvHidHaarTreeNode* node = classifier->node; 00796 double sum, t = node->threshold*variance_norm_factor, a, b; 00797 00798 sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 00799 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 00800 00801 a = classifier->alpha[0]; 00802 b = classifier->alpha[1]; 00803 stage_sum += sum < t ? a : b; 00804 } 00805 } 00806 else 00807 { 00808 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 00809 { 00810 CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j; 00811 CvHidHaarTreeNode* node = classifier->node; 00812 double sum, t = node->threshold*variance_norm_factor, a, b; 00813 00814 sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight; 00815 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight; 00816 00817 if( node->feature.rect[2].p0 ) 00818 sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight; 00819 00820 a = classifier->alpha[0]; 00821 b = classifier->alpha[1]; 00822 stage_sum += sum < t ? a : b; 00823 } 00824 } 00825 00826 if( stage_sum < cascade->stage_classifier[i].threshold ) 00827 { 00828 result = -i; 00829 EXIT; 00830 } 00831 } 00832 } 00833 else 00834 { 00835 for( i = start_stage; i < cascade->count; i++ ) 00836 { 00837 double stage_sum = 0; 00838 00839 for( j = 0; j < cascade->stage_classifier[i].count; j++ ) 00840 { 00841 stage_sum += icvEvalHidHaarClassifier( 00842 cascade->stage_classifier[i].classifier + j, 00843 variance_norm_factor, p_offset ); 00844 } 00845 00846 if( stage_sum < cascade->stage_classifier[i].threshold ) 00847 { 00848 result = -i; 00849 EXIT; 00850 } 00851 } 00852 } 00853 00854 result = 1; 00855 00856 __END__; 00857 00858 return result; 00859 } 00860 00861 00862 static int is_equal( const void* _r1, const void* _r2, void* ) 00863 { 00864 const CvRect* r1 = (const CvRect*)_r1; 00865 const CvRect* r2 = (const CvRect*)_r2; 00866 int distance = cvRound(r1->width*0.2); 00867 00868 return r2->x <= r1->x + distance && 00869 r2->x >= r1->x - distance && 00870 r2->y <= r1->y + distance && 00871 r2->y >= r1->y - distance && 00872 r2->width <= cvRound( r1->width * 1.2 ) && 00873 cvRound( r2->width * 1.2 ) >= r1->width; 00874 } 00875 00876 CvSeq* 00877 cvHaarDetectObjects2( const CvArr* _img, 00878 CvHaarClassifierCascade* cascade, 00879 CvMemStorage* storage, double scale_factor, 00880 int min_neighbors, int flags, CvSize min_size ) 00881 { 00882 int split_stage = 2; 00883 00884 IplImage* iplImg = (IplImage*)_img; 00885 CvMat stub, *img = (CvMat*)_img; 00886 CvMat *temp = 0, *sum = 0, *tilted = 0, *sqsum = 0, *norm_img = 0, *sumcanny = 0, *img_small = 0; 00887 CvSeq* seq = 0; 00888 CvSeq* seq2 = 0; 00889 CvSeq* idx_seq = 0; 00890 CvSeq* result_seq = 0; 00891 CvMemStorage* temp_storage = 0; 00892 CvAvgComp* comps = 0; 00893 int i; 00894 00895 00896 double factor; 00897 int npass = 2, coi; 00898 int do_canny_pruning = flags & CV_HAAR_DO_CANNY_PRUNING; 00899 00900 img = cvGetMat(_img, &stub, &coi ); 00901 00902 if( !CV_IS_HAAR_CLASSIFIER(cascade) ) 00903 LFATAL( "Invalid classifier cascade" ); 00904 00905 //if( !storage ) 00906 // CV_ERROR( CV_StsNullPtr, "Null storage pointer" ); 00907 00908 if( coi ) 00909 LFATAL("COI is not supported" ); 00910 00911 if( CV_MAT_DEPTH(img->type) != CV_8U ) 00912 LFATAL("Only 8-bit images are supported" ); 00913 00914 temp = cvCreateMat( iplImg->height, iplImg->width, CV_8UC1 ); 00915 sum = cvCreateMat( iplImg->height + 1, iplImg->width + 1, CV_32SC1 ); 00916 sqsum = cvCreateMat( iplImg->height + 1, iplImg->width + 1, CV_64FC1 ); 00917 temp_storage = cvCreateChildMemStorage( storage ); 00918 00919 #ifdef _OPENMP 00920 max_threads = cvGetNumThreads(); 00921 for( i = 0; i < max_threads; i++ ) 00922 { 00923 CvMemStorage* temp_storage_thread; 00924 temp_storage_thread = cvCreateMemStorage(0); 00925 CV_CALL( seq_thread[i] = cvCreateSeq( 0, sizeof(CvSeq), 00926 sizeof(CvRect), temp_storage_thread )); 00927 } 00928 #endif 00929 00930 if( !cascade->hid_cascade ) 00931 icvCreateHidHaarClassifierCascade(cascade); 00932 00933 if( cascade->hid_cascade->has_tilted_features ) 00934 tilted = cvCreateMat( iplImg->height + 1, iplImg->width + 1, CV_32SC1 ); 00935 00936 seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage ); 00937 seq2 = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), temp_storage ); 00938 result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage ); 00939 00940 if( min_neighbors == 0 ) 00941 seq = result_seq; 00942 00943 if( CV_MAT_CN(img->type) > 1 ) 00944 { 00945 cvCvtColor( img, temp, CV_BGR2GRAY ); 00946 img = temp; 00947 } 00948 00949 if( flags & CV_HAAR_SCALE_IMAGE ) 00950 { 00951 CvSize win_size0 = cascade->orig_window_size; 00952 int use_ipp = cascade->hid_cascade->ipp_stages != 0 && 00953 icvApplyHaarClassifier_32s32f_C1R_p != 0; 00954 00955 img_small = cvCreateMat( iplImg->height + 1, iplImg->width + 1, CV_8UC1 ); 00956 00957 for( factor = 1; ; factor *= scale_factor ) 00958 { 00959 int positive = 0; 00960 int x, y; 00961 CvSize win_size = { cvRound(win_size0.width*factor), 00962 cvRound(win_size0.height*factor) }; 00963 CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) }; 00964 CvSize sz1 = { sz.width - win_size0.width, sz.height - win_size0.height }; 00965 //CvRect rect1 = { icv_object_win_border, icv_object_win_border, 00966 // win_size0.width - icv_object_win_border*2, 00967 // win_size0.height - icv_object_win_border*2 }; 00968 CvMat img1, sum1, sqsum1, norm1, tilted1, mask1; 00969 CvMat* _tilted = 0; 00970 00971 if( sz1.width <= 0 || sz1.height <= 0 ) 00972 break; 00973 if( win_size.width < min_size.width || win_size.height < min_size.height ) 00974 continue; 00975 00976 img1 = cvMat( sz.height, sz.width, CV_8UC1, img_small->data.ptr ); 00977 sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr ); 00978 sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr ); 00979 if( tilted ) 00980 { 00981 tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr ); 00982 _tilted = &tilted1; 00983 } 00984 norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, norm_img ? norm_img->data.ptr : 0 ); 00985 mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr ); 00986 00987 cvResize( img, &img1, CV_INTER_LINEAR ); 00988 cvIntegral( &img1, &sum1, &sqsum1, _tilted ); 00989 00990 // if( use_ipp && icvRectStdDev_32s32f_C1R_p( sum1.data.i, sum1.step, 00991 // sqsum1.data.db, sqsum1.step, norm1.data.fl, norm1.step, sz1, rect1 ) < 0 ) 00992 // use_ipp = 0; 00993 use_ipp = 0; 00994 00995 if( use_ipp ) 00996 { 00997 positive = mask1.cols*mask1.rows; 00998 cvSet( &mask1, cvScalarAll(255) ); 00999 for( i = 0; i < cascade->count; i++ ) 01000 { 01001 //if( icvApplyHaarClassifier_32s32f_C1R_p(sum1.data.i, sum1.step, 01002 // norm1.data.fl, norm1.step, mask1.data.ptr, mask1.step, 01003 // sz1, &positive, cascade->hid_cascade->stage_classifier[i].threshold, 01004 // cascade->hid_cascade->ipp_stages[i]) < 0 ) 01005 //{ 01006 // use_ipp = 0; 01007 // break; 01008 //} 01009 if( positive <= 0 ) 01010 break; 01011 } 01012 } 01013 01014 if( !use_ipp ) 01015 { 01016 cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, 0, 1. ); 01017 for( y = 0, positive = 0; y < sz1.height; y++ ) 01018 for( x = 0; x < sz1.width; x++ ) 01019 { 01020 mask1.data.ptr[mask1.step*y + x] = 01021 cvRunHaarClassifierCascade( cascade, cvPoint(x,y), 0 ) > 0; 01022 positive += mask1.data.ptr[mask1.step*y + x]; 01023 } 01024 } 01025 01026 if( positive > 0 ) 01027 { 01028 for( y = 0; y < sz1.height; y++ ) 01029 for( x = 0; x < sz1.width; x++ ) 01030 if( mask1.data.ptr[mask1.step*y + x] != 0 ) 01031 { 01032 CvRect obj_rect = { cvRound(y*factor), cvRound(x*factor), 01033 win_size.width, win_size.height }; 01034 cvSeqPush( seq, &obj_rect ); 01035 } 01036 } 01037 } 01038 } 01039 else 01040 { 01041 cvIntegral(img, sum, sqsum, tilted ); 01042 01043 if( do_canny_pruning ) 01044 { 01045 sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ); 01046 cvCanny( img, temp, 0, 50, 3 ); 01047 cvIntegral( temp, sumcanny ); 01048 } 01049 01050 if( (unsigned)split_stage >= (unsigned)cascade->count || 01051 cascade->hid_cascade->is_tree ) 01052 { 01053 split_stage = cascade->count; 01054 npass = 1; 01055 } 01056 01057 LINFO("1"); 01058 for( factor = 1; factor*cascade->orig_window_size.width < img->cols - 10 && 01059 factor*cascade->orig_window_size.height < img->rows - 10; 01060 factor *= scale_factor ) 01061 { 01062 const double ystep = MAX( 2, factor ); 01063 CvSize win_size = { cvRound( cascade->orig_window_size.width * factor ), 01064 cvRound( cascade->orig_window_size.height * factor )}; 01065 CvRect equ_rect = { 0, 0, 0, 0 }; 01066 int *p0 = 0, *p1 = 0, *p2 = 0, *p3 = 0; 01067 int *pq0 = 0, *pq1 = 0, *pq2 = 0, *pq3 = 0; 01068 int pass, stage_offset = 0; 01069 int stop_height = cvRound((img->rows - win_size.height) / ystep); 01070 01071 if( win_size.width < min_size.width || win_size.height < min_size.height ) 01072 continue; 01073 01074 LINFO("1.1"); 01075 cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor ); 01076 LINFO("1.2"); 01077 cvZero( temp ); 01078 01079 if( do_canny_pruning ) 01080 { 01081 equ_rect.x = cvRound(win_size.width*0.15); 01082 equ_rect.y = cvRound(win_size.height*0.15); 01083 equ_rect.width = cvRound(win_size.width*0.7); 01084 equ_rect.height = cvRound(win_size.height*0.7); 01085 01086 p0 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step) + equ_rect.x; 01087 p1 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step) 01088 + equ_rect.x + equ_rect.width; 01089 p2 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step) + equ_rect.x; 01090 p3 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step) 01091 + equ_rect.x + equ_rect.width; 01092 01093 pq0 = (int*)(sum->data.ptr + equ_rect.y*sum->step) + equ_rect.x; 01094 pq1 = (int*)(sum->data.ptr + equ_rect.y*sum->step) 01095 + equ_rect.x + equ_rect.width; 01096 pq2 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step) + equ_rect.x; 01097 pq3 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step) 01098 + equ_rect.x + equ_rect.width; 01099 } 01100 01101 cascade->hid_cascade->count = split_stage; 01102 01103 for( pass = 0; pass < npass; pass++ ) 01104 { 01105 #ifdef _OPENMP 01106 #pragma omp parallel for num_threads(max_threads), schedule(dynamic) 01107 #endif 01108 for( int _iy = 0; _iy < stop_height; _iy++ ) 01109 { 01110 int iy = cvRound(_iy*ystep); 01111 int _ix, _xstep = 1; 01112 int stop_width = cvRound((img->cols - win_size.width) / ystep); 01113 uchar* mask_row = temp->data.ptr + temp->step * iy; 01114 01115 for( _ix = 0; _ix < stop_width; _ix += _xstep ) 01116 { 01117 int ix = cvRound(_ix*ystep); // it really should be ystep 01118 01119 if( pass == 0 ) 01120 { 01121 int result; 01122 _xstep = 2; 01123 01124 if( do_canny_pruning ) 01125 { 01126 int offset; 01127 int s, sq; 01128 01129 offset = iy*(sum->step/sizeof(p0[0])) + ix; 01130 s = p0[offset] - p1[offset] - p2[offset] + p3[offset]; 01131 sq = pq0[offset] - pq1[offset] - pq2[offset] + pq3[offset]; 01132 if( s < 100 || sq < 20 ) 01133 continue; 01134 } 01135 01136 result = cvRunHaarClassifierCascade( cascade, cvPoint(ix,iy), 0 ); 01137 if( result > 0 ) 01138 { 01139 if( pass < npass - 1 ) 01140 mask_row[ix] = 1; 01141 else 01142 { 01143 CvRect rect = cvRect(ix,iy,win_size.width,win_size.height); 01144 #ifndef _OPENMP 01145 cvSeqPush( seq, &rect ); 01146 #else 01147 cvSeqPush( seq_thread[omp_get_thread_num()], &rect ); 01148 #endif 01149 } 01150 } 01151 if( result < 0 ) 01152 _xstep = 1; 01153 } 01154 else if( mask_row[ix] ) 01155 { 01156 int result = cvRunHaarClassifierCascade( cascade, cvPoint(ix,iy), 01157 stage_offset ); 01158 if( result > 0 ) 01159 { 01160 if( pass == npass - 1 ) 01161 { 01162 CvRect rect = cvRect(ix,iy,win_size.width,win_size.height); 01163 #ifndef _OPENMP 01164 cvSeqPush( seq, &rect ); 01165 #else 01166 cvSeqPush( seq_thread[omp_get_thread_num()], &rect ); 01167 #endif 01168 } 01169 } 01170 else 01171 mask_row[ix] = 0; 01172 } 01173 } 01174 } 01175 stage_offset = cascade->hid_cascade->count; 01176 cascade->hid_cascade->count = cascade->count; 01177 } 01178 } 01179 LINFO("end"); 01180 } 01181 01182 #ifdef _OPENMP 01183 // gather the results 01184 for( i = 0; i < max_threads; i++ ) 01185 { 01186 CvSeq* s = seq_thread[i]; 01187 int j, total = s->total; 01188 CvSeqBlock* b = s->first; 01189 for( j = 0; j < total; j += b->count, b = b->next ) 01190 cvSeqPushMulti( seq, b->data, b->count ); 01191 } 01192 #endif 01193 01194 if( min_neighbors != 0 ) 01195 { 01196 // group retrieved rectangles in order to filter out noise 01197 int ncomp = cvSeqPartition( seq, 0, &idx_seq, is_equal, 0 ); 01198 comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])); 01199 memset( comps, 0, (ncomp+1)*sizeof(comps[0])); 01200 01201 // count number of neighbors 01202 for( i = 0; i < seq->total; i++ ) 01203 { 01204 CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i ); 01205 int idx = *(int*)cvGetSeqElem( idx_seq, i ); 01206 assert( (unsigned)idx < (unsigned)ncomp ); 01207 01208 comps[idx].neighbors++; 01209 01210 comps[idx].rect.x += r1.x; 01211 comps[idx].rect.y += r1.y; 01212 comps[idx].rect.width += r1.width; 01213 comps[idx].rect.height += r1.height; 01214 } 01215 01216 // calculate average bounding box 01217 for( i = 0; i < ncomp; i++ ) 01218 { 01219 int n = comps[i].neighbors; 01220 if( n >= min_neighbors ) 01221 { 01222 CvAvgComp comp; 01223 comp.rect.x = (comps[i].rect.x*2 + n)/(2*n); 01224 comp.rect.y = (comps[i].rect.y*2 + n)/(2*n); 01225 comp.rect.width = (comps[i].rect.width*2 + n)/(2*n); 01226 comp.rect.height = (comps[i].rect.height*2 + n)/(2*n); 01227 comp.neighbors = comps[i].neighbors; 01228 01229 cvSeqPush( seq2, &comp ); 01230 } 01231 } 01232 01233 // filter out small face rectangles inside large face rectangles 01234 for( i = 0; i < seq2->total; i++ ) 01235 { 01236 CvAvgComp r1 = *(CvAvgComp*)cvGetSeqElem( seq2, i ); 01237 int j, flag = 1; 01238 01239 for( j = 0; j < seq2->total; j++ ) 01240 { 01241 CvAvgComp r2 = *(CvAvgComp*)cvGetSeqElem( seq2, j ); 01242 int distance = cvRound( r2.rect.width * 0.2 ); 01243 01244 if( i != j && 01245 r1.rect.x >= r2.rect.x - distance && 01246 r1.rect.y >= r2.rect.y - distance && 01247 r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance && 01248 r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance && 01249 (r2.neighbors > MAX( 3, r1.neighbors ) || r1.neighbors < 3) ) 01250 { 01251 flag = 0; 01252 break; 01253 } 01254 } 01255 01256 if( flag ) 01257 { 01258 cvSeqPush( result_seq, &r1 ); 01259 // cvSeqPush( result_seq, &r1.rect ); 01260 } 01261 } 01262 } 01263 01264 01265 #ifdef _OPENMP 01266 for( i = 0; i < max_threads; i++ ) 01267 { 01268 if( seq_thread[i] ) 01269 cvReleaseMemStorage( &seq_thread[i]->storage ); 01270 } 01271 #endif 01272 01273 cvReleaseMemStorage( &temp_storage ); 01274 cvReleaseMat( &sum ); 01275 cvReleaseMat( &sqsum ); 01276 cvReleaseMat( &tilted ); 01277 cvReleaseMat( &temp ); 01278 cvReleaseMat( &sumcanny ); 01279 cvReleaseMat( &norm_img ); 01280 cvReleaseMat( &img_small ); 01281 //cvFree( &comps ); 01282 01283 return result_seq; 01284 } 01285 01286 01287 01288 void detect_and_draw( IplImage* img , std::vector<Rectangle> &facesRec) 01289 { 01290 01291 double scale = 1.3; 01292 IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 ); 01293 IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale), 01294 cvRound (img->height/scale)), 01295 8, 1 ); 01296 int i; 01297 01298 cvCvtColor( img, gray, CV_BGR2GRAY ); 01299 01300 cvResize( gray, small_img, CV_INTER_LINEAR ); 01301 cvEqualizeHist( small_img, small_img ); 01302 01303 cvClearMemStorage( storage ); 01304 01305 int coi; 01306 CvMat stub; 01307 CvMat *iimg = cvGetMat(small_img, &stub, &coi ); 01308 LINFO("Tracei %ix%i", iimg->width, iimg->height); 01309 01310 if( cascade ) 01311 { 01312 double t = (double)cvGetTickCount(); 01313 LINFO("Size %ix%i", small_img->width, small_img->height); 01314 CvSeq* faces = cvHaarDetectObjects2( small_img, cascade, storage, 01315 1.1, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/, 01316 cvSize(30, 30) ); 01317 t = (double)cvGetTickCount() - t; 01318 //printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) ); 01319 for( i = 0; i < (faces ? faces->total : 0); i++ ) 01320 { 01321 CvRect* r = (CvRect*)cvGetSeqElem( faces, i ); 01322 01323 Rectangle faceRect(Point2D<int>((int)(r->x*scale), (int)(r->y*scale)), 01324 Dims((int)(r->width*scale), (int)(r->height*scale))); 01325 facesRec.push_back(faceRect); 01326 } 01327 } 01328 01329 cvReleaseImage( &gray ); 01330 cvReleaseImage( &small_img ); 01331 } 01332 01333 01334 int main(const int argc, const char **argv) 01335 { 01336 MYLOGVERB = LOG_INFO; 01337 ModelManager *mgr = new ModelManager("Test ObjRec"); 01338 01339 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(*mgr)); 01340 mgr->addSubComponent(ofs); 01341 01342 nub::soft_ref<BeoHeadBrain> beoHeadBrain(new BeoHeadBrain(*mgr)); 01343 mgr->addSubComponent(beoHeadBrain); 01344 01345 01346 mgr->exportOptions(MC_RECURSE); 01347 01348 if (mgr->parseCommandLine( 01349 (const int)argc, (const char**)argv, "", 0, 0) == false) 01350 return 1; 01351 01352 mgr->start(); 01353 01354 const char* cascade_name = "/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml"; 01355 cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); 01356 01357 if( !cascade ) 01358 { 01359 fprintf( stderr, "ERROR: Could not load classifier cascade\n" ); 01360 return -1; 01361 } 01362 storage = cvCreateMemStorage(0); 01363 01364 Image<float> avgFace(256,256,ZEROS); 01365 01366 // do post-command-line configs: 01367 01368 beoHeadBrain->initHead(); 01369 01370 unsigned long imgNum = 0; 01371 uint64 avgtime = 0; int avgn = 0; 01372 float faceDetRate = 0.0F; 01373 Timer timer; 01374 01375 while(1) 01376 { 01377 Image< PixRGB<byte> > inputImg = beoHeadBrain->getLeftEyeImg(); 01378 01379 if (!inputImg.initialized()) 01380 continue; 01381 01382 Image<byte> greyInput = luminance(inputImg); 01383 01384 std::vector<Rectangle> faces; 01385 detect_and_draw(img2ipl(inputImg), faces ); 01386 01387 Point2D<int> targetLoc(-1,-1); 01388 for(uint i=0; i<faces.size(); i++) 01389 { 01390 Point2D<int> faceCenter = Point2D<int>( 01391 faces[i].topLeft().i + faces[i].width()/2, 01392 faces[i].topLeft().j + faces[i].height()/2); 01393 01394 beoHeadBrain->setTarget(faceCenter); 01395 targetLoc = faceCenter; 01396 01397 Image<PixRGB<byte> > faceImg = crop(inputImg, faces[i]); 01398 01399 ofs->writeRGB(faceImg, "faceImg", FrameInfo("faceImg", SRC_POS)); 01400 01401 char filename[255]; 01402 sprintf(filename, "faces/face%.6lu.pnm", imgNum++); 01403 Raster::WriteRGB(faceImg, filename); 01404 01405 ofs->updateNext(); 01406 01407 drawRect(inputImg, faces[i], PixRGB<byte>(255,0,0)); 01408 avgn++; 01409 } 01410 01411 01412 targetLoc = beoHeadBrain->getTargetLoc(); 01413 01414 if (targetLoc.isValid()) 01415 drawCircle(inputImg, targetLoc, 3, PixRGB<byte>(255,0,0)); 01416 01417 ofs->writeRGB(inputImg, "inputImg", FrameInfo("inputImg", SRC_POS)); 01418 01419 //compute the face detection Rate 01420 avgtime += timer.getReset(); 01421 if (avgtime > 1000.0F) 01422 { 01423 faceDetRate = avgn; 01424 avgtime = 0; 01425 avgn = 0; 01426 } 01427 01428 01429 //if (faceDetRate > 10) 01430 //{ 01431 // LINFO("Waking up"); 01432 // beoHeadBrain->wakeUp(); 01433 //} else { 01434 // //move head to relax position. aka sleep 01435 // if (!beoHeadBrain->isSleeping()) 01436 // beoHeadBrain->gotoSleep(); 01437 //} 01438 01439 } 01440 mgr->stop(); 01441 01442 return 0; 01443 01444 } 01445