refactored MOG algorithm
converted it to abstract interface
This commit is contained in:
parent
88e67545ef
commit
a2adab7283
@ -47,13 +47,37 @@
|
||||
# error gpubgsegm.hpp header must be compiled as C++
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "opencv2/core/gpu.hpp"
|
||||
#include "opencv2/video/background_segm.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include "opencv2/gpufilters.hpp"
|
||||
|
||||
namespace cv { namespace gpu {
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// MOG
|
||||
|
||||
class CV_EXPORTS BackgroundSubtractorMOG : public cv::BackgroundSubtractorMOG
|
||||
{
|
||||
public:
|
||||
using cv::BackgroundSubtractorMOG::apply;
|
||||
using cv::BackgroundSubtractorMOG::getBackgroundImage;
|
||||
|
||||
virtual void apply(InputArray image, OutputArray fgmask, double learningRate, Stream& stream) = 0;
|
||||
|
||||
virtual void getBackgroundImage(OutputArray backgroundImage, Stream& stream) const = 0;
|
||||
};
|
||||
|
||||
CV_EXPORTS Ptr<gpu::BackgroundSubtractorMOG>
|
||||
createBackgroundSubtractorMOG(int history = 200, int nmixtures = 5,
|
||||
double backgroundRatio = 0.7, double noiseSigma = 0);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Foreground Object Detection from Videos Containing Complex Background.
|
||||
// Liyuan Li, Weimin Huang, Irene Y.H. Gu, and Qi Tian.
|
||||
// ACM MM2003 9p
|
||||
@ -116,51 +140,6 @@ private:
|
||||
std::auto_ptr<Impl> impl_;
|
||||
};
|
||||
|
||||
/*!
|
||||
Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm
|
||||
|
||||
The class implements the following algorithm:
|
||||
"An improved adaptive background mixture model for real-time tracking with shadow detection"
|
||||
P. KadewTraKuPong and R. Bowden,
|
||||
Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001."
|
||||
http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
|
||||
*/
|
||||
class CV_EXPORTS MOG_GPU
|
||||
{
|
||||
public:
|
||||
//! the default constructor
|
||||
MOG_GPU(int nmixtures = -1);
|
||||
|
||||
//! re-initiaization method
|
||||
void initialize(Size frameSize, int frameType);
|
||||
|
||||
//! the update operator
|
||||
void operator()(const GpuMat& frame, GpuMat& fgmask, float learningRate = 0.0f, Stream& stream = Stream::Null());
|
||||
|
||||
//! computes a background image which are the mean of all background gaussians
|
||||
void getBackgroundImage(GpuMat& backgroundImage, Stream& stream = Stream::Null()) const;
|
||||
|
||||
//! releases all inner buffers
|
||||
void release();
|
||||
|
||||
int history;
|
||||
float varThreshold;
|
||||
float backgroundRatio;
|
||||
float noiseSigma;
|
||||
|
||||
private:
|
||||
int nmixtures_;
|
||||
|
||||
Size frameSize_;
|
||||
int frameType_;
|
||||
int nframes_;
|
||||
|
||||
GpuMat weight_;
|
||||
GpuMat sortKey_;
|
||||
GpuMat mean_;
|
||||
GpuMat var_;
|
||||
};
|
||||
|
||||
/*!
|
||||
The class implements the following algorithm:
|
||||
"Improved adaptive Gausian mixture model for background subtraction"
|
||||
|
@ -176,11 +176,12 @@ PERF_TEST_P(Video_Cn_LearningRate, MOG,
|
||||
|
||||
if (PERF_RUN_GPU())
|
||||
{
|
||||
cv::Ptr<cv::BackgroundSubtractor> d_mog = cv::gpu::createBackgroundSubtractorMOG();
|
||||
|
||||
cv::gpu::GpuMat d_frame(frame);
|
||||
cv::gpu::MOG_GPU d_mog;
|
||||
cv::gpu::GpuMat foreground;
|
||||
|
||||
d_mog(d_frame, foreground, learningRate);
|
||||
d_mog->apply(d_frame, foreground, learningRate);
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
@ -200,7 +201,7 @@ PERF_TEST_P(Video_Cn_LearningRate, MOG,
|
||||
d_frame.upload(frame);
|
||||
|
||||
startTimer(); next();
|
||||
d_mog(d_frame, foreground, learningRate);
|
||||
d_mog->apply(d_frame, foreground, learningRate);
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
|
@ -42,13 +42,12 @@
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::gpu;
|
||||
|
||||
#if !defined HAVE_CUDA || defined(CUDA_DISABLER)
|
||||
|
||||
cv::gpu::MOG_GPU::MOG_GPU(int) { throw_no_cuda(); }
|
||||
void cv::gpu::MOG_GPU::initialize(cv::Size, int) { throw_no_cuda(); }
|
||||
void cv::gpu::MOG_GPU::operator()(const cv::gpu::GpuMat&, cv::gpu::GpuMat&, float, Stream&) { throw_no_cuda(); }
|
||||
void cv::gpu::MOG_GPU::getBackgroundImage(GpuMat&, Stream&) const { throw_no_cuda(); }
|
||||
void cv::gpu::MOG_GPU::release() {}
|
||||
Ptr<gpu::BackgroundSubtractorMOG> cv::gpu::createBackgroundSubtractorMOG(int, int, double, double) { throw_no_cuda(); return Ptr<gpu::BackgroundSubtractorMOG>(); }
|
||||
|
||||
#else
|
||||
|
||||
@ -63,7 +62,7 @@ namespace cv { namespace gpu { namespace cudev
|
||||
}
|
||||
}}}
|
||||
|
||||
namespace mog
|
||||
namespace
|
||||
{
|
||||
const int defaultNMixtures = 5;
|
||||
const int defaultHistory = 200;
|
||||
@ -71,88 +70,140 @@ namespace mog
|
||||
const float defaultVarThreshold = 2.5f * 2.5f;
|
||||
const float defaultNoiseSigma = 30.0f * 0.5f;
|
||||
const float defaultInitialWeight = 0.05f;
|
||||
|
||||
class MOGImpl : public gpu::BackgroundSubtractorMOG
|
||||
{
|
||||
public:
|
||||
MOGImpl(int history, int nmixtures, double backgroundRatio, double noiseSigma);
|
||||
|
||||
void apply(InputArray image, OutputArray fgmask, double learningRate=-1);
|
||||
void apply(InputArray image, OutputArray fgmask, double learningRate, Stream& stream);
|
||||
|
||||
void getBackgroundImage(OutputArray backgroundImage) const;
|
||||
void getBackgroundImage(OutputArray backgroundImage, Stream& stream) const;
|
||||
|
||||
int getHistory() const { return history_; }
|
||||
void setHistory(int nframes) { history_ = nframes; }
|
||||
|
||||
int getNMixtures() const { return nmixtures_; }
|
||||
void setNMixtures(int nmix) { nmixtures_ = nmix; }
|
||||
|
||||
double getBackgroundRatio() const { return backgroundRatio_; }
|
||||
void setBackgroundRatio(double backgroundRatio) { backgroundRatio_ = (float) backgroundRatio; }
|
||||
|
||||
double getNoiseSigma() const { return noiseSigma_; }
|
||||
void setNoiseSigma(double noiseSigma) { noiseSigma_ = (float) noiseSigma; }
|
||||
|
||||
private:
|
||||
//! re-initiaization method
|
||||
void initialize(Size frameSize, int frameType);
|
||||
|
||||
int history_;
|
||||
int nmixtures_;
|
||||
float backgroundRatio_;
|
||||
float noiseSigma_;
|
||||
|
||||
float varThreshold_;
|
||||
|
||||
Size frameSize_;
|
||||
int frameType_;
|
||||
int nframes_;
|
||||
|
||||
GpuMat weight_;
|
||||
GpuMat sortKey_;
|
||||
GpuMat mean_;
|
||||
GpuMat var_;
|
||||
};
|
||||
|
||||
MOGImpl::MOGImpl(int history, int nmixtures, double backgroundRatio, double noiseSigma) :
|
||||
frameSize_(0, 0), frameType_(0), nframes_(0)
|
||||
{
|
||||
history_ = history > 0 ? history : defaultHistory;
|
||||
nmixtures_ = std::min(nmixtures > 0 ? nmixtures : defaultNMixtures, 8);
|
||||
backgroundRatio_ = backgroundRatio > 0 ? (float) backgroundRatio : defaultBackgroundRatio;
|
||||
noiseSigma_ = noiseSigma > 0 ? (float) noiseSigma : defaultNoiseSigma;
|
||||
|
||||
varThreshold_ = defaultVarThreshold;
|
||||
}
|
||||
|
||||
void MOGImpl::apply(InputArray image, OutputArray fgmask, double learningRate)
|
||||
{
|
||||
apply(image, fgmask, learningRate, Stream::Null());
|
||||
}
|
||||
|
||||
void MOGImpl::apply(InputArray _frame, OutputArray _fgmask, double learningRate, Stream& stream)
|
||||
{
|
||||
using namespace cv::gpu::cudev::mog;
|
||||
|
||||
GpuMat frame = _frame.getGpuMat();
|
||||
|
||||
CV_Assert( frame.depth() == CV_8U );
|
||||
|
||||
int ch = frame.channels();
|
||||
int work_ch = ch;
|
||||
|
||||
if (nframes_ == 0 || learningRate >= 1.0 || frame.size() != frameSize_ || work_ch != mean_.channels())
|
||||
initialize(frame.size(), frame.type());
|
||||
|
||||
_fgmask.create(frameSize_, CV_8UC1);
|
||||
GpuMat fgmask = _fgmask.getGpuMat();
|
||||
|
||||
++nframes_;
|
||||
learningRate = learningRate >= 0 && nframes_ > 1 ? learningRate : 1.0 / std::min(nframes_, history_);
|
||||
CV_Assert( learningRate >= 0 );
|
||||
|
||||
mog_gpu(frame, ch, fgmask, weight_, sortKey_, mean_, var_, nmixtures_,
|
||||
varThreshold_, (float) learningRate, backgroundRatio_, noiseSigma_,
|
||||
StreamAccessor::getStream(stream));
|
||||
}
|
||||
|
||||
void MOGImpl::getBackgroundImage(OutputArray backgroundImage) const
|
||||
{
|
||||
getBackgroundImage(backgroundImage, Stream::Null());
|
||||
}
|
||||
|
||||
void MOGImpl::getBackgroundImage(OutputArray _backgroundImage, Stream& stream) const
|
||||
{
|
||||
using namespace cv::gpu::cudev::mog;
|
||||
|
||||
_backgroundImage.create(frameSize_, frameType_);
|
||||
GpuMat backgroundImage = _backgroundImage.getGpuMat();
|
||||
|
||||
getBackgroundImage_gpu(backgroundImage.channels(), weight_, mean_, backgroundImage, nmixtures_, backgroundRatio_, StreamAccessor::getStream(stream));
|
||||
}
|
||||
|
||||
void MOGImpl::initialize(Size frameSize, int frameType)
|
||||
{
|
||||
CV_Assert( frameType == CV_8UC1 || frameType == CV_8UC3 || frameType == CV_8UC4 );
|
||||
|
||||
frameSize_ = frameSize;
|
||||
frameType_ = frameType;
|
||||
|
||||
int ch = CV_MAT_CN(frameType);
|
||||
int work_ch = ch;
|
||||
|
||||
// for each gaussian mixture of each pixel bg model we store
|
||||
// the mixture sort key (w/sum_of_variances), the mixture weight (w),
|
||||
// the mean (nchannels values) and
|
||||
// the diagonal covariance matrix (another nchannels values)
|
||||
|
||||
weight_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC1);
|
||||
sortKey_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC1);
|
||||
mean_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC(work_ch));
|
||||
var_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC(work_ch));
|
||||
|
||||
weight_.setTo(cv::Scalar::all(0));
|
||||
sortKey_.setTo(cv::Scalar::all(0));
|
||||
mean_.setTo(cv::Scalar::all(0));
|
||||
var_.setTo(cv::Scalar::all(0));
|
||||
|
||||
nframes_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cv::gpu::MOG_GPU::MOG_GPU(int nmixtures) :
|
||||
frameSize_(0, 0), frameType_(0), nframes_(0)
|
||||
Ptr<gpu::BackgroundSubtractorMOG> cv::gpu::createBackgroundSubtractorMOG(int history, int nmixtures, double backgroundRatio, double noiseSigma)
|
||||
{
|
||||
nmixtures_ = std::min(nmixtures > 0 ? nmixtures : mog::defaultNMixtures, 8);
|
||||
history = mog::defaultHistory;
|
||||
varThreshold = mog::defaultVarThreshold;
|
||||
backgroundRatio = mog::defaultBackgroundRatio;
|
||||
noiseSigma = mog::defaultNoiseSigma;
|
||||
}
|
||||
|
||||
void cv::gpu::MOG_GPU::initialize(cv::Size frameSize, int frameType)
|
||||
{
|
||||
CV_Assert(frameType == CV_8UC1 || frameType == CV_8UC3 || frameType == CV_8UC4);
|
||||
|
||||
frameSize_ = frameSize;
|
||||
frameType_ = frameType;
|
||||
|
||||
int ch = CV_MAT_CN(frameType);
|
||||
int work_ch = ch;
|
||||
|
||||
// for each gaussian mixture of each pixel bg model we store
|
||||
// the mixture sort key (w/sum_of_variances), the mixture weight (w),
|
||||
// the mean (nchannels values) and
|
||||
// the diagonal covariance matrix (another nchannels values)
|
||||
|
||||
weight_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC1);
|
||||
sortKey_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC1);
|
||||
mean_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC(work_ch));
|
||||
var_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC(work_ch));
|
||||
|
||||
weight_.setTo(cv::Scalar::all(0));
|
||||
sortKey_.setTo(cv::Scalar::all(0));
|
||||
mean_.setTo(cv::Scalar::all(0));
|
||||
var_.setTo(cv::Scalar::all(0));
|
||||
|
||||
nframes_ = 0;
|
||||
}
|
||||
|
||||
void cv::gpu::MOG_GPU::operator()(const cv::gpu::GpuMat& frame, cv::gpu::GpuMat& fgmask, float learningRate, Stream& stream)
|
||||
{
|
||||
using namespace cv::gpu::cudev::mog;
|
||||
|
||||
CV_Assert(frame.depth() == CV_8U);
|
||||
|
||||
int ch = frame.channels();
|
||||
int work_ch = ch;
|
||||
|
||||
if (nframes_ == 0 || learningRate >= 1.0 || frame.size() != frameSize_ || work_ch != mean_.channels())
|
||||
initialize(frame.size(), frame.type());
|
||||
|
||||
fgmask.create(frameSize_, CV_8UC1);
|
||||
|
||||
++nframes_;
|
||||
learningRate = learningRate >= 0.0f && nframes_ > 1 ? learningRate : 1.0f / std::min(nframes_, history);
|
||||
CV_Assert(learningRate >= 0.0f);
|
||||
|
||||
mog_gpu(frame, ch, fgmask, weight_, sortKey_, mean_, var_, nmixtures_,
|
||||
varThreshold, learningRate, backgroundRatio, noiseSigma,
|
||||
StreamAccessor::getStream(stream));
|
||||
}
|
||||
|
||||
void cv::gpu::MOG_GPU::getBackgroundImage(GpuMat& backgroundImage, Stream& stream) const
|
||||
{
|
||||
using namespace cv::gpu::cudev::mog;
|
||||
|
||||
backgroundImage.create(frameSize_, frameType_);
|
||||
|
||||
getBackgroundImage_gpu(backgroundImage.channels(), weight_, mean_, backgroundImage, nmixtures_, backgroundRatio, StreamAccessor::getStream(stream));
|
||||
}
|
||||
|
||||
void cv::gpu::MOG_GPU::release()
|
||||
{
|
||||
frameSize_ = Size(0, 0);
|
||||
frameType_ = 0;
|
||||
nframes_ = 0;
|
||||
|
||||
weight_.release();
|
||||
sortKey_.release();
|
||||
mean_.release();
|
||||
var_.release();
|
||||
return new MOGImpl(history, nmixtures, backgroundRatio, noiseSigma);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -193,7 +193,7 @@ GPU_TEST_P(MOG, Update)
|
||||
cap >> frame;
|
||||
ASSERT_FALSE(frame.empty());
|
||||
|
||||
cv::gpu::MOG_GPU mog;
|
||||
cv::Ptr<cv::BackgroundSubtractorMOG> mog = cv::gpu::createBackgroundSubtractorMOG();
|
||||
cv::gpu::GpuMat foreground = createMat(frame.size(), CV_8UC1, useRoi);
|
||||
|
||||
cv::Ptr<cv::BackgroundSubtractorMOG> mog_gold = cv::createBackgroundSubtractorMOG();
|
||||
@ -211,7 +211,7 @@ GPU_TEST_P(MOG, Update)
|
||||
cv::swap(temp, frame);
|
||||
}
|
||||
|
||||
mog(loadMat(frame, useRoi), foreground, (float)learningRate);
|
||||
mog->apply(loadMat(frame, useRoi), foreground, learningRate);
|
||||
|
||||
mog_gold->apply(frame, foreground_gold, learningRate);
|
||||
|
||||
|
@ -76,7 +76,7 @@ int main(int argc, const char** argv)
|
||||
GpuMat d_frame(frame);
|
||||
|
||||
FGDStatModel fgd_stat;
|
||||
MOG_GPU mog;
|
||||
cv::Ptr<cv::BackgroundSubtractorMOG> mog = cv::gpu::createBackgroundSubtractorMOG();
|
||||
MOG2_GPU mog2;
|
||||
GMG_GPU gmg;
|
||||
gmg.numInitializationFrames = 40;
|
||||
@ -96,7 +96,7 @@ int main(int argc, const char** argv)
|
||||
break;
|
||||
|
||||
case MOG:
|
||||
mog(d_frame, d_fgmask, 0.01f);
|
||||
mog->apply(d_frame, d_fgmask, 0.01);
|
||||
break;
|
||||
|
||||
case MOG2:
|
||||
@ -135,8 +135,8 @@ int main(int argc, const char** argv)
|
||||
break;
|
||||
|
||||
case MOG:
|
||||
mog(d_frame, d_fgmask, 0.01f);
|
||||
mog.getBackgroundImage(d_bgimg);
|
||||
mog->apply(d_frame, d_fgmask, 0.01);
|
||||
mog->getBackgroundImage(d_bgimg);
|
||||
break;
|
||||
|
||||
case MOG2:
|
||||
|
@ -1346,10 +1346,10 @@ TEST(MOG)
|
||||
cap >> frame;
|
||||
|
||||
cv::gpu::GpuMat d_frame(frame);
|
||||
cv::gpu::MOG_GPU d_mog;
|
||||
cv::Ptr<cv::BackgroundSubtractor> d_mog = cv::gpu::createBackgroundSubtractorMOG();
|
||||
cv::gpu::GpuMat d_foreground;
|
||||
|
||||
d_mog(d_frame, d_foreground, 0.01f);
|
||||
d_mog->apply(d_frame, d_foreground, 0.01);
|
||||
|
||||
while (!TestSystem::instance().stop())
|
||||
{
|
||||
@ -1358,7 +1358,7 @@ TEST(MOG)
|
||||
|
||||
TestSystem::instance().gpuOn();
|
||||
|
||||
d_mog(d_frame, d_foreground, 0.01f);
|
||||
d_mog->apply(d_frame, d_foreground, 0.01);
|
||||
|
||||
TestSystem::instance().gpuOff();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user