00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
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
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
00188 continue;
00189
00190 }
00191 else
00192 {
00193 CvBox2D box = cvMinAreaRect2( temp_contour );
00194
00195
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
00211
00212
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
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
00282 rgbnorm = cvCreateImage(this->size, IPL_DEPTH_32F, 3 );
00283
00284
00285
00286
00287
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
00343 this->rgb_norm = icvRGBnorm(this->source);
00344
00345
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
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 (
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 (
00385 (
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 (
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 (
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
00400 (original_r > 30) && (original_g > 25) && (original_b > 20)
00401
00402 )
00403 {
00404
00405
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 }