1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
12 // Copyright (C) 2000, Intel Corporation, all rights reserved.
13 // Third party copyrights are property of their respective owners.
15 // Redistribution and use in source and binary forms, with or without modification,
16 // are permitted provided that the following conditions are met:
18 // * Redistribution's of source code must retain the above copyright notice,
19 // this list of conditions and the following disclaimer.
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.
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.
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.
46 //#include <algorithm>
48 static double* _cv_max_element( double* start, double* end )
51 for( ; start != end; start++ )
57 static void CV_CDECL icvReleaseFGDStatModel( CvFGDStatModel** model );
58 static int CV_CDECL icvUpdateFGDStatModel( IplImage* curr_frame,
59 CvFGDStatModel* model );
61 // Function cvCreateFGDStatModel initializes foreground detection process
63 // first_frame - frame from video sequence
64 // parameters - (optional) if NULL default parameters of the algorithm will be used
65 // p_model - pointer to CvFGDStatModel structure
66 CV_IMPL CvBGStatModel*
67 cvCreateFGDStatModel( IplImage* first_frame, CvFGDStatModelParams* parameters )
69 CvFGDStatModel* p_model = 0;
71 CV_FUNCNAME( "cvCreateFGDStatModel" );
75 int i, j, k, pixel_count, buf_size;
76 CvFGDStatModelParams params;
78 if( !CV_IS_IMAGE(first_frame) )
79 CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
81 if (first_frame->nChannels != 3)
82 CV_ERROR( CV_StsBadArg, "first_frame must have 3 color channels" );
85 if( parameters == NULL )
87 params.Lc = CV_BGFG_FGD_LC;
88 params.N1c = CV_BGFG_FGD_N1C;
89 params.N2c = CV_BGFG_FGD_N2C;
90 params.Lcc = CV_BGFG_FGD_LCC;
91 params.N1cc = CV_BGFG_FGD_N1CC;
92 params.N2cc = CV_BGFG_FGD_N2CC;
93 params.delta = CV_BGFG_FGD_DELTA;
94 params.alpha1 = CV_BGFG_FGD_ALPHA_1;
95 params.alpha2 = CV_BGFG_FGD_ALPHA_2;
96 params.alpha3 = CV_BGFG_FGD_ALPHA_3;
97 params.T = CV_BGFG_FGD_T;
98 params.minArea = CV_BGFG_FGD_MINAREA;
99 params.is_obj_without_holes = 1;
100 params.perform_morphing = 1;
104 params = *parameters;
107 CV_CALL( p_model = (CvFGDStatModel*)cvAlloc( sizeof(*p_model) ));
108 memset( p_model, 0, sizeof(*p_model) );
109 p_model->type = CV_BG_MODEL_FGD;
110 p_model->release = (CvReleaseBGStatModel)icvReleaseFGDStatModel;
111 p_model->update = (CvUpdateBGStatModel)icvUpdateFGDStatModel;;
112 p_model->params = params;
115 pixel_count = first_frame->width*first_frame->height;
117 buf_size = pixel_count*sizeof(p_model->pixel_stat[0]);
118 CV_CALL( p_model->pixel_stat = (CvBGPixelStat*)cvAlloc(buf_size) );
119 memset( p_model->pixel_stat, 0, buf_size );
121 buf_size = pixel_count*params.N2c*sizeof(p_model->pixel_stat[0].ctable[0]);
122 CV_CALL( p_model->pixel_stat[0].ctable = (CvBGPixelCStatTable*)cvAlloc(buf_size) );
123 memset( p_model->pixel_stat[0].ctable, 0, buf_size );
125 buf_size = pixel_count*params.N2cc*sizeof(p_model->pixel_stat[0].cctable[0]);
126 CV_CALL( p_model->pixel_stat[0].cctable = (CvBGPixelCCStatTable*)cvAlloc(buf_size) );
127 memset( p_model->pixel_stat[0].cctable, 0, buf_size );
129 for( i = 0, k = 0; i < first_frame->height; i++ )
130 for( j = 0; j < first_frame->width; j++, k++ )
132 p_model->pixel_stat[k].ctable = p_model->pixel_stat[0].ctable + k*params.N2c;
133 p_model->pixel_stat[k].cctable = p_model->pixel_stat[0].cctable + k*params.N2cc;
136 //init temporary images
137 CV_CALL( p_model->Ftd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
138 CV_CALL( p_model->Fbd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
139 CV_CALL( p_model->foreground = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
141 CV_CALL( p_model->background = cvCloneImage(first_frame));
142 CV_CALL( p_model->prev_frame = cvCloneImage(first_frame));
143 CV_CALL( p_model->storage = cvCreateMemStorage());
147 if( cvGetErrStatus() < 0 )
149 CvBGStatModel* base_ptr = (CvBGStatModel*)p_model;
151 if( p_model && p_model->release )
152 p_model->release( &base_ptr );
158 return (CvBGStatModel*)p_model;
163 icvReleaseFGDStatModel( CvFGDStatModel** _model )
165 CV_FUNCNAME( "icvReleaseFGDStatModel" );
170 CV_ERROR( CV_StsNullPtr, "" );
174 CvFGDStatModel* model = *_model;
175 if( model->pixel_stat )
177 cvFree( &model->pixel_stat[0].ctable );
178 cvFree( &model->pixel_stat[0].cctable );
179 cvFree( &model->pixel_stat );
182 cvReleaseImage( &model->Ftd );
183 cvReleaseImage( &model->Fbd );
184 cvReleaseImage( &model->foreground );
185 cvReleaseImage( &model->background );
186 cvReleaseImage( &model->prev_frame );
187 cvReleaseMemStorage(&model->storage);
195 // Function cvChangeDetection performs change detection for Foreground detection algorithm
201 cvChangeDetection( IplImage* prev_frame,
202 IplImage* curr_frame,
203 IplImage* change_mask )
205 int i, j, b, x, y, thres;
206 const int PIXELRANGE=256;
208 if( !prev_frame || !curr_frame || !change_mask ||
209 prev_frame->nChannels != 3 || curr_frame->nChannels != 3 || change_mask->nChannels != 1 ||
210 prev_frame->depth != IPL_DEPTH_8U || curr_frame->depth != IPL_DEPTH_8U || change_mask->depth != IPL_DEPTH_8U ||
211 !CV_ARE_SIZES_EQ( prev_frame, curr_frame ) || !CV_ARE_SIZES_EQ( prev_frame, change_mask ) ) return 0;
213 cvZero ( change_mask );
215 // All operations per colour
216 for (b=0 ; b<prev_frame->nChannels ; b++) {
219 long HISTOGRAM[PIXELRANGE];
220 for (i=0 ; i<PIXELRANGE; i++) HISTOGRAM[i]=0;
222 for (y=0 ; y<curr_frame->height ; y++)
224 uchar* rowStart1 = (uchar*)curr_frame->imageData + y * curr_frame->widthStep + b;
225 uchar* rowStart2 = (uchar*)prev_frame->imageData + y * prev_frame->widthStep + b;
226 for (x=0 ; x<curr_frame->width ; x++, rowStart1+=curr_frame->nChannels, rowStart2+=prev_frame->nChannels) {
227 int diff = abs( int(*rowStart1) - int(*rowStart2) );
232 double relativeVariance[PIXELRANGE];
233 for (i=0 ; i<PIXELRANGE; i++) relativeVariance[i]=0;
235 for (thres=PIXELRANGE-2; thres>=0 ; thres--)
237 // fprintf(stderr, "Iter %d\n", thres);
241 // fprintf(stderr, "Iter %d entering loop\n", thres);
242 for (j=thres ; j<PIXELRANGE ; j++) {
243 sum += double(j)*double(HISTOGRAM[j]);
244 sqsum += double(j*j)*double(HISTOGRAM[j]);
245 count += HISTOGRAM[j];
247 count = count == 0 ? 1 : count;
248 // fprintf(stderr, "Iter %d finishing loop\n", thres);
249 double my = sum / count;
250 double sigma = sqrt( sqsum/count - my*my);
251 // fprintf(stderr, "Iter %d sum=%g sqsum=%g count=%d sigma = %g\n", thres, sum, sqsum, count, sigma);
252 // fprintf(stderr, "Writing to %x\n", &(relativeVariance[thres]));
253 relativeVariance[thres] = sigma;
254 // fprintf(stderr, "Iter %d finished\n", thres);
259 double* pBestThres = _cv_max_element(relativeVariance, relativeVariance+PIXELRANGE);
260 bestThres = (uchar)(*pBestThres); if (bestThres <10) bestThres=10;
262 for (y=0 ; y<prev_frame->height ; y++)
264 uchar* rowStart1 = (uchar*)(curr_frame->imageData) + y * curr_frame->widthStep + b;
265 uchar* rowStart2 = (uchar*)(prev_frame->imageData) + y * prev_frame->widthStep + b;
266 uchar* rowStart3 = (uchar*)(change_mask->imageData) + y * change_mask->widthStep;
267 for (x = 0; x < curr_frame->width; x++, rowStart1+=curr_frame->nChannels,
268 rowStart2+=prev_frame->nChannels, rowStart3+=change_mask->nChannels) {
269 // OR between different color channels
270 int diff = abs( int(*rowStart1) - int(*rowStart2) );
271 if ( diff > bestThres)
284 #define V_C(k,l) ctable[k].v[l]
285 #define PV_C(k) ctable[k].Pv
286 #define PVB_C(k) ctable[k].Pvb
287 #define V_CC(k,l) cctable[k].v[l]
288 #define PV_CC(k) cctable[k].Pv
289 #define PVB_CC(k) cctable[k].Pvb
292 // Function cvUpdateFGDStatModel updates statistical model and returns number of foreground regions
294 // curr_frame - current frame from video sequence
295 // p_model - pointer to CvFGDStatModel structure
297 icvUpdateFGDStatModel( IplImage* curr_frame, CvFGDStatModel* model )
299 int mask_step = model->Ftd->widthStep;
300 CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
301 IplImage* prev_frame = model->prev_frame;
302 int region_count = 0;
303 int FG_pixels_count = 0;
304 int deltaC = cvRound(model->params.delta * 256 / model->params.Lc);
305 int deltaCC = cvRound(model->params.delta * 256 / model->params.Lcc);
309 cvClearMemStorage(model->storage);
310 cvZero(model->foreground);
312 //form FG pixels candidates using image differencing with adaptive threshold [P.Rosin, Thresholding for change detection, ICCV, 1998 ]
313 cvChangeDetection( prev_frame, curr_frame, model->Ftd );
314 cvChangeDetection( model->background, curr_frame, model->Fbd );
316 for( i = 0; i < model->Ftd->height; i++ )
318 for( j = 0; j < model->Ftd->width; j++ )
320 if( ((uchar*)model->Fbd->imageData)[i*mask_step+j] || ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
322 float Pb=0, Pv=0, Pvb=0;
323 CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
324 CvBGPixelCStatTable* ctable = stat->ctable;
325 CvBGPixelCCStatTable* cctable = stat->cctable;
327 uchar* curr_data = (uchar*)(curr_frame->imageData)+i*curr_frame->widthStep+j*3;
328 uchar* prev_data = (uchar*)(prev_frame->imageData)+i*prev_frame->widthStep+j*3;
331 // is it a motion pixel?
332 if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
334 if( !stat->is_trained_dyn_model ) val = 1;
337 //compare with stored CCt vectors
338 for( k = 0; PV_CC(k) > model->params.alpha2 && k < model->params.N1cc; k++ )
340 if ( abs( V_CC(k,0) - prev_data[0]) <= deltaCC &&
341 abs( V_CC(k,1) - prev_data[1]) <= deltaCC &&
342 abs( V_CC(k,2) - prev_data[2]) <= deltaCC &&
343 abs( V_CC(k,3) - curr_data[0]) <= deltaCC &&
344 abs( V_CC(k,4) - curr_data[1]) <= deltaCC &&
345 abs( V_CC(k,5) - curr_data[2]) <= deltaCC)
352 if( 2 * Pvb * Pb <= Pv ) val = 1;
355 else if( stat->is_trained_st_model )
357 //compare with stored Ct vectors
358 for( k = 0; PV_C(k) > model->params.alpha2 && k < model->params.N1c; k++ )
360 if ( abs( V_C(k,0) - curr_data[0]) <= deltaC &&
361 abs( V_C(k,1) - curr_data[1]) <= deltaC &&
362 abs( V_C(k,2) - curr_data[2]) <= deltaC )
369 if( 2 * Pvb * Pb <= Pv ) val = 1;
372 ((uchar*)model->foreground->imageData)[i*mask_step+j] = (uchar)(val*255);
373 FG_pixels_count += val;
374 }// end if( change detection...
377 //end BG/FG classification
379 //foreground segmentation
381 if( model->params.perform_morphing ){
382 cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_OPEN, 1 );
383 cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_CLOSE, 1 );
387 if( model->params.minArea > 0 || model->params.is_obj_without_holes ){
388 //filter small regions
389 cvFindContours( model->foreground, model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
390 for( seq = first_seq; seq; seq = seq->h_next )
392 CvContour* cnt = (CvContour*)seq;
393 if( cnt->rect.width * cnt->rect.height < model->params.minArea ||
394 (model->params.is_obj_without_holes && CV_IS_SEQ_HOLE(seq)) )
396 //delete small contour
397 prev_seq = seq->h_prev;
400 prev_seq->h_next = seq->h_next;
401 if( seq->h_next ) seq->h_next->h_prev = prev_seq;
405 first_seq = seq->h_next;
406 if( seq->h_next ) seq->h_next->h_prev = NULL;
414 model->foreground_regions = first_seq;
415 cvZero(model->foreground);
416 cvDrawContours(model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
419 model->foreground_regions = NULL;
422 //check ALL BG update condition
423 if( ((float)FG_pixels_count/(model->Ftd->width*model->Ftd->height)) > CV_BGFG_FGD_BG_UPDATE_TRESH )
425 for( i = 0; i < model->Ftd->height; i++ )
426 for( j = 0; j < model->Ftd->width; j++ )
428 CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
429 stat->is_trained_st_model = stat->is_trained_dyn_model = 1;
435 for( i = 0; i < model->Ftd->height; i++ )
437 for( j = 0; j < model->Ftd->width; j++ )
439 CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
440 CvBGPixelCStatTable* ctable = stat->ctable;
441 CvBGPixelCCStatTable* cctable = stat->cctable;
443 uchar *curr_data = (uchar*)(curr_frame->imageData)+i*curr_frame->widthStep+j*3;
444 uchar *prev_data = (uchar*)(prev_frame->imageData)+i*prev_frame->widthStep+j*3;
446 if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] || !stat->is_trained_dyn_model )
448 float alpha = stat->is_trained_dyn_model ? model->params.alpha2 : model->params.alpha3;
450 int dist, min_dist = 2147483647, indx = -1;
453 stat->Pbcc *= (1.f-alpha);
454 if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
459 // find best Vi match
460 for(k = 0; PV_CC(k) && k < model->params.N2cc; k++ )
462 // Exponential decay of memory
463 PV_CC(k) *= (1-alpha);
464 PVB_CC(k) *= (1-alpha);
465 if( PV_CC(k) < MIN_PV )
473 for( l = 0; l < 3; l++ )
475 int val = abs( V_CC(k,l) - prev_data[l] );
476 if( val > deltaCC ) break;
478 val = abs( V_CC(k,l+3) - curr_data[l] );
479 if( val > deltaCC) break;
482 if( l == 3 && dist < min_dist )
491 {//N2th elem in the table is replaced by a new features
492 indx = model->params.N2cc - 1;
494 PVB_CC(indx) = alpha;
496 for( l = 0; l < 3; l++ )
498 V_CC(indx,l) = prev_data[l];
499 V_CC(indx,l+3) = curr_data[l];
504 PV_CC(indx) += alpha;
505 if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
507 PVB_CC(indx) += alpha;
511 //re-sort CCt table by Pv
512 for( k = 0; k < indx; k++ )
514 if( PV_CC(k) <= PV_CC(indx) )
517 CvBGPixelCCStatTable tmp1, tmp2 = cctable[indx];
518 for( l = k; l <= indx; l++ )
529 float sum1=0, sum2=0;
530 //check "once-off" changes
531 for(k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
536 if( sum1 > model->params.T ) stat->is_trained_dyn_model = 1;
538 diff = sum1 - stat->Pbcc * sum2;
540 if( diff > model->params.T )
542 //printf("once off change at motion mode\n");
543 //new BG features are discovered
544 for( k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
547 (PV_CC(k)-stat->Pbcc*PVB_CC(k))/(1-stat->Pbcc);
549 assert(stat->Pbcc<=1 && stat->Pbcc>=0);
553 //case of stational pixel
554 if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] )
556 float alpha = stat->is_trained_st_model ? model->params.alpha2 : model->params.alpha3;
558 int dist, min_dist = 2147483647, indx = -1;
561 stat->Pbc *= (1.f-alpha);
562 if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
568 for( k = 0; k < model->params.N2c; k++ )
570 // Exponential decay of memory
571 PV_C(k) *= (1-alpha);
572 PVB_C(k) *= (1-alpha);
573 if( PV_C(k) < MIN_PV )
581 for( l = 0; l < 3; l++ )
583 int val = abs( V_C(k,l) - curr_data[l] );
584 if( val > deltaC ) break;
587 if( l == 3 && dist < min_dist )
595 {//N2th elem in the table is replaced by a new features
596 indx = model->params.N2c - 1;
600 for( l = 0; l < 3; l++ )
602 V_C(indx,l) = curr_data[l];
607 if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
609 PVB_C(indx) += alpha;
613 //re-sort Ct table by Pv
614 for( k = 0; k < indx; k++ )
616 if( PV_C(k) <= PV_C(indx) )
619 CvBGPixelCStatTable tmp1, tmp2 = ctable[indx];
620 for( l = k; l <= indx; l++ )
630 //check "once-off" changes
631 float sum1=0, sum2=0;
632 for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
637 diff = sum1 - stat->Pbc * sum2;
638 if( sum1 > model->params.T ) stat->is_trained_st_model = 1;
641 if( diff > model->params.T )
643 //printf("once off change at stat mode\n");
644 //new BG features are discovered
645 for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
647 PVB_C(k) = (PV_C(k)-stat->Pbc*PVB_C(k))/(1-stat->Pbc);
649 stat->Pbc = 1 - stat->Pbc;
651 }//if !(change detection) at pixel (i,j)
653 //update the reference BG image
654 if( !((uchar*)model->foreground->imageData)[i*mask_step+j])
656 uchar* ptr = ((uchar*)model->background->imageData) + i*model->background->widthStep+j*3;
658 if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] &&
659 !((uchar*)model->Fbd->imageData)[i*mask_step+j] )
662 for( l = 0; l < 3; l++ )
664 int a = cvRound(ptr[l]*(1 - model->params.alpha1) + model->params.alpha1*curr_data[l]);
666 //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l]*=(1 - model->params.alpha1);
667 //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] += model->params.alpha1*curr_data[l];
672 //background change is detected
673 for( l = 0; l < 3; l++ )
675 //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] = curr_data[l];
676 ptr[l] = curr_data[l];
684 cvCopy( curr_frame, model->prev_frame );