提交 a2adab72 编写于 作者: V Vladislav Vinogradov

refactored MOG algorithm

converted it to abstract interface
上级 88e67545
......@@ -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;
}
cv::gpu::MOG_GPU::MOG_GPU(int nmixtures) :
frameSize_(0, 0), frameType_(0), nframes_(0)
{
nmixtures_ = std::min(nmixtures > 0 ? nmixtures : mog::defaultNMixtures, 8);
history = mog::defaultHistory;
varThreshold = mog::defaultVarThreshold;
backgroundRatio = mog::defaultBackgroundRatio;
noiseSigma = mog::defaultNoiseSigma;
}
class MOGImpl : public gpu::BackgroundSubtractorMOG
{
public:
MOGImpl(int history, int nmixtures, double backgroundRatio, double noiseSigma);
void cv::gpu::MOG_GPU::initialize(cv::Size frameSize, int frameType)
{
CV_Assert(frameType == CV_8UC1 || frameType == CV_8UC3 || frameType == CV_8UC4);
void apply(InputArray image, OutputArray fgmask, double learningRate=-1);
void apply(InputArray image, OutputArray fgmask, double learningRate, Stream& stream);
frameSize_ = frameSize;
frameType_ = frameType;
void getBackgroundImage(OutputArray backgroundImage) const;
void getBackgroundImage(OutputArray backgroundImage, Stream& stream) const;
int ch = CV_MAT_CN(frameType);
int work_ch = ch;
int getHistory() const { return history_; }
void setHistory(int nframes) { history_ = nframes; }
// 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)
int getNMixtures() const { return nmixtures_; }
void setNMixtures(int nmix) { nmixtures_ = nmix; }
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));
double getBackgroundRatio() const { return backgroundRatio_; }
void setBackgroundRatio(double backgroundRatio) { backgroundRatio_ = (float) backgroundRatio; }
weight_.setTo(cv::Scalar::all(0));
sortKey_.setTo(cv::Scalar::all(0));
mean_.setTo(cv::Scalar::all(0));
var_.setTo(cv::Scalar::all(0));
double getNoiseSigma() const { return noiseSigma_; }
void setNoiseSigma(double noiseSigma) { noiseSigma_ = (float) noiseSigma; }
nframes_ = 0;
}
private:
//! re-initiaization method
void initialize(Size frameSize, int frameType);
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;
int history_;
int nmixtures_;
float backgroundRatio_;
float noiseSigma_;
CV_Assert(frame.depth() == CV_8U);
float varThreshold_;
int ch = frame.channels();
int work_ch = ch;
Size frameSize_;
int frameType_;
int nframes_;
if (nframes_ == 0 || learningRate >= 1.0 || frame.size() != frameSize_ || work_ch != mean_.channels())
initialize(frame.size(), frame.type());
GpuMat weight_;
GpuMat sortKey_;
GpuMat mean_;
GpuMat var_;
};
fgmask.create(frameSize_, CV_8UC1);
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;
++nframes_;
learningRate = learningRate >= 0.0f && nframes_ > 1 ? learningRate : 1.0f / std::min(nframes_, history);
CV_Assert(learningRate >= 0.0f);
varThreshold_ = defaultVarThreshold;
}
mog_gpu(frame, ch, fgmask, weight_, sortKey_, mean_, var_, nmixtures_,
varThreshold, learningRate, backgroundRatio, noiseSigma,
StreamAccessor::getStream(stream));
}
void MOGImpl::apply(InputArray image, OutputArray fgmask, double learningRate)
{
apply(image, fgmask, learningRate, Stream::Null());
}
void cv::gpu::MOG_GPU::getBackgroundImage(GpuMat& backgroundImage, Stream& stream) const
{
using namespace cv::gpu::cudev::mog;
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());
backgroundImage.create(frameSize_, frameType_);
_fgmask.create(frameSize_, CV_8UC1);
GpuMat fgmask = _fgmask.getGpuMat();
getBackgroundImage_gpu(backgroundImage.channels(), weight_, mean_, backgroundImage, nmixtures_, backgroundRatio, StreamAccessor::getStream(stream));
++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;
}
}
void cv::gpu::MOG_GPU::release()
Ptr<gpu::BackgroundSubtractorMOG> cv::gpu::createBackgroundSubtractorMOG(int history, int nmixtures, double backgroundRatio, double noiseSigma)
{
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();
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册