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 file implements the foreground/background pixel
436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// discrimination algorithm described in
446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//
456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//     Foreground Object Detection from Videos Containing Complex Background
466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//     Li, Huan, Gu, Tian 2003 9p
476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//     http://muq.org/~cynbe/bib/foreground-object-detection-from-videos-containing-complex-background.pdf
486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "_cvaux.h"
516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <math.h>
536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <stdio.h>
546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <stdlib.h>
556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//#include <algorithm>
566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic double* _cv_max_element( double* start, double* end )
586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    double* p = start++;
606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( ; start != end;  ++start) {
626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if (*p < *start)   p = start;
646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return p;
676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void CV_CDECL icvReleaseFGDStatModel( CvFGDStatModel** model );
706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int CV_CDECL icvUpdateFGDStatModel( IplImage* curr_frame,
716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                           CvFGDStatModel*  model );
726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Function cvCreateFGDStatModel initializes foreground detection process
746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// parameters:
756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//      first_frame - frame from video sequence
766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//      parameters  - (optional) if NULL default parameters of the algorithm will be used
776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//      p_model     - pointer to CvFGDStatModel structure
786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennCV_IMPL CvBGStatModel*
796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RenncvCreateFGDStatModel( IplImage* first_frame, CvFGDStatModelParams* parameters )
806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CvFGDStatModel* p_model = 0;
826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_FUNCNAME( "cvCreateFGDStatModel" );
846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    __BEGIN__;
866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int i, j, k, pixel_count, buf_size;
886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CvFGDStatModelParams params;
896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !CV_IS_IMAGE(first_frame) )
916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if (first_frame->nChannels != 3)
946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CV_ERROR( CV_StsBadArg, "first_frame must have 3 color channels" );
956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Initialize parameters:
976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( parameters == NULL )
986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.Lc      = CV_BGFG_FGD_LC;
1006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.N1c     = CV_BGFG_FGD_N1C;
1016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.N2c     = CV_BGFG_FGD_N2C;
1026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.Lcc     = CV_BGFG_FGD_LCC;
1046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.N1cc    = CV_BGFG_FGD_N1CC;
1056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.N2cc    = CV_BGFG_FGD_N2CC;
1066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.delta   = CV_BGFG_FGD_DELTA;
1086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.alpha1  = CV_BGFG_FGD_ALPHA_1;
1106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.alpha2  = CV_BGFG_FGD_ALPHA_2;
1116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.alpha3  = CV_BGFG_FGD_ALPHA_3;
1126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.T       = CV_BGFG_FGD_T;
1146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.minArea = CV_BGFG_FGD_MINAREA;
1156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.is_obj_without_holes = 1;
1176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params.perform_morphing     = 1;
1186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else
1206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        params = *parameters;
1226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model = (CvFGDStatModel*)cvAlloc( sizeof(*p_model) ));
1256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    memset( p_model, 0, sizeof(*p_model) );
1266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    p_model->type = CV_BG_MODEL_FGD;
1276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    p_model->release = (CvReleaseBGStatModel)icvReleaseFGDStatModel;
1286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    p_model->update = (CvUpdateBGStatModel)icvUpdateFGDStatModel;;
1296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    p_model->params = params;
1306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Initialize storage pools:
1326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    pixel_count = first_frame->width * first_frame->height;
1336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    buf_size = pixel_count*sizeof(p_model->pixel_stat[0]);
1356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->pixel_stat = (CvBGPixelStat*)cvAlloc(buf_size) );
1366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    memset( p_model->pixel_stat, 0, buf_size );
1376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    buf_size = pixel_count*params.N2c*sizeof(p_model->pixel_stat[0].ctable[0]);
1396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->pixel_stat[0].ctable = (CvBGPixelCStatTable*)cvAlloc(buf_size) );
1406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    memset( p_model->pixel_stat[0].ctable, 0, buf_size );
1416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    buf_size = pixel_count*params.N2cc*sizeof(p_model->pixel_stat[0].cctable[0]);
1436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->pixel_stat[0].cctable = (CvBGPixelCCStatTable*)cvAlloc(buf_size) );
1446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    memset( p_model->pixel_stat[0].cctable, 0, buf_size );
1456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for(     i = 0, k = 0; i < first_frame->height; i++ ) {
1476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for( j = 0;        j < first_frame->width;  j++, k++ )
1486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
1496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            p_model->pixel_stat[k].ctable = p_model->pixel_stat[0].ctable + k*params.N2c;
1506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            p_model->pixel_stat[k].cctable = p_model->pixel_stat[0].cctable + k*params.N2cc;
1516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
1526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Init temporary images:
1556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->Ftd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
1566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->Fbd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
1576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->foreground = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
1586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->background = cvCloneImage(first_frame));
1606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->prev_frame = cvCloneImage(first_frame));
1616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_CALL( p_model->storage = cvCreateMemStorage());
1626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    __END__;
1646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( cvGetErrStatus() < 0 )
1666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CvBGStatModel* base_ptr = (CvBGStatModel*)p_model;
1686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( p_model && p_model->release )
1706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            p_model->release( &base_ptr );
1716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        else
1726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            cvFree( &p_model );
1736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        p_model = 0;
1746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return (CvBGStatModel*)p_model;
1776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
1786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic void CV_CDECL
1816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennicvReleaseFGDStatModel( CvFGDStatModel** _model )
1826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
1836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CV_FUNCNAME( "icvReleaseFGDStatModel" );
1846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    __BEGIN__;
1866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !_model )
1886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CV_ERROR( CV_StsNullPtr, "" );
1896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( *_model )
1916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CvFGDStatModel* model = *_model;
1936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( model->pixel_stat )
1946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
1956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            cvFree( &model->pixel_stat[0].ctable );
1966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            cvFree( &model->pixel_stat[0].cctable );
1976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            cvFree( &model->pixel_stat );
1986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
1996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseImage( &model->Ftd );
2016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseImage( &model->Fbd );
2026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseImage( &model->foreground );
2036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseImage( &model->background );
2046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseImage( &model->prev_frame );
2056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvReleaseMemStorage(&model->storage);
2066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvFree( _model );
2086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    __END__;
2116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//  Function cvChangeDetection performs change detection for Foreground detection algorithm
2146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// parameters:
2156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//      prev_frame -
2166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//      curr_frame -
2176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//      change_mask -
2186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennCV_IMPL int
2196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RenncvChangeDetection( IplImage*  prev_frame,
2206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                   IplImage*  curr_frame,
2216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                   IplImage*  change_mask )
2226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
2236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int i, j, b, x, y, thres;
2246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    const int PIXELRANGE=256;
2256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !prev_frame
2276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||  !curr_frame
2286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||  !change_mask
2296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   prev_frame->nChannels  != 3
2306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   curr_frame->nChannels  != 3
2316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   change_mask->nChannels != 1
2326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   prev_frame->depth  != IPL_DEPTH_8U
2336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   curr_frame->depth  != IPL_DEPTH_8U
2346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   change_mask->depth != IPL_DEPTH_8U
2356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   prev_frame->width  != curr_frame->width
2366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   prev_frame->height != curr_frame->height
2376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   prev_frame->width  != change_mask->width
2386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ||   prev_frame->height != change_mask->height
2396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ){
2406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return 0;
2416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvZero ( change_mask );
2446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // All operations per colour
2466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for (b=0 ; b<prev_frame->nChannels ; b++) {
2476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        // Create histogram:
2496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        long HISTOGRAM[PIXELRANGE];
2516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for (i=0 ; i<PIXELRANGE; i++) HISTOGRAM[i]=0;
2526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for (y=0 ; y<curr_frame->height ; y++)
2546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
2556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            uchar* rowStart1 = (uchar*)curr_frame->imageData + y * curr_frame->widthStep + b;
2566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            uchar* rowStart2 = (uchar*)prev_frame->imageData + y * prev_frame->widthStep + b;
2576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for (x=0 ; x<curr_frame->width ; x++, rowStart1+=curr_frame->nChannels, rowStart2+=prev_frame->nChannels) {
2586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                int diff = abs( int(*rowStart1) - int(*rowStart2) );
2596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                HISTOGRAM[diff]++;
2606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
2616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
2626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        double relativeVariance[PIXELRANGE];
2646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for (i=0 ; i<PIXELRANGE; i++) relativeVariance[i]=0;
2656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for (thres=PIXELRANGE-2; thres>=0 ; thres--)
2676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
2686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            //            fprintf(stderr, "Iter %d\n", thres);
2696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double sum=0;
2706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double sqsum=0;
2716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            int count=0;
2726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            //            fprintf(stderr, "Iter %d entering loop\n", thres);
2736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for (j=thres ; j<PIXELRANGE ; j++) {
2746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                sum   += double(j)*double(HISTOGRAM[j]);
2756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                sqsum += double(j*j)*double(HISTOGRAM[j]);
2766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                count += HISTOGRAM[j];
2776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
2786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            count = count == 0 ? 1 : count;
2796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            //            fprintf(stderr, "Iter %d finishing loop\n", thres);
2806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double my = sum / count;
2816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            double sigma = sqrt( sqsum/count - my*my);
2826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            //            fprintf(stderr, "Iter %d sum=%g sqsum=%g count=%d sigma = %g\n", thres, sum, sqsum, count, sigma);
2836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            //            fprintf(stderr, "Writing to %x\n", &(relativeVariance[thres]));
2846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            relativeVariance[thres] = sigma;
2856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            //            fprintf(stderr, "Iter %d finished\n", thres);
2866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
2876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        // Find maximum:
2896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        uchar bestThres = 0;
2906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        double* pBestThres = _cv_max_element(relativeVariance, relativeVariance+PIXELRANGE);
2926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        bestThres = (uchar)(*pBestThres); if (bestThres <10) bestThres=10;
2936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for (y=0 ; y<prev_frame->height ; y++)
2956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
2966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            uchar* rowStart1 = (uchar*)(curr_frame->imageData) + y * curr_frame->widthStep + b;
2976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            uchar* rowStart2 = (uchar*)(prev_frame->imageData) + y * prev_frame->widthStep + b;
2986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            uchar* rowStart3 = (uchar*)(change_mask->imageData) + y * change_mask->widthStep;
2996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            for (x = 0; x < curr_frame->width; x++, rowStart1+=curr_frame->nChannels,
3006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                rowStart2+=prev_frame->nChannels, rowStart3+=change_mask->nChannels) {
3016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                // OR between different color channels
3026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                int diff = abs( int(*rowStart1) - int(*rowStart2) );
3036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if ( diff > bestThres)
3046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    *rowStart3 |=255;
3056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
3066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
3076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return 1;
3106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
3116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define MIN_PV 1E-10
3146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define V_C(k,l) ctable[k].v[l]
3176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define PV_C(k) ctable[k].Pv
3186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define PVB_C(k) ctable[k].Pvb
3196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define V_CC(k,l) cctable[k].v[l]
3206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define PV_CC(k) cctable[k].Pv
3216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define PVB_CC(k) cctable[k].Pvb
3226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Function cvUpdateFGDStatModel updates statistical model and returns number of foreground regions
3256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// parameters:
3266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//      curr_frame  - current frame from video sequence
3276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn//      p_model     - pointer to CvFGDStatModel structure
3286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int CV_CDECL
3296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennicvUpdateFGDStatModel( IplImage* curr_frame, CvFGDStatModel*  model )
3306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
3316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int            mask_step = model->Ftd->widthStep;
3326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CvSeq         *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
3336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    IplImage*      prev_frame = model->prev_frame;
3346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int            region_count = 0;
3356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int            FG_pixels_count = 0;
3366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int            deltaC  = cvRound(model->params.delta * 256 / model->params.Lc);
3376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int            deltaCC = cvRound(model->params.delta * 256 / model->params.Lcc);
3386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int            i, j, k, l;
3396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //clear storages
3416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvClearMemStorage(model->storage);
3426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvZero(model->foreground);
3436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // From foreground pixel candidates using image differencing
3456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // with adaptive thresholding.  The algorithm is from:
3466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //
3476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //    Thresholding for Change Detection
3486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //    Paul L. Rosin 1998 6p
3496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //    http://www.cis.temple.edu/~latecki/Courses/CIS750-03/Papers/thresh-iccv.pdf
3506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //
3516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvChangeDetection( prev_frame, curr_frame, model->Ftd );
3526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvChangeDetection( model->background, curr_frame, model->Fbd );
3536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( i = 0; i < model->Ftd->height; i++ )
3556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for( j = 0; j < model->Ftd->width; j++ )
3576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
3586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            if( ((uchar*)model->Fbd->imageData)[i*mask_step+j] || ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
3596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
3606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	        float Pb  = 0;
3616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                float Pv  = 0;
3626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                float Pvb = 0;
3636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
3656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                CvBGPixelCStatTable*   ctable = stat->ctable;
3676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                CvBGPixelCCStatTable* cctable = stat->cctable;
3686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                uchar* curr_data = (uchar*)(curr_frame->imageData) + i*curr_frame->widthStep + j*3;
3706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                uchar* prev_data = (uchar*)(prev_frame->imageData) + i*prev_frame->widthStep + j*3;
3716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                int val = 0;
3736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                // Is it a motion pixel?
3756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
3766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
3776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		    if( !stat->is_trained_dyn_model ) {
3786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        val = 1;
3806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		    } else {
3826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        // Compare with stored CCt vectors:
3846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        for( k = 0;  PV_CC(k) > model->params.alpha2 && k < model->params.N1cc;  k++ )
3856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        {
3866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            if ( abs( V_CC(k,0) - prev_data[0]) <=  deltaCC &&
3876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                 abs( V_CC(k,1) - prev_data[1]) <=  deltaCC &&
3886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                 abs( V_CC(k,2) - prev_data[2]) <=  deltaCC &&
3896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                 abs( V_CC(k,3) - curr_data[0]) <=  deltaCC &&
3906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                 abs( V_CC(k,4) - curr_data[1]) <=  deltaCC &&
3916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                 abs( V_CC(k,5) - curr_data[2]) <=  deltaCC)
3926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            {
3936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                Pv += PV_CC(k);
3946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                Pvb += PVB_CC(k);
3956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            }
3966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        }
3976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        Pb = stat->Pbcc;
3986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        if( 2 * Pvb * Pb <= Pv ) val = 1;
3996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
4006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
4016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                else if( stat->is_trained_st_model )
4026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
4036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    // Compare with stored Ct vectors:
4046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( k = 0;  PV_C(k) > model->params.alpha2 && k < model->params.N1c;  k++ )
4056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
4066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        if ( abs( V_C(k,0) - curr_data[0]) <=  deltaC &&
4076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                             abs( V_C(k,1) - curr_data[1]) <=  deltaC &&
4086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                             abs( V_C(k,2) - curr_data[2]) <=  deltaC )
4096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        {
4106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            Pv += PV_C(k);
4116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            Pvb += PVB_C(k);
4126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        }
4136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
4146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    Pb = stat->Pbc;
4156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( 2 * Pvb * Pb <= Pv ) val = 1;
4166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
4176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                // Update foreground:
4196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                ((uchar*)model->foreground->imageData)[i*mask_step+j] = (uchar)(val*255);
4206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                FG_pixels_count += val;
4216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }		// end if( change detection...
4236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }		// for j...
4246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }			// for i...
4256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    //end BG/FG classification
4266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Foreground segmentation.
4286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Smooth foreground map:
4296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( model->params.perform_morphing ){
4306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_OPEN,  model->params.perform_morphing );
4316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_CLOSE, model->params.perform_morphing );
4326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
4336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( model->params.minArea > 0 || model->params.is_obj_without_holes ){
4366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        // Discard under-size foreground regions:
4386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	//
4396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvFindContours( model->foreground, model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
4406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for( seq = first_seq; seq; seq = seq->h_next )
4416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
4426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            CvContour* cnt = (CvContour*)seq;
4436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            if( cnt->rect.width * cnt->rect.height < model->params.minArea ||
4446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                (model->params.is_obj_without_holes && CV_IS_SEQ_HOLE(seq)) )
4456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
4466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                // Delete under-size contour:
4476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                prev_seq = seq->h_prev;
4486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( prev_seq )
4496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
4506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    prev_seq->h_next = seq->h_next;
4516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( seq->h_next ) seq->h_next->h_prev = prev_seq;
4526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
4536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                else
4546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
4556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    first_seq = seq->h_next;
4566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( seq->h_next ) seq->h_next->h_prev = NULL;
4576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
4586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
4596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            else
4606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
4616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                region_count++;
4626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
4636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
4646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        model->foreground_regions = first_seq;
4656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvZero(model->foreground);
4666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        cvDrawContours(model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
4676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    } else {
4696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        model->foreground_regions = NULL;
4716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
4726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Check ALL BG update condition:
4746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( ((float)FG_pixels_count/(model->Ftd->width*model->Ftd->height)) > CV_BGFG_FGD_BG_UPDATE_TRESH )
4756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
4766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn         for( i = 0; i < model->Ftd->height; i++ )
4776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn             for( j = 0; j < model->Ftd->width; j++ )
4786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn             {
4796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                 CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
4806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                 stat->is_trained_st_model = stat->is_trained_dyn_model = 1;
4816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn             }
4826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
4836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Update background model:
4866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for( i = 0; i < model->Ftd->height; i++ )
4876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
4886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        for( j = 0; j < model->Ftd->width; j++ )
4896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
4906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
4916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            CvBGPixelCStatTable* ctable = stat->ctable;
4926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            CvBGPixelCCStatTable* cctable = stat->cctable;
4936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            uchar *curr_data = (uchar*)(curr_frame->imageData)+i*curr_frame->widthStep+j*3;
4956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            uchar *prev_data = (uchar*)(prev_frame->imageData)+i*prev_frame->widthStep+j*3;
4966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] || !stat->is_trained_dyn_model )
4986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
4996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                float alpha = stat->is_trained_dyn_model ? model->params.alpha2 : model->params.alpha3;
5006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                float diff = 0;
5016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                int dist, min_dist = 2147483647, indx = -1;
5026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                //update Pb
5046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                stat->Pbcc *= (1.f-alpha);
5056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
5066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
5076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    stat->Pbcc += alpha;
5086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
5096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                // Find best Vi match:
5116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                for(k = 0; PV_CC(k) && k < model->params.N2cc; k++ )
5126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
5136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    // Exponential decay of memory
5146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PV_CC(k)  *= (1-alpha);
5156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PVB_CC(k) *= (1-alpha);
5166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( PV_CC(k) < MIN_PV )
5176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
5186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        PV_CC(k) = 0;
5196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        PVB_CC(k) = 0;
5206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        continue;
5216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
5226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    dist = 0;
5246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( l = 0; l < 3; l++ )
5256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
5266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        int val = abs( V_CC(k,l) - prev_data[l] );
5276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        if( val > deltaCC ) break;
5286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        dist += val;
5296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        val = abs( V_CC(k,l+3) - curr_data[l] );
5306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        if( val > deltaCC) break;
5316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        dist += val;
5326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
5336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( l == 3 && dist < min_dist )
5346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
5356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        min_dist = dist;
5366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        indx = k;
5376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
5386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
5396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( indx < 0 )
5426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {   // Replace N2th elem in the table by new feature:
5436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    indx = model->params.N2cc - 1;
5446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PV_CC(indx) = alpha;
5456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PVB_CC(indx) = alpha;
5466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    //udate Vt
5476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( l = 0; l < 3; l++ )
5486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
5496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        V_CC(indx,l) = prev_data[l];
5506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        V_CC(indx,l+3) = curr_data[l];
5516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
5526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
5536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                else
5546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {   // Update:
5556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PV_CC(indx) += alpha;
5566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
5576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
5586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        PVB_CC(indx) += alpha;
5596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
5606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
5616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                //re-sort CCt table by Pv
5636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                for( k = 0; k < indx; k++ )
5646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
5656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( PV_CC(k) <= PV_CC(indx) )
5666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
5676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        //shift elements
5686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        CvBGPixelCCStatTable tmp1, tmp2 = cctable[indx];
5696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        for( l = k; l <= indx; l++ )
5706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        {
5716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            tmp1 = cctable[l];
5726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            cctable[l] = tmp2;
5736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            tmp2 = tmp1;
5746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        }
5756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        break;
5766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
5776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
5786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                float sum1=0, sum2=0;
5816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                //check "once-off" changes
5826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                for(k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
5836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
5846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    sum1 += PV_CC(k);
5856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    sum2 += PVB_CC(k);
5866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
5876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( sum1 > model->params.T ) stat->is_trained_dyn_model = 1;
5886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                diff = sum1 - stat->Pbcc * sum2;
5906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                // Update stat table:
5916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( diff >  model->params.T )
5926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
5936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    //printf("once off change at motion mode\n");
5946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    //new BG features are discovered
5956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
5966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
5976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        PVB_CC(k) =
5986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            (PV_CC(k)-stat->Pbcc*PVB_CC(k))/(1-stat->Pbcc);
5996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
6006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    assert(stat->Pbcc<=1 && stat->Pbcc>=0);
6016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
6026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
6036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            // Handle "stationary" pixel:
6056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] )
6066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
6076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                float alpha = stat->is_trained_st_model ? model->params.alpha2 : model->params.alpha3;
6086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                float diff = 0;
6096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                int dist, min_dist = 2147483647, indx = -1;
6106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                //update Pb
6126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                stat->Pbc *= (1.f-alpha);
6136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
6146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
6156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    stat->Pbc += alpha;
6166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
6176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                //find best Vi match
6196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                for( k = 0; k < model->params.N2c; k++ )
6206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
6216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    // Exponential decay of memory
6226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PV_C(k) *= (1-alpha);
6236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PVB_C(k) *= (1-alpha);
6246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( PV_C(k) < MIN_PV )
6256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
6266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        PV_C(k) = 0;
6276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        PVB_C(k) = 0;
6286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        continue;
6296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
6306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    dist = 0;
6326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( l = 0; l < 3; l++ )
6336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
6346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        int val = abs( V_C(k,l) - curr_data[l] );
6356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        if( val > deltaC ) break;
6366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        dist += val;
6376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
6386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( l == 3 && dist < min_dist )
6396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
6406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        min_dist = dist;
6416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        indx = k;
6426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
6436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
6446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( indx < 0 )
6466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {//N2th elem in the table is replaced by a new features
6476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    indx = model->params.N2c - 1;
6486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PV_C(indx) = alpha;
6496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PVB_C(indx) = alpha;
6506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    //udate Vt
6516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( l = 0; l < 3; l++ )
6526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
6536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        V_C(indx,l) = curr_data[l];
6546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
6556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                } else
6566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {//update
6576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    PV_C(indx) += alpha;
6586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
6596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
6606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        PVB_C(indx) += alpha;
6616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
6626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
6636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                //re-sort Ct table by Pv
6656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                for( k = 0; k < indx; k++ )
6666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
6676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    if( PV_C(k) <= PV_C(indx) )
6686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
6696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        //shift elements
6706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        CvBGPixelCStatTable tmp1, tmp2 = ctable[indx];
6716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        for( l = k; l <= indx; l++ )
6726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        {
6736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            tmp1 = ctable[l];
6746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            ctable[l] = tmp2;
6756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                            tmp2 = tmp1;
6766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        }
6776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        break;
6786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
6796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
6806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                // Check "once-off" changes:
6826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                float sum1=0, sum2=0;
6836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
6846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
6856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    sum1 += PV_C(k);
6866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    sum2 += PVB_C(k);
6876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
6886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                diff = sum1 - stat->Pbc * sum2;
6896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( sum1 > model->params.T ) stat->is_trained_st_model = 1;
6906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                // Update stat table:
6926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( diff >  model->params.T )
6936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
6946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    //printf("once off change at stat mode\n");
6956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    //new BG features are discovered
6966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
6976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
6986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        PVB_C(k) = (PV_C(k)-stat->Pbc*PVB_C(k))/(1-stat->Pbc);
6996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
7006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    stat->Pbc = 1 - stat->Pbc;
7016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
7026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }		// if !(change detection) at pixel (i,j)
7036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            // Update the reference BG image:
7056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            if( !((uchar*)model->foreground->imageData)[i*mask_step+j])
7066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            {
7076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                uchar* ptr = ((uchar*)model->background->imageData) + i*model->background->widthStep+j*3;
7086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] &&
7106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    !((uchar*)model->Fbd->imageData)[i*mask_step+j] )
7116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
7126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    // Apply IIR filter:
7136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( l = 0; l < 3; l++ )
7146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
7156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        int a = cvRound(ptr[l]*(1 - model->params.alpha1) + model->params.alpha1*curr_data[l]);
7166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        ptr[l] = (uchar)a;
7176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l]*=(1 - model->params.alpha1);
7186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] += model->params.alpha1*curr_data[l];
7196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
7206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
7216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                else
7226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                {
7236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    // Background change detected:
7246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    for( l = 0; l < 3; l++ )
7256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    {
7266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] = curr_data[l];
7276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                        ptr[l] = curr_data[l];
7286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                    }
7296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                }
7306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn            }
7316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }		// j
7326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }			// i
7336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Keep previous frame:
7356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvCopy( curr_frame, model->prev_frame );
7366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return region_count;
7386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
7396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/* End of file. */
741