Update to 2.0.0 tree from current Fremantle build
[opencv] / cvaux / src / cvbgfg_acmmm2003.cpp
diff --git a/cvaux/src/cvbgfg_acmmm2003.cpp b/cvaux/src/cvbgfg_acmmm2003.cpp
deleted file mode 100644 (file)
index bcb03b3..0000000
+++ /dev/null
@@ -1,740 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                        Intel License Agreement
-//
-// Copyright (C) 2000, Intel Corporation, all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of Intel Corporation may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-
-// This file implements the foreground/background pixel
-// discrimination algorithm described in
-//
-//     Foreground Object Detection from Videos Containing Complex Background
-//     Li, Huan, Gu, Tian 2003 9p
-//     http://muq.org/~cynbe/bib/foreground-object-detection-from-videos-containing-complex-background.pdf 
-
-
-#include "_cvaux.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-//#include <algorithm>
-
-static double* _cv_max_element( double* start, double* end )
-{
-    double* p = start++;
-
-    for( ; start != end;  ++start) {
-
-        if (*p < *start)   p = start;
-    } 
-
-    return p;
-}
-
-static void CV_CDECL icvReleaseFGDStatModel( CvFGDStatModel** model );
-static int CV_CDECL icvUpdateFGDStatModel( IplImage* curr_frame,
-                                           CvFGDStatModel*  model );
-
-// Function cvCreateFGDStatModel initializes foreground detection process
-// parameters:
-//      first_frame - frame from video sequence
-//      parameters  - (optional) if NULL default parameters of the algorithm will be used
-//      p_model     - pointer to CvFGDStatModel structure
-CV_IMPL CvBGStatModel*
-cvCreateFGDStatModel( IplImage* first_frame, CvFGDStatModelParams* parameters )
-{
-    CvFGDStatModel* p_model = 0;
-    
-    CV_FUNCNAME( "cvCreateFGDStatModel" );
-
-    __BEGIN__;
-    
-    int i, j, k, pixel_count, buf_size;
-    CvFGDStatModelParams params;
-
-    if( !CV_IS_IMAGE(first_frame) )
-        CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
-
-    if (first_frame->nChannels != 3)
-        CV_ERROR( CV_StsBadArg, "first_frame must have 3 color channels" );
-
-    // Initialize parameters:
-    if( parameters == NULL )
-    {
-        params.Lc      = CV_BGFG_FGD_LC;
-        params.N1c     = CV_BGFG_FGD_N1C;
-        params.N2c     = CV_BGFG_FGD_N2C;
-
-        params.Lcc     = CV_BGFG_FGD_LCC;
-        params.N1cc    = CV_BGFG_FGD_N1CC;
-        params.N2cc    = CV_BGFG_FGD_N2CC;
-
-        params.delta   = CV_BGFG_FGD_DELTA;
-
-        params.alpha1  = CV_BGFG_FGD_ALPHA_1;
-        params.alpha2  = CV_BGFG_FGD_ALPHA_2;
-        params.alpha3  = CV_BGFG_FGD_ALPHA_3;
-
-        params.T       = CV_BGFG_FGD_T;
-        params.minArea = CV_BGFG_FGD_MINAREA;
-
-        params.is_obj_without_holes = 1;
-        params.perform_morphing     = 1;
-    }
-    else
-    {
-        params = *parameters;
-    }
-
-    CV_CALL( p_model = (CvFGDStatModel*)cvAlloc( sizeof(*p_model) ));
-    memset( p_model, 0, sizeof(*p_model) );
-    p_model->type = CV_BG_MODEL_FGD;
-    p_model->release = (CvReleaseBGStatModel)icvReleaseFGDStatModel;
-    p_model->update = (CvUpdateBGStatModel)icvUpdateFGDStatModel;;
-    p_model->params = params;
-
-    // Initialize storage pools:
-    pixel_count = first_frame->width * first_frame->height;
-    
-    buf_size = pixel_count*sizeof(p_model->pixel_stat[0]);
-    CV_CALL( p_model->pixel_stat = (CvBGPixelStat*)cvAlloc(buf_size) );
-    memset( p_model->pixel_stat, 0, buf_size );
-    
-    buf_size = pixel_count*params.N2c*sizeof(p_model->pixel_stat[0].ctable[0]);
-    CV_CALL( p_model->pixel_stat[0].ctable = (CvBGPixelCStatTable*)cvAlloc(buf_size) );
-    memset( p_model->pixel_stat[0].ctable, 0, buf_size );
-
-    buf_size = pixel_count*params.N2cc*sizeof(p_model->pixel_stat[0].cctable[0]);
-    CV_CALL( p_model->pixel_stat[0].cctable = (CvBGPixelCCStatTable*)cvAlloc(buf_size) );
-    memset( p_model->pixel_stat[0].cctable, 0, buf_size );
-
-    for(     i = 0, k = 0; i < first_frame->height; i++ ) {
-        for( j = 0;        j < first_frame->width;  j++, k++ )
-        {
-            p_model->pixel_stat[k].ctable = p_model->pixel_stat[0].ctable + k*params.N2c;
-            p_model->pixel_stat[k].cctable = p_model->pixel_stat[0].cctable + k*params.N2cc;
-        }
-    }
-
-    // Init temporary images:
-    CV_CALL( p_model->Ftd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
-    CV_CALL( p_model->Fbd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
-    CV_CALL( p_model->foreground = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
-
-    CV_CALL( p_model->background = cvCloneImage(first_frame));
-    CV_CALL( p_model->prev_frame = cvCloneImage(first_frame));
-    CV_CALL( p_model->storage = cvCreateMemStorage());
-
-    __END__;
-
-    if( cvGetErrStatus() < 0 )
-    {
-        CvBGStatModel* base_ptr = (CvBGStatModel*)p_model;
-
-        if( p_model && p_model->release )
-            p_model->release( &base_ptr );
-        else
-            cvFree( &p_model );
-        p_model = 0;
-    }
-
-    return (CvBGStatModel*)p_model;
-}
-
-
-static void CV_CDECL
-icvReleaseFGDStatModel( CvFGDStatModel** _model )
-{
-    CV_FUNCNAME( "icvReleaseFGDStatModel" );
-
-    __BEGIN__;
-    
-    if( !_model )
-        CV_ERROR( CV_StsNullPtr, "" );
-
-    if( *_model )
-    {
-        CvFGDStatModel* model = *_model;
-        if( model->pixel_stat )
-        {
-            cvFree( &model->pixel_stat[0].ctable );
-            cvFree( &model->pixel_stat[0].cctable );
-            cvFree( &model->pixel_stat );
-        }
-
-        cvReleaseImage( &model->Ftd );
-        cvReleaseImage( &model->Fbd );
-        cvReleaseImage( &model->foreground );
-        cvReleaseImage( &model->background );
-        cvReleaseImage( &model->prev_frame );
-        cvReleaseMemStorage(&model->storage);
-
-        cvFree( _model );
-    }
-
-    __END__;
-}
-
-//  Function cvChangeDetection performs change detection for Foreground detection algorithm
-// parameters:
-//      prev_frame -
-//      curr_frame -
-//      change_mask -
-CV_IMPL int
-cvChangeDetection( IplImage*  prev_frame,
-                   IplImage*  curr_frame,
-                   IplImage*  change_mask )
-{
-    int i, j, b, x, y, thres;
-    const int PIXELRANGE=256;
-
-    if( !prev_frame
-    ||  !curr_frame
-    ||  !change_mask
-    ||   prev_frame->nChannels  != 3
-    ||   curr_frame->nChannels  != 3
-    ||   change_mask->nChannels != 1
-    ||   prev_frame->depth  != IPL_DEPTH_8U
-    ||   curr_frame->depth  != IPL_DEPTH_8U
-    ||   change_mask->depth != IPL_DEPTH_8U
-    ||   prev_frame->width  != curr_frame->width
-    ||   prev_frame->height != curr_frame->height
-    ||   prev_frame->width  != change_mask->width
-    ||   prev_frame->height != change_mask->height
-    ){
-        return 0;
-    }
-
-    cvZero ( change_mask );
-
-    // All operations per colour
-    for (b=0 ; b<prev_frame->nChannels ; b++) {
-
-        // Create histogram:
-
-        long HISTOGRAM[PIXELRANGE]; 
-        for (i=0 ; i<PIXELRANGE; i++) HISTOGRAM[i]=0;
-        
-        for (y=0 ; y<curr_frame->height ; y++)
-        {
-            uchar* rowStart1 = (uchar*)curr_frame->imageData + y * curr_frame->widthStep + b;
-            uchar* rowStart2 = (uchar*)prev_frame->imageData + y * prev_frame->widthStep + b;
-            for (x=0 ; x<curr_frame->width ; x++, rowStart1+=curr_frame->nChannels, rowStart2+=prev_frame->nChannels) {
-                int diff = abs( int(*rowStart1) - int(*rowStart2) );
-                HISTOGRAM[diff]++;
-            }
-        }
-
-        double relativeVariance[PIXELRANGE];
-        for (i=0 ; i<PIXELRANGE; i++) relativeVariance[i]=0;
-
-        for (thres=PIXELRANGE-2; thres>=0 ; thres--)
-        {
-            //            fprintf(stderr, "Iter %d\n", thres);
-            double sum=0;
-            double sqsum=0;
-            int count=0;
-            //            fprintf(stderr, "Iter %d entering loop\n", thres);
-            for (j=thres ; j<PIXELRANGE ; j++) {
-                sum   += double(j)*double(HISTOGRAM[j]);
-                sqsum += double(j*j)*double(HISTOGRAM[j]);
-                count += HISTOGRAM[j];
-            }
-            count = count == 0 ? 1 : count;
-            //            fprintf(stderr, "Iter %d finishing loop\n", thres);
-            double my = sum / count;
-            double sigma = sqrt( sqsum/count - my*my);
-            //            fprintf(stderr, "Iter %d sum=%g sqsum=%g count=%d sigma = %g\n", thres, sum, sqsum, count, sigma);
-            //            fprintf(stderr, "Writing to %x\n", &(relativeVariance[thres]));
-            relativeVariance[thres] = sigma;
-            //            fprintf(stderr, "Iter %d finished\n", thres);
-        }
-
-        // Find maximum:
-        uchar bestThres = 0;
-
-        double* pBestThres = _cv_max_element(relativeVariance, relativeVariance+PIXELRANGE);
-        bestThres = (uchar)(*pBestThres); if (bestThres <10) bestThres=10;
-
-        for (y=0 ; y<prev_frame->height ; y++)
-        {
-            uchar* rowStart1 = (uchar*)(curr_frame->imageData) + y * curr_frame->widthStep + b;
-            uchar* rowStart2 = (uchar*)(prev_frame->imageData) + y * prev_frame->widthStep + b;
-            uchar* rowStart3 = (uchar*)(change_mask->imageData) + y * change_mask->widthStep;
-            for (x = 0; x < curr_frame->width; x++, rowStart1+=curr_frame->nChannels,
-                rowStart2+=prev_frame->nChannels, rowStart3+=change_mask->nChannels) {
-                // OR between different color channels
-                int diff = abs( int(*rowStart1) - int(*rowStart2) );
-                if ( diff > bestThres)
-                    *rowStart3 |=255;
-            }
-        }
-    }
-
-    return 1;
-}
-
-
-#define MIN_PV 1E-10
-
-
-#define V_C(k,l) ctable[k].v[l]
-#define PV_C(k) ctable[k].Pv
-#define PVB_C(k) ctable[k].Pvb
-#define V_CC(k,l) cctable[k].v[l]
-#define PV_CC(k) cctable[k].Pv
-#define PVB_CC(k) cctable[k].Pvb
-
-
-// Function cvUpdateFGDStatModel updates statistical model and returns number of foreground regions
-// parameters:
-//      curr_frame  - current frame from video sequence
-//      p_model     - pointer to CvFGDStatModel structure
-static int CV_CDECL
-icvUpdateFGDStatModel( IplImage* curr_frame, CvFGDStatModel*  model )
-{
-    int            mask_step = model->Ftd->widthStep;
-    CvSeq         *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
-    IplImage*      prev_frame = model->prev_frame;
-    int            region_count = 0;
-    int            FG_pixels_count = 0;
-    int            deltaC  = cvRound(model->params.delta * 256 / model->params.Lc);
-    int            deltaCC = cvRound(model->params.delta * 256 / model->params.Lcc);
-    int            i, j, k, l;
-
-    //clear storages
-    cvClearMemStorage(model->storage);
-    cvZero(model->foreground);
-
-    // From foreground pixel candidates using image differencing
-    // with adaptive thresholding.  The algorithm is from:
-    //
-    //    Thresholding for Change Detection
-    //    Paul L. Rosin 1998 6p
-    //    http://www.cis.temple.edu/~latecki/Courses/CIS750-03/Papers/thresh-iccv.pdf
-    //
-    cvChangeDetection( prev_frame, curr_frame, model->Ftd );
-    cvChangeDetection( model->background, curr_frame, model->Fbd );
-
-    for( i = 0; i < model->Ftd->height; i++ )
-    {
-        for( j = 0; j < model->Ftd->width; j++ )
-        {
-            if( ((uchar*)model->Fbd->imageData)[i*mask_step+j] || ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
-            {
-               float Pb  = 0;
-                float Pv  = 0;
-                float Pvb = 0;
-
-                CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
-
-                CvBGPixelCStatTable*   ctable = stat->ctable;
-                CvBGPixelCCStatTable* cctable = stat->cctable;
-    
-                uchar* curr_data = (uchar*)(curr_frame->imageData) + i*curr_frame->widthStep + j*3;
-                uchar* prev_data = (uchar*)(prev_frame->imageData) + i*prev_frame->widthStep + j*3;
-
-                int val = 0;
-
-                // Is it a motion pixel?
-                if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
-                {
-                   if( !stat->is_trained_dyn_model ) {
-
-                        val = 1;
-
-                   } else {
-
-                        // Compare with stored CCt vectors:
-                        for( k = 0;  PV_CC(k) > model->params.alpha2 && k < model->params.N1cc;  k++ )
-                        {
-                            if ( abs( V_CC(k,0) - prev_data[0]) <=  deltaCC &&
-                                 abs( V_CC(k,1) - prev_data[1]) <=  deltaCC &&
-                                 abs( V_CC(k,2) - prev_data[2]) <=  deltaCC &&
-                                 abs( V_CC(k,3) - curr_data[0]) <=  deltaCC &&
-                                 abs( V_CC(k,4) - curr_data[1]) <=  deltaCC &&
-                                 abs( V_CC(k,5) - curr_data[2]) <=  deltaCC)
-                            {
-                                Pv += PV_CC(k);
-                                Pvb += PVB_CC(k);
-                            }
-                        }
-                        Pb = stat->Pbcc;
-                        if( 2 * Pvb * Pb <= Pv ) val = 1;
-                    }
-                }
-                else if( stat->is_trained_st_model )
-                {
-                    // Compare with stored Ct vectors:
-                    for( k = 0;  PV_C(k) > model->params.alpha2 && k < model->params.N1c;  k++ )
-                    {
-                        if ( abs( V_C(k,0) - curr_data[0]) <=  deltaC &&
-                             abs( V_C(k,1) - curr_data[1]) <=  deltaC &&
-                             abs( V_C(k,2) - curr_data[2]) <=  deltaC )
-                        {
-                            Pv += PV_C(k);
-                            Pvb += PVB_C(k);
-                        }
-                    }
-                    Pb = stat->Pbc;
-                    if( 2 * Pvb * Pb <= Pv ) val = 1;
-                }
-
-                // Update foreground:
-                ((uchar*)model->foreground->imageData)[i*mask_step+j] = (uchar)(val*255);
-                FG_pixels_count += val;
-
-            }          // end if( change detection...
-        }              // for j...
-    }                  // for i...
-    //end BG/FG classification
-
-    // Foreground segmentation.
-    // Smooth foreground map:
-    if( model->params.perform_morphing ){
-        cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_OPEN,  model->params.perform_morphing );
-        cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_CLOSE, model->params.perform_morphing );
-    }
-   
-   
-    if( model->params.minArea > 0 || model->params.is_obj_without_holes ){
-
-        // Discard under-size foreground regions:
-       //
-        cvFindContours( model->foreground, model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
-        for( seq = first_seq; seq; seq = seq->h_next )
-        {
-            CvContour* cnt = (CvContour*)seq;
-            if( cnt->rect.width * cnt->rect.height < model->params.minArea || 
-                (model->params.is_obj_without_holes && CV_IS_SEQ_HOLE(seq)) )
-            {
-                // Delete under-size contour:
-                prev_seq = seq->h_prev;
-                if( prev_seq )
-                {
-                    prev_seq->h_next = seq->h_next;
-                    if( seq->h_next ) seq->h_next->h_prev = prev_seq;
-                }
-                else
-                {
-                    first_seq = seq->h_next;
-                    if( seq->h_next ) seq->h_next->h_prev = NULL;
-                }
-            }
-            else
-            {
-                region_count++;
-            }
-        }        
-        model->foreground_regions = first_seq;
-        cvZero(model->foreground);
-        cvDrawContours(model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
-
-    } else {
-
-        model->foreground_regions = NULL;
-    }
-
-    // Check ALL BG update condition:
-    if( ((float)FG_pixels_count/(model->Ftd->width*model->Ftd->height)) > CV_BGFG_FGD_BG_UPDATE_TRESH )
-    {
-         for( i = 0; i < model->Ftd->height; i++ )
-             for( j = 0; j < model->Ftd->width; j++ )
-             {
-                 CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
-                 stat->is_trained_st_model = stat->is_trained_dyn_model = 1;
-             }
-    }
-
-
-    // Update background model:
-    for( i = 0; i < model->Ftd->height; i++ )
-    {
-        for( j = 0; j < model->Ftd->width; j++ )
-        {
-            CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
-            CvBGPixelCStatTable* ctable = stat->ctable;
-            CvBGPixelCCStatTable* cctable = stat->cctable;
-
-            uchar *curr_data = (uchar*)(curr_frame->imageData)+i*curr_frame->widthStep+j*3;
-            uchar *prev_data = (uchar*)(prev_frame->imageData)+i*prev_frame->widthStep+j*3;
-
-            if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] || !stat->is_trained_dyn_model )
-            {
-                float alpha = stat->is_trained_dyn_model ? model->params.alpha2 : model->params.alpha3;
-                float diff = 0;
-                int dist, min_dist = 2147483647, indx = -1;
-
-                //update Pb
-                stat->Pbcc *= (1.f-alpha);
-                if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
-                {
-                    stat->Pbcc += alpha;
-                }
-
-                // Find best Vi match:
-                for(k = 0; PV_CC(k) && k < model->params.N2cc; k++ )
-                {
-                    // Exponential decay of memory
-                    PV_CC(k)  *= (1-alpha);
-                    PVB_CC(k) *= (1-alpha);
-                    if( PV_CC(k) < MIN_PV )
-                    {
-                        PV_CC(k) = 0;
-                        PVB_CC(k) = 0;
-                        continue;
-                    }
-
-                    dist = 0;
-                    for( l = 0; l < 3; l++ )
-                    {
-                        int val = abs( V_CC(k,l) - prev_data[l] );
-                        if( val > deltaCC ) break;
-                        dist += val;
-                        val = abs( V_CC(k,l+3) - curr_data[l] );
-                        if( val > deltaCC) break;
-                        dist += val;
-                    }
-                    if( l == 3 && dist < min_dist )
-                    {
-                        min_dist = dist;
-                        indx = k;
-                    }
-                }
-
-
-                if( indx < 0 )
-                {   // Replace N2th elem in the table by new feature:
-                    indx = model->params.N2cc - 1;
-                    PV_CC(indx) = alpha;
-                    PVB_CC(indx) = alpha;
-                    //udate Vt
-                    for( l = 0; l < 3; l++ )
-                    {
-                        V_CC(indx,l) = prev_data[l];
-                        V_CC(indx,l+3) = curr_data[l];
-                    }
-                }
-                else
-                {   // Update:
-                    PV_CC(indx) += alpha;
-                    if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
-                    {
-                        PVB_CC(indx) += alpha;
-                    }
-                }
-
-                //re-sort CCt table by Pv
-                for( k = 0; k < indx; k++ )
-                {
-                    if( PV_CC(k) <= PV_CC(indx) )
-                    {
-                        //shift elements
-                        CvBGPixelCCStatTable tmp1, tmp2 = cctable[indx];
-                        for( l = k; l <= indx; l++ )
-                        {
-                            tmp1 = cctable[l];
-                            cctable[l] = tmp2;
-                            tmp2 = tmp1;
-                        }
-                        break;
-                    }
-                }
-
-
-                float sum1=0, sum2=0;
-                //check "once-off" changes
-                for(k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
-                {
-                    sum1 += PV_CC(k);
-                    sum2 += PVB_CC(k);
-                }
-                if( sum1 > model->params.T ) stat->is_trained_dyn_model = 1;
-                
-                diff = sum1 - stat->Pbcc * sum2;
-                // Update stat table:
-                if( diff >  model->params.T )
-                {
-                    //printf("once off change at motion mode\n");
-                    //new BG features are discovered
-                    for( k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
-                    {
-                        PVB_CC(k) =
-                            (PV_CC(k)-stat->Pbcc*PVB_CC(k))/(1-stat->Pbcc);
-                    }
-                    assert(stat->Pbcc<=1 && stat->Pbcc>=0);
-                }
-            }
-
-            // Handle "stationary" pixel:
-            if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] )
-            {
-                float alpha = stat->is_trained_st_model ? model->params.alpha2 : model->params.alpha3;
-                float diff = 0;
-                int dist, min_dist = 2147483647, indx = -1;
-
-                //update Pb
-                stat->Pbc *= (1.f-alpha);
-                if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
-                {
-                    stat->Pbc += alpha;
-                }
-
-                //find best Vi match
-                for( k = 0; k < model->params.N2c; k++ )
-                {
-                    // Exponential decay of memory
-                    PV_C(k) *= (1-alpha);
-                    PVB_C(k) *= (1-alpha);
-                    if( PV_C(k) < MIN_PV )
-                    {
-                        PV_C(k) = 0;
-                        PVB_C(k) = 0;
-                        continue;
-                    }
-                    
-                    dist = 0;
-                    for( l = 0; l < 3; l++ )
-                    {
-                        int val = abs( V_C(k,l) - curr_data[l] );
-                        if( val > deltaC ) break;
-                        dist += val;
-                    }
-                    if( l == 3 && dist < min_dist )
-                    {
-                        min_dist = dist;
-                        indx = k;
-                    }
-                }
-
-                if( indx < 0 )
-                {//N2th elem in the table is replaced by a new features
-                    indx = model->params.N2c - 1;
-                    PV_C(indx) = alpha;
-                    PVB_C(indx) = alpha;
-                    //udate Vt
-                    for( l = 0; l < 3; l++ )
-                    {
-                        V_C(indx,l) = curr_data[l];
-                    }
-                } else
-                {//update
-                    PV_C(indx) += alpha;
-                    if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
-                    {
-                        PVB_C(indx) += alpha;
-                    }
-                }
-
-                //re-sort Ct table by Pv
-                for( k = 0; k < indx; k++ )
-                {
-                    if( PV_C(k) <= PV_C(indx) )
-                    {
-                        //shift elements
-                        CvBGPixelCStatTable tmp1, tmp2 = ctable[indx];
-                        for( l = k; l <= indx; l++ )
-                        {
-                            tmp1 = ctable[l];
-                            ctable[l] = tmp2;
-                            tmp2 = tmp1;
-                        }
-                        break;
-                    }
-                }
-
-                // Check "once-off" changes:
-                float sum1=0, sum2=0;
-                for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
-                {
-                    sum1 += PV_C(k);
-                    sum2 += PVB_C(k);
-                }
-                diff = sum1 - stat->Pbc * sum2;
-                if( sum1 > model->params.T ) stat->is_trained_st_model = 1;
-
-                // Update stat table:
-                if( diff >  model->params.T )
-                {
-                    //printf("once off change at stat mode\n");
-                    //new BG features are discovered
-                    for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
-                    {
-                        PVB_C(k) = (PV_C(k)-stat->Pbc*PVB_C(k))/(1-stat->Pbc);
-                    }
-                    stat->Pbc = 1 - stat->Pbc;
-                }
-            }          // if !(change detection) at pixel (i,j)
-
-            // Update the reference BG image:
-            if( !((uchar*)model->foreground->imageData)[i*mask_step+j])
-            {
-                uchar* ptr = ((uchar*)model->background->imageData) + i*model->background->widthStep+j*3;
-                
-                if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] &&
-                    !((uchar*)model->Fbd->imageData)[i*mask_step+j] )
-                {
-                    // Apply IIR filter:
-                    for( l = 0; l < 3; l++ )
-                    {
-                        int a = cvRound(ptr[l]*(1 - model->params.alpha1) + model->params.alpha1*curr_data[l]);
-                        ptr[l] = (uchar)a;
-                        //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l]*=(1 - model->params.alpha1);
-                        //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] += model->params.alpha1*curr_data[l];
-                    }
-                }
-                else
-                {
-                    // Background change detected:
-                    for( l = 0; l < 3; l++ )
-                    {
-                        //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] = curr_data[l];
-                        ptr[l] = curr_data[l];
-                    }
-                }
-            }
-        }              // j
-    }                  // i
-
-    // Keep previous frame:
-    cvCopy( curr_frame, model->prev_frame );
-
-    return region_count;
-}
-
-/* End of file. */