16acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/*M///////////////////////////////////////////////////////////////////////////////////////
26acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
36acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
46acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
56acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//  By downloading, copying, installing or using the software you agree to this license.
66acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//  If you do not agree to this license, do not download, install,
76acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//  copy or use the software.
86acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
96acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//                        Intel License Agreement
116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Copyright (C) 2000, Intel Corporation, all rights reserved.
136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Third party copyrights are property of their respective owners.
146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Redistribution and use in source and binary forms, with or without modification,
166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// are permitted provided that the following conditions are met:
176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//   * Redistribution's of source code must retain the above copyright notice,
196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//     this list of conditions and the following disclaimer.
206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//   * Redistribution's in binary form must reproduce the above copyright notice,
226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//     this list of conditions and the following disclaimer in the documentation
236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//     and/or other materials provided with the distribution.
246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//   * The name of Intel Corporation may not be used to endorse or promote products
266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//     derived from this software without specific prior written permission.
276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// This software is provided by the copyright holders and contributors "as is" and
296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// any express or implied warranties, including, but not limited to, the implied
306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// warranties of merchantability and fitness for a particular purpose are disclaimed.
316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// In no event shall the Intel Corporation or contributors be liable for any direct,
326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// indirect, incidental, special, exemplary, or consequential damages
336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// (including, but not limited to, procurement of substitute goods or services;
346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// loss of use, data, or profits; or business interruption) however caused
356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// and on any theory of liability, whether in contract, strict liability,
366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// or tort (including negligence or otherwise) arising in any way out of
376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// the use of this software, even if advised of the possibility of such damage.
386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//M*/
406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// This is based on the "An Improved Adaptive Background Mixture Model for
436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Real-time Tracking with Shadow Detection" by P. KaewTraKulPong and R. Bowden
446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// The windowing method is used, but not the shadow detection. I make some of my
476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// own modifications which make more sense. There are some errors in some of their
486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// equations.
496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//IplImage values of image that are useful
516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//int  nSize;         /* sizeof(IplImage) */
526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//int  depth;         /* pixel depth in bits: IPL_DEPTH_8U ...*/
536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//int  nChannels;     /* OpenCV functions support 1,2,3 or 4 channels */
546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//int  width;         /* image width in pixels */
556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//int  height;        /* image height in pixels */
566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//int  imageSize;     /* image data size in bytes in case of interleaved data)*/
576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//char *imageData;    /* pointer to aligned image data */
586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//char *imageDataOrigin; /* pointer to very origin of image -deallocation */
596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//Values useful for gaussian integral
606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//0.5 - 0.19146 - 0.38292
616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//1.0 - 0.34134 - 0.68268
626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//1.5 - 0.43319 - 0.86638
636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//2.0 - 0.47725 - 0.95450
646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//2.5 - 0.49379 - 0.98758
656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//3.0 - 0.49865 - 0.99730
666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//3.5 - 0.4997674 - 0.9995348
676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//4.0 - 0.4999683 - 0.9999366
686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "_cvaux.h"
706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//internal functions for gaussian background detection
736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvInsertionSortGaussians( CvGaussBGPoint* g_point, double* sort_key, CvGaussBGStatModelParams *bg_model_params );
746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/*
766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   Test whether pixel can be explained by background model;
776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   Return -1 if no match was found; otherwise the index in match[] is returned
786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   icvMatchTest(...) assumes what all color channels component exhibit the same variance
806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   icvMatchTest2(...) accounts for different variances per color channel
816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn */
826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int icvMatchTest( double* src_pixel, int nChannels, int* match,
836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                 const CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params );
846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/*static int icvMatchTest2( double* src_pixel, int nChannels, int* match,
856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                 const CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params );*/
866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/*
896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   The update procedure differs between
906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      * the initialization phase (named *Partial* ) and
916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      * the normal phase (named *Full* )
926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   The initalization phase is defined as not having processed <win_size> frames yet
936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn */
946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvUpdateFullWindow( double* src_pixel, int nChannels,
956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                         int* match,
966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                         CvGaussBGPoint* g_point,
976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                         const CvGaussBGStatModelParams *bg_model_params );
986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvUpdateFullNoMatch( IplImage* gm_image, int p,
996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                          int* match,
1006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                          CvGaussBGPoint* g_point,
1016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                          const CvGaussBGStatModelParams *bg_model_params);
1026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvUpdatePartialWindow( double* src_pixel, int nChannels, int* match,
1036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params );
1046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvUpdatePartialNoMatch( double* src_pixel, int nChannels,
1056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                             int* match,
1066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                             CvGaussBGPoint* g_point,
1076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                             const CvGaussBGStatModelParams *bg_model_params);
1086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvGetSortKey( const int nChannels, double* sort_key, const CvGaussBGPoint* g_point,
1116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    const CvGaussBGStatModelParams *bg_model_params );
1126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvBackgroundTest( const int nChannels, int n, int i, int j, int *match, CvGaussBGModel* bg_model );
1136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void CV_CDECL icvReleaseGaussianBGModel( CvGaussBGModel** bg_model );
1156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int CV_CDECL icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel*  bg_model );
1166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//#define for if(0);else for
1186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//g = 1 for first gaussian in list that matches else g = 0
1206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//Rw is the learning rate for weight and Rg is leaning rate for mean and variance
1216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//Ms is the match_sum which is the sum of matches for a particular gaussian
1226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//Ms values are incremented until the sum of Ms values in the list equals window size L
1236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//SMs is the sum of match_sums for gaussians in the list
1246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//Rw = 1/SMs note the smallest Rw gets is 1/L
1256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//Rg = g/Ms for SMs < L and Rg = g/(w*L) for SMs = L
1266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//The list is maintained in sorted order using w/sqrt(variance) as a key
1276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//If there is no match the last gaussian in the list is replaced by the new gaussian
1286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//This will result in changes to SMs which results in changes in Rw and Rg.
1296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//If a gaussian is replaced and SMs previously equaled L values of Ms are computed from w
1306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//w[n+1] = w[n] + Rw*(g - w[n])   weight
1316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//u[n+1] = u[n] + Rg*(x[n+1] - u[n]) mean value Sg is sum n values of g
1326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//v[n+1] = v[n] + Rg*((x[n+1] - u[n])*(x[n+1] - u[n])) - v[n]) variance
1336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
1346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennCV_IMPL CvBGStatModel*
1366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RenncvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters )
1376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
1386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CvGaussBGModel* bg_model = 0;
1396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_FUNCNAME( "cvCreateGaussianBGModel" );
1416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    __BEGIN__;
1436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    double var_init;
1456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CvGaussBGStatModelParams params;
1466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int i, j, k, m, n;
1476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //init parameters
1496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( parameters == NULL )
1506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      {                        /* These constants are defined in cvaux/include/cvaux.h: */
1516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.win_size      = CV_BGFG_MOG_WINDOW_SIZE;
1526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.bg_threshold  = CV_BGFG_MOG_BACKGROUND_THRESHOLD;
1536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD;
1556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.weight_init   = CV_BGFG_MOG_WEIGHT_INIT;
1566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT;
1586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.minArea       = CV_BGFG_MOG_MINAREA;
1596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.n_gauss       = CV_BGFG_MOG_NGAUSSIANS;
1606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else
1626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params = *parameters;
1646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !CV_IS_IMAGE(first_frame) )
1676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
1686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( bg_model = (CvGaussBGModel*)cvAlloc( sizeof(*bg_model) ));
1706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    memset( bg_model, 0, sizeof(*bg_model) );
1716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bg_model->type = CV_BG_MODEL_MOG;
1726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel;
1736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel;
1746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bg_model->params = params;
1766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //prepare storages
1786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( bg_model->g_point = (CvGaussBGPoint*)cvAlloc(sizeof(CvGaussBGPoint)*
1796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        ((first_frame->width*first_frame->height) + 256)));
1806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( bg_model->background = cvCreateImage(cvSize(first_frame->width,
1826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        first_frame->height), IPL_DEPTH_8U, first_frame->nChannels));
1836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( bg_model->foreground = cvCreateImage(cvSize(first_frame->width,
1846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        first_frame->height), IPL_DEPTH_8U, 1));
1856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( bg_model->storage = cvCreateMemStorage());
1876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //initializing
1896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    var_init = 2 * params.std_threshold * params.std_threshold;
1906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( bg_model->g_point[0].g_values =
1916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        (CvGaussBGValues*)cvAlloc( sizeof(CvGaussBGValues)*params.n_gauss*
1926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        (first_frame->width*first_frame->height + 128)));
1936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( i = 0, n = 0; i < first_frame->height; i++ )
1956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for( j = 0; j < first_frame->width; j++, n++ )
1976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
1986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            const int p = i*first_frame->widthStep+j*first_frame->nChannels;
1996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            bg_model->g_point[n].g_values =
2016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                bg_model->g_point[0].g_values + n*params.n_gauss;
2026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            bg_model->g_point[n].g_values[0].weight = 1;    //the first value seen has weight one
2036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            bg_model->g_point[n].g_values[0].match_sum = 1;
2046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for( m = 0; m < first_frame->nChannels; m++)
2056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
2066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                bg_model->g_point[n].g_values[0].variance[m] = var_init;
2076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                bg_model->g_point[n].g_values[0].mean[m] = (unsigned char)first_frame->imageData[p + m];
2086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
2096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for( k = 1; k < params.n_gauss; k++)
2106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
2116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                bg_model->g_point[n].g_values[k].weight = 0;
2126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                bg_model->g_point[n].g_values[k].match_sum = 0;
2136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                for( m = 0; m < first_frame->nChannels; m++){
2146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    bg_model->g_point[n].g_values[k].variance[m] = var_init;
2156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    bg_model->g_point[n].g_values[k].mean[m] = 0;
2166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
2176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
2186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
2196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bg_model->countFrames = 0;
2226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    __END__;
2246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( cvGetErrStatus() < 0 )
2266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
2276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model;
2286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( bg_model && bg_model->release )
2306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            bg_model->release( &base_ptr );
2316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        else
2326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            cvFree( &bg_model );
2336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        bg_model = 0;
2346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return (CvBGStatModel*)bg_model;
2376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void CV_CDECL
2416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennicvReleaseGaussianBGModel( CvGaussBGModel** _bg_model )
2426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
2436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_FUNCNAME( "icvReleaseGaussianBGModel" );
2446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    __BEGIN__;
2466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !_bg_model )
2486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CV_ERROR( CV_StsNullPtr, "" );
2496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( *_bg_model )
2516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
2526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CvGaussBGModel* bg_model = *_bg_model;
2536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( bg_model->g_point )
2546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
2556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            cvFree( &bg_model->g_point[0].g_values );
2566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            cvFree( &bg_model->g_point );
2576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
2586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseImage( &bg_model->background );
2606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseImage( &bg_model->foreground );
2616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseMemStorage(&bg_model->storage);
2626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        memset( bg_model, 0, sizeof(*bg_model) );
2636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvFree( _bg_model );
2646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    __END__;
2676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int CV_CDECL
2716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennicvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel*  bg_model )
2726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
2736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int i, j, k, n;
2746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int region_count = 0;
2756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
2766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bg_model->countFrames++;
2786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( i = 0, n = 0; i < curr_frame->height; i++ )
2806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
2816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for( j = 0; j < curr_frame->width; j++, n++ )
2826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
2836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            int match[CV_BGFG_MOG_MAX_NGAUSSIANS];
2846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double sort_key[CV_BGFG_MOG_MAX_NGAUSSIANS];
2856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            const int nChannels = curr_frame->nChannels;
2866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            const int p = curr_frame->widthStep*i+j*nChannels;
2876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            // A few short cuts
2896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            CvGaussBGPoint* g_point = &bg_model->g_point[n];
2906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            const CvGaussBGStatModelParams bg_model_params = bg_model->params;
2916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double pixel[4];
2926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            int no_match;
2936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for( k = 0; k < nChannels; k++ )
2956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                pixel[k] = (uchar)curr_frame->imageData[p+k];
2966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            no_match = icvMatchTest( pixel, nChannels, match, g_point, &bg_model_params );
2986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            if( bg_model->countFrames >= bg_model->params.win_size )
2996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
3006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                icvUpdateFullWindow( pixel, nChannels, match, g_point, &bg_model->params );
3016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( no_match == -1)
3026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    icvUpdateFullNoMatch( curr_frame, p, match, g_point, &bg_model_params );
3036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
3046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            else
3056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
3066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                icvUpdatePartialWindow( pixel, nChannels, match, g_point, &bg_model_params );
3076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( no_match == -1)
3086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    icvUpdatePartialNoMatch( pixel, nChannels, match, g_point, &bg_model_params );
3096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
3106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            icvGetSortKey( nChannels, sort_key, g_point, &bg_model_params );
3116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            icvInsertionSortGaussians( g_point, sort_key, (CvGaussBGStatModelParams *)&bg_model_params );
3126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            icvBackgroundTest( nChannels, n, i, j, match, bg_model );
3136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
3146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //foreground filtering
3176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //filter small regions
3196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvClearMemStorage(bg_model->storage);
3206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 );
3226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 );
3236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
3256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( seq = first_seq; seq; seq = seq->h_next )
3266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CvContour* cnt = (CvContour*)seq;
3286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea )
3296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
3306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            //delete small contour
3316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            prev_seq = seq->h_prev;
3326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            if( prev_seq )
3336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
3346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                prev_seq->h_next = seq->h_next;
3356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( seq->h_next ) seq->h_next->h_prev = prev_seq;
3366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
3376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            else
3386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
3396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                first_seq = seq->h_next;
3406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( seq->h_next ) seq->h_next->h_prev = NULL;
3416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
3426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
3436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        else
3446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
3456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            region_count++;
3466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
3476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bg_model->foreground_regions = first_seq;
3496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvZero(bg_model->foreground);
3506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
3516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return region_count;
3536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
3546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvInsertionSortGaussians( CvGaussBGPoint* g_point, double* sort_key, CvGaussBGStatModelParams *bg_model_params )
3566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
3576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int i, j;
3586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( i = 1; i < bg_model_params->n_gauss; i++ )
3596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        double index = sort_key[i];
3616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for( j = i; j > 0 && sort_key[j-1] < index; j-- ) //sort decending order
3626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
3636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double temp_sort_key = sort_key[j];
3646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            sort_key[j] = sort_key[j-1];
3656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            sort_key[j-1] = temp_sort_key;
3666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            CvGaussBGValues temp_gauss_values = g_point->g_values[j];
3686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            g_point->g_values[j] = g_point->g_values[j-1];
3696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            g_point->g_values[j-1] = temp_gauss_values;
3706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
3716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//        sort_key[j] = index;
3726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
3746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int icvMatchTest( double* src_pixel, int nChannels, int* match,
3776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                         const CvGaussBGPoint* g_point,
3786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                         const CvGaussBGStatModelParams *bg_model_params )
3796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
3806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int k;
3816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int matchPosition=-1;
3826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for ( k = 0; k < bg_model_params->n_gauss; k++) match[k]=0;
3836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for ( k = 0; k < bg_model_params->n_gauss; k++) {
3856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        double sum_d2 = 0.0;
3866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        double var_threshold = 0.0;
3876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for(int m = 0; m < nChannels; m++){
3886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double d = g_point->g_values[k].mean[m]- src_pixel[m];
3896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            sum_d2 += (d*d);
3906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            var_threshold += g_point->g_values[k].variance[m];
3916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }  //difference < STD_LIMIT*STD_LIMIT or difference**2 < STD_LIMIT*STD_LIMIT*VAR
3926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        var_threshold = bg_model_params->std_threshold*bg_model_params->std_threshold*var_threshold;
3936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if(sum_d2 < var_threshold){
3946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            match[k] = 1;
3956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            matchPosition = k;
3966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            break;
3976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
3986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return matchPosition;
4016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
4026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/*
4046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int icvMatchTest2( double* src_pixel, int nChannels, int* match,
4056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                          const CvGaussBGPoint* g_point,
4066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                          const CvGaussBGStatModelParams *bg_model_params )
4076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
4086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int k, m;
4096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int matchPosition=-1;
4106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( k = 0; k < bg_model_params->n_gauss; k++ )
4126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        match[k] = 0;
4136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( k = 0; k < bg_model_params->n_gauss; k++ )
4156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
4166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        double sum_d2 = 0.0, var_threshold;
4176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for( m = 0; m < nChannels; m++ )
4186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
4196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double d = g_point->g_values[k].mean[m]- src_pixel[m];
4206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            sum_d2 += (d*d) / (g_point->g_values[k].variance[m] * g_point->g_values[k].variance[m]);
4216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }  //difference < STD_LIMIT*STD_LIMIT or difference**2 < STD_LIMIT*STD_LIMIT*VAR
4226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        var_threshold = bg_model_params->std_threshold*bg_model_params->std_threshold;
4246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( sum_d2 < var_threshold )
4256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
4266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            match[k] = 1;
4276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            matchPosition = k;
4286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            break;
4296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
4306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
4316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return matchPosition;
4336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
4346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn*/
4356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvUpdateFullWindow( double* src_pixel, int nChannels, int* match,
4376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                 CvGaussBGPoint* g_point,
4386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                 const CvGaussBGStatModelParams *bg_model_params )
4396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
4406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    const double learning_rate_weight = (1.0/(double)bg_model_params->win_size);
4416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for(int k = 0; k < bg_model_params->n_gauss; k++){
4426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[k].weight = g_point->g_values[k].weight +
4436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            (learning_rate_weight*((double)match[k] -
4446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            g_point->g_values[k].weight));
4456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if(match[k]){
4466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double learning_rate_gaussian = (double)match[k]/(g_point->g_values[k].weight*
4476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                (double)bg_model_params->win_size);
4486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for(int m = 0; m < nChannels; m++){
4496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                const double tmpDiff = src_pixel[m] - g_point->g_values[k].mean[m];
4506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                g_point->g_values[k].mean[m] = g_point->g_values[k].mean[m] +
4516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    (learning_rate_gaussian * tmpDiff);
4526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                g_point->g_values[k].variance[m] = g_point->g_values[k].variance[m]+
4536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    (learning_rate_gaussian*((tmpDiff*tmpDiff) - g_point->g_values[k].variance[m]));
4546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
4556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
4566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
4576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
4586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvUpdatePartialWindow( double* src_pixel, int nChannels, int* match, CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params )
4616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
4626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int k, m;
4636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int window_current = 0;
4646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( k = 0; k < bg_model_params->n_gauss; k++ )
4666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        window_current += g_point->g_values[k].match_sum;
4676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( k = 0; k < bg_model_params->n_gauss; k++ )
4696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
4706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[k].match_sum += match[k];
4716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        double learning_rate_weight = (1.0/((double)window_current + 1.0)); //increased by one since sum
4726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[k].weight = g_point->g_values[k].weight +
4736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            (learning_rate_weight*((double)match[k] - g_point->g_values[k].weight));
4746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( g_point->g_values[k].match_sum > 0 && match[k] )
4766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
4776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double learning_rate_gaussian = (double)match[k]/((double)g_point->g_values[k].match_sum);
4786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for( m = 0; m < nChannels; m++ )
4796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
4806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                const double tmpDiff = src_pixel[m] - g_point->g_values[k].mean[m];
4816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                g_point->g_values[k].mean[m] = g_point->g_values[k].mean[m] +
4826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    (learning_rate_gaussian*tmpDiff);
4836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                g_point->g_values[k].variance[m] = g_point->g_values[k].variance[m]+
4846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    (learning_rate_gaussian*((tmpDiff*tmpDiff) - g_point->g_values[k].variance[m]));
4856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
4866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
4876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
4886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
4896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvUpdateFullNoMatch( IplImage* gm_image, int p, int* match,
4916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                  CvGaussBGPoint* g_point,
4926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                  const CvGaussBGStatModelParams *bg_model_params)
4936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
4946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int k, m;
4956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    double alpha;
4966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int match_sum_total = 0;
4976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //new value of last one
4996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    g_point->g_values[bg_model_params->n_gauss - 1].match_sum = 1;
5006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //get sum of all but last value of match_sum
5026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( k = 0; k < bg_model_params->n_gauss ; k++ )
5046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        match_sum_total += g_point->g_values[k].match_sum;
5056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    g_point->g_values[bg_model_params->n_gauss - 1].weight = 1./(double)match_sum_total;
5076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( m = 0; m < gm_image->nChannels ; m++ )
5086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
5096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        // first pass mean is image value
5106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[bg_model_params->n_gauss - 1].variance[m] = bg_model_params->variance_init;
5116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[bg_model_params->n_gauss - 1].mean[m] = (unsigned char)gm_image->imageData[p + m];
5126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
5136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    alpha = 1.0 - (1.0/bg_model_params->win_size);
5156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( k = 0; k < bg_model_params->n_gauss - 1; k++ )
5166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
5176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[k].weight *= alpha;
5186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( match[k] )
5196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            g_point->g_values[k].weight += alpha;
5206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
5216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
5226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void
5256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennicvUpdatePartialNoMatch(double *pixel,
5266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        int nChannels,
5276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        int* /*match*/,
5286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        CvGaussBGPoint* g_point,
5296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        const CvGaussBGStatModelParams *bg_model_params)
5306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
5316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int k, m;
5326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //new value of last one
5336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    g_point->g_values[bg_model_params->n_gauss - 1].match_sum = 1;
5346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //get sum of all but last value of match_sum
5366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int match_sum_total = 0;
5376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for(k = 0; k < bg_model_params->n_gauss ; k++)
5386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        match_sum_total += g_point->g_values[k].match_sum;
5396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for(m = 0; m < nChannels; m++)
5416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
5426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        //first pass mean is image value
5436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[bg_model_params->n_gauss - 1].variance[m] = bg_model_params->variance_init;
5446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[bg_model_params->n_gauss - 1].mean[m] = pixel[m];
5456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
5466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for(k = 0; k < bg_model_params->n_gauss; k++)
5476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
5486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        g_point->g_values[k].weight = (double)g_point->g_values[k].match_sum /
5496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            (double)match_sum_total;
5506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
5516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
5526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvGetSortKey( const int nChannels, double* sort_key, const CvGaussBGPoint* g_point,
5546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                           const CvGaussBGStatModelParams *bg_model_params )
5556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
5566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int k, m;
5576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( k = 0; k < bg_model_params->n_gauss; k++ )
5586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
5596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        // Avoid division by zero
5606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( g_point->g_values[k].match_sum > 0 )
5616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
5626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            // Independence assumption between components
5636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double variance_sum = 0.0;
5646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for( m = 0; m < nChannels; m++ )
5656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                variance_sum += g_point->g_values[k].variance[m];
5666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            sort_key[k] = g_point->g_values[k].weight/sqrt(variance_sum);
5686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
5696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        else
5706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            sort_key[k]= 0.0;
5716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
5726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
5736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void icvBackgroundTest( const int nChannels, int n, int i, int j, int *match, CvGaussBGModel* bg_model )
5766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
5776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int m, b;
5786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    uchar pixelValue = (uchar)255; // will switch to 0 if match found
5796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    double weight_sum = 0.0;
5806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CvGaussBGPoint* g_point = bg_model->g_point;
5816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( m = 0; m < nChannels; m++)
5836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        bg_model->background->imageData[ bg_model->background->widthStep*i + j*nChannels + m]  = (unsigned char)(g_point[n].g_values[0].mean[m]+0.5);
5846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( b = 0; b < bg_model->params.n_gauss; b++)
5866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
5876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        weight_sum += g_point[n].g_values[b].weight;
5886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( match[b] )
5896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            pixelValue = 0;
5906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( weight_sum > bg_model->params.bg_threshold )
5916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            break;
5926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
5936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bg_model->foreground->imageData[ bg_model->foreground->widthStep*i + j] = pixelValue;
5956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
5966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/* End of file. */
598