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