Home | History | Annotate | Download | only in src
      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 file implements the foreground/background pixel
     43 // discrimination algorithm described in
     44 //
     45 //     Foreground Object Detection from Videos Containing Complex Background
     46 //     Li, Huan, Gu, Tian 2003 9p
     47 //     http://muq.org/~cynbe/bib/foreground-object-detection-from-videos-containing-complex-background.pdf
     48 
     49 
     50 #include "_cvaux.h"
     51 
     52 #include <math.h>
     53 #include <stdio.h>
     54 #include <stdlib.h>
     55 //#include <algorithm>
     56 
     57 static double* _cv_max_element( double* start, double* end )
     58 {
     59     double* p = start++;
     60 
     61     for( ; start != end;  ++start) {
     62 
     63         if (*p < *start)   p = start;
     64     }
     65 
     66     return p;
     67 }
     68 
     69 static void CV_CDECL icvReleaseFGDStatModel( CvFGDStatModel** model );
     70 static int CV_CDECL icvUpdateFGDStatModel( IplImage* curr_frame,
     71                                            CvFGDStatModel*  model );
     72 
     73 // Function cvCreateFGDStatModel initializes foreground detection process
     74 // parameters:
     75 //      first_frame - frame from video sequence
     76 //      parameters  - (optional) if NULL default parameters of the algorithm will be used
     77 //      p_model     - pointer to CvFGDStatModel structure
     78 CV_IMPL CvBGStatModel*
     79 cvCreateFGDStatModel( IplImage* first_frame, CvFGDStatModelParams* parameters )
     80 {
     81     CvFGDStatModel* p_model = 0;
     82 
     83     CV_FUNCNAME( "cvCreateFGDStatModel" );
     84 
     85     __BEGIN__;
     86 
     87     int i, j, k, pixel_count, buf_size;
     88     CvFGDStatModelParams params;
     89 
     90     if( !CV_IS_IMAGE(first_frame) )
     91         CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
     92 
     93     if (first_frame->nChannels != 3)
     94         CV_ERROR( CV_StsBadArg, "first_frame must have 3 color channels" );
     95 
     96     // Initialize parameters:
     97     if( parameters == NULL )
     98     {
     99         params.Lc      = CV_BGFG_FGD_LC;
    100         params.N1c     = CV_BGFG_FGD_N1C;
    101         params.N2c     = CV_BGFG_FGD_N2C;
    102 
    103         params.Lcc     = CV_BGFG_FGD_LCC;
    104         params.N1cc    = CV_BGFG_FGD_N1CC;
    105         params.N2cc    = CV_BGFG_FGD_N2CC;
    106 
    107         params.delta   = CV_BGFG_FGD_DELTA;
    108 
    109         params.alpha1  = CV_BGFG_FGD_ALPHA_1;
    110         params.alpha2  = CV_BGFG_FGD_ALPHA_2;
    111         params.alpha3  = CV_BGFG_FGD_ALPHA_3;
    112 
    113         params.T       = CV_BGFG_FGD_T;
    114         params.minArea = CV_BGFG_FGD_MINAREA;
    115 
    116         params.is_obj_without_holes = 1;
    117         params.perform_morphing     = 1;
    118     }
    119     else
    120     {
    121         params = *parameters;
    122     }
    123 
    124     CV_CALL( p_model = (CvFGDStatModel*)cvAlloc( sizeof(*p_model) ));
    125     memset( p_model, 0, sizeof(*p_model) );
    126     p_model->type = CV_BG_MODEL_FGD;
    127     p_model->release = (CvReleaseBGStatModel)icvReleaseFGDStatModel;
    128     p_model->update = (CvUpdateBGStatModel)icvUpdateFGDStatModel;;
    129     p_model->params = params;
    130 
    131     // Initialize storage pools:
    132     pixel_count = first_frame->width * first_frame->height;
    133 
    134     buf_size = pixel_count*sizeof(p_model->pixel_stat[0]);
    135     CV_CALL( p_model->pixel_stat = (CvBGPixelStat*)cvAlloc(buf_size) );
    136     memset( p_model->pixel_stat, 0, buf_size );
    137 
    138     buf_size = pixel_count*params.N2c*sizeof(p_model->pixel_stat[0].ctable[0]);
    139     CV_CALL( p_model->pixel_stat[0].ctable = (CvBGPixelCStatTable*)cvAlloc(buf_size) );
    140     memset( p_model->pixel_stat[0].ctable, 0, buf_size );
    141 
    142     buf_size = pixel_count*params.N2cc*sizeof(p_model->pixel_stat[0].cctable[0]);
    143     CV_CALL( p_model->pixel_stat[0].cctable = (CvBGPixelCCStatTable*)cvAlloc(buf_size) );
    144     memset( p_model->pixel_stat[0].cctable, 0, buf_size );
    145 
    146     for(     i = 0, k = 0; i < first_frame->height; i++ ) {
    147         for( j = 0;        j < first_frame->width;  j++, k++ )
    148         {
    149             p_model->pixel_stat[k].ctable = p_model->pixel_stat[0].ctable + k*params.N2c;
    150             p_model->pixel_stat[k].cctable = p_model->pixel_stat[0].cctable + k*params.N2cc;
    151         }
    152     }
    153 
    154     // Init temporary images:
    155     CV_CALL( p_model->Ftd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
    156     CV_CALL( p_model->Fbd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
    157     CV_CALL( p_model->foreground = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
    158 
    159     CV_CALL( p_model->background = cvCloneImage(first_frame));
    160     CV_CALL( p_model->prev_frame = cvCloneImage(first_frame));
    161     CV_CALL( p_model->storage = cvCreateMemStorage());
    162 
    163     __END__;
    164 
    165     if( cvGetErrStatus() < 0 )
    166     {
    167         CvBGStatModel* base_ptr = (CvBGStatModel*)p_model;
    168 
    169         if( p_model && p_model->release )
    170             p_model->release( &base_ptr );
    171         else
    172             cvFree( &p_model );
    173         p_model = 0;
    174     }
    175 
    176     return (CvBGStatModel*)p_model;
    177 }
    178 
    179 
    180 static void CV_CDECL
    181 icvReleaseFGDStatModel( CvFGDStatModel** _model )
    182 {
    183     CV_FUNCNAME( "icvReleaseFGDStatModel" );
    184 
    185     __BEGIN__;
    186 
    187     if( !_model )
    188         CV_ERROR( CV_StsNullPtr, "" );
    189 
    190     if( *_model )
    191     {
    192         CvFGDStatModel* model = *_model;
    193         if( model->pixel_stat )
    194         {
    195             cvFree( &model->pixel_stat[0].ctable );
    196             cvFree( &model->pixel_stat[0].cctable );
    197             cvFree( &model->pixel_stat );
    198         }
    199 
    200         cvReleaseImage( &model->Ftd );
    201         cvReleaseImage( &model->Fbd );
    202         cvReleaseImage( &model->foreground );
    203         cvReleaseImage( &model->background );
    204         cvReleaseImage( &model->prev_frame );
    205         cvReleaseMemStorage(&model->storage);
    206 
    207         cvFree( _model );
    208     }
    209 
    210     __END__;
    211 }
    212 
    213 //  Function cvChangeDetection performs change detection for Foreground detection algorithm
    214 // parameters:
    215 //      prev_frame -
    216 //      curr_frame -
    217 //      change_mask -
    218 CV_IMPL int
    219 cvChangeDetection( IplImage*  prev_frame,
    220                    IplImage*  curr_frame,
    221                    IplImage*  change_mask )
    222 {
    223     int i, j, b, x, y, thres;
    224     const int PIXELRANGE=256;
    225 
    226     if( !prev_frame
    227     ||  !curr_frame
    228     ||  !change_mask
    229     ||   prev_frame->nChannels  != 3
    230     ||   curr_frame->nChannels  != 3
    231     ||   change_mask->nChannels != 1
    232     ||   prev_frame->depth  != IPL_DEPTH_8U
    233     ||   curr_frame->depth  != IPL_DEPTH_8U
    234     ||   change_mask->depth != IPL_DEPTH_8U
    235     ||   prev_frame->width  != curr_frame->width
    236     ||   prev_frame->height != curr_frame->height
    237     ||   prev_frame->width  != change_mask->width
    238     ||   prev_frame->height != change_mask->height
    239     ){
    240         return 0;
    241     }
    242 
    243     cvZero ( change_mask );
    244 
    245     // All operations per colour
    246     for (b=0 ; b<prev_frame->nChannels ; b++) {
    247 
    248         // Create histogram:
    249 
    250         long HISTOGRAM[PIXELRANGE];
    251         for (i=0 ; i<PIXELRANGE; i++) HISTOGRAM[i]=0;
    252 
    253         for (y=0 ; y<curr_frame->height ; y++)
    254         {
    255             uchar* rowStart1 = (uchar*)curr_frame->imageData + y * curr_frame->widthStep + b;
    256             uchar* rowStart2 = (uchar*)prev_frame->imageData + y * prev_frame->widthStep + b;
    257             for (x=0 ; x<curr_frame->width ; x++, rowStart1+=curr_frame->nChannels, rowStart2+=prev_frame->nChannels) {
    258                 int diff = abs( int(*rowStart1) - int(*rowStart2) );
    259                 HISTOGRAM[diff]++;
    260             }
    261         }
    262 
    263         double relativeVariance[PIXELRANGE];
    264         for (i=0 ; i<PIXELRANGE; i++) relativeVariance[i]=0;
    265 
    266         for (thres=PIXELRANGE-2; thres>=0 ; thres--)
    267         {
    268             //            fprintf(stderr, "Iter %d\n", thres);
    269             double sum=0;
    270             double sqsum=0;
    271             int count=0;
    272             //            fprintf(stderr, "Iter %d entering loop\n", thres);
    273             for (j=thres ; j<PIXELRANGE ; j++) {
    274                 sum   += double(j)*double(HISTOGRAM[j]);
    275                 sqsum += double(j*j)*double(HISTOGRAM[j]);
    276                 count += HISTOGRAM[j];
    277             }
    278             count = count == 0 ? 1 : count;
    279             //            fprintf(stderr, "Iter %d finishing loop\n", thres);
    280             double my = sum / count;
    281             double sigma = sqrt( sqsum/count - my*my);
    282             //            fprintf(stderr, "Iter %d sum=%g sqsum=%g count=%d sigma = %g\n", thres, sum, sqsum, count, sigma);
    283             //            fprintf(stderr, "Writing to %x\n", &(relativeVariance[thres]));
    284             relativeVariance[thres] = sigma;
    285             //            fprintf(stderr, "Iter %d finished\n", thres);
    286         }
    287 
    288         // Find maximum:
    289         uchar bestThres = 0;
    290 
    291         double* pBestThres = _cv_max_element(relativeVariance, relativeVariance+PIXELRANGE);
    292         bestThres = (uchar)(*pBestThres); if (bestThres <10) bestThres=10;
    293 
    294         for (y=0 ; y<prev_frame->height ; y++)
    295         {
    296             uchar* rowStart1 = (uchar*)(curr_frame->imageData) + y * curr_frame->widthStep + b;
    297             uchar* rowStart2 = (uchar*)(prev_frame->imageData) + y * prev_frame->widthStep + b;
    298             uchar* rowStart3 = (uchar*)(change_mask->imageData) + y * change_mask->widthStep;
    299             for (x = 0; x < curr_frame->width; x++, rowStart1+=curr_frame->nChannels,
    300                 rowStart2+=prev_frame->nChannels, rowStart3+=change_mask->nChannels) {
    301                 // OR between different color channels
    302                 int diff = abs( int(*rowStart1) - int(*rowStart2) );
    303                 if ( diff > bestThres)
    304                     *rowStart3 |=255;
    305             }
    306         }
    307     }
    308 
    309     return 1;
    310 }
    311 
    312 
    313 #define MIN_PV 1E-10
    314 
    315 
    316 #define V_C(k,l) ctable[k].v[l]
    317 #define PV_C(k) ctable[k].Pv
    318 #define PVB_C(k) ctable[k].Pvb
    319 #define V_CC(k,l) cctable[k].v[l]
    320 #define PV_CC(k) cctable[k].Pv
    321 #define PVB_CC(k) cctable[k].Pvb
    322 
    323 
    324 // Function cvUpdateFGDStatModel updates statistical model and returns number of foreground regions
    325 // parameters:
    326 //      curr_frame  - current frame from video sequence
    327 //      p_model     - pointer to CvFGDStatModel structure
    328 static int CV_CDECL
    329 icvUpdateFGDStatModel( IplImage* curr_frame, CvFGDStatModel*  model )
    330 {
    331     int            mask_step = model->Ftd->widthStep;
    332     CvSeq         *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
    333     IplImage*      prev_frame = model->prev_frame;
    334     int            region_count = 0;
    335     int            FG_pixels_count = 0;
    336     int            deltaC  = cvRound(model->params.delta * 256 / model->params.Lc);
    337     int            deltaCC = cvRound(model->params.delta * 256 / model->params.Lcc);
    338     int            i, j, k, l;
    339 
    340     //clear storages
    341     cvClearMemStorage(model->storage);
    342     cvZero(model->foreground);
    343 
    344     // From foreground pixel candidates using image differencing
    345     // with adaptive thresholding.  The algorithm is from:
    346     //
    347     //    Thresholding for Change Detection
    348     //    Paul L. Rosin 1998 6p
    349     //    http://www.cis.temple.edu/~latecki/Courses/CIS750-03/Papers/thresh-iccv.pdf
    350     //
    351     cvChangeDetection( prev_frame, curr_frame, model->Ftd );
    352     cvChangeDetection( model->background, curr_frame, model->Fbd );
    353 
    354     for( i = 0; i < model->Ftd->height; i++ )
    355     {
    356         for( j = 0; j < model->Ftd->width; j++ )
    357         {
    358             if( ((uchar*)model->Fbd->imageData)[i*mask_step+j] || ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
    359             {
    360 	        float Pb  = 0;
    361                 float Pv  = 0;
    362                 float Pvb = 0;
    363 
    364                 CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
    365 
    366                 CvBGPixelCStatTable*   ctable = stat->ctable;
    367                 CvBGPixelCCStatTable* cctable = stat->cctable;
    368 
    369                 uchar* curr_data = (uchar*)(curr_frame->imageData) + i*curr_frame->widthStep + j*3;
    370                 uchar* prev_data = (uchar*)(prev_frame->imageData) + i*prev_frame->widthStep + j*3;
    371 
    372                 int val = 0;
    373 
    374                 // Is it a motion pixel?
    375                 if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
    376                 {
    377 		    if( !stat->is_trained_dyn_model ) {
    378 
    379                         val = 1;
    380 
    381 		    } else {
    382 
    383                         // Compare with stored CCt vectors:
    384                         for( k = 0;  PV_CC(k) > model->params.alpha2 && k < model->params.N1cc;  k++ )
    385                         {
    386                             if ( abs( V_CC(k,0) - prev_data[0]) <=  deltaCC &&
    387                                  abs( V_CC(k,1) - prev_data[1]) <=  deltaCC &&
    388                                  abs( V_CC(k,2) - prev_data[2]) <=  deltaCC &&
    389                                  abs( V_CC(k,3) - curr_data[0]) <=  deltaCC &&
    390                                  abs( V_CC(k,4) - curr_data[1]) <=  deltaCC &&
    391                                  abs( V_CC(k,5) - curr_data[2]) <=  deltaCC)
    392                             {
    393                                 Pv += PV_CC(k);
    394                                 Pvb += PVB_CC(k);
    395                             }
    396                         }
    397                         Pb = stat->Pbcc;
    398                         if( 2 * Pvb * Pb <= Pv ) val = 1;
    399                     }
    400                 }
    401                 else if( stat->is_trained_st_model )
    402                 {
    403                     // Compare with stored Ct vectors:
    404                     for( k = 0;  PV_C(k) > model->params.alpha2 && k < model->params.N1c;  k++ )
    405                     {
    406                         if ( abs( V_C(k,0) - curr_data[0]) <=  deltaC &&
    407                              abs( V_C(k,1) - curr_data[1]) <=  deltaC &&
    408                              abs( V_C(k,2) - curr_data[2]) <=  deltaC )
    409                         {
    410                             Pv += PV_C(k);
    411                             Pvb += PVB_C(k);
    412                         }
    413                     }
    414                     Pb = stat->Pbc;
    415                     if( 2 * Pvb * Pb <= Pv ) val = 1;
    416                 }
    417 
    418                 // Update foreground:
    419                 ((uchar*)model->foreground->imageData)[i*mask_step+j] = (uchar)(val*255);
    420                 FG_pixels_count += val;
    421 
    422             }		// end if( change detection...
    423         }		// for j...
    424     }			// for i...
    425     //end BG/FG classification
    426 
    427     // Foreground segmentation.
    428     // Smooth foreground map:
    429     if( model->params.perform_morphing ){
    430         cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_OPEN,  model->params.perform_morphing );
    431         cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_CLOSE, model->params.perform_morphing );
    432     }
    433 
    434 
    435     if( model->params.minArea > 0 || model->params.is_obj_without_holes ){
    436 
    437         // Discard under-size foreground regions:
    438 	//
    439         cvFindContours( model->foreground, model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
    440         for( seq = first_seq; seq; seq = seq->h_next )
    441         {
    442             CvContour* cnt = (CvContour*)seq;
    443             if( cnt->rect.width * cnt->rect.height < model->params.minArea ||
    444                 (model->params.is_obj_without_holes && CV_IS_SEQ_HOLE(seq)) )
    445             {
    446                 // Delete under-size contour:
    447                 prev_seq = seq->h_prev;
    448                 if( prev_seq )
    449                 {
    450                     prev_seq->h_next = seq->h_next;
    451                     if( seq->h_next ) seq->h_next->h_prev = prev_seq;
    452                 }
    453                 else
    454                 {
    455                     first_seq = seq->h_next;
    456                     if( seq->h_next ) seq->h_next->h_prev = NULL;
    457                 }
    458             }
    459             else
    460             {
    461                 region_count++;
    462             }
    463         }
    464         model->foreground_regions = first_seq;
    465         cvZero(model->foreground);
    466         cvDrawContours(model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
    467 
    468     } else {
    469 
    470         model->foreground_regions = NULL;
    471     }
    472 
    473     // Check ALL BG update condition:
    474     if( ((float)FG_pixels_count/(model->Ftd->width*model->Ftd->height)) > CV_BGFG_FGD_BG_UPDATE_TRESH )
    475     {
    476          for( i = 0; i < model->Ftd->height; i++ )
    477              for( j = 0; j < model->Ftd->width; j++ )
    478              {
    479                  CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
    480                  stat->is_trained_st_model = stat->is_trained_dyn_model = 1;
    481              }
    482     }
    483 
    484 
    485     // Update background model:
    486     for( i = 0; i < model->Ftd->height; i++ )
    487     {
    488         for( j = 0; j < model->Ftd->width; j++ )
    489         {
    490             CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
    491             CvBGPixelCStatTable* ctable = stat->ctable;
    492             CvBGPixelCCStatTable* cctable = stat->cctable;
    493 
    494             uchar *curr_data = (uchar*)(curr_frame->imageData)+i*curr_frame->widthStep+j*3;
    495             uchar *prev_data = (uchar*)(prev_frame->imageData)+i*prev_frame->widthStep+j*3;
    496 
    497             if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] || !stat->is_trained_dyn_model )
    498             {
    499                 float alpha = stat->is_trained_dyn_model ? model->params.alpha2 : model->params.alpha3;
    500                 float diff = 0;
    501                 int dist, min_dist = 2147483647, indx = -1;
    502 
    503                 //update Pb
    504                 stat->Pbcc *= (1.f-alpha);
    505                 if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
    506                 {
    507                     stat->Pbcc += alpha;
    508                 }
    509 
    510                 // Find best Vi match:
    511                 for(k = 0; PV_CC(k) && k < model->params.N2cc; k++ )
    512                 {
    513                     // Exponential decay of memory
    514                     PV_CC(k)  *= (1-alpha);
    515                     PVB_CC(k) *= (1-alpha);
    516                     if( PV_CC(k) < MIN_PV )
    517                     {
    518                         PV_CC(k) = 0;
    519                         PVB_CC(k) = 0;
    520                         continue;
    521                     }
    522 
    523                     dist = 0;
    524                     for( l = 0; l < 3; l++ )
    525                     {
    526                         int val = abs( V_CC(k,l) - prev_data[l] );
    527                         if( val > deltaCC ) break;
    528                         dist += val;
    529                         val = abs( V_CC(k,l+3) - curr_data[l] );
    530                         if( val > deltaCC) break;
    531                         dist += val;
    532                     }
    533                     if( l == 3 && dist < min_dist )
    534                     {
    535                         min_dist = dist;
    536                         indx = k;
    537                     }
    538                 }
    539 
    540 
    541                 if( indx < 0 )
    542                 {   // Replace N2th elem in the table by new feature:
    543                     indx = model->params.N2cc - 1;
    544                     PV_CC(indx) = alpha;
    545                     PVB_CC(indx) = alpha;
    546                     //udate Vt
    547                     for( l = 0; l < 3; l++ )
    548                     {
    549                         V_CC(indx,l) = prev_data[l];
    550                         V_CC(indx,l+3) = curr_data[l];
    551                     }
    552                 }
    553                 else
    554                 {   // Update:
    555                     PV_CC(indx) += alpha;
    556                     if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
    557                     {
    558                         PVB_CC(indx) += alpha;
    559                     }
    560                 }
    561 
    562                 //re-sort CCt table by Pv
    563                 for( k = 0; k < indx; k++ )
    564                 {
    565                     if( PV_CC(k) <= PV_CC(indx) )
    566                     {
    567                         //shift elements
    568                         CvBGPixelCCStatTable tmp1, tmp2 = cctable[indx];
    569                         for( l = k; l <= indx; l++ )
    570                         {
    571                             tmp1 = cctable[l];
    572                             cctable[l] = tmp2;
    573                             tmp2 = tmp1;
    574                         }
    575                         break;
    576                     }
    577                 }
    578 
    579 
    580                 float sum1=0, sum2=0;
    581                 //check "once-off" changes
    582                 for(k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
    583                 {
    584                     sum1 += PV_CC(k);
    585                     sum2 += PVB_CC(k);
    586                 }
    587                 if( sum1 > model->params.T ) stat->is_trained_dyn_model = 1;
    588 
    589                 diff = sum1 - stat->Pbcc * sum2;
    590                 // Update stat table:
    591                 if( diff >  model->params.T )
    592                 {
    593                     //printf("once off change at motion mode\n");
    594                     //new BG features are discovered
    595                     for( k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
    596                     {
    597                         PVB_CC(k) =
    598                             (PV_CC(k)-stat->Pbcc*PVB_CC(k))/(1-stat->Pbcc);
    599                     }
    600                     assert(stat->Pbcc<=1 && stat->Pbcc>=0);
    601                 }
    602             }
    603 
    604             // Handle "stationary" pixel:
    605             if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] )
    606             {
    607                 float alpha = stat->is_trained_st_model ? model->params.alpha2 : model->params.alpha3;
    608                 float diff = 0;
    609                 int dist, min_dist = 2147483647, indx = -1;
    610 
    611                 //update Pb
    612                 stat->Pbc *= (1.f-alpha);
    613                 if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
    614                 {
    615                     stat->Pbc += alpha;
    616                 }
    617 
    618                 //find best Vi match
    619                 for( k = 0; k < model->params.N2c; k++ )
    620                 {
    621                     // Exponential decay of memory
    622                     PV_C(k) *= (1-alpha);
    623                     PVB_C(k) *= (1-alpha);
    624                     if( PV_C(k) < MIN_PV )
    625                     {
    626                         PV_C(k) = 0;
    627                         PVB_C(k) = 0;
    628                         continue;
    629                     }
    630 
    631                     dist = 0;
    632                     for( l = 0; l < 3; l++ )
    633                     {
    634                         int val = abs( V_C(k,l) - curr_data[l] );
    635                         if( val > deltaC ) break;
    636                         dist += val;
    637                     }
    638                     if( l == 3 && dist < min_dist )
    639                     {
    640                         min_dist = dist;
    641                         indx = k;
    642                     }
    643                 }
    644 
    645                 if( indx < 0 )
    646                 {//N2th elem in the table is replaced by a new features
    647                     indx = model->params.N2c - 1;
    648                     PV_C(indx) = alpha;
    649                     PVB_C(indx) = alpha;
    650                     //udate Vt
    651                     for( l = 0; l < 3; l++ )
    652                     {
    653                         V_C(indx,l) = curr_data[l];
    654                     }
    655                 } else
    656                 {//update
    657                     PV_C(indx) += alpha;
    658                     if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
    659                     {
    660                         PVB_C(indx) += alpha;
    661                     }
    662                 }
    663 
    664                 //re-sort Ct table by Pv
    665                 for( k = 0; k < indx; k++ )
    666                 {
    667                     if( PV_C(k) <= PV_C(indx) )
    668                     {
    669                         //shift elements
    670                         CvBGPixelCStatTable tmp1, tmp2 = ctable[indx];
    671                         for( l = k; l <= indx; l++ )
    672                         {
    673                             tmp1 = ctable[l];
    674                             ctable[l] = tmp2;
    675                             tmp2 = tmp1;
    676                         }
    677                         break;
    678                     }
    679                 }
    680 
    681                 // Check "once-off" changes:
    682                 float sum1=0, sum2=0;
    683                 for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
    684                 {
    685                     sum1 += PV_C(k);
    686                     sum2 += PVB_C(k);
    687                 }
    688                 diff = sum1 - stat->Pbc * sum2;
    689                 if( sum1 > model->params.T ) stat->is_trained_st_model = 1;
    690 
    691                 // Update stat table:
    692                 if( diff >  model->params.T )
    693                 {
    694                     //printf("once off change at stat mode\n");
    695                     //new BG features are discovered
    696                     for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
    697                     {
    698                         PVB_C(k) = (PV_C(k)-stat->Pbc*PVB_C(k))/(1-stat->Pbc);
    699                     }
    700                     stat->Pbc = 1 - stat->Pbc;
    701                 }
    702             }		// if !(change detection) at pixel (i,j)
    703 
    704             // Update the reference BG image:
    705             if( !((uchar*)model->foreground->imageData)[i*mask_step+j])
    706             {
    707                 uchar* ptr = ((uchar*)model->background->imageData) + i*model->background->widthStep+j*3;
    708 
    709                 if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] &&
    710                     !((uchar*)model->Fbd->imageData)[i*mask_step+j] )
    711                 {
    712                     // Apply IIR filter:
    713                     for( l = 0; l < 3; l++ )
    714                     {
    715                         int a = cvRound(ptr[l]*(1 - model->params.alpha1) + model->params.alpha1*curr_data[l]);
    716                         ptr[l] = (uchar)a;
    717                         //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l]*=(1 - model->params.alpha1);
    718                         //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] += model->params.alpha1*curr_data[l];
    719                     }
    720                 }
    721                 else
    722                 {
    723                     // Background change detected:
    724                     for( l = 0; l < 3; l++ )
    725                     {
    726                         //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] = curr_data[l];
    727                         ptr[l] = curr_data[l];
    728                     }
    729                 }
    730             }
    731         }		// j
    732     }			// i
    733 
    734     // Keep previous frame:
    735     cvCopy( curr_frame, model->prev_frame );
    736 
    737     return region_count;
    738 }
    739 
    740 /* End of file. */
    741