Commit 60456083 authored by Glue Crow's avatar Glue Crow

Parallelization of BackgroundSubtractorKNN

parent 047764f4
...@@ -259,10 +259,8 @@ protected: ...@@ -259,10 +259,8 @@ protected:
String name_; String name_;
}; };
//{ to do - paralelization ...
//struct KNNInvoker....
CV_INLINE void CV_INLINE void
_cvUpdatePixelBackgroundNP( long pixel,const uchar* data, int nchannels, int m_nN, _cvUpdatePixelBackgroundNP(int x_idx, const uchar* data, int nchannels, int m_nN,
uchar* m_aModel, uchar* m_aModel,
uchar* m_nNextLongUpdate, uchar* m_nNextLongUpdate,
uchar* m_nNextMidUpdate, uchar* m_nNextMidUpdate,
...@@ -273,70 +271,53 @@ CV_INLINE void ...@@ -273,70 +271,53 @@ CV_INLINE void
int m_nLongCounter, int m_nLongCounter,
int m_nMidCounter, int m_nMidCounter,
int m_nShortCounter, int m_nShortCounter,
int m_nLongUpdate,
int m_nMidUpdate,
int m_nShortUpdate,
uchar include uchar include
) )
{ {
// hold the offset // hold the offset
int ndata=1+nchannels; int ndata=1+nchannels;
long offsetLong = ndata * (pixel * m_nN * 3 + m_aModelIndexLong[pixel] + m_nN * 2); long offsetLong = ndata * (m_aModelIndexLong[x_idx] + m_nN * 2);
long offsetMid = ndata * (pixel * m_nN * 3 + m_aModelIndexMid[pixel] + m_nN * 1); long offsetMid = ndata * (m_aModelIndexMid[x_idx] + m_nN * 1);
long offsetShort = ndata * (pixel * m_nN * 3 + m_aModelIndexShort[pixel]); long offsetShort = ndata * (m_aModelIndexShort[x_idx]);
// Long update? // Long update?
if (m_nNextLongUpdate[pixel] == m_nLongCounter) if (m_nNextLongUpdate[x_idx] == m_nLongCounter)
{ {
// add the oldest pixel from Mid to the list of values (for each color) // add the oldest pixel from Mid to the list of values (for each color)
memcpy(&m_aModel[offsetLong],&m_aModel[offsetMid],ndata*sizeof(unsigned char)); memcpy(&m_aModel[offsetLong],&m_aModel[offsetMid],ndata*sizeof(unsigned char));
// increase the index // increase the index
m_aModelIndexLong[pixel] = (m_aModelIndexLong[pixel] >= (m_nN-1)) ? 0 : (m_aModelIndexLong[pixel] + 1); m_aModelIndexLong[x_idx] = (m_aModelIndexLong[x_idx] >= (m_nN-1)) ? 0 : (m_aModelIndexLong[x_idx] + 1);
};
if (m_nLongCounter == (m_nLongUpdate-1))
{
//m_nNextLongUpdate[pixel] = (uchar)(((m_nLongUpdate)*(rand()-1))/RAND_MAX);//0,...m_nLongUpdate-1;
m_nNextLongUpdate[pixel] = (uchar)( rand() % m_nLongUpdate );//0,...m_nLongUpdate-1;
}; };
// Mid update? // Mid update?
if (m_nNextMidUpdate[pixel] == m_nMidCounter) if (m_nNextMidUpdate[x_idx] == m_nMidCounter)
{ {
// add this pixel to the list of values (for each color) // add this pixel to the list of values (for each color)
memcpy(&m_aModel[offsetMid],&m_aModel[offsetShort],ndata*sizeof(unsigned char)); memcpy(&m_aModel[offsetMid],&m_aModel[offsetShort],ndata*sizeof(unsigned char));
// increase the index // increase the index
m_aModelIndexMid[pixel] = (m_aModelIndexMid[pixel] >= (m_nN-1)) ? 0 : (m_aModelIndexMid[pixel] + 1); m_aModelIndexMid[x_idx] = (m_aModelIndexMid[x_idx] >= (m_nN-1)) ? 0 : (m_aModelIndexMid[x_idx] + 1);
};
if (m_nMidCounter == (m_nMidUpdate-1))
{
m_nNextMidUpdate[pixel] = (uchar)( rand() % m_nMidUpdate );
}; };
// Short update? // Short update?
if (m_nNextShortUpdate[pixel] == m_nShortCounter) if (m_nNextShortUpdate[x_idx] == m_nShortCounter)
{ {
// add this pixel to the list of values (for each color) // add this pixel to the list of values (for each color)
memcpy(&m_aModel[offsetShort],data,ndata*sizeof(unsigned char)); memcpy(&m_aModel[offsetShort],data,nchannels*sizeof(unsigned char));
//set the include flag //set the include flag
m_aModel[offsetShort+nchannels]=include; m_aModel[offsetShort+nchannels]=include;
// increase the index // increase the index
m_aModelIndexShort[pixel] = (m_aModelIndexShort[pixel] >= (m_nN-1)) ? 0 : (m_aModelIndexShort[pixel] + 1); m_aModelIndexShort[x_idx] = (m_aModelIndexShort[x_idx] >= (m_nN-1)) ? 0 : (m_aModelIndexShort[x_idx] + 1);
};
if (m_nShortCounter == (m_nShortUpdate-1))
{
m_nNextShortUpdate[pixel] = (uchar)( rand() % m_nShortUpdate );
}; };
} }
CV_INLINE int CV_INLINE int
_cvCheckPixelBackgroundNP(long pixel, _cvCheckPixelBackgroundNP(const uchar* data, int nchannels,
const uchar* data, int nchannels,
int m_nN, int m_nN,
uchar* m_aModel, uchar* m_aModel,
float m_fTb, float m_fTb,
int m_nkNN, int m_nkNN,
float tau, float tau,
int m_nShadowDetection, bool m_bShadowDetection,
uchar& include) uchar& include)
{ {
int Pbf = 0; // the total probability that this pixel is background int Pbf = 0; // the total probability that this pixel is background
...@@ -347,12 +328,11 @@ CV_INLINE int ...@@ -347,12 +328,11 @@ CV_INLINE int
include=0;//do we include this pixel into background model? include=0;//do we include this pixel into background model?
int ndata=nchannels+1; int ndata=nchannels+1;
long posPixel = pixel * ndata * m_nN * 3;
// float k; // float k;
// now increase the probability for each pixel // now increase the probability for each pixel
for (int n = 0; n < m_nN*3; n++) for (int n = 0; n < m_nN*3; n++)
{ {
uchar* mean_m = &m_aModel[posPixel + n*ndata]; uchar* mean_m = &m_aModel[n*ndata];
//calculate difference and distance //calculate difference and distance
float dist2; float dist2;
...@@ -399,12 +379,12 @@ CV_INLINE int ...@@ -399,12 +379,12 @@ CV_INLINE int
int Ps = 0; // the total probability that this pixel is background shadow int Ps = 0; // the total probability that this pixel is background shadow
// Detected as moving object, perform shadow detection // Detected as moving object, perform shadow detection
if (m_nShadowDetection) if (m_bShadowDetection)
{ {
for (int n = 0; n < m_nN*3; n++) for (int n = 0; n < m_nN*3; n++)
{ {
//long subPosPixel = posPixel + n*ndata; //long subPosPixel = posPixel + n*ndata;
uchar* mean_m = &m_aModel[posPixel + n*ndata]; uchar* mean_m = &m_aModel[n*ndata];
if(mean_m[nchannels])//check only background if(mean_m[nchannels])//check only background
{ {
...@@ -445,123 +425,126 @@ CV_INLINE int ...@@ -445,123 +425,126 @@ CV_INLINE int
return 0; return 0;
} }
CV_INLINE void class KNNInvoker : public ParallelLoopBody
icvUpdatePixelBackgroundNP(const Mat& _src, Mat& _dst,
Mat& _bgmodel,
Mat& _nNextLongUpdate,
Mat& _nNextMidUpdate,
Mat& _nNextShortUpdate,
Mat& _aModelIndexLong,
Mat& _aModelIndexMid,
Mat& _aModelIndexShort,
int& _nLongCounter,
int& _nMidCounter,
int& _nShortCounter,
int _nN,
float _fAlphaT,
float _fTb,
int _nkNN,
float _fTau,
int _bShadowDetection,
uchar nShadowDetection
)
{ {
int nchannels = CV_MAT_CN(_src.type()); public:
KNNInvoker(const Mat& _src, Mat& _dst,
//model uchar* _bgmodel,
uchar* m_aModel=_bgmodel.ptr(0); uchar* _nNextLongUpdate,
uchar* m_nNextLongUpdate=_nNextLongUpdate.ptr(0); uchar* _nNextMidUpdate,
uchar* m_nNextMidUpdate=_nNextMidUpdate.ptr(0); uchar* _nNextShortUpdate,
uchar* m_nNextShortUpdate=_nNextShortUpdate.ptr(0); uchar* _aModelIndexLong,
uchar* m_aModelIndexLong=_aModelIndexLong.ptr(0); uchar* _aModelIndexMid,
uchar* m_aModelIndexMid=_aModelIndexMid.ptr(0); uchar* _aModelIndexShort,
uchar* m_aModelIndexShort=_aModelIndexShort.ptr(0); int _nLongCounter,
int _nMidCounter,
//some constants int _nShortCounter,
int m_nN=_nN; int _nN,
float m_fAlphaT=_fAlphaT; float _fTb,
float m_fTb=_fTb;//Tb - threshold on the distance int _nkNN,
float m_fTau=_fTau; float _fTau,
int m_nkNN=_nkNN; bool _bShadowDetection,
int m_bShadowDetection=_bShadowDetection; uchar _nShadowDetection)
{
//recalculate update rates - in case alpha is changed src = &_src;
// calculate update parameters (using alpha) dst = &_dst;
int Kshort,Kmid,Klong; m_aModel0 = _bgmodel;
//approximate exponential learning curve m_nNextLongUpdate0 = _nNextLongUpdate;
Kshort=(int)(log(0.7)/log(1-m_fAlphaT))+1;//Kshort m_nNextMidUpdate0 = _nNextMidUpdate;
Kmid=(int)(log(0.4)/log(1-m_fAlphaT))-Kshort+1;//Kmid m_nNextShortUpdate0 = _nNextShortUpdate;
Klong=(int)(log(0.1)/log(1-m_fAlphaT))-Kshort-Kmid+1;//Klong m_aModelIndexLong0 = _aModelIndexLong;
m_aModelIndexMid0 = _aModelIndexMid;
m_aModelIndexShort0 = _aModelIndexShort;
m_nLongCounter = _nLongCounter;
m_nMidCounter = _nMidCounter;
m_nShortCounter = _nShortCounter;
m_nN = _nN;
m_fTb = _fTb;
m_fTau = _fTau;
m_nkNN = _nkNN;
m_bShadowDetection = _bShadowDetection;
m_nShadowDetection = _nShadowDetection;
}
//refresh rates void operator()(const Range& range) const
int m_nShortUpdate = (Kshort/m_nN)+1;
int m_nMidUpdate = (Kmid/m_nN)+1;
int m_nLongUpdate = (Klong/m_nN)+1;
//int m_nShortUpdate = MAX((Kshort/m_nN),m_nN);
//int m_nMidUpdate = MAX((Kmid/m_nN),m_nN);
//int m_nLongUpdate = MAX((Klong/m_nN),m_nN);
//update counters for the refresh rate
int m_nLongCounter=_nLongCounter;
int m_nMidCounter=_nMidCounter;
int m_nShortCounter=_nShortCounter;
_nShortCounter++;//0,1,...,m_nShortUpdate-1
_nMidCounter++;
_nLongCounter++;
if (_nShortCounter >= m_nShortUpdate) _nShortCounter = 0;
if (_nMidCounter >= m_nMidUpdate) _nMidCounter = 0;
if (_nLongCounter >= m_nLongUpdate) _nLongCounter = 0;
//go through the image
long i = 0;
for (long y = 0; y < _src.rows; y++)
{ {
for (long x = 0; x < _src.cols; x++) int y0 = range.start, y1 = range.end;
int ncols = src->cols, nchannels = src->channels();
int ndata=nchannels+1;
for ( int y = y0; y < y1; y++ )
{ {
const uchar* data = _src.ptr((int)y, (int)x); const uchar* data = src->ptr(y);
uchar* m_aModel = m_aModel0 + ncols*m_nN*3*ndata*y;
//update model+ background subtract uchar* m_nNextLongUpdate = m_nNextLongUpdate0 + ncols*y;
uchar include=0; uchar* m_nNextMidUpdate = m_nNextMidUpdate0 + ncols*y;
int result= _cvCheckPixelBackgroundNP(i, data, nchannels, uchar* m_nNextShortUpdate = m_nNextShortUpdate0 + ncols*y;
m_nN, m_aModel, m_fTb,m_nkNN, m_fTau,m_bShadowDetection,include); uchar* m_aModelIndexLong = m_aModelIndexLong0 + ncols*y;
uchar* m_aModelIndexMid = m_aModelIndexMid0 + ncols*y;
_cvUpdatePixelBackgroundNP(i,data,nchannels, uchar* m_aModelIndexShort = m_aModelIndexShort0 + ncols*y;
m_nN, m_aModel, uchar* mask = dst->ptr(y);
m_nNextLongUpdate,
m_nNextMidUpdate, for ( int x = 0; x < ncols; x++ )
m_nNextShortUpdate,
m_aModelIndexLong,
m_aModelIndexMid,
m_aModelIndexShort,
m_nLongCounter,
m_nMidCounter,
m_nShortCounter,
m_nLongUpdate,
m_nMidUpdate,
m_nShortUpdate,
include
);
switch (result)
{ {
case 0:
//foreground //update model+ background subtract
*_dst.ptr((int)y, (int)x) = 255; uchar include=0;
break; int result= _cvCheckPixelBackgroundNP(data, nchannels,
case 1: m_nN, m_aModel, m_fTb,m_nkNN, m_fTau,m_bShadowDetection,include);
//background
*_dst.ptr((int)y, (int)x) = 0; _cvUpdatePixelBackgroundNP(x,data,nchannels,
break; m_nN, m_aModel,
case 2: m_nNextLongUpdate,
//shadow m_nNextMidUpdate,
*_dst.ptr((int)y, (int)x) = nShadowDetection; m_nNextShortUpdate,
break; m_aModelIndexLong,
m_aModelIndexMid,
m_aModelIndexShort,
m_nLongCounter,
m_nMidCounter,
m_nShortCounter,
include
);
switch (result)
{
case 0:
//foreground
mask[x] = 255;
break;
case 1:
//background
mask[x] = 0;
break;
case 2:
//shadow
mask[x] = m_nShadowDetection;
break;
}
data += nchannels;
m_aModel += m_nN*3*ndata;
} }
i++;
} }
} }
}
const Mat* src;
Mat* dst;
uchar* m_aModel0;
uchar* m_nNextLongUpdate0;
uchar* m_nNextMidUpdate0;
uchar* m_nNextShortUpdate0;
uchar* m_aModelIndexLong0;
uchar* m_aModelIndexMid0;
uchar* m_aModelIndexShort0;
int m_nLongCounter;
int m_nMidCounter;
int m_nShortCounter;
int m_nN;
float m_fTb;
float m_fTau;
int m_nkNN;
bool m_bShadowDetection;
uchar m_nShadowDetection;
};
...@@ -582,27 +565,57 @@ void BackgroundSubtractorKNNImpl::apply(InputArray _image, OutputArray _fgmask, ...@@ -582,27 +565,57 @@ void BackgroundSubtractorKNNImpl::apply(InputArray _image, OutputArray _fgmask,
learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( 2*nframes, history ); learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( 2*nframes, history );
CV_Assert(learningRate >= 0); CV_Assert(learningRate >= 0);
//parallel_for_(Range(0, image.rows), //recalculate update rates - in case alpha is changed
// KNNInvoker(image, fgmask, // calculate update parameters (using alpha)
icvUpdatePixelBackgroundNP(image, fgmask, int Kshort,Kmid,Klong;
bgmodel, //approximate exponential learning curve
nNextLongUpdate, Kshort=(int)(log(0.7)/log(1-learningRate))+1;//Kshort
nNextMidUpdate, Kmid=(int)(log(0.4)/log(1-learningRate))-Kshort+1;//Kmid
nNextShortUpdate, Klong=(int)(log(0.1)/log(1-learningRate))-Kshort-Kmid+1;//Klong
aModelIndexLong,
aModelIndexMid, //refresh rates
aModelIndexShort, int nShortUpdate = (Kshort/nN)+1;
nLongCounter, int nMidUpdate = (Kmid/nN)+1;
nMidCounter, int nLongUpdate = (Klong/nN)+1;
nShortCounter,
nN, parallel_for_(Range(0, image.rows),
(float)learningRate, KNNInvoker(image, fgmask,
fTb, bgmodel.ptr(),
nkNN, nNextLongUpdate.ptr(),
fTau, nNextMidUpdate.ptr(),
bShadowDetection, nNextShortUpdate.ptr(),
nShadowDetection aModelIndexLong.ptr(),
); aModelIndexMid.ptr(),
aModelIndexShort.ptr(),
nLongCounter,
nMidCounter,
nShortCounter,
nN,
fTb,
nkNN,
fTau,
bShadowDetection,
nShadowDetection),
image.total()/(double)(1 << 16));
nShortCounter++;//0,1,...,nShortUpdate-1
nMidCounter++;
nLongCounter++;
if (nShortCounter >= nShortUpdate)
{
nShortCounter = 0;
randu(nNextShortUpdate, Scalar::all(0), Scalar::all(nShortUpdate));
}
if (nMidCounter >= nMidUpdate)
{
nMidCounter = 0;
randu(nNextMidUpdate, Scalar::all(0), Scalar::all(nMidUpdate));
}
if (nLongCounter >= nLongUpdate)
{
nLongCounter = 0;
randu(nNextLongUpdate, Scalar::all(0), Scalar::all(nLongUpdate));
}
} }
void BackgroundSubtractorKNNImpl::getBackgroundImage(OutputArray backgroundImage) const void BackgroundSubtractorKNNImpl::getBackgroundImage(OutputArray backgroundImage) const
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment