CvVRFilter.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 
00047 //#include "precomp.h"
00048 #include "CvVRFilter.hh"
00049 
00050 
00051 CvVrFilter::CvVrFilter (int min, int max)
00052 {
00053         
00054         this->min_point = min;
00055         this->max_point = max;
00056 
00057         this->started = false ;
00058 
00059 }
00060 
00061 CvVrFilter::~CvVrFilter ()
00062 {       
00063         cvReleaseImage( &this->median );
00064         cvReleaseImage( &this->rgb_norm );
00065         cvReleaseImage( &this->skin_mask );
00066 
00067         
00068 }
00069 
00070 IplImage *
00071 CvVrFilter::cvVrFilter(IplImage * image , CvMemStorage *storage, CvSeq *seq)
00072 {       
00073         if (started)
00074         {       
00075                 cvReleaseImage( &this->median );
00076                 cvReleaseImage( &this->rgb_norm );
00077                 cvReleaseImage( &this->skin_mask );
00078 
00079         }
00080         else
00081         {       
00082                 this->size = cvGetSize(image);
00083         }
00084 
00085         this->started = true ;
00086         this->source = image;
00087 
00088         
00089         icvSkinMask ();
00090         icvContours(storage, seq);
00091 
00092         return cvGetContoursMap(seq);
00093         
00094 }
00095 
00096 IplImage * 
00097 CvVrFilter::cvGetSkinMask()
00098 {       
00099         IplImage *_skin_mask ;
00100         _skin_mask = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00101         cvSmooth (this->median, _skin_mask, CV_MEDIAN, 9, 9, 0);
00102 
00103         return _skin_mask;
00104 }
00105 
00106 IplImage * 
00107 CvVrFilter::cvGetSkinMap(CvSeq *seq)
00108 {       
00109         IplImage *skin_map;
00110         cvGetContoursMask(seq);
00111 
00112         skin_map = icvCreateMap(this->source, this->skin_mask);
00113 
00114         return skin_map;
00115 }
00116 
00117 IplImage * 
00118 CvVrFilter::cvGetContoursMask( CvSeq *seq, bool color_mask )
00119 {       
00120         IplImage *contours_mask;
00121 
00122         if (color_mask)
00123                 contours_mask = cvCreateImage(this->size, IPL_DEPTH_8U, 3  );
00124         else
00125                 contours_mask = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00126 
00127         CvScalar color ;
00128         
00129         for (int i = 0; i < seq->total ; i++)
00130         {       
00131                 Cvface *face;
00132                 face = (Cvface *)cvGetSeqElem( seq, i );
00133 
00134                 if (color_mask)
00135                         color = CV_RGB( rand()&255, rand()&255, rand()&255 );
00136                 else    
00137                         color = CV_RGB( 255, 255, 255 );
00138 
00139                 // replace CV_FILLED with 1 to see only the outlines 
00140                 cvDrawContours( contours_mask, &face->skin_face.skin_contour , color, color, -1, CV_FILLED, 8 );
00141         }
00142 
00143 #ifdef SKIN_SHOW
00144         cvNamedWindow( "mask_contours", 1 );
00145         cvShowImage( "mask_contours", contours_mask);
00146         cvWaitKey(0);
00147 #endif
00148 
00149         return contours_mask;
00150 }
00151 
00152 IplImage * 
00153 CvVrFilter::cvGetContoursMap(CvSeq *seq)
00154 {       
00155         IplImage *contours_map, *contours_mask;
00156         contours_mask = cvGetContoursMask(seq);
00157 
00158         contours_map = icvCreateMap(this->source, contours_mask);
00159 
00160 #ifdef SKIN_SHOW
00161         cvNamedWindow( "skin_contours", 1 );
00162         cvShowImage( "skin_contours", contours_map);
00163         cvWaitKey(0);
00164 #endif
00165         
00166         cvReleaseImage( &contours_mask );
00167 
00168         return contours_map;
00169 
00170 }
00171 
00172 
00173 void 
00174 CvVrFilter::icvContours(CvMemStorage *storage , CvSeq * seq)
00175 {       
00176         CvSeq *contour = 0;
00177 
00178         int cont = cvFindContours( this->skin_mask , storage, &(contour) ,  
00179                                                                                 sizeof(CvContour), CV_RETR_EXTERNAL  );
00180         
00181         for(CvSeq* temp_contour = contour; temp_contour != 0; temp_contour = temp_contour->h_next )
00182         {       
00183         
00184 
00185                 if ( (temp_contour->total  < this->min_point) || (temp_contour->total  > this->max_point))
00186                 {
00187                         //cvClearSeq(temp_contour );
00188                         continue;
00189 
00190                 }
00191                 else
00192                 {       
00193                         CvBox2D box = cvMinAreaRect2( temp_contour );
00194                         
00195                         //CHANGE THIS PARAMETER SPECIFIC FOR YOUR APPLICATION POURPOSE
00196                         if( box.size.height/box.size.width > H_ON_W_VALUE ||
00197                                 box.size.width/box.size.height > W_ON_H_VALUE )
00198                                 continue;
00199                         
00200                         Cvface face;
00201                         memset(&face, 0, sizeof(Cvface));
00202 
00203                         face.skin_face.skin_rect = cvBoundingRect(temp_contour, 0 );
00204                         face.skin_face.skin_box = cvMinAreaRect2( temp_contour );
00205 
00206                         face.skin_face.skin_contour = *temp_contour;
00207                         
00208                         face.track = false ;
00209 
00210                         //memset(&face.mouth_box, 0, sizeof(CvBox2D));
00211                         //memset(&face.eyes_box[0], 0, sizeof(CvBox2D));
00212                         //memset(&face.eyes_box[1], 0, sizeof(CvBox2D));
00213 
00214                         cvSeqPush( seq ,  &face );
00215 
00216                 }
00217         }
00218 
00219 }
00220 
00221 IplImage * 
00222 CvVrFilter::icvCreateMap(const IplImage * src, const IplImage * mask)
00223 {
00224         if ((src->width != mask->width) || (src->height != mask->height))
00225                  cvError( 0, "icvCreateMap","src and mask image must have the same size",
00226                                 "cvvrfilter.cpp", 178);
00227 
00228         if (mask->nChannels != 1)
00229                 cvError( 0, "icvCreateMap","mask image must be a 1 channel image",
00230                                 "cvvrfilter.cpp", 178);
00231 
00232         IplImage *temp;
00233         
00234         // create the resulting image
00235         temp = cvCreateImage(cvSize(src->width,src->height),src->depth, src->nChannels );
00236         
00237         uchar * temp_ptr , *src_ptr;
00238         temp_ptr = &(CV_IMAGE_ELEM( temp, unsigned char, 0, 0));
00239         src_ptr = &(CV_IMAGE_ELEM(src, unsigned char, 0, 0));
00240 
00241         int pos = 0 ;
00242         int step = src->widthStep ;
00243 
00244         int original_r, original_g, original_b ;
00245         for ( int j = 0; j < src->height ; j++ ) {
00246                 for ( int i=0; i < src->width ; i++ ) {
00247                         
00248                         pos = 3*i + j*step ;
00249 
00250                         if ( 0xFF == CV_IMAGE_ELEM(mask, unsigned char, j, i )  )
00251                         {
00252                                 
00253                                 original_b = src_ptr[pos + 0];
00254                                 original_g = src_ptr[pos + 1];
00255                                 original_r = src_ptr[pos + 2];
00256 
00257                                                                 
00258                                 temp_ptr[pos + 0] = original_b;
00259                                 temp_ptr[pos + 1] = original_g;
00260                                 temp_ptr[pos + 2] = original_r;
00261 
00262                         }
00263                         else
00264                         {
00265                                 
00266                                 temp_ptr[pos + 0] = 0xFF;
00267                                 temp_ptr[pos + 1] = 0xFF;
00268                                 temp_ptr[pos + 2] = 0xFF;
00269                         }
00270                 }
00271         }
00272         
00273         return temp;
00274 }
00275 
00276 IplImage * 
00277 CvVrFilter::icvRGBnorm(IplImage * image)
00278 {       
00279         IplImage *rgbnorm ;
00280         
00281         // create the resulting image
00282         rgbnorm = cvCreateImage(this->size, IPL_DEPTH_32F, 3  );
00283 
00284 
00285         //build rgb normalized space
00286         
00287         //pointer to the images data
00288         uchar * src_ptr ; float * dest_ptr;
00289         src_ptr = &(CV_IMAGE_ELEM( image, unsigned char, 0, 0));
00290         dest_ptr = &(CV_IMAGE_ELEM( rgbnorm, float, 0, 0));
00291         int pos = 0;
00292         int step = image->widthStep ;
00293         
00294         int original_r, original_g, original_b, sum;
00295         for ( int j = 0; j < this->size.height ; j++ ) 
00296         {
00297                 for ( int i=0; i < this->size.width ; i++ ) 
00298                 {
00299 
00300                         pos = 3*i + j*step ;
00301 
00302                         original_b = src_ptr[pos + 0];
00303                         original_g = src_ptr[pos + 1];
00304                         original_r = src_ptr[pos + 2];
00305 
00306                         sum = original_r + original_b + original_g + 1;
00307                         
00308                         dest_ptr[pos + 0] = (float)(original_r + 1)/sum;
00309                         dest_ptr[pos + 1] = (float)(original_g + 1)/sum;
00310                         dest_ptr[pos + 2] = (float)(original_b + 1)/sum;
00311                         
00312                 }
00313         }
00314 
00315         return rgbnorm ;
00316 
00317 }
00318 
00319 double * 
00320 CvVrFilter::icvPline (double x1, double x2, double y1, double y2 )
00321 {
00322         double *pline;
00323         pline = new double[2];
00324 
00325         pline[0] = (y2 - y1)/(x2 - x1);
00326         pline[1] = y2 -(x2*pline[0]);
00327 
00328         return pline;
00329 
00330 }
00331 
00332 void 
00333 CvVrFilter::icvSkinMask ()
00334 {       
00335 
00336         this->median = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00337         this->skin_mask = cvCreateImage(this->size, IPL_DEPTH_8U, 1  );
00338 
00339         cvZero( median );
00340         cvZero( skin_mask );
00341 
00342         //create rgb normalized color space
00343         this->rgb_norm = icvRGBnorm(this->source);
00344 
00345     //create statistic of image channels r/b
00346         CvScalar rgb_mean , rgb_sdv ;
00347         rgb_mean = rgb_sdv = cvScalarAll(0);
00348 
00349         cvAvgSdv( rgb_norm, &rgb_mean, &rgb_sdv, NULL );
00350         
00351         double *bg_pline ;
00352         bg_pline = icvPline (rgb_mean.val[2], (rgb_mean.val[2] - rgb_sdv.val[2]), rgb_mean.val[1], (rgb_mean.val[1] - rgb_sdv.val[1]));
00353         
00354         double norm_b, norm_g;
00355         int original_r, original_g, original_b;
00356         
00357         //pointer to the images data
00358         uchar * src_ptr ; float * dest_ptr;
00359         src_ptr = &(CV_IMAGE_ELEM( this->source, unsigned char, 0, 0));
00360         dest_ptr = &(CV_IMAGE_ELEM( this->rgb_norm, float, 0, 0));
00361         int pos = 0;
00362         int step = this->source->widthStep ;
00363 
00364         for ( int j = 0; j <  this->size.height ; j++ ) 
00365         {
00366                 for ( int i = 0; i < this->size.width ; i++ ) 
00367                 {       
00368                         pos = 3*i + j*step ;
00369                                                 
00370                         original_b = src_ptr[pos + 0];
00371                         original_g = src_ptr[pos + 1];
00372                         original_r = src_ptr[pos + 2];
00373                         
00374                         norm_b = dest_ptr[pos + 2];
00375                         norm_g = dest_ptr[pos + 1];
00376 
00377                         if ( 
00378                                 (//Filt3
00379                                   (original_g < 165) && (original_g < original_r - 25) &&
00380                                   (original_g < 0.8*original_r) && (original_g > 0.6*original_r) && 
00381                                   (original_b < (original_g + original_r)/2)
00382                 )&&
00383                                 
00384                                 (//F3 OR F2
00385                                  (//F3
00386                                   ((norm_g > rgb_mean.val[1] - rgb_sdv.val[1]) && (norm_g < rgb_mean.val[1] + rgb_sdv.val[1]) && (norm_b < rgb_mean.val[2]))
00387                                 )||
00388                                  (//F2
00389                                   (norm_g > bg_pline[0]*norm_b + bg_pline[1] - rgb_sdv.val[1]) &&
00390                                   (norm_g < bg_pline[0]*norm_b + bg_pline[1] + rgb_sdv.val[1]) &&
00391                                   (norm_g < rgb_mean.val[1] + rgb_sdv.val[1])
00392                                  )
00393                                 )&&
00394                                 
00395                                 (//F1
00396                                   ( (((norm_b - rgb_mean.val[2])/0.2)*((norm_b - rgb_mean.val[2])/0.2) + ((norm_g - rgb_mean.val[2])/0.2)*((norm_g - rgb_mean.val[2])/0.2)) < 1 ) 
00397                                 )&&
00398                                 
00399                                 //thresold
00400                                 (original_r > 30) && (original_g > 25) && (original_b > 20)
00401                                 
00402                                 )
00403                         {
00404                         
00405                         //black and white mask
00406                         CV_IMAGE_ELEM (this->median, unsigned char, j, i )   = 0xff; 
00407             
00408             
00409                         }
00410                 }
00411         }
00412 
00413 #ifdef SKIN_SHOW
00414         cvNamedWindow( "debug", 1 );
00415         cvShowImage( "debug", this->median);
00416         cvWaitKey(0);
00417 #endif
00418 
00419 
00420         cvSmooth (this->median, this->skin_mask, CV_MEDIAN, 9, 9, 0);
00421         
00422 #ifdef SKIN_SHOW
00423         cvNamedWindow( "skin_mask", 1 );
00424         cvShowImage( "skin_mask", this->skin_mask);
00425         cvWaitKey(0);
00426 #endif
00427         
00428 }

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