mirror of
https://github.com/opencv/opencv.git
synced 2025-06-28 15:30:49 +08:00
Merge pull request #10432 from GlueCrow:bgfg_knn_fix
This commit is contained in:
commit
f5862dacb6
@ -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
|
|||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
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,89 +425,74 @@ CV_INLINE int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CV_INLINE void
|
class KNNInvoker : public ParallelLoopBody
|
||||||
icvUpdatePixelBackgroundNP(const Mat& _src, Mat& _dst,
|
{
|
||||||
Mat& _bgmodel,
|
public:
|
||||||
Mat& _nNextLongUpdate,
|
KNNInvoker(const Mat& _src, Mat& _dst,
|
||||||
Mat& _nNextMidUpdate,
|
uchar* _bgmodel,
|
||||||
Mat& _nNextShortUpdate,
|
uchar* _nNextLongUpdate,
|
||||||
Mat& _aModelIndexLong,
|
uchar* _nNextMidUpdate,
|
||||||
Mat& _aModelIndexMid,
|
uchar* _nNextShortUpdate,
|
||||||
Mat& _aModelIndexShort,
|
uchar* _aModelIndexLong,
|
||||||
int& _nLongCounter,
|
uchar* _aModelIndexMid,
|
||||||
int& _nMidCounter,
|
uchar* _aModelIndexShort,
|
||||||
int& _nShortCounter,
|
int _nLongCounter,
|
||||||
|
int _nMidCounter,
|
||||||
|
int _nShortCounter,
|
||||||
int _nN,
|
int _nN,
|
||||||
float _fAlphaT,
|
|
||||||
float _fTb,
|
float _fTb,
|
||||||
int _nkNN,
|
int _nkNN,
|
||||||
float _fTau,
|
float _fTau,
|
||||||
int _bShadowDetection,
|
bool _bShadowDetection,
|
||||||
uchar nShadowDetection
|
uchar _nShadowDetection)
|
||||||
)
|
|
||||||
{
|
|
||||||
int nchannels = CV_MAT_CN(_src.type());
|
|
||||||
|
|
||||||
//model
|
|
||||||
uchar* m_aModel=_bgmodel.ptr(0);
|
|
||||||
uchar* m_nNextLongUpdate=_nNextLongUpdate.ptr(0);
|
|
||||||
uchar* m_nNextMidUpdate=_nNextMidUpdate.ptr(0);
|
|
||||||
uchar* m_nNextShortUpdate=_nNextShortUpdate.ptr(0);
|
|
||||||
uchar* m_aModelIndexLong=_aModelIndexLong.ptr(0);
|
|
||||||
uchar* m_aModelIndexMid=_aModelIndexMid.ptr(0);
|
|
||||||
uchar* m_aModelIndexShort=_aModelIndexShort.ptr(0);
|
|
||||||
|
|
||||||
//some constants
|
|
||||||
int m_nN=_nN;
|
|
||||||
float m_fAlphaT=_fAlphaT;
|
|
||||||
float m_fTb=_fTb;//Tb - threshold on the distance
|
|
||||||
float m_fTau=_fTau;
|
|
||||||
int m_nkNN=_nkNN;
|
|
||||||
int m_bShadowDetection=_bShadowDetection;
|
|
||||||
|
|
||||||
//recalculate update rates - in case alpha is changed
|
|
||||||
// calculate update parameters (using alpha)
|
|
||||||
int Kshort,Kmid,Klong;
|
|
||||||
//approximate exponential learning curve
|
|
||||||
Kshort=(int)(log(0.7)/log(1-m_fAlphaT))+1;//Kshort
|
|
||||||
Kmid=(int)(log(0.4)/log(1-m_fAlphaT))-Kshort+1;//Kmid
|
|
||||||
Klong=(int)(log(0.1)/log(1-m_fAlphaT))-Kshort-Kmid+1;//Klong
|
|
||||||
|
|
||||||
//refresh rates
|
|
||||||
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++)
|
src = &_src;
|
||||||
|
dst = &_dst;
|
||||||
|
m_aModel0 = _bgmodel;
|
||||||
|
m_nNextLongUpdate0 = _nNextLongUpdate;
|
||||||
|
m_nNextMidUpdate0 = _nNextMidUpdate;
|
||||||
|
m_nNextShortUpdate0 = _nNextShortUpdate;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const Range& range) const
|
||||||
|
{
|
||||||
|
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(y);
|
||||||
|
uchar* m_aModel = m_aModel0 + ncols*m_nN*3*ndata*y;
|
||||||
|
uchar* m_nNextLongUpdate = m_nNextLongUpdate0 + ncols*y;
|
||||||
|
uchar* m_nNextMidUpdate = m_nNextMidUpdate0 + ncols*y;
|
||||||
|
uchar* m_nNextShortUpdate = m_nNextShortUpdate0 + ncols*y;
|
||||||
|
uchar* m_aModelIndexLong = m_aModelIndexLong0 + ncols*y;
|
||||||
|
uchar* m_aModelIndexMid = m_aModelIndexMid0 + ncols*y;
|
||||||
|
uchar* m_aModelIndexShort = m_aModelIndexShort0 + ncols*y;
|
||||||
|
uchar* mask = dst->ptr(y);
|
||||||
|
|
||||||
|
for ( int x = 0; x < ncols; x++ )
|
||||||
{
|
{
|
||||||
const uchar* data = _src.ptr((int)y, (int)x);
|
|
||||||
|
|
||||||
//update model+ background subtract
|
//update model+ background subtract
|
||||||
uchar include=0;
|
uchar include=0;
|
||||||
int result= _cvCheckPixelBackgroundNP(i, data, nchannels,
|
int result= _cvCheckPixelBackgroundNP(data, nchannels,
|
||||||
m_nN, m_aModel, m_fTb,m_nkNN, m_fTau,m_bShadowDetection,include);
|
m_nN, m_aModel, m_fTb,m_nkNN, m_fTau,m_bShadowDetection,include);
|
||||||
|
|
||||||
_cvUpdatePixelBackgroundNP(i,data,nchannels,
|
_cvUpdatePixelBackgroundNP(x,data,nchannels,
|
||||||
m_nN, m_aModel,
|
m_nN, m_aModel,
|
||||||
m_nNextLongUpdate,
|
m_nNextLongUpdate,
|
||||||
m_nNextMidUpdate,
|
m_nNextMidUpdate,
|
||||||
@ -538,30 +503,48 @@ CV_INLINE void
|
|||||||
m_nLongCounter,
|
m_nLongCounter,
|
||||||
m_nMidCounter,
|
m_nMidCounter,
|
||||||
m_nShortCounter,
|
m_nShortCounter,
|
||||||
m_nLongUpdate,
|
|
||||||
m_nMidUpdate,
|
|
||||||
m_nShortUpdate,
|
|
||||||
include
|
include
|
||||||
);
|
);
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
//foreground
|
//foreground
|
||||||
*_dst.ptr((int)y, (int)x) = 255;
|
mask[x] = 255;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//background
|
//background
|
||||||
*_dst.ptr((int)y, (int)x) = 0;
|
mask[x] = 0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
//shadow
|
//shadow
|
||||||
*_dst.ptr((int)y, (int)x) = nShadowDetection;
|
mask[x] = m_nShadowDetection;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
data += nchannels;
|
||||||
|
m_aModel += m_nN*3*ndata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
|||||||
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;
|
||||||
|
int nMidUpdate = (Kmid/nN)+1;
|
||||||
|
int nLongUpdate = (Klong/nN)+1;
|
||||||
|
|
||||||
|
parallel_for_(Range(0, image.rows),
|
||||||
|
KNNInvoker(image, fgmask,
|
||||||
|
bgmodel.ptr(),
|
||||||
|
nNextLongUpdate.ptr(),
|
||||||
|
nNextMidUpdate.ptr(),
|
||||||
|
nNextShortUpdate.ptr(),
|
||||||
|
aModelIndexLong.ptr(),
|
||||||
|
aModelIndexMid.ptr(),
|
||||||
|
aModelIndexShort.ptr(),
|
||||||
nLongCounter,
|
nLongCounter,
|
||||||
nMidCounter,
|
nMidCounter,
|
||||||
nShortCounter,
|
nShortCounter,
|
||||||
nN,
|
nN,
|
||||||
(float)learningRate,
|
|
||||||
fTb,
|
fTb,
|
||||||
nkNN,
|
nkNN,
|
||||||
fTau,
|
fTau,
|
||||||
bShadowDetection,
|
bShadowDetection,
|
||||||
nShadowDetection
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user