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*
cvCreateGaussianBGModel(IplImage * first_frame,CvGaussBGStatModelParams * parameters)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
icvReleaseGaussianBGModel(CvGaussBGModel ** _bg_model)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
icvUpdateGaussianBGModel(IplImage * curr_frame,CvGaussBGModel * bg_model)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
icvInsertionSortGaussians(CvGaussBGPoint * g_point,double * sort_key,CvGaussBGStatModelParams * bg_model_params)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
icvMatchTest(double * src_pixel,int nChannels,int * match,const CvGaussBGPoint * g_point,const CvGaussBGStatModelParams * bg_model_params)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
icvUpdateFullWindow(double * src_pixel,int nChannels,int * match,CvGaussBGPoint * g_point,const CvGaussBGStatModelParams * bg_model_params)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
icvUpdatePartialWindow(double * src_pixel,int nChannels,int * match,CvGaussBGPoint * g_point,const CvGaussBGStatModelParams * bg_model_params)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
icvUpdateFullNoMatch(IplImage * gm_image,int p,int * match,CvGaussBGPoint * g_point,const CvGaussBGStatModelParams * bg_model_params)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
icvUpdatePartialNoMatch(double * pixel,int nChannels,int *,CvGaussBGPoint * g_point,const CvGaussBGStatModelParams * bg_model_params)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
icvGetSortKey(const int nChannels,double * sort_key,const CvGaussBGPoint * g_point,const CvGaussBGStatModelParams * bg_model_params)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
icvBackgroundTest(const int nChannels,int n,int i,int j,int * match,CvGaussBGModel * bg_model)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