test-faceDet.C

Go to the documentation of this file.
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 
Generated on Sun May 8 08:41:08 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3