00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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
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
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
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
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
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
00182
00183 }
00184 }
00185
00186
00187 }
00188 }
00189
00190
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
00230
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
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
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
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
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
00401 ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale;
00402 }
00403 }
00404
00405
00406
00407
00408
00409 }
00410
00411 if( i < cascade->count )
00412 {
00413
00414
00415
00416
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
00431
00432
00433
00434
00435
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
00539
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
00555
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
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
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
00644 float target_ratio = orig_feature_size / orig_norm_size;
00645
00646
00647 correction_ratio = target_ratio / feature_size;
00648
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 }
00680 }
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
00906
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
00966
00967
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
00991
00992
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
01002
01003
01004
01005
01006
01007
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);
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
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
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
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
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
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
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
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,
01316 cvSize(30, 30) );
01317 t = (double)cvGetTickCount() - t;
01318
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
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
01420 avgtime += timer.getReset();
01421 if (avgtime > 1000.0F)
01422 {
01423 faceDetRate = avgn;
01424 avgtime = 0;
01425 avgn = 0;
01426 }
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439 }
01440 mgr->stop();
01441
01442 return 0;
01443
01444 }
01445