CvFaceDetect.cpp

Go to the documentation of this file.
00001 /*M///////////////////////////////////////////////////////////////////////////////////////
00002 //
00003 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
00004 //
00005 //  By downloading, copying, installing or using the software you agree to this license.
00006 //  If you do not agree to this license, do not download, install,
00007 //  copy or use the software.
00008 //
00009 //
00010 //                        Intel License Agreement
00011 //                For Open Source Computer Vision Library
00012 //                                   
00013 //                    Contributors License Agreement
00014 //
00015 // Copyright (C) 2006, Zecchini Fabio, all rights reserved.
00016 //
00017 // Copyright (C) 2006, Cora' Massimo, all rights reserved. Code adapting and integration into Omnimeeting.
00018 //
00019 // Third party copyrights are property of their respective owners.
00020 //
00021 // Redistribution and use in source and binary forms, with or without modification,
00022 // are permitted provided that the following conditions are met:
00023 //
00024 //   * Redistribution's of source code must retain the above copyright notice,
00025 //     this list of conditions and the following disclaimer.
00026 //
00027 //   * Redistribution's in binary form must reproduce the above copyright notice,
00028 //     this list of conditions and the following disclaimer in the documentation
00029 //     and/or other materials provided with the distribution.
00030 //
00031 //   * The name of Intel Corporation may not be used to endorse or promote products
00032 //     derived from this software without specific prior written permission.
00033 //
00034 // This software is provided by the copyright holders and contributors "as is" and
00035 // any express or implied warranties, including, but not limited to, the implied
00036 // warranties of merchantability and fitness for a particular purpose are disclaimed.
00037 // In no event shall the Intel Corporation or contributors be liable for any direct,
00038 // indirect, incidental, special, exemplary, or consequential damages
00039 // (including, but not limited to, procurement of substitute goods or services;
00040 // loss of use, data, or profits; or business interruption) however caused
00041 // and on any theory of liability, whether in contract, strict liability,
00042 // or tort (including negligence or otherwise) arising in any way out of
00043 // the use of this software, even if advised of the possibility of such damage.
00044 //
00045 //M*/
00046 
00048 //
00049 // Mouth and eye detection based on the paper:
00050 //                                                            
00051 // P. Campadelli, F. Cusmai, and R. Lanzarotti, A color-based method for face detection
00052 // http://homes.dsi.unimi.it/%7Ecampadel/Articoli/IST2003.pdf
00053 //
00055 
00056 #include "CvFaceDetect.hh"
00057 
00058 CvFaceDetect::CvFaceDetect(int min, int max)
00059 {       
00060         this->started = false;
00061         this->vrfilter = new CvVrFilter(min, max);
00062         //this->storage = 0;
00063 
00064         this->storage = cvCreateMemStorage(0);
00065 
00066 }
00067 
00068 CvFaceDetect::~CvFaceDetect()
00069 {       
00070         cvReleaseImage( &this->skin_locus_map );
00071 #ifdef DETECT
00072         cvReleaseImage( &this->ycc );
00073         cvReleaseImage( &this->y );
00074         cvReleaseImage( &this->mouth_map );
00075         cvReleaseImage( &this->mouth_map_bin );
00076         cvReleaseImage( &this->eyes_map );
00077         cvReleaseImage( &this->eyes_map_bin );
00078 #endif
00079 
00080         cvReleaseMemStorage( &this->storage );
00081 }
00082 
00083 void
00084 CvFaceDetect::cvFaceDetect(IplImage * image, int DRAW_TYPE)
00085 {       
00086         if(started)
00087         {
00088 
00089                 cvReleaseImage( &this->skin_locus_map );
00090 
00091 #ifdef DETECT
00092                 cvReleaseImage( &this->ycc );
00093                 cvReleaseImage( &this->y );
00094                 cvReleaseImage( &this->mouth_map );
00095                 cvReleaseImage( &this->mouth_map_bin );
00096                 cvReleaseImage( &this->eyes_map );
00097                 cvReleaseImage( &this->eyes_map_bin );
00098 #endif
00099                 cvClearMemStorage(this->storage);
00100                 //cvRelease( (void **)&this->faces );
00101                 //cvReleaseMemStorage( &this->storage );
00102 
00103         }
00104         
00105         //this->storage = cvCreateMemStorage(0);
00106 
00107         this->started = true;
00108         this->size = cvGetSize(image);
00109         this->source = image ;
00110 
00111         this->faces = cvCreateSeq( 0,                           // sequence of generic elements 
00112                                                           sizeof(CvSeq),        // header size - no extra fields 
00113                                                           sizeof(Cvface),       // element size 
00114                                                           storage                       // the container storage 
00115                                                           );
00116         
00117     this->skin_locus_map = this->vrfilter->cvVrFilter(image, this->storage, this->faces);
00118 
00119 
00120 #ifdef DETECT
00121 
00122         //YCrCb skin locus converted image
00123         ycc = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 3  );
00124         cvCvtColor( this->skin_locus_map , ycc, CV_BGR2YCrCb );
00125         
00126         
00127         /*
00128         icvMouthMap(ycc);
00129         icvMouthMask();
00130         icvMouthDetect();
00131         
00132 
00133         icvEyesMap(ycc);
00134         icvEyesMask();
00135         icvEyesDetect();
00136         /*/
00137 
00138         icvMouthEyesMap(ycc);
00139         icvMouthEyesMask();
00140         icvMouthEyesDetect();
00141         
00142 
00143 
00144         if (DRAW_TYPE > 0)
00145         {       
00146                 //printf("face_detect.cpp faces->total : %d \n", this->faces->total);   
00147                 
00148                 for (int i = 0; i < this->faces->total ; i++)
00149                 {       
00150                         
00151                         Cvface *face;
00152 
00153                         face = (Cvface *)cvGetSeqElem( this->faces, i );
00154 
00155                         if (DRAW_TYPE == DRAW_BOX_ONLY || DRAW_TYPE == DRAW_ALL)
00156                         {
00157                                 //draw a box
00158                                 int n = 4;
00159                                 CvPoint2D32f _box_point[4];
00160                                 CvPoint box_point[4], *bpp = box_point;
00161 
00162                                 cvBoxPoints( face->skin_face.skin_box , _box_point );
00163                 
00164                                 for (int i=0; i<n ; i++)
00165                                 {
00166                                         box_point[i] = cvPoint(cvRound(_box_point[i].x),cvRound(_box_point[i].y));
00167                                 }
00168                                 
00169                                 if(face->track)
00170                                         cvPolyLine( image, &bpp , &n, 1, 1, CV_RGB(255,0,255), 2, CV_AA , 0 );
00171                                 /*else
00172                                         cvPolyLine( image, &bpp , &n, 1, 1, CV_RGB(255,0,0), 2, CV_AA , 0 );*/
00173                                 
00174                         }
00175 
00176                         if (DRAW_TYPE == DRAW_EYES || DRAW_TYPE == DRAW_ALL)
00177                         {       
00178                                 for (int i= 0 ; i < 2; i++)
00179                                 {       
00180                                         if ( &face->eyes_box[i] != 0)
00181                                         {
00182                                                 
00183                                                 //printf("occhio x%d :%d ",i ,(int) face->eyes_box[i].center.x  );
00184 
00185                                                 cvEllipse(      image, 
00186                                                                         cvPoint((int) face->eyes_box[i].center.x , 
00187                                                                                         (int) face->eyes_box[i].center.y) , 
00188                                                                         cvSize( (int) face->eyes_box[i].size.width , 
00189                                                                                         (int) face->eyes_box[i].size.height), 
00190                                                                         (double)(360 * face->eyes_box[i].angle)/ (2 * CV_PI) - 90, 
00191                                                                         0, 360, 
00192                                                                         cvScalar( 0, 255, 0 ),
00193                                                                         1, CV_AA );
00194                                         }
00195                                 }
00196                         }
00197 
00198                         if (DRAW_TYPE == DRAW_MOUTH || DRAW_TYPE == DRAW_ALL)
00199                         {       
00200                                 if ( &face->mouth_box != 0)
00201                                 {
00202                                         //printf("bocca angolo : %d \n", (int)((360 * face->mouth_box.angle)/ (2 * CV_PI) - 90));
00203 
00204                                         cvEllipse(      image, 
00205                                                                 cvPoint((int) face->mouth_box.center.x , 
00206                                                                                 (int) face->mouth_box.center.y) , 
00207                                                                 cvSize( (int) face->mouth_box.size.width , 
00208                                                                                 (int) face->mouth_box.size.height), 
00209                                                                 (double)(360 * face->mouth_box.angle)/ (2 * CV_PI) - 90, 
00210                                                                 0, 360, 
00211                                                                 cvScalar( 0, 255, 255 ),
00212                                                                 1, CV_AA );
00213 
00214                                         
00215                                 }
00216         
00217                         }
00218 
00219                         if (DRAW_TYPE == DRAW_ALL)
00220                         {       
00221                                 float angle = 0;
00222 
00223                                 if (&face->eyes_box[0] != 0 && &face->eyes_box[1] != 0)
00224                                 {
00225                                         cvLine( image, 
00226                                                         cvPoint((int) face->eyes_box[0].center.x , 
00227                                                                         (int) face->eyes_box[0].center.y),  
00228                                                         cvPoint((int) face->eyes_box[1].center.x , 
00229                                                                         (int) face->eyes_box[1].center.y),  
00230                                                         cvScalar( 231, 169, 0 ),
00231                                                         2, CV_AA, 0 );
00232                                         
00233                                         angle = (float)(atan2((face->eyes_box[1].center.y - face->eyes_box[0].center.y),
00234                                                                   (face->eyes_box[1].center.x - face->eyes_box[0].center.x)) 
00235                                                         + CV_PI/2);
00236                                         
00237                                         //printf("angle : %f \n", angle);
00238 
00239                                 }
00240                                 
00241                                 if (&face->mouth_box != 0 )
00242                                 {       
00243                                         int mult = (int)(MAX(face->skin_face.skin_box.size.width,
00244                                                                                  face->skin_face.skin_box.size.height ) /2);
00245                                         
00246                                         cvLine( image, 
00247                                                         cvPoint((int) ((face->mouth_box.center.x) - mult *
00248                                                                                 cos(angle)), 
00249                                                                                 (int) ((face->mouth_box.center.y) - mult *
00250                                                                                 sin(angle))),  
00251                                                         cvPoint((int) ((face->mouth_box.center.x) + mult *
00252                                                                                 cos(angle)), 
00253                                                                                 (int) ((face->mouth_box.center.y) + mult *
00254                                                                                 sin(angle))),  
00255                                                         cvScalar( 186, 114, 8 ),
00256                                                         2, CV_AA, 0 );
00257                                 }
00258 
00259                         }
00260 
00261                 }
00262         }
00263 #endif
00264 
00265 }
00266 
00267 void
00268 CvFaceDetect::icvMouthMap(IplImage * image)
00269 {
00270         this->mouth_map = cvCreateImage(this->size, IPL_DEPTH_32F, 1  );
00271 
00272         int _cr, _cb ;
00273         for ( int j = 0; j < this->size.height; j++ ) {
00274                 for ( int i=0; i < this->size.width; i++ ) {
00275 
00276                         _cr = CV_IMAGE_ELEM(ycc, unsigned char, j, 3*i +1);
00277                         _cb = CV_IMAGE_ELEM(ycc, unsigned char, j, 3*i +2);
00278                         
00279                         CV_IMAGE_ELEM( this->mouth_map, float, j, i )  = 
00280                                                                         (float) ( _cr * (255 - (_cr - _cb) ) * _cr ) ;
00281                                                                                 
00282                 }
00283         }
00284 }
00285 
00286 void  
00287 CvFaceDetect::icvMouthMask()
00288 {       
00289         this->mouth_map_bin = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00290 
00291         IplImage * _mouth_map_bin;
00292         _mouth_map_bin = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00293 
00294         // find the max value
00295         double map_min = 0 , map_max = 0 , map_range;
00296         cvMinMaxLoc( this->mouth_map, &map_min , &map_max );
00297         map_range = map_max - ( map_max * 0.06 );
00298 
00299         cvThreshold( this->mouth_map, _mouth_map_bin, map_range, 255, CV_THRESH_BINARY );
00300         
00301         /*
00302         cvNamedWindow("mouth_bin", 1);
00303         cvShowImage("mouth_bin", _mouth_map_bin);
00304         
00305         cvWaitKey(0);
00306         */
00307         
00308         IplConvKernel* kernelOp = cvCreateStructuringElementEx( 4, 3, 1, 1, CV_SHAPE_CROSS, NULL );
00309         cvDilate( _mouth_map_bin , this->mouth_map_bin, kernelOp,  1 );
00310 
00311         /*
00312         cvNamedWindow("mouth", 1);
00313         cvShowImage("mouth", this->mouth_map_bin);
00314 
00315         cvWaitKey(0);
00316         */
00317         
00318 #ifdef MOUTH
00319         cvNamedWindow("mouth", 1);
00320         cvShowImage("mouth", this->mouth_map_bin);
00321 #endif
00322         
00323         cvReleaseImage( &_mouth_map_bin );
00324 }
00325 
00326 void  
00327 CvFaceDetect::icvMouthDetect()
00328 {
00329         
00330         int mouth = 0 ;
00331         int x , y, width, height, count;
00332         double angle ;
00333         
00334         Cvface *face;
00335 
00336         for (int i = 0; i < faces->total; i++)
00337         {       
00338                 //printf("width: %d , height: %d\n", this->skin_rect[i].width, this->skin_rect[i].height);
00339                 
00340                 /*
00341                 // draw a rectangle
00342                 CvPoint left_bottom = { this->skin_rect[i].x, this->skin_rect[i].y };
00343                 CvPoint right_top   = { this->skin_rect[i].x + this->skin_rect[i].width, 
00344                                                             this->skin_rect[i].y + this->skin_rect[i].height };
00345                 
00346                 cvRectangle( this->src, left_bottom, right_top, CV_RGB(255,0,0), 2, 4, 0 );
00347                 //*/
00348                 
00349                 /*
00350                 //draw a box
00351                 int n = 4;
00352                 CvPoint2D32f _box_point[4];
00353                 CvPoint box_point[4], *bpp = box_point;
00354 
00355                 cvBoxPoints( this->skin_box[i], _box_point );
00356                 
00357                 for (int i=0; i<n ; i++)
00358                 {
00359                         box_point[i] = cvPoint(cvRound(_box_point[i].x),cvRound(_box_point[i].y));
00360                 }
00361 
00362                 cvPolyLine( this->src, &bpp , &n, 1, 1, CV_RGB(255,0,0), 2, 8, 0 );
00363                 */
00364                 /*
00365                 cvNamedWindow("mouth_", 1);
00366                 cvShowImage("mouth_", this->src);
00367                 cvWaitKey(0);
00368                 */
00369                 //cvSetImageROI(this->mouth_map_bin, this->skin_rect[i]);
00370 
00371                 face = (Cvface *)cvGetSeqElem( this->faces, i);
00372 
00373                 cvSetImageROI(this->mouth_map_bin, face->skin_face.skin_rect );
00374 
00375                 x = y = height = width = count = 0;
00376                 angle = 0;
00377                                         
00378                 mouth = cvFindContours( this->mouth_map_bin , this->storage, &(this->contour) ,  
00379                                                 sizeof(CvContour), CV_RETR_EXTERNAL ,
00380                                                 CV_CHAIN_APPROX_SIMPLE ,
00381                                                 cvPoint( face->skin_face.skin_rect.x,face->skin_face.skin_rect.y )  );
00382                 
00383                 //if no mouth is detect jump..
00384                 if (mouth == 0) 
00385                 {
00386                         continue;
00387                 }
00388                 //printf("mouth : %d \n" , mouth);
00389 
00390                 for(CvSeq* temp_contour = this->contour; temp_contour != 0; temp_contour = temp_contour->h_next )
00391                 {                       
00392                         CvBox2D  box = cvMinAreaRect2( temp_contour );
00393                         
00394                         //CHANGE THIS PARAMETER SPECIFIC FOR YOUR APPLICATION POURPOSE
00395                         /*
00396                         if (box.size.width  > (face->skin_face->skin_rect.width)/2.5   ||       //TOO BIG
00397                                 box.size.height > (face->skin_face->skin_rect.height)/4    ||
00398                                 box.size.width  < (face->skin_face->skin_rect.width)/14    ||   //TOO SMALL
00399                                 box.size.height < (face->skin_face->skin_rect.height)/14  
00400                                 )
00401                         continue;
00402                         */
00403 
00404                         /*
00405                         cvEllipse( image, cvPoint ((int) box.center.x , (int) box.center.y) , 
00406                                         cvSize( (int)box.size.width , (int)box.size.height), 
00407                                         (double)(360 * box.angle)/ (2 * CV_PI) - 90, 
00408                                         0, 360, cvScalar( 0, 255, 255 ),
00409                                         2, 4 );
00410                         */
00411                         count ++;
00412                         x     += (int)box.center.x ;
00413                         y     += (int)box.center.y ;
00414                         width = MAX ((int)box.size.width, width) ;
00415                         height= MAX((int)box.size.height, height );
00416                         angle += box.angle ;
00417 
00418                         //printf ("angle : %f\n" , box.angle);
00419                 }
00420                 
00421                 if (count > 0)
00422                 {       
00423                         /*
00424                         cvEllipse( this->src, cvPoint ((int) x/count , (int) y/count) , 
00425                                         cvSize( width , height ), 
00426                                         (double)(360 * (angle /count))/ (2 * CV_PI) - 90, 
00427                                         0, 360, cvScalar( 0, 255, 255 ),
00428                                         2, 4 );
00429                         */
00430                         //face->mouth_box ;
00431 
00432                         face->mouth_box.center = cvPoint2D32f( x/count , y/count); 
00433                         face->mouth_box.size   = cvSize2D32f( width , height );
00434                         face->mouth_box.angle  = (float) angle /count ;
00435 
00436                         //printf ("angle : %d\n" , (int)((360 * face->mouth_box.angle)/ (2 * CV_PI) - 90));
00437 
00438                 }
00439                 
00440                 /*
00441                 cvNamedWindow("mouth_", 1);
00442                 cvShowImage("mouth_", this->src);
00443                 cvWaitKey(0);
00444                 */
00445         }
00446 
00447 
00448         //cvClearMemStorage( storage );
00449 
00450 }
00451 
00452 void 
00453 CvFaceDetect::icvEyesMap(IplImage * image)
00454 {
00455         this->eyes_map  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00456         this->y         = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00457 
00458         cvSplit (ycc, y, 0, 0, 0);
00459 
00460         IplImage *cb2, *cr_2, *cbcr ;
00461         cb2   = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1  );
00462         cr_2  = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1  );
00463         cbcr  = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1  );
00464 
00465         // build the two channels  cr^2 , cr-^2 and cb/cr (they'll be normalized later)
00466         int _cr, _cb ;
00467         for ( int j = 0; j < this->size.height; j++ ) {
00468                 for ( int i=0; i < this->size.width; i++ ) {
00469 
00470                         _cr = CV_IMAGE_ELEM(ycc, unsigned char, j, 3*i +1);
00471                         _cb = CV_IMAGE_ELEM(ycc, unsigned char, j, 3*i +2);
00472                         
00473                         CV_IMAGE_ELEM( cb2, float, j, i )   = (float)(_cb * _cb) ;
00474                         CV_IMAGE_ELEM( cr_2, float, j, i )  = (float)(255 - _cr) * (255 - _cr) ;
00475                         CV_IMAGE_ELEM( cbcr, float, j, i )  = (float)(_cb / _cr) ;
00476 
00477                 }
00478         }
00479 
00480         // calculate max and min value of the two channels cr^2 and crcb for the normalization
00481         double cb2_min = 0 , cb2_max = 0 , cr_2_min = 0, cr_2_max = 0 , cbcr_min = 0 , cbcr_max = 0;
00482 
00483         cvMinMaxLoc( cb2, &cb2_min , &cb2_max );
00484         cvMinMaxLoc( cr_2, &cr_2_min , &cr_2_max );
00485         cvMinMaxLoc( cbcr, &cbcr_min , &cbcr_max );
00486 
00487         // create channels
00488         IplImage *cb2_norm, *cr_2_norm, *cbcr_norm ;
00489         cb2_norm   = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1  );
00490         cr_2_norm  = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1  );
00491         cbcr_norm  = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1  );
00492 
00493         // normalize channels just built on [0, 255]
00494         float _cbcr , _cb2, _cr_2 ;
00495         double cr_2_range  = cr_2_max - cr_2_min;
00496         double cbcr_range = cbcr_max - cbcr_min;
00497         double cb2_range = cb2_max - cb2_min;
00498 
00499         for ( int j = 0; j < this->size.height; j++ ) {
00500                 for ( int i=0; i < this->size.width; i++ ) {
00501 
00502                         _cb2 =  CV_IMAGE_ELEM( cb2 , float, j, i )  ;
00503                         _cr_2 = CV_IMAGE_ELEM( cr_2, float, j, i )      ;
00504                         _cbcr = CV_IMAGE_ELEM( cbcr, float, j, i )      ;
00505                         
00506                         // to normalize on [0, 255] I'll use the formula
00507                         // [(x - min)/(max - min)] * scale
00508                         CV_IMAGE_ELEM( cb2_norm  , unsigned char, j, i )  = 
00509                                                                 (unsigned char)(( (_cb2 - cb2_min) / cb2_range) * 255);
00510                         CV_IMAGE_ELEM( cr_2_norm  , unsigned char, j, i )  = 
00511                                                                 (unsigned char)(( (_cr_2 - cr_2_min) / cr_2_range) * 255);
00512                         CV_IMAGE_ELEM( cbcr_norm , unsigned char, j, i )  = 
00513                                                                 (unsigned char)(( (_cbcr - cbcr_min) / cbcr_range) * 255);
00514                                         
00515                 }
00516         }
00517 
00518         // build the eyes map
00519         for ( int j = 0; j < this->size.height; j++ ) {
00520                 for ( int i=0; i < this->size.width; i++ ) {
00521 
00522                         _cb2 =  CV_IMAGE_ELEM( cb2_norm , unsigned char, j, i )  ;
00523                         _cr_2 = CV_IMAGE_ELEM( cr_2_norm, unsigned char, j, i ) ;
00524                         _cbcr = CV_IMAGE_ELEM( cbcr_norm, unsigned char, j, i ) ;
00525                         
00526                         CV_IMAGE_ELEM( this->eyes_map  , unsigned char, j, i )  = 
00527                                                 (unsigned char) ( (_cb2 + _cr_2 + _cbcr  ) / 3 ) ;
00528                                         
00529                 }
00530         }
00531 
00532         cvReleaseImage( &cb2 );
00533         cvReleaseImage( &cr_2 );
00534         cvReleaseImage( &cbcr );
00535         cvReleaseImage( &cb2_norm );
00536         cvReleaseImage( &cr_2_norm );
00537         cvReleaseImage( &cbcr_norm );
00538 }
00539 
00540 void 
00541 CvFaceDetect::icvEyesMask(){
00542         
00543         IplImage *_eyes_map_bin,  *eyes_map_y , *eyes;
00544 
00545         eyes_map_bin  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00546         
00547         _eyes_map_bin  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00548         eyes_map_y  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00549         eyes  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00550 
00551         // calculate max value
00552         double map_min = 0 , map_max = 0 , map_range;
00553         cvMinMaxLoc( this->eyes_map, &map_min , &map_max );
00554         map_range = map_max - ( map_max * 0.60 );
00555         
00556 
00557         // binarize the map with 20% of highest values
00558         cvThreshold( this->eyes_map, _eyes_map_bin, map_range, 255, CV_THRESH_BINARY );
00559         
00560         // take the channel y and take the darkest values of skin locus
00561         cvThreshold( this->y , eyes_map_y, 80, 255, CV_THRESH_BINARY_INV);
00562         
00563         cvAnd( _eyes_map_bin, eyes_map_y, eyes );
00564         // cvAnd( eyes_map, eyes_map_y, eyes );
00565 
00566         // open the eye region
00567         //IplConvKernel* kernelOp = cvCreateStructuringElementEx( 4, 4, 1, 1, CV_SHAPE_CROSS, NULL );
00568         cvDilate( eyes , eyes_map_bin, NULL/*kernelOp*/ ,  1 );
00569 
00570 #ifdef EYES
00571         cvNamedWindow( "eyes", 1 );
00572         cvShowImage( "eyes", eyes_map_bin);
00573 #endif
00574 
00575         /*
00576         cvNamedWindow( "eyes_map", 1 );
00577         cvShowImage( "eyes_map", eyes_map);
00578         
00579         cvNamedWindow( "eyes_map_bin", 1 );
00580         cvShowImage( "eyes_map_bin", eyes_map_bin);
00581 
00582         cvNamedWindow( "eyes_Y", 1 );
00583         cvShowImage( "eyes_Y", eyes_map_y);
00584         
00585         cvNamedWindow( "eyes", 1 );
00586         cvShowImage( "eyes", eyes);
00587         */
00588 
00589         cvReleaseImage( &_eyes_map_bin );
00590         cvReleaseImage( &eyes_map_y );
00591         cvReleaseImage( &eyes );
00592 }
00593 
00594 void 
00595 CvFaceDetect::icvEyesDetect()
00596 {
00597 
00598         int eyes = 0 ;
00599 /*
00600         int x , y, width, height, count;
00601         double angle ;
00602 */
00603         Cvface *face;
00604         
00605         //printf ("face skin presenti : %d", this->faces->total);
00606         //printf ("face skin presenti : %d", this->contours);
00607 
00608         //for (int i = 0; i < this->contours; i++)
00609         for (int i = 0; i < this->faces->total ; i++)
00610         {       
00611                 //printf("width: %d , height: %d\n", this->skin_rect[i].width, this->skin_rect[i].height);
00612                 
00613                 /*
00614                 // draw a rectangle
00615                 CvPoint left_bottom = { this->skin_rect[i].x, this->skin_rect[i].y };
00616                 CvPoint right_top   = { this->skin_rect[i].x + this->skin_rect[i].width, 
00617                                                             this->skin_rect[i].y + this->skin_rect[i].height };
00618                 
00619                 cvRectangle( this->src, left_bottom, right_top, CV_RGB(255,0,0), 2, 4, 0 );
00620                 //*/
00621                 
00622                 /*
00623                 //draw a box
00624                 int n = 4;
00625                 CvPoint2D32f _box_point[4];
00626                 CvPoint box_point[4], *bpp = box_point;
00627 
00628                 cvBoxPoints( this->skin_box[i], _box_point );
00629                 
00630                 for (int i=0; i<n ; i++)
00631                 {
00632                         box_point[i] = cvPoint(cvRound(_box_point[i].x),cvRound(_box_point[i].y));
00633                 }
00634 
00635                 cvPolyLine( this->src, &bpp , &n, 1, 1, CV_RGB(255,0,0), 2, 8, 0 );
00636                 */
00637                 
00638                 /*
00639                 cvNamedWindow("eyes_", 1);
00640                 cvShowImage("eyes_", this->src);
00641                 cvWaitKey(0);
00642                 */
00643                 
00644                 face = (Cvface *)cvGetSeqElem( this->faces, i);
00645 
00646                 cvSetImageROI(this->eyes_map_bin, face->skin_face.skin_rect );
00647                 //cvSetImageROI(this->eyes_map_bin, this->skin_rect[i]);
00648                 
00649                                         
00650                 eyes = cvFindContours( this->eyes_map_bin , this->storage, &(this->contour) ,  
00651                                                 sizeof(CvContour), CV_RETR_EXTERNAL ,
00652                                                 CV_CHAIN_APPROX_SIMPLE ,
00653                                                 cvPoint( face->skin_face.skin_rect.x, face->skin_face.skin_rect.y )   );
00654                 
00655                 //if no eye is detect jump..
00656                 if (eyes == 0) continue;
00657                 
00658                 int _ey = 0;
00659 
00660                 for(CvSeq* temp_contour = this->contour; temp_contour != 0; temp_contour = temp_contour->h_next )
00661                 {                       
00662                         CvBox2D  box = cvMinAreaRect2( temp_contour );
00663                         
00664                         //printf("box_width : %f \t skin_rect : %d\n",box.size.width , this->skin_rect[i].width);
00665                         //printf("box_height : %f \t skin_rect: %d\n\n", box.size.height ,this->skin_rect[i].height);
00666                         
00667                         //CHANGE THIS PARAMETER SPECIFIC FOR YOUR APPLICATION POURPOSE
00668                         if (box.size.width  < (face->skin_face.skin_rect.width)/16   || //TOO SMALL
00669                                 box.size.height < (face->skin_face.skin_rect.height)/16 /* ||
00670                                 
00671                                 box.size.width  > (face->skin_face->skin_rect.width)/5.5    ||  //TOO BIG
00672                                 box.size.height > (face->skin_face->skin_rect.height)/4 */
00673                                 )
00674                         continue;
00675                         
00676                         //printf("pos : %d\t x: %f \n", _ey%2 , box.center.x);
00677                         //face->eyes_box[_ey%2] = new CvBox2D ;
00678 
00679                         face->eyes_box[_ey%2] = box ;
00680                         
00681                         _ey++;
00682 
00683                         /*
00684                         cvEllipse( this->src, cvPoint ((int) box.center.x , (int) box.center.y) , 
00685                                         cvSize( (int)box.size.width , (int)box.size.height), 
00686                                         (double)(360 * box.angle)/ (2 * CV_PI) - 90, 
00687                                         0, 360, cvScalar( 0, 255, 0 ),
00688                                         2, 4 );
00689                         */
00690 
00691                         /*
00692                         count ++;
00693                         x     += (int)box.center.x ;
00694                         y     += (int)box.center.y ;
00695                         width = max ((int)box.size.width, width) ;
00696                         height= max((int)box.size.height, height );
00697                         angle += box.angle ;
00698                         */
00699                         //printf ("angle : %f\n" , box.angle);
00700                 }
00701                 /*
00702                 if (count > 0)
00703                 {
00704                         cvEllipse( this->src, cvPoint ((int) x/count , (int) y/count) , 
00705                                         cvSize( width , height ), 
00706                                         (double)(360 * (angle /count))/ (2 * CV_PI) - 90, 
00707                                         0, 360, cvScalar( 0, 255, 255 ),
00708                                         2, 4 );
00709 
00710                 }
00711                 */
00712                 
00713                 /*
00714                 cvNamedWindow("eyes_", 1);
00715                 cvShowImage("eyes_", this->src);
00716                 cvWaitKey(0);
00717                 */
00718         }
00719         
00720         //cvClearMemStorage( storage );
00721 }
00722 
00723 void 
00724 CvFaceDetect::icvMouthEyesMap(IplImage * image)
00725 {
00726         this->eyes_map  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00727         this->y         = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00728         this->mouth_map = cvCreateImage(this->size, IPL_DEPTH_32F, 1  );
00729         
00730         cvSplit (ycc, y, 0, 0, 0);
00731 
00732         IplImage *cb2, *cr_2, *cbcr ;
00733         cb2   = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1  );
00734         cr_2  = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1  );
00735         cbcr  = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1  );
00736 
00737         // build channel cr^2 , cr-^2 and cb/cr (then normalize them)
00738         int _cr, _cb ;
00739         for ( int j = 0; j < this->size.height; j++ ) {
00740                 for ( int i=0; i < this->size.width; i++ ) {
00741 
00742                         _cr = CV_IMAGE_ELEM(ycc, unsigned char, j, 3*i +1);
00743                         _cb = CV_IMAGE_ELEM(ycc, unsigned char, j, 3*i +2);
00744                         
00745                         CV_IMAGE_ELEM( cb2, float, j, i )   = (float)(_cb * _cb) ;
00746                         CV_IMAGE_ELEM( cr_2, float, j, i )  = (float)(255 - _cr) * (255 - _cr) ;
00747                         CV_IMAGE_ELEM( cbcr, float, j, i )  = (float)(_cb / _cr) ;
00748                         
00749                         // build mouth_map
00750                         CV_IMAGE_ELEM( this->mouth_map, float, j, i )  = 
00751                                                                         (float) ( _cr * (255 - (_cr - _cb) ) * _cr ) ;
00752 
00753                 }
00754         }
00755 
00756         // calculate max and min value on two the channels cr^2 and crcb for the normalization
00757         double cb2_min = 0 , cb2_max = 0 , cr_2_min = 0, cr_2_max = 0 , cbcr_min = 0 , cbcr_max = 0;
00758 
00759         cvMinMaxLoc( cb2, &cb2_min , &cb2_max );
00760         cvMinMaxLoc( cr_2, &cr_2_min , &cr_2_max );
00761         cvMinMaxLoc( cbcr, &cbcr_min , &cbcr_max );
00762 
00763         // build normalized channels
00764         IplImage *cb2_norm, *cr_2_norm, *cbcr_norm ;
00765         cb2_norm   = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1  );
00766         cr_2_norm  = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1  );
00767         cbcr_norm  = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1  );
00768 
00769         // normalize channels on [0, 255]
00770         float _cbcr , _cb2, _cr_2 ;
00771         double cr_2_range  = cr_2_max - cr_2_min;
00772         double cbcr_range = cbcr_max - cbcr_min;
00773         double cb2_range = cb2_max - cb2_min;
00774 
00775         for ( int j = 0; j < this->size.height; j++ ) {
00776                 for ( int i=0; i < this->size.width; i++ ) {
00777 
00778                         _cb2 =  CV_IMAGE_ELEM( cb2 , float, j, i )  ;
00779                         _cr_2 = CV_IMAGE_ELEM( cr_2, float, j, i )      ;
00780                         _cbcr = CV_IMAGE_ELEM( cbcr, float, j, i )      ;
00781                         
00782                         // x normalizzare su [0, 255] uso la formula
00783                         // [(x - min)/(max - min)] * scala
00784                         CV_IMAGE_ELEM( cb2_norm  , unsigned char, j, i )  = 
00785                                                                 (unsigned char)(( (_cb2 - cb2_min) / cb2_range) * 255);
00786                         CV_IMAGE_ELEM( cr_2_norm  , unsigned char, j, i )  = 
00787                                                                 (unsigned char)(( (_cr_2 - cr_2_min) / cr_2_range) * 255);
00788                         CV_IMAGE_ELEM( cbcr_norm , unsigned char, j, i )  = 
00789                                                                 (unsigned char)(( (_cbcr - cbcr_min) / cbcr_range) * 255);
00790                                         
00791                 }
00792         }
00793 
00794         // build the eyes map
00795         for ( int j = 0; j < this->size.height; j++ ) {
00796                 for ( int i=0; i < this->size.width; i++ ) {
00797 
00798                         _cb2 =  CV_IMAGE_ELEM( cb2_norm , unsigned char, j, i )  ;
00799                         _cr_2 = CV_IMAGE_ELEM( cr_2_norm, unsigned char, j, i ) ;
00800                         _cbcr = CV_IMAGE_ELEM( cbcr_norm, unsigned char, j, i ) ;
00801                         
00802                         CV_IMAGE_ELEM( this->eyes_map  , unsigned char, j, i )  = 
00803                                                 (unsigned char) ( (_cb2 + _cr_2 + _cbcr  ) / 3 ) ;
00804                                         
00805                 }
00806         }
00807 
00808         cvReleaseImage( &cb2 );
00809         cvReleaseImage( &cr_2 );
00810         cvReleaseImage( &cbcr );
00811         cvReleaseImage( &cb2_norm );
00812         cvReleaseImage( &cr_2_norm );
00813         cvReleaseImage( &cbcr_norm );
00814 }
00815 
00816 void 
00817 CvFaceDetect::icvMouthEyesMask()
00818 {
00819         this->mouth_map_bin = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00820         this->eyes_map_bin  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00821 
00822         IplImage * _mouth_map_bin;
00823         _mouth_map_bin = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00824 
00825         IplImage *_eyes_map_bin,  *eyes_map_y , *eyes;
00826         _eyes_map_bin  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00827         eyes_map_y  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00828         eyes  = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00829 
00830         // max value MOUTH
00831         double map_min = 0 , map_max = 0 , map_range;
00832         cvMinMaxLoc( this->mouth_map, &map_min , &map_max );
00833         map_range = map_max - ( map_max * 0.04 );
00834 
00835         cvThreshold( this->mouth_map, _mouth_map_bin, map_range, 255, CV_THRESH_BINARY );
00836         
00837         IplConvKernel* kernelOp = cvCreateStructuringElementEx( 4, 3, 1, 1, CV_SHAPE_CROSS, NULL );
00838         cvDilate( _mouth_map_bin , this->mouth_map_bin, kernelOp,  1 );
00839 
00840         
00841 #ifdef MOUTH
00842         cvNamedWindow("mouth map bin", 1);
00843         cvShowImage("mouth", this->mouth_map_bin);
00844         cvWaitKey(0);
00845 #endif
00846 
00847         // max value EYES
00848         cvMinMaxLoc( this->eyes_map, &map_min , &map_max );
00849         map_range = map_max - ( map_max * 0.60 );
00850 
00851         // binarize map with 20% of highest values.
00852         cvThreshold( this->eyes_map, _eyes_map_bin, map_range, 255, CV_THRESH_BINARY );
00853         
00854         // take channel y and take darkest values of skin locus
00855         cvThreshold( this->y , eyes_map_y, 80, 255, CV_THRESH_BINARY_INV);
00856         
00857         cvAnd( _eyes_map_bin, eyes_map_y, eyes );
00858         //cvAnd( eyes_map, eyes_map_y, eyes );
00859 
00860         // open eye region
00861         //IplConvKernel* kernelOp = cvCreateStructuringElementEx( 4, 4, 1, 1, CV_SHAPE_CROSS, NULL );
00862         cvDilate( eyes , eyes_map_bin, NULL/*kernelOp*/ ,  1 );
00863 
00864 #ifdef EYES
00865         cvNamedWindow( "eyes", 1 );
00866         cvShowImage( "eyes", eyes_map_bin);
00867 #endif
00868 
00869         /*
00870 //      cvNamedWindow( "eyes_map", 1 );
00871 //      cvShowImage( "eyes_map", eyes_map);
00872         
00873         cvNamedWindow( "eyes_map_bin", 1 );
00874         cvShowImage( "eyes_map_bin", eyes_map_bin);
00875 
00876         cvNamedWindow( "eyes_Y", 1 );
00877         cvShowImage( "eyes_Y", eyes_map_y);
00878         
00879         cvNamedWindow( "eyes", 1 );
00880         cvShowImage( "eyes", eyes);
00881         //*/
00882 
00883         cvReleaseImage( &_eyes_map_bin );
00884         cvReleaseImage( &eyes_map_y );
00885         cvReleaseImage( &eyes );
00886 
00887         cvReleaseImage( &_mouth_map_bin );
00888 }
00889 
00890 void 
00891 CvFaceDetect::icvMouthEyesDetect()
00892 {
00893         int mouth = 0 ;
00894         int eyes = 0 ;
00895 
00896         int x , y, width, height, count;
00897         double angle ;
00898         
00899         Cvface *face ;
00900 
00901         for (int i = 0; i < this->faces->total; i++)
00902         {       
00903 
00904                 face = (Cvface *)cvGetSeqElem( this->faces, i);
00905 
00906                 cvSetImageROI(this->mouth_map_bin, face->skin_face.skin_rect );
00907                 cvSetImageROI(this->eyes_map_bin, face->skin_face.skin_rect );
00908 
00909                 x = y = height = width = count = 0;
00910                 angle = 0;
00911                                         
00912                 mouth = cvFindContours( this->mouth_map_bin , this->storage, &(this->contour) ,  
00913                                                 sizeof(CvContour), CV_RETR_EXTERNAL ,
00914                                                 CV_CHAIN_APPROX_SIMPLE ,
00915                                                 cvPoint( face->skin_face.skin_rect.x,face->skin_face.skin_rect.y )  );
00916                 
00917                 //if no mouth is detect jump..
00918                 if (mouth == 0) 
00919                 {
00920                         continue;
00921                 }
00922                 //printf("mouth : %d \n" , mouth);
00923 
00924                 for(CvSeq* temp_contour = this->contour; temp_contour != 0; temp_contour = temp_contour->h_next )
00925                 {                       
00926                         CvBox2D  box = cvMinAreaRect2( temp_contour );
00927                         
00928                         //CHANGE THIS PARAMETER SPECIFIC FOR YOUR APPLICATION POURPOSE
00929                         if (box.size.width  > (face->skin_face.skin_rect.width)/2.5   ||        //TOO BIG
00930                                 box.size.height > (face->skin_face.skin_rect.height)/4    ||
00931                                 box.size.width  < (face->skin_face.skin_rect.width)/14    ||    //TOO SMALL
00932                                 box.size.height < (face->skin_face.skin_rect.height)/14  
00933                                 )
00934                         continue;
00935                         
00936 
00937                         count ++;
00938                         x     += (int)box.center.x ;
00939                         y     += (int)box.center.y ;
00940                         width = MAX ((int)box.size.width, width) ;
00941                         height= MAX((int)box.size.height, height );
00942                         angle += box.angle ;
00943 
00944                         //printf ("angle : %f\n" , box.angle);
00945                 }
00946                 
00947                 if (count > 0)
00948                 {       
00949                         //face->mouth_box = new CvBox2D;
00950 
00951                         face->mouth_box.center = cvPoint2D32f( x/count , y/count); 
00952                         face->mouth_box.size   = cvSize2D32f( width , height );
00953                         face->mouth_box.angle  = (float) angle /count ;
00954 
00955                         //printf ("angle : %d\n" , (int)((360 * face->mouth_box.angle)/ (2 * CV_PI) - 90));
00956 
00957                 }
00958                 
00959                 /*
00960                 cvNamedWindow("mouth_", 1);
00961                 cvShowImage("mouth_", this->src);
00962                 cvWaitKey(0);
00963                 /*/
00964                 
00965                 eyes = cvFindContours( this->eyes_map_bin , this->storage, &(this->contour) ,  
00966                                                 sizeof(CvContour), CV_RETR_EXTERNAL ,
00967                                                 CV_CHAIN_APPROX_SIMPLE ,
00968                                                 cvPoint( face->skin_face.skin_rect.x, face->skin_face.skin_rect.y )   );
00969 
00970 
00971                 // if no eye is detect jump..
00972                 if (eyes == 0) continue;
00973                 
00974                 int _ey = 0;
00975                 
00976                 
00977                 for(CvSeq* temp_contour = this->contour; temp_contour != 0; temp_contour = temp_contour->h_next )
00978                 {                       
00979                         CvBox2D  box = cvMinAreaRect2( temp_contour );
00980                         
00981                         // CHANGE THIS PARAMETER SPECIFIC FOR YOUR APPLICATION POURPOSE
00982                         if (box.size.width  < (face->skin_face.skin_rect.width)/16   || //TOO SMALL
00983                                 box.size.height < (face->skin_face.skin_rect.height)/16  ||
00984                                 
00985                                 box.size.width  > (face->skin_face.skin_rect.width)/5.5    ||   //TOO BIG
00986                                 box.size.height > (face->skin_face.skin_rect.height)/4 
00987                                 )
00988                         continue;
00989                         
00990                         //face->eyes_box[_ey%2] = new CvBox2D ;
00991 
00992                         face->eyes_box[_ey%2] = box ;
00993                         
00994                         _ey++;
00995 
00996                 }
00997 
00998                 if ( &face->eyes_box[0]!=0 &&
00999                          &face->eyes_box[1]!=0 &&
01000                          &face->mouth_box !=0                   
01001                         //add other check like perpendicularity between eyes & mouth
01002                         )
01003                 {
01004                         face->track = true;
01005                         //printf("face %d enale to be tracked!\n\n", i);
01006                 }
01007                 /*
01008                 cvNamedWindow("eyes_", 1);
01009                 cvShowImage("eyes_", this->src);
01010                 cvWaitKey(0);
01011                 */
01012 
01013         }
01014 }
01015 
01016 

Generated on Tue Dec 26 10:32:38 2006 for Omnimeeting by  doxygen 1.4.7