pull/13383/head
parent
97d9a672cc
commit
0468bdeadd
1 changed files with 640 additions and 0 deletions
@ -0,0 +1,640 @@ |
|||||||
|
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||||
|
//
|
||||||
|
// By downloading, copying, installing or using the software you agree to this license.
|
||||||
|
// If you do not agree to this license, do not download, install,
|
||||||
|
// copy or use the software.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Intel License Agreement
|
||||||
|
//
|
||||||
|
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||||
|
// Third party copyrights are property of their respective owners.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
// are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistribution's of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// This software is provided by the copyright holders and contributors "as is" and
|
||||||
|
// any express or implied warranties, including, but not limited to, the implied
|
||||||
|
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||||
|
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||||
|
// indirect, incidental, special, exemplary, or consequential damages
|
||||||
|
// (including, but not limited to, procurement of substitute goods or services;
|
||||||
|
// loss of use, data, or profits; or business interruption) however caused
|
||||||
|
// and on any theory of liability, whether in contract, strict liability,
|
||||||
|
// or tort (including negligence or otherwise) arising in any way out of
|
||||||
|
// the use of this software, even if advised of the possibility of such damage.
|
||||||
|
//
|
||||||
|
//M*/
|
||||||
|
|
||||||
|
/*//Implementation of the Gaussian mixture model background subtraction from:
|
||||||
|
//
|
||||||
|
//"Improved adaptive Gausian mixture model for background subtraction"
|
||||||
|
//Z.Zivkovic
|
||||||
|
//International Conference Pattern Recognition, UK, August, 2004
|
||||||
|
//http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
|
||||||
|
//The code is very fast and performs also shadow detection.
|
||||||
|
//Number of Gausssian components is adapted per pixel.
|
||||||
|
//
|
||||||
|
// and
|
||||||
|
//
|
||||||
|
//"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
|
||||||
|
//Z.Zivkovic, F. van der Heijden
|
||||||
|
//Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
|
||||||
|
//
|
||||||
|
//The algorithm similar to the standard Stauffer&Grimson algorithm with
|
||||||
|
//additional selection of the number of the Gaussian components based on:
|
||||||
|
//
|
||||||
|
//"Recursive unsupervised learning of finite mixture models "
|
||||||
|
//Z.Zivkovic, F.van der Heijden
|
||||||
|
//IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
|
||||||
|
//http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//Example usage as part of the CvBGStatModel:
|
||||||
|
// CvBGStatModel* bg_model = cvCreateGaussianBGModel2( first_frame );
|
||||||
|
//
|
||||||
|
// //update for each frame
|
||||||
|
// cvUpdateBGStatModel( tmp_frame, bg_model );//segmentation result is in bg_model->foreground
|
||||||
|
//
|
||||||
|
// //release at the program termination
|
||||||
|
// cvReleaseBGStatModel( &bg_model );
|
||||||
|
//
|
||||||
|
//Author: Z.Zivkovic, www.zoranz.net
|
||||||
|
//Date: 27-April-2005, Version:0.9
|
||||||
|
///////////*/
|
||||||
|
|
||||||
|
#include "cvaux.h" |
||||||
|
#include "cvaux_mog2.h" |
||||||
|
|
||||||
|
int _icvRemoveShadowGMM(long posPixel,
|
||||||
|
float red, float green, float blue,
|
||||||
|
unsigned char nModes,
|
||||||
|
CvPBGMMGaussian* m_aGaussians, |
||||||
|
float m_fTb, |
||||||
|
float m_fTB,
|
||||||
|
float m_fTau) |
||||||
|
{ |
||||||
|
//calculate distances to the modes (+ sort???)
|
||||||
|
//here we need to go in descending order!!!
|
||||||
|
long pos; |
||||||
|
float tWeight = 0; |
||||||
|
float numerator, denominator; |
||||||
|
// check all the distributions, marked as background:
|
||||||
|
for (int iModes=0;iModes<nModes;iModes++) |
||||||
|
{ |
||||||
|
pos=posPixel+iModes; |
||||||
|
float var = m_aGaussians[pos].sigma; |
||||||
|
float muR = m_aGaussians[pos].muR; |
||||||
|
float muG = m_aGaussians[pos].muG; |
||||||
|
float muB = m_aGaussians[pos].muB; |
||||||
|
float weight = m_aGaussians[pos].weight; |
||||||
|
tWeight += weight; |
||||||
|
|
||||||
|
numerator = red * muR + green * muG + blue * muB; |
||||||
|
denominator = muR * muR + muG * muG + muB * muB; |
||||||
|
// no division by zero allowed
|
||||||
|
if (denominator == 0) |
||||||
|
{ |
||||||
|
break; |
||||||
|
}; |
||||||
|
float a = numerator / denominator; |
||||||
|
|
||||||
|
// if tau < a < 1 then also check the color distortion
|
||||||
|
if ((a <= 1) && (a >= m_fTau))//m_nBeta=1
|
||||||
|
{ |
||||||
|
float dR=a * muR - red; |
||||||
|
float dG=a * muG - green; |
||||||
|
float dB=a * muB - blue; |
||||||
|
|
||||||
|
//square distance -slower and less accurate
|
||||||
|
//float maxDistance = cvSqrt(m_fTb*var);
|
||||||
|
//if ((fabs(dR) <= maxDistance) && (fabs(dG) <= maxDistance) && (fabs(dB) <= maxDistance))
|
||||||
|
//circle
|
||||||
|
float dist=(dR*dR+dG*dG+dB*dB); |
||||||
|
if (dist<m_fTb*var*a*a) |
||||||
|
{ |
||||||
|
return 2; |
||||||
|
} |
||||||
|
}; |
||||||
|
if (tWeight > m_fTB) |
||||||
|
{ |
||||||
|
break; |
||||||
|
}; |
||||||
|
}; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int _icvUpdatePixelBackgroundGMM(long posPixel,
|
||||||
|
float red, float green, float blue,
|
||||||
|
unsigned char* pModesUsed,
|
||||||
|
CvPBGMMGaussian* m_aGaussians, |
||||||
|
int m_nM, |
||||||
|
float m_fAlphaT, |
||||||
|
float m_fTb, |
||||||
|
float m_fTB,
|
||||||
|
float m_fTg, |
||||||
|
float m_fSigma, |
||||||
|
float m_fPrune) |
||||||
|
{ |
||||||
|
//calculate distances to the modes (+ sort???)
|
||||||
|
//here we need to go in descending order!!!
|
||||||
|
|
||||||
|
long pos; |
||||||
|
|
||||||
|
|
||||||
|
bool bFitsPDF=0; |
||||||
|
bool bBackground=0; |
||||||
|
|
||||||
|
float m_fOneMinAlpha=1-m_fAlphaT; |
||||||
|
|
||||||
|
unsigned char nModes=*pModesUsed; |
||||||
|
float totalWeight=0.0f; |
||||||
|
|
||||||
|
//////
|
||||||
|
//go through all modes
|
||||||
|
for (int iModes=0;iModes<nModes;iModes++) |
||||||
|
{ |
||||||
|
pos=posPixel+iModes; |
||||||
|
float weight = m_aGaussians[pos].weight; |
||||||
|
|
||||||
|
////
|
||||||
|
//fit not found yet
|
||||||
|
if (!bFitsPDF) |
||||||
|
{ |
||||||
|
//check if it belongs to some of the modes
|
||||||
|
//calculate distance
|
||||||
|
float var = m_aGaussians[pos].sigma; |
||||||
|
float muR = m_aGaussians[pos].muR; |
||||||
|
float muG = m_aGaussians[pos].muG; |
||||||
|
float muB = m_aGaussians[pos].muB; |
||||||
|
|
||||||
|
float dR=muR - red; |
||||||
|
float dG=muG - green; |
||||||
|
float dB=muB - blue; |
||||||
|
|
||||||
|
///////
|
||||||
|
//check if it fits the current mode (Factor * sigma)
|
||||||
|
|
||||||
|
//square distance -slower and less accurate
|
||||||
|
//float maxDistance = cvSqrt(m_fTg*var);
|
||||||
|
//if ((fabs(dR) <= maxDistance) && (fabs(dG) <= maxDistance) && (fabs(dB) <= maxDistance))
|
||||||
|
//circle
|
||||||
|
float dist=(dR*dR+dG*dG+dB*dB); |
||||||
|
//background? - m_fTb
|
||||||
|
if ((totalWeight<m_fTB)&&(dist<m_fTb*var)) |
||||||
|
bBackground=1; |
||||||
|
//check fit
|
||||||
|
if (dist<m_fTg*var) |
||||||
|
{ |
||||||
|
/////
|
||||||
|
//belongs to the mode
|
||||||
|
bFitsPDF=1; |
||||||
|
|
||||||
|
//update distribution
|
||||||
|
float k = m_fAlphaT/weight; |
||||||
|
weight=m_fOneMinAlpha*weight+m_fPrune; |
||||||
|
weight+=m_fAlphaT; |
||||||
|
m_aGaussians[pos].muR = muR - k*(dR); |
||||||
|
m_aGaussians[pos].muG = muG - k*(dG); |
||||||
|
m_aGaussians[pos].muB = muB - k*(dB); |
||||||
|
|
||||||
|
//limit update speed for cov matrice
|
||||||
|
//not needed
|
||||||
|
//k=k>20*m_fAlphaT?20*m_fAlphaT:k;
|
||||||
|
//float sigmanew = var + k*((0.33*(dR*dR+dG*dG+dB*dB))-var);
|
||||||
|
//float sigmanew = var + k*((dR*dR+dG*dG+dB*dB)-var);
|
||||||
|
//float sigmanew = var + k*((0.33*dist)-var);
|
||||||
|
float sigmanew = var + k*(dist-var); |
||||||
|
//limit the variance
|
||||||
|
//m_aGaussians[pos].sigma = sigmanew>70?70:sigmanew;
|
||||||
|
//m_aGaussians[pos].sigma = sigmanew>5*m_fSigma?5*m_fSigma:sigmanew;
|
||||||
|
m_aGaussians[pos].sigma =sigmanew< 4 ? 4 : sigmanew>5*m_fSigma?5*m_fSigma:sigmanew; |
||||||
|
//m_aGaussians[pos].sigma =sigmanew< 4 ? 4 : sigmanew>3*m_fSigma?3*m_fSigma:sigmanew;
|
||||||
|
//m_aGaussians[pos].sigma = m_fSigma;
|
||||||
|
//sort
|
||||||
|
//all other weights are at the same place and
|
||||||
|
//only the matched (iModes) is higher -> just find the new place for it
|
||||||
|
for (int iLocal = iModes;iLocal>0;iLocal--) |
||||||
|
{ |
||||||
|
long posLocal=posPixel + iLocal; |
||||||
|
if (weight < (m_aGaussians[posLocal-1].weight)) |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
//swap
|
||||||
|
CvPBGMMGaussian temp = m_aGaussians[posLocal]; |
||||||
|
m_aGaussians[posLocal] = m_aGaussians[posLocal-1]; |
||||||
|
m_aGaussians[posLocal-1] = temp; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//belongs to the mode
|
||||||
|
/////
|
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
weight=m_fOneMinAlpha*weight+m_fPrune; |
||||||
|
//check prune
|
||||||
|
if (weight<-m_fPrune) |
||||||
|
{ |
||||||
|
weight=0.0; |
||||||
|
nModes--; |
||||||
|
// bPrune=1;
|
||||||
|
//break;//the components are sorted so we can skip the rest
|
||||||
|
} |
||||||
|
} |
||||||
|
//check if it fits the current mode (2.5 sigma)
|
||||||
|
///////
|
||||||
|
} |
||||||
|
//fit not found yet
|
||||||
|
/////
|
||||||
|
else |
||||||
|
{ |
||||||
|
weight=m_fOneMinAlpha*weight+m_fPrune; |
||||||
|
//check prune
|
||||||
|
if (weight<-m_fPrune) |
||||||
|
{ |
||||||
|
weight=0.0; |
||||||
|
nModes--; |
||||||
|
} |
||||||
|
} |
||||||
|
totalWeight+=weight; |
||||||
|
m_aGaussians[pos].weight=weight; |
||||||
|
} |
||||||
|
//go through all modes
|
||||||
|
//////
|
||||||
|
|
||||||
|
//renormalize weights
|
||||||
|
for (int iLocal = 0; iLocal < nModes; iLocal++) |
||||||
|
{ |
||||||
|
m_aGaussians[posPixel+ iLocal].weight = m_aGaussians[posPixel+ iLocal].weight/totalWeight; |
||||||
|
} |
||||||
|
|
||||||
|
//make new mode if needed and exit
|
||||||
|
if (!bFitsPDF) |
||||||
|
{ |
||||||
|
if (nModes==m_nM) |
||||||
|
{ |
||||||
|
//replace the weakest
|
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
//add a new one
|
||||||
|
nModes++; |
||||||
|
} |
||||||
|
pos=posPixel+nModes-1; |
||||||
|
|
||||||
|
if (nModes==1) |
||||||
|
m_aGaussians[pos].weight=1; |
||||||
|
else |
||||||
|
m_aGaussians[pos].weight=m_fAlphaT; |
||||||
|
|
||||||
|
//renormalize weights
|
||||||
|
int iLocal; |
||||||
|
for (iLocal = 0; iLocal < nModes-1; iLocal++) |
||||||
|
{ |
||||||
|
m_aGaussians[posPixel+ iLocal].weight *=m_fOneMinAlpha; |
||||||
|
} |
||||||
|
|
||||||
|
m_aGaussians[pos].muR=red; |
||||||
|
m_aGaussians[pos].muG=green; |
||||||
|
m_aGaussians[pos].muB=blue; |
||||||
|
m_aGaussians[pos].sigma=m_fSigma; |
||||||
|
|
||||||
|
//sort
|
||||||
|
//find the new place for it
|
||||||
|
for (iLocal = nModes-1;iLocal>0;iLocal--) |
||||||
|
{ |
||||||
|
long posLocal=posPixel + iLocal; |
||||||
|
if (m_fAlphaT < (m_aGaussians[posLocal-1].weight)) |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
//swap
|
||||||
|
CvPBGMMGaussian temp = m_aGaussians[posLocal]; |
||||||
|
m_aGaussians[posLocal] = m_aGaussians[posLocal-1]; |
||||||
|
m_aGaussians[posLocal-1] = temp; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//set the number of modes
|
||||||
|
*pModesUsed=nModes; |
||||||
|
|
||||||
|
return bBackground; |
||||||
|
} |
||||||
|
|
||||||
|
void _icvReplacePixelBackgroundGMM(long pos,
|
||||||
|
unsigned char* pData,
|
||||||
|
CvPBGMMGaussian* m_aGaussians) |
||||||
|
{ |
||||||
|
pData[0]=(unsigned char) m_aGaussians[pos].muR; |
||||||
|
pData[1]=(unsigned char) m_aGaussians[pos].muG; |
||||||
|
pData[2]=(unsigned char) m_aGaussians[pos].muB; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void icvUpdatePixelBackgroundGMM(CvGaussBGStatModel2Data* pGMMData,CvGaussBGStatModel2Params* pGMM, float m_fAlphaT, unsigned char* data,unsigned char* output) |
||||||
|
{ |
||||||
|
int size=pGMMData->nSize; |
||||||
|
unsigned char* pDataCurrent=data; |
||||||
|
unsigned char* pUsedModes=pGMMData->rnUsedModes; |
||||||
|
unsigned char* pDataOutput=output; |
||||||
|
//some constants
|
||||||
|
int m_nM=pGMM->nM; |
||||||
|
//float m_fAlphaT=pGMM->fAlphaT;
|
||||||
|
|
||||||
|
float m_fTb=pGMM->fTb;//Tb - threshold on the Mahalan. dist.
|
||||||
|
float m_fTB=pGMM->fTB;//1-TF from the paper
|
||||||
|
float m_fTg=pGMM->fTg;//Tg - when to generate a new component
|
||||||
|
float m_fSigma=pGMM->fSigma;//initial sigma
|
||||||
|
float m_fCT=pGMM->fCT;//CT - complexity reduction prior
|
||||||
|
float m_fPrune=-m_fAlphaT*m_fCT; |
||||||
|
float m_fTau=pGMM->fTau; |
||||||
|
CvPBGMMGaussian* m_aGaussians=pGMMData->rGMM; |
||||||
|
long posPixel=0; |
||||||
|
bool m_bShadowDetection=pGMM->bShadowDetection; |
||||||
|
unsigned char m_nShadowDetection=pGMM->nShadowDetection; |
||||||
|
|
||||||
|
//go through the image
|
||||||
|
for (int i=0;i<size;i++) |
||||||
|
{ |
||||||
|
// retrieve the colors
|
||||||
|
float red = pDataCurrent[0]; |
||||||
|
float green = pDataCurrent[1]; |
||||||
|
float blue = pDataCurrent[2]; |
||||||
|
|
||||||
|
//update model+ background subtract
|
||||||
|
int result = _icvUpdatePixelBackgroundGMM(posPixel, red, green, blue,pUsedModes,m_aGaussians, |
||||||
|
m_nM,m_fAlphaT, m_fTb, m_fTB, m_fTg, m_fSigma, m_fPrune); |
||||||
|
unsigned char nMLocal=*pUsedModes; |
||||||
|
|
||||||
|
if (m_bShadowDetection) |
||||||
|
if (!result) |
||||||
|
{ |
||||||
|
result= _icvRemoveShadowGMM(posPixel, red, green, blue,nMLocal,m_aGaussians, |
||||||
|
m_fTb, |
||||||
|
m_fTB,
|
||||||
|
m_fTau); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
switch (result) |
||||||
|
{ |
||||||
|
case 0: |
||||||
|
//foreground
|
||||||
|
(* pDataOutput)=255; |
||||||
|
if (pGMM->bRemoveForeground)
|
||||||
|
{ |
||||||
|
_icvReplacePixelBackgroundGMM(posPixel,pDataCurrent,m_aGaussians); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 1: |
||||||
|
//background
|
||||||
|
(* pDataOutput)=0; |
||||||
|
break; |
||||||
|
case 2: |
||||||
|
//shadow
|
||||||
|
(* pDataOutput)=m_nShadowDetection; |
||||||
|
if (pGMM->bRemoveForeground)
|
||||||
|
{ |
||||||
|
_icvReplacePixelBackgroundGMM(posPixel,pDataCurrent,m_aGaussians); |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
} |
||||||
|
posPixel+=m_nM; |
||||||
|
pDataCurrent+=3; |
||||||
|
pDataOutput++; |
||||||
|
pUsedModes++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
//implementation as part of the CvBGStatModel
|
||||||
|
static void CV_CDECL icvReleaseGaussianBGModel2( CvGaussBGModel2** bg_model ); |
||||||
|
static int CV_CDECL icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model ); |
||||||
|
|
||||||
|
|
||||||
|
CV_IMPL CvBGStatModel* |
||||||
|
cvCreateGaussianBGModel2( IplImage* first_frame, CvGaussBGStatModel2Params* parameters ) |
||||||
|
{ |
||||||
|
CvGaussBGModel2* bg_model = 0; |
||||||
|
int w,h,size; |
||||||
|
|
||||||
|
CV_FUNCNAME( "cvCreateGaussianBGModel2" ); |
||||||
|
|
||||||
|
__BEGIN__; |
||||||
|
|
||||||
|
CvGaussBGStatModel2Params params; |
||||||
|
|
||||||
|
if( !CV_IS_IMAGE(first_frame) ) |
||||||
|
CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" ); |
||||||
|
|
||||||
|
if( !(first_frame->nChannels==3) ) |
||||||
|
CV_ERROR( CV_StsBadArg, "Need three channel image (RGB)" ); |
||||||
|
|
||||||
|
CV_CALL( bg_model = (CvGaussBGModel2*)cvAlloc( sizeof(*bg_model) )); |
||||||
|
memset( bg_model, 0, sizeof(*bg_model) ); |
||||||
|
bg_model->type = CV_BG_MODEL_MOG2; |
||||||
|
bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel2; |
||||||
|
bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel2; |
||||||
|
|
||||||
|
//init parameters
|
||||||
|
if( parameters == NULL ) |
||||||
|
{
|
||||||
|
/* These constants are defined in cvaux/include/cvaux.h: */ |
||||||
|
params.bRemoveForeground=0; |
||||||
|
params.bShadowDetection = 1; |
||||||
|
params.bPostFiltering=0; |
||||||
|
params.minArea=CV_BGFG_MOG2_MINAREA; |
||||||
|
|
||||||
|
//set parameters
|
||||||
|
// K - max number of Gaussians per pixel
|
||||||
|
params.nM = CV_BGFG_MOG2_NGAUSSIANS;//4;
|
||||||
|
// Tb - the threshold - n var
|
||||||
|
//pGMM->fTb = 4*4;
|
||||||
|
params.fTb = CV_BGFG_MOG2_STD_THRESHOLD*CV_BGFG_MOG2_STD_THRESHOLD; |
||||||
|
// Tbf - the threshold
|
||||||
|
//pGMM->fTB = 0.9f;//1-cf from the paper
|
||||||
|
params.fTB = CV_BGFG_MOG2_BACKGROUND_THRESHOLD; |
||||||
|
// Tgenerate - the threshold
|
||||||
|
params.fTg = CV_BGFG_MOG2_STD_THRESHOLD_GENERATE*CV_BGFG_MOG2_STD_THRESHOLD_GENERATE;//update the mode or generate new
|
||||||
|
//pGMM->fSigma= 11.0f;//sigma for the new mode
|
||||||
|
params.fSigma= CV_BGFG_MOG2_SIGMA_INIT; |
||||||
|
// alpha - the learning factor
|
||||||
|
params.fAlphaT=1.0f/CV_BGFG_MOG2_WINDOW_SIZE;//0.003f;
|
||||||
|
// complexity reduction prior constant
|
||||||
|
params.fCT=CV_BGFG_MOG2_CT;//0.05f;
|
||||||
|
|
||||||
|
//shadow
|
||||||
|
// Shadow detection
|
||||||
|
params.nShadowDetection = CV_BGFG_MOG2_SHADOW_VALUE;//value 0 to turn off
|
||||||
|
params.fTau = CV_BGFG_MOG2_SHADOW_TAU;//0.5f;// Tau - shadow threshold
|
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
params = *parameters; |
||||||
|
} |
||||||
|
|
||||||
|
bg_model->params = params; |
||||||
|
|
||||||
|
//allocate GMM data
|
||||||
|
w=first_frame->width; |
||||||
|
h=first_frame->height; |
||||||
|
size=w*h; |
||||||
|
|
||||||
|
bg_model->data.nWidth=w; |
||||||
|
bg_model->data.nHeight=h; |
||||||
|
bg_model->data.nNBands=3; |
||||||
|
bg_model->data.nSize=size; |
||||||
|
|
||||||
|
//GMM for each pixel
|
||||||
|
bg_model->data.rGMM=(CvPBGMMGaussian*) malloc(size * params.nM * sizeof(CvPBGMMGaussian)); |
||||||
|
//used modes per pixel
|
||||||
|
bg_model->data.rnUsedModes = (unsigned char* ) malloc(size); |
||||||
|
memset(bg_model->data.rnUsedModes,0,size);//no modes used
|
||||||
|
|
||||||
|
//prepare storages
|
||||||
|
CV_CALL( bg_model->background = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, first_frame->nChannels)); |
||||||
|
CV_CALL( bg_model->foreground = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1)); |
||||||
|
|
||||||
|
//for eventual filtering
|
||||||
|
CV_CALL( bg_model->storage = cvCreateMemStorage()); |
||||||
|
|
||||||
|
bg_model->countFrames = 0; |
||||||
|
|
||||||
|
__END__; |
||||||
|
|
||||||
|
if( cvGetErrStatus() < 0 ) |
||||||
|
{ |
||||||
|
CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model; |
||||||
|
|
||||||
|
if( bg_model && bg_model->release ) |
||||||
|
bg_model->release( &base_ptr ); |
||||||
|
else |
||||||
|
cvFree( &bg_model ); |
||||||
|
bg_model = 0; |
||||||
|
} |
||||||
|
|
||||||
|
return (CvBGStatModel*)bg_model; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static void CV_CDECL |
||||||
|
icvReleaseGaussianBGModel2( CvGaussBGModel2** _bg_model ) |
||||||
|
{ |
||||||
|
CV_FUNCNAME( "icvReleaseGaussianBGModel2" ); |
||||||
|
|
||||||
|
__BEGIN__; |
||||||
|
|
||||||
|
if( !_bg_model ) |
||||||
|
CV_ERROR( CV_StsNullPtr, "" ); |
||||||
|
|
||||||
|
if( *_bg_model ) |
||||||
|
{ |
||||||
|
CvGaussBGModel2* bg_model = *_bg_model; |
||||||
|
|
||||||
|
free (bg_model->data.rGMM); |
||||||
|
free (bg_model->data.rnUsedModes); |
||||||
|
|
||||||
|
cvReleaseImage( &bg_model->background ); |
||||||
|
cvReleaseImage( &bg_model->foreground ); |
||||||
|
cvReleaseMemStorage(&bg_model->storage); |
||||||
|
memset( bg_model, 0, sizeof(*bg_model) ); |
||||||
|
cvFree( _bg_model ); |
||||||
|
} |
||||||
|
|
||||||
|
__END__; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static int CV_CDECL |
||||||
|
icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model ) |
||||||
|
{ |
||||||
|
//int i, j, k, n;
|
||||||
|
int region_count = 0; |
||||||
|
CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL; |
||||||
|
float alpha,alphaInit; |
||||||
|
bg_model->countFrames++; |
||||||
|
alpha=bg_model->params.fAlphaT; |
||||||
|
|
||||||
|
if (bg_model->params.bInit){ |
||||||
|
//faster initial updates
|
||||||
|
alphaInit=(1.0f/(2*bg_model->countFrames+1)); |
||||||
|
if (alphaInit>alpha) |
||||||
|
{ |
||||||
|
alpha=alphaInit; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
bg_model->params.bInit=0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
icvUpdatePixelBackgroundGMM(&bg_model->data,&bg_model->params,alpha,(unsigned char*)curr_frame->imageData,(unsigned char*)bg_model->foreground->imageData); |
||||||
|
|
||||||
|
if (bg_model->params.bPostFiltering==1) |
||||||
|
{ |
||||||
|
//foreground filtering
|
||||||
|
|
||||||
|
//filter small regions
|
||||||
|
cvClearMemStorage(bg_model->storage); |
||||||
|
|
||||||
|
cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 ); |
||||||
|
cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 ); |
||||||
|
|
||||||
|
cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST ); |
||||||
|
for( seq = first_seq; seq; seq = seq->h_next ) |
||||||
|
{ |
||||||
|
CvContour* cnt = (CvContour*)seq; |
||||||
|
if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea ) |
||||||
|
{ |
||||||
|
//delete small contour
|
||||||
|
prev_seq = seq->h_prev; |
||||||
|
if( prev_seq ) |
||||||
|
{ |
||||||
|
prev_seq->h_next = seq->h_next; |
||||||
|
if( seq->h_next ) seq->h_next->h_prev = prev_seq; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
first_seq = seq->h_next; |
||||||
|
if( seq->h_next ) seq->h_next->h_prev = NULL; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
region_count++; |
||||||
|
} |
||||||
|
} |
||||||
|
bg_model->foreground_regions = first_seq; |
||||||
|
cvZero(bg_model->foreground); |
||||||
|
cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1); |
||||||
|
|
||||||
|
return region_count;
|
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* End of file. */ |
Loading…
Reference in new issue