1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // Intel License Agreement 11 // 12 // Copyright (C) 2000, Intel Corporation, all rights reserved. 13 // Third party copyrights are property of their respective owners. 14 // 15 // Redistribution and use in source and binary forms, with or without modification, 16 // are permitted provided that the following conditions are met: 17 // 18 // * Redistribution's of source code must retain the above copyright notice, 19 // this list of conditions and the following disclaimer. 20 // 21 // * Redistribution's in binary form must reproduce the above copyright notice, 22 // this list of conditions and the following disclaimer in the documentation 23 // and/or other materials provided with the distribution. 24 // 25 // * The name of Intel Corporation may not be used to endorse or promote products 26 // derived from this software without specific prior written permission. 27 // 28 // This software is provided by the copyright holders and contributors "as is" and 29 // any express or implied warranties, including, but not limited to, the implied 30 // warranties of merchantability and fitness for a particular purpose are disclaimed. 31 // In no event shall the Intel Corporation or contributors be liable for any direct, 32 // indirect, incidental, special, exemplary, or consequential damages 33 // (including, but not limited to, procurement of substitute goods or services; 34 // loss of use, data, or profits; or business interruption) however caused 35 // and on any theory of liability, whether in contract, strict liability, 36 // or tort (including negligence or otherwise) arising in any way out of 37 // the use of this software, even if advised of the possibility of such damage. 38 // 39 //M*/ 40 41 42 // This is based on the "An Improved Adaptive Background Mixture Model for 43 // Real-time Tracking with Shadow Detection" by P. KaewTraKulPong and R. Bowden 44 // http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf 45 // 46 // The windowing method is used, but not the shadow detection. I make some of my 47 // own modifications which make more sense. There are some errors in some of their 48 // equations. 49 // 50 //IplImage values of image that are useful 51 //int nSize; /* sizeof(IplImage) */ 52 //int depth; /* pixel depth in bits: IPL_DEPTH_8U ...*/ 53 //int nChannels; /* OpenCV functions support 1,2,3 or 4 channels */ 54 //int width; /* image width in pixels */ 55 //int height; /* image height in pixels */ 56 //int imageSize; /* image data size in bytes in case of interleaved data)*/ 57 //char *imageData; /* pointer to aligned image data */ 58 //char *imageDataOrigin; /* pointer to very origin of image -deallocation */ 59 //Values useful for gaussian integral 60 //0.5 - 0.19146 - 0.38292 61 //1.0 - 0.34134 - 0.68268 62 //1.5 - 0.43319 - 0.86638 63 //2.0 - 0.47725 - 0.95450 64 //2.5 - 0.49379 - 0.98758 65 //3.0 - 0.49865 - 0.99730 66 //3.5 - 0.4997674 - 0.9995348 67 //4.0 - 0.4999683 - 0.9999366 68 69 #include "_cvaux.h" 70 71 72 //internal functions for gaussian background detection 73 static void icvInsertionSortGaussians( CvGaussBGPoint* g_point, double* sort_key, CvGaussBGStatModelParams *bg_model_params ); 74 75 /* 76 Test whether pixel can be explained by background model; 77 Return -1 if no match was found; otherwise the index in match[] is returned 78 79 icvMatchTest(...) assumes what all color channels component exhibit the same variance 80 icvMatchTest2(...) accounts for different variances per color channel 81 */ 82 static int icvMatchTest( double* src_pixel, int nChannels, int* match, 83 const CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params ); 84 /*static int icvMatchTest2( double* src_pixel, int nChannels, int* match, 85 const CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params );*/ 86 87 88 /* 89 The update procedure differs between 90 * the initialization phase (named *Partial* ) and 91 * the normal phase (named *Full* ) 92 The initalization phase is defined as not having processed <win_size> frames yet 93 */ 94 static void icvUpdateFullWindow( double* src_pixel, int nChannels, 95 int* match, 96 CvGaussBGPoint* g_point, 97 const CvGaussBGStatModelParams *bg_model_params ); 98 static void icvUpdateFullNoMatch( IplImage* gm_image, int p, 99 int* match, 100 CvGaussBGPoint* g_point, 101 const CvGaussBGStatModelParams *bg_model_params); 102 static void icvUpdatePartialWindow( double* src_pixel, int nChannels, int* match, 103 CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params ); 104 static void icvUpdatePartialNoMatch( double* src_pixel, int nChannels, 105 int* match, 106 CvGaussBGPoint* g_point, 107 const CvGaussBGStatModelParams *bg_model_params); 108 109 110 static void icvGetSortKey( const int nChannels, double* sort_key, const CvGaussBGPoint* g_point, 111 const CvGaussBGStatModelParams *bg_model_params ); 112 static void icvBackgroundTest( const int nChannels, int n, int i, int j, int *match, CvGaussBGModel* bg_model ); 113 114 static void CV_CDECL icvReleaseGaussianBGModel( CvGaussBGModel** bg_model ); 115 static int CV_CDECL icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model ); 116 117 //#define for if(0);else for 118 119 //g = 1 for first gaussian in list that matches else g = 0 120 //Rw is the learning rate for weight and Rg is leaning rate for mean and variance 121 //Ms is the match_sum which is the sum of matches for a particular gaussian 122 //Ms values are incremented until the sum of Ms values in the list equals window size L 123 //SMs is the sum of match_sums for gaussians in the list 124 //Rw = 1/SMs note the smallest Rw gets is 1/L 125 //Rg = g/Ms for SMs < L and Rg = g/(w*L) for SMs = L 126 //The list is maintained in sorted order using w/sqrt(variance) as a key 127 //If there is no match the last gaussian in the list is replaced by the new gaussian 128 //This will result in changes to SMs which results in changes in Rw and Rg. 129 //If a gaussian is replaced and SMs previously equaled L values of Ms are computed from w 130 //w[n+1] = w[n] + Rw*(g - w[n]) weight 131 //u[n+1] = u[n] + Rg*(x[n+1] - u[n]) mean value Sg is sum n values of g 132 //v[n+1] = v[n] + Rg*((x[n+1] - u[n])*(x[n+1] - u[n])) - v[n]) variance 133 // 134 135 CV_IMPL CvBGStatModel* 136 cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters ) 137 { 138 CvGaussBGModel* bg_model = 0; 139 140 CV_FUNCNAME( "cvCreateGaussianBGModel" ); 141 142 __BEGIN__; 143 144 double var_init; 145 CvGaussBGStatModelParams params; 146 int i, j, k, m, n; 147 148 //init parameters 149 if( parameters == NULL ) 150 { /* These constants are defined in cvaux/include/cvaux.h: */ 151 params.win_size = CV_BGFG_MOG_WINDOW_SIZE; 152 params.bg_threshold = CV_BGFG_MOG_BACKGROUND_THRESHOLD; 153 154 params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD; 155 params.weight_init = CV_BGFG_MOG_WEIGHT_INIT; 156 157 params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT; 158 params.minArea = CV_BGFG_MOG_MINAREA; 159 params.n_gauss = CV_BGFG_MOG_NGAUSSIANS; 160 } 161 else 162 { 163 params = *parameters; 164 } 165 166 if( !CV_IS_IMAGE(first_frame) ) 167 CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" ); 168 169 CV_CALL( bg_model = (CvGaussBGModel*)cvAlloc( sizeof(*bg_model) )); 170 memset( bg_model, 0, sizeof(*bg_model) ); 171 bg_model->type = CV_BG_MODEL_MOG; 172 bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel; 173 bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel; 174 175 bg_model->params = params; 176 177 //prepare storages 178 CV_CALL( bg_model->g_point = (CvGaussBGPoint*)cvAlloc(sizeof(CvGaussBGPoint)* 179 ((first_frame->width*first_frame->height) + 256))); 180 181 CV_CALL( bg_model->background = cvCreateImage(cvSize(first_frame->width, 182 first_frame->height), IPL_DEPTH_8U, first_frame->nChannels)); 183 CV_CALL( bg_model->foreground = cvCreateImage(cvSize(first_frame->width, 184 first_frame->height), IPL_DEPTH_8U, 1)); 185 186 CV_CALL( bg_model->storage = cvCreateMemStorage()); 187 188 //initializing 189 var_init = 2 * params.std_threshold * params.std_threshold; 190 CV_CALL( bg_model->g_point[0].g_values = 191 (CvGaussBGValues*)cvAlloc( sizeof(CvGaussBGValues)*params.n_gauss* 192 (first_frame->width*first_frame->height + 128))); 193 194 for( i = 0, n = 0; i < first_frame->height; i++ ) 195 { 196 for( j = 0; j < first_frame->width; j++, n++ ) 197 { 198 const int p = i*first_frame->widthStep+j*first_frame->nChannels; 199 200 bg_model->g_point[n].g_values = 201 bg_model->g_point[0].g_values + n*params.n_gauss; 202 bg_model->g_point[n].g_values[0].weight = 1; //the first value seen has weight one 203 bg_model->g_point[n].g_values[0].match_sum = 1; 204 for( m = 0; m < first_frame->nChannels; m++) 205 { 206 bg_model->g_point[n].g_values[0].variance[m] = var_init; 207 bg_model->g_point[n].g_values[0].mean[m] = (unsigned char)first_frame->imageData[p + m]; 208 } 209 for( k = 1; k < params.n_gauss; k++) 210 { 211 bg_model->g_point[n].g_values[k].weight = 0; 212 bg_model->g_point[n].g_values[k].match_sum = 0; 213 for( m = 0; m < first_frame->nChannels; m++){ 214 bg_model->g_point[n].g_values[k].variance[m] = var_init; 215 bg_model->g_point[n].g_values[k].mean[m] = 0; 216 } 217 } 218 } 219 } 220 221 bg_model->countFrames = 0; 222 223 __END__; 224 225 if( cvGetErrStatus() < 0 ) 226 { 227 CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model; 228 229 if( bg_model && bg_model->release ) 230 bg_model->release( &base_ptr ); 231 else 232 cvFree( &bg_model ); 233 bg_model = 0; 234 } 235 236 return (CvBGStatModel*)bg_model; 237 } 238 239 240 static void CV_CDECL 241 icvReleaseGaussianBGModel( CvGaussBGModel** _bg_model ) 242 { 243 CV_FUNCNAME( "icvReleaseGaussianBGModel" ); 244 245 __BEGIN__; 246 247 if( !_bg_model ) 248 CV_ERROR( CV_StsNullPtr, "" ); 249 250 if( *_bg_model ) 251 { 252 CvGaussBGModel* bg_model = *_bg_model; 253 if( bg_model->g_point ) 254 { 255 cvFree( &bg_model->g_point[0].g_values ); 256 cvFree( &bg_model->g_point ); 257 } 258 259 cvReleaseImage( &bg_model->background ); 260 cvReleaseImage( &bg_model->foreground ); 261 cvReleaseMemStorage(&bg_model->storage); 262 memset( bg_model, 0, sizeof(*bg_model) ); 263 cvFree( _bg_model ); 264 } 265 266 __END__; 267 } 268 269 270 static int CV_CDECL 271 icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model ) 272 { 273 int i, j, k, n; 274 int region_count = 0; 275 CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL; 276 277 bg_model->countFrames++; 278 279 for( i = 0, n = 0; i < curr_frame->height; i++ ) 280 { 281 for( j = 0; j < curr_frame->width; j++, n++ ) 282 { 283 int match[CV_BGFG_MOG_MAX_NGAUSSIANS]; 284 double sort_key[CV_BGFG_MOG_MAX_NGAUSSIANS]; 285 const int nChannels = curr_frame->nChannels; 286 const int p = curr_frame->widthStep*i+j*nChannels; 287 288 // A few short cuts 289 CvGaussBGPoint* g_point = &bg_model->g_point[n]; 290 const CvGaussBGStatModelParams bg_model_params = bg_model->params; 291 double pixel[4]; 292 int no_match; 293 294 for( k = 0; k < nChannels; k++ ) 295 pixel[k] = (uchar)curr_frame->imageData[p+k]; 296 297 no_match = icvMatchTest( pixel, nChannels, match, g_point, &bg_model_params ); 298 if( bg_model->countFrames >= bg_model->params.win_size ) 299 { 300 icvUpdateFullWindow( pixel, nChannels, match, g_point, &bg_model->params ); 301 if( no_match == -1) 302 icvUpdateFullNoMatch( curr_frame, p, match, g_point, &bg_model_params ); 303 } 304 else 305 { 306 icvUpdatePartialWindow( pixel, nChannels, match, g_point, &bg_model_params ); 307 if( no_match == -1) 308 icvUpdatePartialNoMatch( pixel, nChannels, match, g_point, &bg_model_params ); 309 } 310 icvGetSortKey( nChannels, sort_key, g_point, &bg_model_params ); 311 icvInsertionSortGaussians( g_point, sort_key, (CvGaussBGStatModelParams *)&bg_model_params ); 312 icvBackgroundTest( nChannels, n, i, j, match, bg_model ); 313 } 314 } 315 316 //foreground filtering 317 318 //filter small regions 319 cvClearMemStorage(bg_model->storage); 320 321 //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 ); 322 //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 ); 323 324 cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST ); 325 for( seq = first_seq; seq; seq = seq->h_next ) 326 { 327 CvContour* cnt = (CvContour*)seq; 328 if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea ) 329 { 330 //delete small contour 331 prev_seq = seq->h_prev; 332 if( prev_seq ) 333 { 334 prev_seq->h_next = seq->h_next; 335 if( seq->h_next ) seq->h_next->h_prev = prev_seq; 336 } 337 else 338 { 339 first_seq = seq->h_next; 340 if( seq->h_next ) seq->h_next->h_prev = NULL; 341 } 342 } 343 else 344 { 345 region_count++; 346 } 347 } 348 bg_model->foreground_regions = first_seq; 349 cvZero(bg_model->foreground); 350 cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1); 351 352 return region_count; 353 } 354 355 static void icvInsertionSortGaussians( CvGaussBGPoint* g_point, double* sort_key, CvGaussBGStatModelParams *bg_model_params ) 356 { 357 int i, j; 358 for( i = 1; i < bg_model_params->n_gauss; i++ ) 359 { 360 double index = sort_key[i]; 361 for( j = i; j > 0 && sort_key[j-1] < index; j-- ) //sort decending order 362 { 363 double temp_sort_key = sort_key[j]; 364 sort_key[j] = sort_key[j-1]; 365 sort_key[j-1] = temp_sort_key; 366 367 CvGaussBGValues temp_gauss_values = g_point->g_values[j]; 368 g_point->g_values[j] = g_point->g_values[j-1]; 369 g_point->g_values[j-1] = temp_gauss_values; 370 } 371 // sort_key[j] = index; 372 } 373 } 374 375 376 static int icvMatchTest( double* src_pixel, int nChannels, int* match, 377 const CvGaussBGPoint* g_point, 378 const CvGaussBGStatModelParams *bg_model_params ) 379 { 380 int k; 381 int matchPosition=-1; 382 for ( k = 0; k < bg_model_params->n_gauss; k++) match[k]=0; 383 384 for ( k = 0; k < bg_model_params->n_gauss; k++) { 385 double sum_d2 = 0.0; 386 double var_threshold = 0.0; 387 for(int m = 0; m < nChannels; m++){ 388 double d = g_point->g_values[k].mean[m]- src_pixel[m]; 389 sum_d2 += (d*d); 390 var_threshold += g_point->g_values[k].variance[m]; 391 } //difference < STD_LIMIT*STD_LIMIT or difference**2 < STD_LIMIT*STD_LIMIT*VAR 392 var_threshold = bg_model_params->std_threshold*bg_model_params->std_threshold*var_threshold; 393 if(sum_d2 < var_threshold){ 394 match[k] = 1; 395 matchPosition = k; 396 break; 397 } 398 } 399 400 return matchPosition; 401 } 402 403 /* 404 static int icvMatchTest2( double* src_pixel, int nChannels, int* match, 405 const CvGaussBGPoint* g_point, 406 const CvGaussBGStatModelParams *bg_model_params ) 407 { 408 int k, m; 409 int matchPosition=-1; 410 411 for( k = 0; k < bg_model_params->n_gauss; k++ ) 412 match[k] = 0; 413 414 for( k = 0; k < bg_model_params->n_gauss; k++ ) 415 { 416 double sum_d2 = 0.0, var_threshold; 417 for( m = 0; m < nChannels; m++ ) 418 { 419 double d = g_point->g_values[k].mean[m]- src_pixel[m]; 420 sum_d2 += (d*d) / (g_point->g_values[k].variance[m] * g_point->g_values[k].variance[m]); 421 } //difference < STD_LIMIT*STD_LIMIT or difference**2 < STD_LIMIT*STD_LIMIT*VAR 422 423 var_threshold = bg_model_params->std_threshold*bg_model_params->std_threshold; 424 if( sum_d2 < var_threshold ) 425 { 426 match[k] = 1; 427 matchPosition = k; 428 break; 429 } 430 } 431 432 return matchPosition; 433 } 434 */ 435 436 static void icvUpdateFullWindow( double* src_pixel, int nChannels, int* match, 437 CvGaussBGPoint* g_point, 438 const CvGaussBGStatModelParams *bg_model_params ) 439 { 440 const double learning_rate_weight = (1.0/(double)bg_model_params->win_size); 441 for(int k = 0; k < bg_model_params->n_gauss; k++){ 442 g_point->g_values[k].weight = g_point->g_values[k].weight + 443 (learning_rate_weight*((double)match[k] - 444 g_point->g_values[k].weight)); 445 if(match[k]){ 446 double learning_rate_gaussian = (double)match[k]/(g_point->g_values[k].weight* 447 (double)bg_model_params->win_size); 448 for(int m = 0; m < nChannels; m++){ 449 const double tmpDiff = src_pixel[m] - g_point->g_values[k].mean[m]; 450 g_point->g_values[k].mean[m] = g_point->g_values[k].mean[m] + 451 (learning_rate_gaussian * tmpDiff); 452 g_point->g_values[k].variance[m] = g_point->g_values[k].variance[m]+ 453 (learning_rate_gaussian*((tmpDiff*tmpDiff) - g_point->g_values[k].variance[m])); 454 } 455 } 456 } 457 } 458 459 460 static void icvUpdatePartialWindow( double* src_pixel, int nChannels, int* match, CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params ) 461 { 462 int k, m; 463 int window_current = 0; 464 465 for( k = 0; k < bg_model_params->n_gauss; k++ ) 466 window_current += g_point->g_values[k].match_sum; 467 468 for( k = 0; k < bg_model_params->n_gauss; k++ ) 469 { 470 g_point->g_values[k].match_sum += match[k]; 471 double learning_rate_weight = (1.0/((double)window_current + 1.0)); //increased by one since sum 472 g_point->g_values[k].weight = g_point->g_values[k].weight + 473 (learning_rate_weight*((double)match[k] - g_point->g_values[k].weight)); 474 475 if( g_point->g_values[k].match_sum > 0 && match[k] ) 476 { 477 double learning_rate_gaussian = (double)match[k]/((double)g_point->g_values[k].match_sum); 478 for( m = 0; m < nChannels; m++ ) 479 { 480 const double tmpDiff = src_pixel[m] - g_point->g_values[k].mean[m]; 481 g_point->g_values[k].mean[m] = g_point->g_values[k].mean[m] + 482 (learning_rate_gaussian*tmpDiff); 483 g_point->g_values[k].variance[m] = g_point->g_values[k].variance[m]+ 484 (learning_rate_gaussian*((tmpDiff*tmpDiff) - g_point->g_values[k].variance[m])); 485 } 486 } 487 } 488 } 489 490 static void icvUpdateFullNoMatch( IplImage* gm_image, int p, int* match, 491 CvGaussBGPoint* g_point, 492 const CvGaussBGStatModelParams *bg_model_params) 493 { 494 int k, m; 495 double alpha; 496 int match_sum_total = 0; 497 498 //new value of last one 499 g_point->g_values[bg_model_params->n_gauss - 1].match_sum = 1; 500 501 //get sum of all but last value of match_sum 502 503 for( k = 0; k < bg_model_params->n_gauss ; k++ ) 504 match_sum_total += g_point->g_values[k].match_sum; 505 506 g_point->g_values[bg_model_params->n_gauss - 1].weight = 1./(double)match_sum_total; 507 for( m = 0; m < gm_image->nChannels ; m++ ) 508 { 509 // first pass mean is image value 510 g_point->g_values[bg_model_params->n_gauss - 1].variance[m] = bg_model_params->variance_init; 511 g_point->g_values[bg_model_params->n_gauss - 1].mean[m] = (unsigned char)gm_image->imageData[p + m]; 512 } 513 514 alpha = 1.0 - (1.0/bg_model_params->win_size); 515 for( k = 0; k < bg_model_params->n_gauss - 1; k++ ) 516 { 517 g_point->g_values[k].weight *= alpha; 518 if( match[k] ) 519 g_point->g_values[k].weight += alpha; 520 } 521 } 522 523 524 static void 525 icvUpdatePartialNoMatch(double *pixel, 526 int nChannels, 527 int* /*match*/, 528 CvGaussBGPoint* g_point, 529 const CvGaussBGStatModelParams *bg_model_params) 530 { 531 int k, m; 532 //new value of last one 533 g_point->g_values[bg_model_params->n_gauss - 1].match_sum = 1; 534 535 //get sum of all but last value of match_sum 536 int match_sum_total = 0; 537 for(k = 0; k < bg_model_params->n_gauss ; k++) 538 match_sum_total += g_point->g_values[k].match_sum; 539 540 for(m = 0; m < nChannels; m++) 541 { 542 //first pass mean is image value 543 g_point->g_values[bg_model_params->n_gauss - 1].variance[m] = bg_model_params->variance_init; 544 g_point->g_values[bg_model_params->n_gauss - 1].mean[m] = pixel[m]; 545 } 546 for(k = 0; k < bg_model_params->n_gauss; k++) 547 { 548 g_point->g_values[k].weight = (double)g_point->g_values[k].match_sum / 549 (double)match_sum_total; 550 } 551 } 552 553 static void icvGetSortKey( const int nChannels, double* sort_key, const CvGaussBGPoint* g_point, 554 const CvGaussBGStatModelParams *bg_model_params ) 555 { 556 int k, m; 557 for( k = 0; k < bg_model_params->n_gauss; k++ ) 558 { 559 // Avoid division by zero 560 if( g_point->g_values[k].match_sum > 0 ) 561 { 562 // Independence assumption between components 563 double variance_sum = 0.0; 564 for( m = 0; m < nChannels; m++ ) 565 variance_sum += g_point->g_values[k].variance[m]; 566 567 sort_key[k] = g_point->g_values[k].weight/sqrt(variance_sum); 568 } 569 else 570 sort_key[k]= 0.0; 571 } 572 } 573 574 575 static void icvBackgroundTest( const int nChannels, int n, int i, int j, int *match, CvGaussBGModel* bg_model ) 576 { 577 int m, b; 578 uchar pixelValue = (uchar)255; // will switch to 0 if match found 579 double weight_sum = 0.0; 580 CvGaussBGPoint* g_point = bg_model->g_point; 581 582 for( m = 0; m < nChannels; m++) 583 bg_model->background->imageData[ bg_model->background->widthStep*i + j*nChannels + m] = (unsigned char)(g_point[n].g_values[0].mean[m]+0.5); 584 585 for( b = 0; b < bg_model->params.n_gauss; b++) 586 { 587 weight_sum += g_point[n].g_values[b].weight; 588 if( match[b] ) 589 pixelValue = 0; 590 if( weight_sum > bg_model->params.bg_threshold ) 591 break; 592 } 593 594 bg_model->foreground->imageData[ bg_model->foreground->widthStep*i + j] = pixelValue; 595 } 596 597 /* End of file. */ 598