refactored FGD algorithm
authorVladislav Vinogradov <vlad.vinogradov@itseez.com>
Tue, 7 May 2013 08:04:21 +0000 (12:04 +0400)
committerVladislav Vinogradov <vlad.vinogradov@itseez.com>
Thu, 18 Jul 2013 11:39:42 +0000 (15:39 +0400)
modules/gpubgsegm/include/opencv2/gpubgsegm.hpp
modules/gpubgsegm/perf/perf_bgsegm.cpp
modules/gpubgsegm/src/cuda/fgd.cu
modules/gpubgsegm/src/cuda/fgd.hpp
modules/gpubgsegm/src/fgd.cpp
modules/gpubgsegm/test/test_bgsegm.cpp
samples/gpu/bgfg_segm.cpp
samples/gpu/performance/tests.cpp

index d686b3c..c6d9223 100644 (file)
@@ -50,9 +50,6 @@
 #include "opencv2/core/gpu.hpp"
 #include "opencv2/video/background_segm.hpp"
 
-#include <memory>
-#include "opencv2/gpufilters.hpp"
-
 namespace cv { namespace gpu {
 
 ////////////////////////////////////////////////////
@@ -105,76 +102,51 @@ public:
 CV_EXPORTS Ptr<gpu::BackgroundSubtractorGMG>
     createBackgroundSubtractorGMG(int initializationFrames = 120, double decisionThreshold = 0.8);
 
-
-
-
-
-
-
-
-
-// Foreground Object Detection from Videos Containing Complex Background.
-// Liyuan Li, Weimin Huang, Irene Y.H. Gu, and Qi Tian.
-// ACM MM2003 9p
-class CV_EXPORTS FGDStatModel
+////////////////////////////////////////////////////
+// FGD
+
+/**
+ * Foreground Object Detection from Videos Containing Complex Background.
+ * Liyuan Li, Weimin Huang, Irene Y.H. Gu, and Qi Tian.
+ * ACM MM2003 9p
+ */
+class CV_EXPORTS BackgroundSubtractorFGD : public cv::BackgroundSubtractor
 {
 public:
-    struct CV_EXPORTS Params
-    {
-        int Lc;  // Quantized levels per 'color' component. Power of two, typically 32, 64 or 128.
-        int N1c; // Number of color vectors used to model normal background color variation at a given pixel.
-        int N2c; // Number of color vectors retained at given pixel.  Must be > N1c, typically ~ 5/3 of N1c.
-        // Used to allow the first N1c vectors to adapt over time to changing background.
-
-        int Lcc;  // Quantized levels per 'color co-occurrence' component.  Power of two, typically 16, 32 or 64.
-        int N1cc; // Number of color co-occurrence vectors used to model normal background color variation at a given pixel.
-        int N2cc; // Number of color co-occurrence vectors retained at given pixel.  Must be > N1cc, typically ~ 5/3 of N1cc.
-        // Used to allow the first N1cc vectors to adapt over time to changing background.
-
-        bool is_obj_without_holes; // If TRUE we ignore holes within foreground blobs. Defaults to TRUE.
-        int perform_morphing;     // Number of erode-dilate-erode foreground-blob cleanup iterations.
-        // These erase one-pixel junk blobs and merge almost-touching blobs. Default value is 1.
-
-        float alpha1; // How quickly we forget old background pixel values seen. Typically set to 0.1.
-        float alpha2; // "Controls speed of feature learning". Depends on T. Typical value circa 0.005.
-        float alpha3; // Alternate to alpha2, used (e.g.) for quicker initial convergence. Typical value 0.1.
-
-        float delta;   // Affects color and color co-occurrence quantization, typically set to 2.
-        float T;       // A percentage value which determines when new features can be recognized as new background. (Typically 0.9).
-        float minArea; // Discard foreground blobs whose bounding box is smaller than this threshold.
-
-        // default Params
-        Params();
-    };
-
-    // out_cn - channels count in output result (can be 3 or 4)
-    // 4-channels require more memory, but a bit faster
-    explicit FGDStatModel(int out_cn = 3);
-    explicit FGDStatModel(const cv::gpu::GpuMat& firstFrame, const Params& params = Params(), int out_cn = 3);
-
-    ~FGDStatModel();
-
-    void create(const cv::gpu::GpuMat& firstFrame, const Params& params = Params());
-    void release();
-
-    int update(const cv::gpu::GpuMat& curFrame);
-
-    //8UC3 or 8UC4 reference background image
-    cv::gpu::GpuMat background;
-
-    //8UC1 foreground image
-    cv::gpu::GpuMat foreground;
-
-    std::vector< std::vector<cv::Point> > foreground_regions;
-
-private:
-    FGDStatModel(const FGDStatModel&);
-    FGDStatModel& operator=(const FGDStatModel&);
+    virtual void getForegroundRegions(OutputArrayOfArrays foreground_regions) = 0;
+};
 
-    class Impl;
-    std::auto_ptr<Impl> impl_;
+struct CV_EXPORTS FGDParams
+{
+    int Lc;  // Quantized levels per 'color' component. Power of two, typically 32, 64 or 128.
+    int N1c; // Number of color vectors used to model normal background color variation at a given pixel.
+    int N2c; // Number of color vectors retained at given pixel.  Must be > N1c, typically ~ 5/3 of N1c.
+    // Used to allow the first N1c vectors to adapt over time to changing background.
+
+    int Lcc;  // Quantized levels per 'color co-occurrence' component.  Power of two, typically 16, 32 or 64.
+    int N1cc; // Number of color co-occurrence vectors used to model normal background color variation at a given pixel.
+    int N2cc; // Number of color co-occurrence vectors retained at given pixel.  Must be > N1cc, typically ~ 5/3 of N1cc.
+    // Used to allow the first N1cc vectors to adapt over time to changing background.
+
+    bool is_obj_without_holes; // If TRUE we ignore holes within foreground blobs. Defaults to TRUE.
+    int perform_morphing;     // Number of erode-dilate-erode foreground-blob cleanup iterations.
+    // These erase one-pixel junk blobs and merge almost-touching blobs. Default value is 1.
+
+    float alpha1; // How quickly we forget old background pixel values seen. Typically set to 0.1.
+    float alpha2; // "Controls speed of feature learning". Depends on T. Typical value circa 0.005.
+    float alpha3; // Alternate to alpha2, used (e.g.) for quicker initial convergence. Typical value 0.1.
+
+    float delta;   // Affects color and color co-occurrence quantization, typically set to 2.
+    float T;       // A percentage value which determines when new features can be recognized as new background. (Typically 0.9).
+    float minArea; // Discard foreground blobs whose bounding box is smaller than this threshold.
+
+    // default Params
+    FGDParams();
 };
 
+CV_EXPORTS Ptr<gpu::BackgroundSubtractorFGD>
+    createBackgroundSubtractorFGD(const FGDParams& params = FGDParams());
+
 }} // namespace cv { namespace gpu {
 
 #endif /* __OPENCV_GPUBGSEGM_HPP__ */
index 9fd3811..33e4403 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "perf_precomp.hpp"
 #include "opencv2/legacy.hpp"
+#include "opencv2/gpuimgproc.hpp"
 
 using namespace std;
 using namespace testing;
@@ -90,10 +91,10 @@ PERF_TEST_P(Video, FGDStatModel,
 
     if (PERF_RUN_GPU())
     {
-        cv::gpu::GpuMat d_frame(frame);
+        cv::gpu::GpuMat d_frame(frame), foreground, background3, background;
 
-        cv::gpu::FGDStatModel d_model(4);
-        d_model.create(d_frame);
+        cv::Ptr<cv::gpu::BackgroundSubtractorFGD> d_fgd = cv::gpu::createBackgroundSubtractorFGD();
+        d_fgd->apply(d_frame, foreground);
 
         for (int i = 0; i < 10; ++i)
         {
@@ -103,12 +104,12 @@ PERF_TEST_P(Video, FGDStatModel,
             d_frame.upload(frame);
 
             startTimer(); next();
-            d_model.update(d_frame);
+            d_fgd->apply(d_frame, foreground);
             stopTimer();
         }
 
-        const cv::gpu::GpuMat background = d_model.background;
-        const cv::gpu::GpuMat foreground = d_model.foreground;
+        d_fgd->getBackgroundImage(background3);
+        cv::gpu::cvtColor(background3, background, cv::COLOR_BGR2BGRA);
 
         GPU_SANITY_CHECK(background, 1e-2, ERROR_RELATIVE);
         GPU_SANITY_CHECK(foreground, 1e-2, ERROR_RELATIVE);
index 3d55199..7dd616c 100644 (file)
@@ -53,7 +53,7 @@
 using namespace cv::gpu;
 using namespace cv::gpu::cudev;
 
-namespace bgfg
+namespace fgd
 {
     ////////////////////////////////////////////////////////////////////////////
     // calcDiffHistogram
index dd71519..50b9838 100644 (file)
@@ -45,7 +45,7 @@
 
 #include "opencv2/core/gpu_types.hpp"
 
-namespace bgfg
+namespace fgd
 {
     struct BGPixelStat
     {
index fb14ff1..14dcc78 100644 (file)
 
 #include "precomp.hpp"
 
-#if !defined HAVE_CUDA || defined(CUDA_DISABLER)
+using namespace cv;
+using namespace cv::gpu;
 
-class cv::gpu::FGDStatModel::Impl
-{
-};
+#if !defined HAVE_CUDA || defined(CUDA_DISABLER)
 
-cv::gpu::FGDStatModel::Params::Params() { throw_no_cuda(); }
+cv::gpu::FGDParams::FGDParams() { throw_no_cuda(); }
 
-cv::gpu::FGDStatModel::FGDStatModel(int) { throw_no_cuda(); }
-cv::gpu::FGDStatModel::FGDStatModel(const cv::gpu::GpuMat&, const Params&, int) { throw_no_cuda(); }
-cv::gpu::FGDStatModel::~FGDStatModel() {}
-void cv::gpu::FGDStatModel::create(const cv::gpu::GpuMat&, const Params&) { throw_no_cuda(); }
-void cv::gpu::FGDStatModel::release() {}
-int cv::gpu::FGDStatModel::update(const cv::gpu::GpuMat&) { throw_no_cuda(); return 0; }
+Ptr<gpu::BackgroundSubtractorFGD> cv::gpu::createBackgroundSubtractorFGD(const FGDParams&) { throw_no_cuda(); return Ptr<gpu::BackgroundSubtractorFGD>(); }
 
 #else
 
 #include "cuda/fgd.hpp"
 #include "opencv2/imgproc/imgproc_c.h"
 
+/////////////////////////////////////////////////////////////////////////
+// FGDParams
+
 namespace
 {
-    class BGPixelStat
-    {
-    public:
-        void create(cv::Size size, const cv::gpu::FGDStatModel::Params& params, int out_cn);
-        void release();
-
-        void setTrained();
-
-        operator bgfg::BGPixelStat();
-
-    private:
-        cv::gpu::GpuMat Pbc_;
-        cv::gpu::GpuMat Pbcc_;
-        cv::gpu::GpuMat is_trained_st_model_;
-        cv::gpu::GpuMat is_trained_dyn_model_;
-
-        cv::gpu::GpuMat ctable_Pv_;
-        cv::gpu::GpuMat ctable_Pvb_;
-        cv::gpu::GpuMat ctable_v_;
-
-        cv::gpu::GpuMat cctable_Pv_;
-        cv::gpu::GpuMat cctable_Pvb_;
-        cv::gpu::GpuMat cctable_v1_;
-        cv::gpu::GpuMat cctable_v2_;
-    };
-
-    void BGPixelStat::create(cv::Size size, const cv::gpu::FGDStatModel::Params& params, int out_cn)
-    {
-        cv::gpu::ensureSizeIsEnough(size, CV_32FC1, Pbc_);
-        Pbc_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(size, CV_32FC1, Pbcc_);
-        Pbcc_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(size, CV_8UC1, is_trained_st_model_);
-        is_trained_st_model_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(size, CV_8UC1, is_trained_dyn_model_);
-        is_trained_dyn_model_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_32FC1, ctable_Pv_);
-        ctable_Pv_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_32FC1, ctable_Pvb_);
-        ctable_Pvb_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_8UC(out_cn), ctable_v_);
-        ctable_v_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_32FC1, cctable_Pv_);
-        cctable_Pv_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_32FC1, cctable_Pvb_);
-        cctable_Pvb_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_8UC(out_cn), cctable_v1_);
-        cctable_v1_.setTo(cv::Scalar::all(0));
-
-        cv::gpu::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_8UC(out_cn), cctable_v2_);
-        cctable_v2_.setTo(cv::Scalar::all(0));
-    }
-
-    void BGPixelStat::release()
-    {
-        Pbc_.release();
-        Pbcc_.release();
-        is_trained_st_model_.release();
-        is_trained_dyn_model_.release();
-
-        ctable_Pv_.release();
-        ctable_Pvb_.release();
-        ctable_v_.release();
-
-        cctable_Pv_.release();
-        cctable_Pvb_.release();
-        cctable_v1_.release();
-        cctable_v2_.release();
-    }
-
-    void BGPixelStat::setTrained()
-    {
-        is_trained_st_model_.setTo(cv::Scalar::all(1));
-        is_trained_dyn_model_.setTo(cv::Scalar::all(1));
-    }
-
-    BGPixelStat::operator bgfg::BGPixelStat()
-    {
-        bgfg::BGPixelStat stat;
-
-        stat.rows_ = Pbc_.rows;
-
-        stat.Pbc_data_ = Pbc_.data;
-        stat.Pbc_step_ = Pbc_.step;
-
-        stat.Pbcc_data_ = Pbcc_.data;
-        stat.Pbcc_step_ = Pbcc_.step;
-
-        stat.is_trained_st_model_data_ = is_trained_st_model_.data;
-        stat.is_trained_st_model_step_ = is_trained_st_model_.step;
-
-        stat.is_trained_dyn_model_data_ = is_trained_dyn_model_.data;
-        stat.is_trained_dyn_model_step_ = is_trained_dyn_model_.step;
-
-        stat.ctable_Pv_data_ = ctable_Pv_.data;
-        stat.ctable_Pv_step_ = ctable_Pv_.step;
+    // Default parameters of foreground detection algorithm:
+    const int BGFG_FGD_LC  = 128;
+    const int BGFG_FGD_N1C = 15;
+    const int BGFG_FGD_N2C = 25;
 
-        stat.ctable_Pvb_data_ = ctable_Pvb_.data;
-        stat.ctable_Pvb_step_ = ctable_Pvb_.step;
+    const int BGFG_FGD_LCC   = 64;
+    const int BGFG_FGD_N1CC = 25;
+    const int BGFG_FGD_N2CC = 40;
 
-        stat.ctable_v_data_ = ctable_v_.data;
-        stat.ctable_v_step_ = ctable_v_.step;
+    // Background reference image update parameter:
+    const float BGFG_FGD_ALPHA_1 = 0.1f;
 
-        stat.cctable_Pv_data_ = cctable_Pv_.data;
-        stat.cctable_Pv_step_ = cctable_Pv_.step;
+    // stat model update parameter
+    // 0.002f ~ 1K frame(~45sec), 0.005 ~ 18sec (if 25fps and absolutely static BG)
+    const float BGFG_FGD_ALPHA_2 = 0.005f;
 
-        stat.cctable_Pvb_data_ = cctable_Pvb_.data;
-        stat.cctable_Pvb_step_ = cctable_Pvb_.step;
+    // start value for alpha parameter (to fast initiate statistic model)
+    const float BGFG_FGD_ALPHA_3 = 0.1f;
 
-        stat.cctable_v1_data_ = cctable_v1_.data;
-        stat.cctable_v1_step_ = cctable_v1_.step;
+    const float BGFG_FGD_DELTA = 2.0f;
 
-        stat.cctable_v2_data_ = cctable_v2_.data;
-        stat.cctable_v2_step_ = cctable_v2_.step;
+    const float BGFG_FGD_T = 0.9f;
 
-        return stat;
-    }
+    const float BGFG_FGD_MINAREA= 15.0f;
 }
 
-class cv::gpu::FGDStatModel::Impl
+cv::gpu::FGDParams::FGDParams()
 {
-public:
-    Impl(cv::gpu::GpuMat& background, cv::gpu::GpuMat& foreground, std::vector< std::vector<cv::Point> >& foreground_regions, int out_cn);
-    ~Impl();
-
-    void create(const cv::gpu::GpuMat& firstFrame, const cv::gpu::FGDStatModel::Params& params);
-    void release();
-
-    int update(const cv::gpu::GpuMat& curFrame);
-
-private:
-    Impl(const Impl&);
-    Impl& operator=(const Impl&);
-
-    int out_cn_;
-
-    cv::gpu::FGDStatModel::Params params_;
-
-    cv::gpu::GpuMat& background_;
-    cv::gpu::GpuMat& foreground_;
-    std::vector< std::vector<cv::Point> >& foreground_regions_;
-
-    cv::Mat h_foreground_;
-
-    cv::gpu::GpuMat prevFrame_;
-    cv::gpu::GpuMat Ftd_;
-    cv::gpu::GpuMat Fbd_;
-    BGPixelStat stat_;
-
-    cv::gpu::GpuMat hist_;
-    cv::gpu::GpuMat histBuf_;
-
-    cv::gpu::GpuMat countBuf_;
+    Lc      = BGFG_FGD_LC;
+    N1c     = BGFG_FGD_N1C;
+    N2c     = BGFG_FGD_N2C;
 
-    cv::gpu::GpuMat buf_;
-    cv::gpu::GpuMat filterBrd_;
+    Lcc     = BGFG_FGD_LCC;
+    N1cc    = BGFG_FGD_N1CC;
+    N2cc    = BGFG_FGD_N2CC;
 
-    cv::Ptr<cv::gpu::Filter> dilateFilter_;
-    cv::Ptr<cv::gpu::Filter> erodeFilter_;
+    delta   = BGFG_FGD_DELTA;
 
-    CvMemStorage* storage_;
-};
+    alpha1  = BGFG_FGD_ALPHA_1;
+    alpha2  = BGFG_FGD_ALPHA_2;
+    alpha3  = BGFG_FGD_ALPHA_3;
 
-cv::gpu::FGDStatModel::Impl::Impl(cv::gpu::GpuMat& background, cv::gpu::GpuMat& foreground, std::vector< std::vector<cv::Point> >& foreground_regions, int out_cn) :
-    out_cn_(out_cn), background_(background), foreground_(foreground), foreground_regions_(foreground_regions)
-{
-    CV_Assert( out_cn_ == 3 || out_cn_ == 4 );
+    T       = BGFG_FGD_T;
+    minArea = BGFG_FGD_MINAREA;
 
-    storage_ = cvCreateMemStorage();
-    CV_Assert( storage_ != 0 );
+    is_obj_without_holes = true;
+    perform_morphing     = 1;
 }
 
-cv::gpu::FGDStatModel::Impl::~Impl()
-{
-    cvReleaseMemStorage(&storage_);
-}
+/////////////////////////////////////////////////////////////////////////
+// copyChannels
 
 namespace
 {
-    void copyChannels(const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst, int dst_cn = -1)
+    void copyChannels(const GpuMat& src, GpuMat& dst, int dst_cn = -1)
     {
         const int src_cn = src.channels();
 
         if (dst_cn < 0)
             dst_cn = src_cn;
 
-        cv::gpu::ensureSizeIsEnough(src.size(), CV_MAKE_TYPE(src.depth(), dst_cn), dst);
+        gpu::ensureSizeIsEnough(src.size(), CV_MAKE_TYPE(src.depth(), dst_cn), dst);
 
         if (src_cn == dst_cn)
+        {
             src.copyTo(dst);
+        }
         else
         {
             static const int cvt_codes[4][4] =
             {
-                {-1, -1, cv::COLOR_GRAY2BGR, cv::COLOR_GRAY2BGRA},
+                {-1, -1, COLOR_GRAY2BGR, COLOR_GRAY2BGRA},
                 {-1, -1, -1, -1},
-                {cv::COLOR_BGR2GRAY, -1, -1, cv::COLOR_BGR2BGRA},
-                {cv::COLOR_BGRA2GRAY, -1, cv::COLOR_BGRA2BGR, -1}
+                {COLOR_BGR2GRAY, -1, -1, COLOR_BGR2BGRA},
+                {COLOR_BGRA2GRAY, -1, COLOR_BGRA2BGR, -1}
             };
 
             const int cvt_code = cvt_codes[src_cn - 1][dst_cn - 1];
             CV_DbgAssert( cvt_code >= 0 );
 
-            cv::gpu::cvtColor(src, dst, cvt_code, dst_cn);
+            gpu::cvtColor(src, dst, cvt_code, dst_cn);
         }
     }
 }
 
-void cv::gpu::FGDStatModel::Impl::create(const cv::gpu::GpuMat& firstFrame, const cv::gpu::FGDStatModel::Params& params)
-{
-    CV_Assert(firstFrame.type() == CV_8UC3 || firstFrame.type() == CV_8UC4);
-
-    params_ = params;
-
-    cv::gpu::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, foreground_);
-
-    copyChannels(firstFrame, background_, out_cn_);
-
-    copyChannels(firstFrame, prevFrame_);
-
-    cv::gpu::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, Ftd_);
-    cv::gpu::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, Fbd_);
-
-    stat_.create(firstFrame.size(), params_, out_cn_);
-    bgfg::setBGPixelStat(stat_);
-
-    if (params_.perform_morphing > 0)
-    {
-        cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1 + params_.perform_morphing * 2, 1 + params_.perform_morphing * 2));
-        cv::Point anchor(params_.perform_morphing, params_.perform_morphing);
-
-        dilateFilter_ = cv::gpu::createMorphologyFilter(cv::MORPH_DILATE, CV_8UC1, kernel, anchor);
-        erodeFilter_ = cv::gpu::createMorphologyFilter(cv::MORPH_ERODE, CV_8UC1, kernel, anchor);
-    }
-}
-
-void cv::gpu::FGDStatModel::Impl::release()
-{
-    background_.release();
-    foreground_.release();
-
-    prevFrame_.release();
-    Ftd_.release();
-    Fbd_.release();
-    stat_.release();
-
-    hist_.release();
-    histBuf_.release();
-
-    countBuf_.release();
-
-    buf_.release();
-    filterBrd_.release();
-}
-
 /////////////////////////////////////////////////////////////////////////
 // changeDetection
 
 namespace
 {
-    void calcDiffHistogram(const cv::gpu::GpuMat& prevFrame, const cv::gpu::GpuMat& curFrame, cv::gpu::GpuMat& hist, cv::gpu::GpuMat& histBuf)
+    void calcDiffHistogram(const GpuMat& prevFrame, const GpuMat& curFrame, GpuMat& hist, GpuMat& histBuf)
     {
-        typedef void (*func_t)(cv::gpu::PtrStepSzb prevFrame, cv::gpu::PtrStepSzb curFrame, unsigned int* hist0, unsigned int* hist1, unsigned int* hist2, unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2, bool cc20, cudaStream_t stream);
+        typedef void (*func_t)(PtrStepSzb prevFrame, PtrStepSzb curFrame,
+                               unsigned int* hist0, unsigned int* hist1, unsigned int* hist2,
+                               unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2,
+                               bool cc20, cudaStream_t stream);
         static const func_t funcs[4][4] =
         {
             {0,0,0,0},
             {0,0,0,0},
-            {0,0,bgfg::calcDiffHistogram_gpu<uchar3, uchar3>,bgfg::calcDiffHistogram_gpu<uchar3, uchar4>},
-            {0,0,bgfg::calcDiffHistogram_gpu<uchar4, uchar3>,bgfg::calcDiffHistogram_gpu<uchar4, uchar4>}
+            {0,0,fgd::calcDiffHistogram_gpu<uchar3, uchar3>,fgd::calcDiffHistogram_gpu<uchar3, uchar4>},
+            {0,0,fgd::calcDiffHistogram_gpu<uchar4, uchar3>,fgd::calcDiffHistogram_gpu<uchar4, uchar4>}
         };
 
         hist.create(3, 256, CV_32SC1);
-        histBuf.create(3, bgfg::PARTIAL_HISTOGRAM_COUNT * bgfg::HISTOGRAM_BIN_COUNT, CV_32SC1);
+        histBuf.create(3, fgd::PARTIAL_HISTOGRAM_COUNT * fgd::HISTOGRAM_BIN_COUNT, CV_32SC1);
 
         funcs[prevFrame.channels() - 1][curFrame.channels() - 1](
                     prevFrame, curFrame,
                     hist.ptr<unsigned int>(0), hist.ptr<unsigned int>(1), hist.ptr<unsigned int>(2),
                     histBuf.ptr<unsigned int>(0), histBuf.ptr<unsigned int>(1), histBuf.ptr<unsigned int>(2),
-                    cv::gpu::deviceSupports(cv::gpu::FEATURE_SET_COMPUTE_20), 0);
+                    deviceSupports(FEATURE_SET_COMPUTE_20), 0);
     }
 
-    void calcRelativeVariance(unsigned int hist[3 * 256], double relativeVariance[3][bgfg::HISTOGRAM_BIN_COUNT])
+    void calcRelativeVariance(unsigned int hist[3 * 256], double relativeVariance[3][fgd::HISTOGRAM_BIN_COUNT])
     {
-        std::memset(relativeVariance, 0, 3 * bgfg::HISTOGRAM_BIN_COUNT * sizeof(double));
+        std::memset(relativeVariance, 0, 3 * fgd::HISTOGRAM_BIN_COUNT * sizeof(double));
 
-        for (int thres = bgfg::HISTOGRAM_BIN_COUNT - 2; thres >= 0; --thres)
+        for (int thres = fgd::HISTOGRAM_BIN_COUNT - 2; thres >= 0; --thres)
         {
-            cv::Vec3d sum(0.0, 0.0, 0.0);
-            cv::Vec3d sqsum(0.0, 0.0, 0.0);
-            cv::Vec3i count(0, 0, 0);
+            Vec3d sum(0.0, 0.0, 0.0);
+            Vec3d sqsum(0.0, 0.0, 0.0);
+            Vec3i count(0, 0, 0);
 
-            for (int j = thres; j < bgfg::HISTOGRAM_BIN_COUNT; ++j)
+            for (int j = thres; j < fgd::HISTOGRAM_BIN_COUNT; ++j)
             {
                 sum[0]   += static_cast<double>(j) * hist[j];
                 sqsum[0] += static_cast<double>(j * j) * hist[j];
@@ -383,7 +204,7 @@ namespace
             count[1] = std::max(count[1], 1);
             count[2] = std::max(count[2], 1);
 
-            cv::Vec3d my(
+            Vec3d my(
                 sum[0] / count[0],
                 sum[1] / count[1],
                 sum[2] / count[2]
@@ -395,37 +216,39 @@ namespace
         }
     }
 
-    void calcDiffThreshMask(const cv::gpu::GpuMat& prevFrame, const cv::gpu::GpuMat& curFrame, cv::Vec3d bestThres, cv::gpu::GpuMat& changeMask)
+    void calcDiffThreshMask(const GpuMat& prevFrame, const GpuMat& curFrame, Vec3d bestThres, GpuMat& changeMask)
     {
-        typedef void (*func_t)(cv::gpu::PtrStepSzb prevFrame, cv::gpu::PtrStepSzb curFrame, uchar3 bestThres, cv::gpu::PtrStepSzb changeMask, cudaStream_t stream);
+        typedef void (*func_t)(PtrStepSzb prevFrame, PtrStepSzb curFrame, uchar3 bestThres, PtrStepSzb changeMask, cudaStream_t stream);
         static const func_t funcs[4][4] =
         {
             {0,0,0,0},
             {0,0,0,0},
-            {0,0,bgfg::calcDiffThreshMask_gpu<uchar3, uchar3>,bgfg::calcDiffThreshMask_gpu<uchar3, uchar4>},
-            {0,0,bgfg::calcDiffThreshMask_gpu<uchar4, uchar3>,bgfg::calcDiffThreshMask_gpu<uchar4, uchar4>}
+            {0,0,fgd::calcDiffThreshMask_gpu<uchar3, uchar3>,fgd::calcDiffThreshMask_gpu<uchar3, uchar4>},
+            {0,0,fgd::calcDiffThreshMask_gpu<uchar4, uchar3>,fgd::calcDiffThreshMask_gpu<uchar4, uchar4>}
         };
 
-        changeMask.setTo(cv::Scalar::all(0));
+        changeMask.setTo(Scalar::all(0));
 
-        funcs[prevFrame.channels() - 1][curFrame.channels() - 1](prevFrame, curFrame, make_uchar3((uchar)bestThres[0], (uchar)bestThres[1], (uchar)bestThres[2]), changeMask, 0);
+        funcs[prevFrame.channels() - 1][curFrame.channels() - 1](prevFrame, curFrame,
+                                                                 make_uchar3((uchar)bestThres[0], (uchar)bestThres[1], (uchar)bestThres[2]),
+                                                                 changeMask, 0);
     }
 
     // performs change detection for Foreground detection algorithm
-    void changeDetection(const cv::gpu::GpuMat& prevFrame, const cv::gpu::GpuMat& curFrame, cv::gpu::GpuMat& changeMask, cv::gpu::GpuMat& hist, cv::gpu::GpuMat& histBuf)
+    void changeDetection(const GpuMat& prevFrame, const GpuMat& curFrame, GpuMat& changeMask, GpuMat& hist, GpuMat& histBuf)
     {
         calcDiffHistogram(prevFrame, curFrame, hist, histBuf);
 
         unsigned int histData[3 * 256];
-        cv::Mat h_hist(3, 256, CV_32SC1, histData);
+        Mat h_hist(3, 256, CV_32SC1, histData);
         hist.download(h_hist);
 
-        double relativeVariance[3][bgfg::HISTOGRAM_BIN_COUNT];
+        double relativeVariance[3][fgd::HISTOGRAM_BIN_COUNT];
         calcRelativeVariance(histData, relativeVariance);
 
         // Find maximum:
-        cv::Vec3d bestThres(10.0, 10.0, 10.0);
-        for (int i = 0; i < bgfg::HISTOGRAM_BIN_COUNT; ++i)
+        Vec3d bestThres(10.0, 10.0, 10.0);
+        for (int i = 0; i < fgd::HISTOGRAM_BIN_COUNT; ++i)
         {
             bestThres[0] = std::max(bestThres[0], relativeVariance[0][i]);
             bestThres[1] = std::max(bestThres[1], relativeVariance[1][i]);
@@ -441,12 +264,12 @@ namespace
 
 namespace
 {
-    int bgfgClassification(const cv::gpu::GpuMat& prevFrame, const cv::gpu::GpuMat& curFrame,
-                           const cv::gpu::GpuMat& Ftd, const cv::gpu::GpuMat& Fbd,
-                           cv::gpu::GpuMat& foreground, cv::gpu::GpuMat& countBuf,
-                           const cv::gpu::FGDStatModel::Params& params, int out_cn)
+    int bgfgClassification(const GpuMat& prevFrame, const GpuMat& curFrame,
+                           const GpuMat& Ftd, const GpuMat& Fbd,
+                           GpuMat& foreground, GpuMat& countBuf,
+                           const FGDParams& params, int out_cn)
     {
-        typedef void (*func_t)(cv::gpu::PtrStepSzb prevFrame, cv::gpu::PtrStepSzb curFrame, cv::gpu::PtrStepSzb Ftd, cv::gpu::PtrStepSzb Fbd, cv::gpu::PtrStepSzb foreground,
+        typedef void (*func_t)(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground,
                                int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
         static const func_t funcs[4][4][4] =
         {
@@ -458,24 +281,26 @@ namespace
             },
             {
                 {0,0,0,0}, {0,0,0,0},
-                {0,0,bgfg::bgfgClassification_gpu<uchar3, uchar3, uchar3>,bgfg::bgfgClassification_gpu<uchar3, uchar3, uchar4>},
-                {0,0,bgfg::bgfgClassification_gpu<uchar3, uchar4, uchar3>,bgfg::bgfgClassification_gpu<uchar3, uchar4, uchar4>}
+                {0,0,fgd::bgfgClassification_gpu<uchar3, uchar3, uchar3>,fgd::bgfgClassification_gpu<uchar3, uchar3, uchar4>},
+                {0,0,fgd::bgfgClassification_gpu<uchar3, uchar4, uchar3>,fgd::bgfgClassification_gpu<uchar3, uchar4, uchar4>}
             },
             {
                 {0,0,0,0}, {0,0,0,0},
-                {0,0,bgfg::bgfgClassification_gpu<uchar4, uchar3, uchar3>,bgfg::bgfgClassification_gpu<uchar4, uchar3, uchar4>},
-                {0,0,bgfg::bgfgClassification_gpu<uchar4, uchar4, uchar3>,bgfg::bgfgClassification_gpu<uchar4, uchar4, uchar4>}
+                {0,0,fgd::bgfgClassification_gpu<uchar4, uchar3, uchar3>,fgd::bgfgClassification_gpu<uchar4, uchar3, uchar4>},
+                {0,0,fgd::bgfgClassification_gpu<uchar4, uchar4, uchar3>,fgd::bgfgClassification_gpu<uchar4, uchar4, uchar4>}
             }
         };
 
         const int deltaC  = cvRound(params.delta * 256 / params.Lc);
         const int deltaCC = cvRound(params.delta * 256 / params.Lcc);
 
-        funcs[prevFrame.channels() - 1][curFrame.channels() - 1][out_cn - 1](prevFrame, curFrame, Ftd, Fbd, foreground, deltaC, deltaCC, params.alpha2, params.N1c, params.N1cc, 0);
+        funcs[prevFrame.channels() - 1][curFrame.channels() - 1][out_cn - 1](prevFrame, curFrame, Ftd, Fbd, foreground,
+                                                                             deltaC, deltaCC, params.alpha2,
+                                                                             params.N1c, params.N1cc, 0);
 
-        int count = cv::gpu::countNonZero(foreground, countBuf);
+        int count = gpu::countNonZero(foreground, countBuf);
 
-        cv::gpu::multiply(foreground, cv::Scalar::all(255), foreground);
+        gpu::multiply(foreground, Scalar::all(255), foreground);
 
         return count;
     }
@@ -486,20 +311,20 @@ namespace
 
 namespace
 {
-    void morphology(const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst, cv::gpu::GpuMat& filterBrd, int brd, cv::Ptr<cv::gpu::Filter>& filter, cv::Scalar brdVal)
+    void morphology(const GpuMat& src, GpuMat& dst, GpuMat& filterBrd, int brd, Ptr<gpu::Filter>& filter, Scalar brdVal)
     {
-        cv::gpu::copyMakeBorder(src, filterBrd, brd, brd, brd, brd, cv::BORDER_CONSTANT, brdVal);
-        filter->apply(filterBrd(cv::Rect(brd, brd, src.cols, src.rows)), dst);
+        gpu::copyMakeBorder(src, filterBrd, brd, brd, brd, brd, BORDER_CONSTANT, brdVal);
+        filter->apply(filterBrd(Rect(brd, brd, src.cols, src.rows)), dst);
     }
 
-    void smoothForeground(cv::gpu::GpuMat& foreground, cv::gpu::GpuMat& filterBrd, cv::gpu::GpuMat& buf,
-                          cv::Ptr<cv::gpu::Filter>& erodeFilter, cv::Ptr<cv::gpu::Filter>& dilateFilter,
-                          const cv::gpu::FGDStatModel::Params& params)
+    void smoothForeground(GpuMat& foreground, GpuMat& filterBrd, GpuMat& buf,
+                          Ptr<gpu::Filter>& erodeFilter, Ptr<gpu::Filter>& dilateFilter,
+                          const FGDParams& params)
     {
         const int brd = params.perform_morphing;
 
-        const cv::Scalar erodeBrdVal = cv::Scalar::all(UCHAR_MAX);
-        const cv::Scalar dilateBrdVal = cv::Scalar::all(0);
+        const Scalar erodeBrdVal = Scalar::all(UCHAR_MAX);
+        const Scalar dilateBrdVal = Scalar::all(0);
 
         // MORPH_OPEN
         morphology(foreground, buf, filterBrd, brd, erodeFilter, erodeBrdVal);
@@ -516,28 +341,28 @@ namespace
 
 namespace
 {
-    void seqToContours(CvSeq* _ccontours, CvMemStorage* storage, cv::OutputArrayOfArrays _contours)
+    void seqToContours(CvSeq* _ccontours, CvMemStorage* storage, OutputArrayOfArrays _contours)
     {
-        cv::Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
+        Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
 
         size_t total = all_contours.size();
 
         _contours.create((int) total, 1, 0, -1, true);
 
-        cv::SeqIterator<CvSeq*> it = all_contours.begin();
+        SeqIterator<CvSeq*> it = all_contours.begin();
         for (size_t i = 0; i < total; ++i, ++it)
         {
             CvSeq* c = *it;
             ((CvContour*)c)->color = (int)i;
             _contours.create((int)c->total, 1, CV_32SC2, (int)i, true);
-            cv::Mat ci = _contours.getMat((int)i);
+            Mat ci = _contours.getMat((int)i);
             CV_Assert( ci.isContinuous() );
             cvCvtSeqToArray(c, ci.data);
         }
     }
 
-    int findForegroundRegions(cv::gpu::GpuMat& d_foreground, cv::Mat& h_foreground, std::vector< std::vector<cv::Point> >& foreground_regions,
-                              CvMemStorage* storage, const cv::gpu::FGDStatModel::Params& params)
+    int findForegroundRegions(GpuMat& d_foreground, Mat& h_foreground, std::vector< std::vector<Point> >& foreground_regions,
+                              CvMemStorage* storage, const FGDParams& params)
     {
         int region_count = 0;
 
@@ -581,7 +406,7 @@ namespace
         seqToContours(first_seq, storage, foreground_regions);
         h_foreground.setTo(0);
 
-        cv::drawContours(h_foreground, foreground_regions, -1, cv::Scalar::all(255), -1);
+        drawContours(h_foreground, foreground_regions, -1, Scalar::all(255), -1);
 
         d_foreground.upload(h_foreground);
 
@@ -594,12 +419,12 @@ namespace
 
 namespace
 {
-    void updateBackgroundModel(const cv::gpu::GpuMat& prevFrame, const cv::gpu::GpuMat& curFrame, const cv::gpu::GpuMat& Ftd, const cv::gpu::GpuMat& Fbd,
-                               const cv::gpu::GpuMat& foreground, cv::gpu::GpuMat& background,
-                               const cv::gpu::FGDStatModel::Params& params)
+    void updateBackgroundModel(const GpuMat& prevFrame, const GpuMat& curFrame, const GpuMat& Ftd, const GpuMat& Fbd,
+                               const GpuMat& foreground, GpuMat& background,
+                               const FGDParams& params)
     {
-        typedef void (*func_t)(cv::gpu::PtrStepSzb prevFrame, cv::gpu::PtrStepSzb curFrame, cv::gpu::PtrStepSzb Ftd, cv::gpu::PtrStepSzb Fbd,
-                               cv::gpu::PtrStepSzb foreground, cv::gpu::PtrStepSzb background,
+        typedef void (*func_t)(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd,
+                               PtrStepSzb foreground, PtrStepSzb background,
                                int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
         static const func_t funcs[4][4][4] =
         {
@@ -611,13 +436,13 @@ namespace
             },
             {
                 {0,0,0,0}, {0,0,0,0},
-                {0,0,bgfg::updateBackgroundModel_gpu<uchar3, uchar3, uchar3>,bgfg::updateBackgroundModel_gpu<uchar3, uchar3, uchar4>},
-                {0,0,bgfg::updateBackgroundModel_gpu<uchar3, uchar4, uchar3>,bgfg::updateBackgroundModel_gpu<uchar3, uchar4, uchar4>}
+                {0,0,fgd::updateBackgroundModel_gpu<uchar3, uchar3, uchar3>,fgd::updateBackgroundModel_gpu<uchar3, uchar3, uchar4>},
+                {0,0,fgd::updateBackgroundModel_gpu<uchar3, uchar4, uchar3>,fgd::updateBackgroundModel_gpu<uchar3, uchar4, uchar4>}
             },
             {
                 {0,0,0,0}, {0,0,0,0},
-                {0,0,bgfg::updateBackgroundModel_gpu<uchar4, uchar3, uchar3>,bgfg::updateBackgroundModel_gpu<uchar4, uchar3, uchar4>},
-                {0,0,bgfg::updateBackgroundModel_gpu<uchar4, uchar4, uchar3>,bgfg::updateBackgroundModel_gpu<uchar4, uchar4, uchar4>}
+                {0,0,fgd::updateBackgroundModel_gpu<uchar4, uchar3, uchar3>,fgd::updateBackgroundModel_gpu<uchar4, uchar3, uchar4>},
+                {0,0,fgd::updateBackgroundModel_gpu<uchar4, uchar4, uchar3>,fgd::updateBackgroundModel_gpu<uchar4, uchar4, uchar4>}
             }
         };
 
@@ -626,126 +451,271 @@ namespace
 
         funcs[prevFrame.channels() - 1][curFrame.channels() - 1][background.channels() - 1](
                     prevFrame, curFrame, Ftd, Fbd, foreground, background,
-                    deltaC, deltaCC, params.alpha1, params.alpha2, params.alpha3, params.N1c, params.N1cc, params.N2c, params.N2cc, params.T,
+                    deltaC, deltaCC, params.alpha1, params.alpha2, params.alpha3,
+                    params.N1c, params.N1cc, params.N2c, params.N2cc, params.T,
                     0);
     }
 }
 
-/////////////////////////////////////////////////////////////////////////
-// Impl::update
 
-int cv::gpu::FGDStatModel::Impl::update(const cv::gpu::GpuMat& curFrame)
+namespace
 {
-    CV_Assert(curFrame.type() == CV_8UC3 || curFrame.type() == CV_8UC4);
-    CV_Assert(curFrame.size() == prevFrame_.size());
+    class BGPixelStat
+    {
+    public:
+        void create(Size size, const FGDParams& params);
+
+        void setTrained();
+
+        operator fgd::BGPixelStat();
 
-    cvClearMemStorage(storage_);
-    foreground_regions_.clear();
-    foreground_.setTo(cv::Scalar::all(0));
+    private:
+        GpuMat Pbc_;
+        GpuMat Pbcc_;
+        GpuMat is_trained_st_model_;
+        GpuMat is_trained_dyn_model_;
+
+        GpuMat ctable_Pv_;
+        GpuMat ctable_Pvb_;
+        GpuMat ctable_v_;
+
+        GpuMat cctable_Pv_;
+        GpuMat cctable_Pvb_;
+        GpuMat cctable_v1_;
+        GpuMat cctable_v2_;
+    };
 
-    changeDetection(prevFrame_, curFrame, Ftd_, hist_, histBuf_);
-    changeDetection(background_, curFrame, Fbd_, hist_, histBuf_);
+    void BGPixelStat::create(Size size, const FGDParams& params)
+    {
+        gpu::ensureSizeIsEnough(size, CV_32FC1, Pbc_);
+        Pbc_.setTo(Scalar::all(0));
 
-    int FG_pixels_count = bgfgClassification(prevFrame_, curFrame, Ftd_, Fbd_, foreground_, countBuf_, params_, out_cn_);
+        gpu::ensureSizeIsEnough(size, CV_32FC1, Pbcc_);
+        Pbcc_.setTo(Scalar::all(0));
 
-    if (params_.perform_morphing > 0)
-        smoothForeground(foreground_, filterBrd_, buf_, erodeFilter_, dilateFilter_, params_);
+        gpu::ensureSizeIsEnough(size, CV_8UC1, is_trained_st_model_);
+        is_trained_st_model_.setTo(Scalar::all(0));
 
-    int region_count = 0;
-    if (params_.minArea > 0 || params_.is_obj_without_holes)
-        region_count = findForegroundRegions(foreground_, h_foreground_, foreground_regions_, storage_, params_);
+        gpu::ensureSizeIsEnough(size, CV_8UC1, is_trained_dyn_model_);
+        is_trained_dyn_model_.setTo(Scalar::all(0));
 
-    // Check ALL BG update condition:
-    const double BGFG_FGD_BG_UPDATE_TRESH = 0.5;
-    if (static_cast<double>(FG_pixels_count) / Ftd_.size().area() > BGFG_FGD_BG_UPDATE_TRESH)
-        stat_.setTrained();
+        gpu::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_32FC1, ctable_Pv_);
+        ctable_Pv_.setTo(Scalar::all(0));
 
-    updateBackgroundModel(prevFrame_, curFrame, Ftd_, Fbd_, foreground_, background_, params_);
+        gpu::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_32FC1, ctable_Pvb_);
+        ctable_Pvb_.setTo(Scalar::all(0));
 
-    copyChannels(curFrame, prevFrame_);
+        gpu::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_8UC4, ctable_v_);
+        ctable_v_.setTo(Scalar::all(0));
 
-    return region_count;
-}
+        gpu::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_32FC1, cctable_Pv_);
+        cctable_Pv_.setTo(Scalar::all(0));
 
-namespace
-{
-    // Default parameters of foreground detection algorithm:
-    const int BGFG_FGD_LC  = 128;
-    const int BGFG_FGD_N1C = 15;
-    const int BGFG_FGD_N2C = 25;
+        gpu::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_32FC1, cctable_Pvb_);
+        cctable_Pvb_.setTo(Scalar::all(0));
 
-    const int BGFG_FGD_LCC   = 64;
-    const int BGFG_FGD_N1CC = 25;
-    const int BGFG_FGD_N2CC = 40;
+        gpu::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_8UC4, cctable_v1_);
+        cctable_v1_.setTo(Scalar::all(0));
 
-    // Background reference image update parameter:
-    const float BGFG_FGD_ALPHA_1 = 0.1f;
+        gpu::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_8UC4, cctable_v2_);
+        cctable_v2_.setTo(Scalar::all(0));
+    }
 
-    // stat model update parameter
-    // 0.002f ~ 1K frame(~45sec), 0.005 ~ 18sec (if 25fps and absolutely static BG)
-    const float BGFG_FGD_ALPHA_2 = 0.005f;
+    void BGPixelStat::setTrained()
+    {
+        is_trained_st_model_.setTo(Scalar::all(1));
+        is_trained_dyn_model_.setTo(Scalar::all(1));
+    }
 
-    // start value for alpha parameter (to fast initiate statistic model)
-    const float BGFG_FGD_ALPHA_3 = 0.1f;
+    BGPixelStat::operator fgd::BGPixelStat()
+    {
+        fgd::BGPixelStat stat;
 
-    const float BGFG_FGD_DELTA = 2.0f;
+        stat.rows_ = Pbc_.rows;
 
-    const float BGFG_FGD_T = 0.9f;
+        stat.Pbc_data_ = Pbc_.data;
+        stat.Pbc_step_ = Pbc_.step;
 
-    const float BGFG_FGD_MINAREA= 15.0f;
-}
+        stat.Pbcc_data_ = Pbcc_.data;
+        stat.Pbcc_step_ = Pbcc_.step;
 
-cv::gpu::FGDStatModel::Params::Params()
-{
-    Lc      = BGFG_FGD_LC;
-    N1c     = BGFG_FGD_N1C;
-    N2c     = BGFG_FGD_N2C;
+        stat.is_trained_st_model_data_ = is_trained_st_model_.data;
+        stat.is_trained_st_model_step_ = is_trained_st_model_.step;
 
-    Lcc     = BGFG_FGD_LCC;
-    N1cc    = BGFG_FGD_N1CC;
-    N2cc    = BGFG_FGD_N2CC;
+        stat.is_trained_dyn_model_data_ = is_trained_dyn_model_.data;
+        stat.is_trained_dyn_model_step_ = is_trained_dyn_model_.step;
 
-    delta   = BGFG_FGD_DELTA;
+        stat.ctable_Pv_data_ = ctable_Pv_.data;
+        stat.ctable_Pv_step_ = ctable_Pv_.step;
 
-    alpha1  = BGFG_FGD_ALPHA_1;
-    alpha2  = BGFG_FGD_ALPHA_2;
-    alpha3  = BGFG_FGD_ALPHA_3;
+        stat.ctable_Pvb_data_ = ctable_Pvb_.data;
+        stat.ctable_Pvb_step_ = ctable_Pvb_.step;
 
-    T       = BGFG_FGD_T;
-    minArea = BGFG_FGD_MINAREA;
+        stat.ctable_v_data_ = ctable_v_.data;
+        stat.ctable_v_step_ = ctable_v_.step;
 
-    is_obj_without_holes = true;
-    perform_morphing     = 1;
-}
+        stat.cctable_Pv_data_ = cctable_Pv_.data;
+        stat.cctable_Pv_step_ = cctable_Pv_.step;
 
-cv::gpu::FGDStatModel::FGDStatModel(int out_cn)
-{
-    impl_.reset(new Impl(background, foreground, foreground_regions, out_cn));
-}
+        stat.cctable_Pvb_data_ = cctable_Pvb_.data;
+        stat.cctable_Pvb_step_ = cctable_Pvb_.step;
 
-cv::gpu::FGDStatModel::FGDStatModel(const cv::gpu::GpuMat& firstFrame, const Params& params, int out_cn)
-{
-    impl_.reset(new Impl(background, foreground, foreground_regions, out_cn));
-    create(firstFrame, params);
-}
+        stat.cctable_v1_data_ = cctable_v1_.data;
+        stat.cctable_v1_step_ = cctable_v1_.step;
 
-cv::gpu::FGDStatModel::~FGDStatModel()
-{
-}
+        stat.cctable_v2_data_ = cctable_v2_.data;
+        stat.cctable_v2_step_ = cctable_v2_.step;
 
-void cv::gpu::FGDStatModel::create(const cv::gpu::GpuMat& firstFrame, const Params& params)
-{
-    impl_->create(firstFrame, params);
-}
+        return stat;
+    }
 
-void cv::gpu::FGDStatModel::release()
-{
-    impl_->release();
+    class FGDImpl : public gpu::BackgroundSubtractorFGD
+    {
+    public:
+        explicit FGDImpl(const FGDParams& params);
+        ~FGDImpl();
+
+        void apply(InputArray image, OutputArray fgmask, double learningRate=-1);
+
+        void getBackgroundImage(OutputArray backgroundImage) const;
+
+        void getForegroundRegions(OutputArrayOfArrays foreground_regions);
+
+    private:
+        void initialize(const GpuMat& firstFrame);
+
+        FGDParams params_;
+        Size frameSize_;
+
+        GpuMat background_;
+        GpuMat foreground_;
+        std::vector< std::vector<Point> > foreground_regions_;
+
+        Mat h_foreground_;
+
+        GpuMat prevFrame_;
+        GpuMat Ftd_;
+        GpuMat Fbd_;
+        BGPixelStat stat_;
+
+        GpuMat hist_;
+        GpuMat histBuf_;
+
+        GpuMat countBuf_;
+
+        GpuMat buf_;
+        GpuMat filterBrd_;
+
+        Ptr<gpu::Filter> dilateFilter_;
+        Ptr<gpu::Filter> erodeFilter_;
+
+        CvMemStorage* storage_;
+    };
+
+    FGDImpl::FGDImpl(const FGDParams& params) : params_(params), frameSize_(0, 0)
+    {
+        storage_ = cvCreateMemStorage();
+        CV_Assert( storage_ != 0 );
+    }
+
+    FGDImpl::~FGDImpl()
+    {
+        cvReleaseMemStorage(&storage_);
+    }
+
+    void FGDImpl::apply(InputArray _frame, OutputArray fgmask, double)
+    {
+        GpuMat curFrame = _frame.getGpuMat();
+
+        if (curFrame.size() != frameSize_)
+        {
+            initialize(curFrame);
+            return;
+        }
+
+        CV_Assert( curFrame.type() == CV_8UC3 || curFrame.type() == CV_8UC4 );
+        CV_Assert( curFrame.size() == prevFrame_.size() );
+
+        cvClearMemStorage(storage_);
+        foreground_regions_.clear();
+        foreground_.setTo(Scalar::all(0));
+
+        changeDetection(prevFrame_, curFrame, Ftd_, hist_, histBuf_);
+        changeDetection(background_, curFrame, Fbd_, hist_, histBuf_);
+
+        int FG_pixels_count = bgfgClassification(prevFrame_, curFrame, Ftd_, Fbd_, foreground_, countBuf_, params_, 4);
+
+        if (params_.perform_morphing > 0)
+            smoothForeground(foreground_, filterBrd_, buf_, erodeFilter_, dilateFilter_, params_);
+
+        if (params_.minArea > 0 || params_.is_obj_without_holes)
+            findForegroundRegions(foreground_, h_foreground_, foreground_regions_, storage_, params_);
+
+        // Check ALL BG update condition:
+        const double BGFG_FGD_BG_UPDATE_TRESH = 0.5;
+        if (static_cast<double>(FG_pixels_count) / Ftd_.size().area() > BGFG_FGD_BG_UPDATE_TRESH)
+            stat_.setTrained();
+
+        updateBackgroundModel(prevFrame_, curFrame, Ftd_, Fbd_, foreground_, background_, params_);
+
+        copyChannels(curFrame, prevFrame_, 4);
+
+        foreground_.copyTo(fgmask);
+    }
+
+    void FGDImpl::getBackgroundImage(OutputArray backgroundImage) const
+    {
+        gpu::cvtColor(background_, backgroundImage, COLOR_BGRA2BGR);
+    }
+
+    void FGDImpl::getForegroundRegions(OutputArrayOfArrays dst)
+    {
+        size_t total = foreground_regions_.size();
+
+        dst.create((int) total, 1, 0, -1, true);
+
+        for (size_t i = 0; i < total; ++i)
+        {
+            std::vector<Point>& c = foreground_regions_[i];
+
+            dst.create((int) c.size(), 1, CV_32SC2, (int) i, true);
+            Mat ci = dst.getMat((int) i);
+
+            Mat(ci.size(), ci.type(), &c[0]).copyTo(ci);
+        }
+    }
+
+    void FGDImpl::initialize(const GpuMat& firstFrame)
+    {
+        CV_Assert( firstFrame.type() == CV_8UC3 || firstFrame.type() == CV_8UC4 );
+
+        frameSize_ = firstFrame.size();
+
+        gpu::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, foreground_);
+
+        copyChannels(firstFrame, background_, 4);
+        copyChannels(firstFrame, prevFrame_, 4);
+
+        gpu::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, Ftd_);
+        gpu::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, Fbd_);
+
+        stat_.create(firstFrame.size(), params_);
+        fgd::setBGPixelStat(stat_);
+
+        if (params_.perform_morphing > 0)
+        {
+            Mat kernel = getStructuringElement(MORPH_RECT, Size(1 + params_.perform_morphing * 2, 1 + params_.perform_morphing * 2));
+            Point anchor(params_.perform_morphing, params_.perform_morphing);
+
+            dilateFilter_ = gpu::createMorphologyFilter(MORPH_DILATE, CV_8UC1, kernel, anchor);
+            erodeFilter_ = gpu::createMorphologyFilter(MORPH_ERODE, CV_8UC1, kernel, anchor);
+        }
+    }
 }
 
-int cv::gpu::FGDStatModel::update(const cv::gpu::GpuMat& curFrame)
+Ptr<gpu::BackgroundSubtractorFGD> cv::gpu::createBackgroundSubtractorFGD(const FGDParams& params)
 {
-    return impl_->update(curFrame);
+    return new FGDImpl(params);
 }
 
 #endif // HAVE_CUDA
index 41405c9..af2d2ff 100644 (file)
@@ -72,11 +72,10 @@ namespace cv
     }
 }
 
-PARAM_TEST_CASE(FGDStatModel, cv::gpu::DeviceInfo, std::string, Channels)
+PARAM_TEST_CASE(FGDStatModel, cv::gpu::DeviceInfo, std::string)
 {
     cv::gpu::DeviceInfo devInfo;
     std::string inputFile;
-    int out_cn;
 
     virtual void SetUp()
     {
@@ -84,8 +83,6 @@ PARAM_TEST_CASE(FGDStatModel, cv::gpu::DeviceInfo, std::string, Channels)
         cv::gpu::setDevice(devInfo.deviceID());
 
         inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "video/" + GET_PARAM(1);
-
-        out_cn = GET_PARAM(2);
     }
 };
 
@@ -102,15 +99,10 @@ GPU_TEST_P(FGDStatModel, Update)
     cv::Ptr<CvBGStatModel> model(cvCreateFGDStatModel(&ipl_frame));
 
     cv::gpu::GpuMat d_frame(frame);
-    cv::gpu::FGDStatModel d_model(out_cn);
-    d_model.create(d_frame);
-
-    cv::Mat h_background;
-    cv::Mat h_foreground;
-    cv::Mat h_background3;
-
-    cv::Mat backgroundDiff;
-    cv::Mat foregroundDiff;
+    cv::Ptr<cv::gpu::BackgroundSubtractorFGD> d_fgd = cv::gpu::createBackgroundSubtractorFGD();
+    cv::gpu::GpuMat d_foreground, d_background;
+    std::vector< std::vector<cv::Point> > foreground_regions;
+    d_fgd->apply(d_frame, d_foreground);
 
     for (int i = 0; i < 5; ++i)
     {
@@ -121,32 +113,23 @@ GPU_TEST_P(FGDStatModel, Update)
         int gold_count = cvUpdateBGStatModel(&ipl_frame, model);
 
         d_frame.upload(frame);
-
-        int count = d_model.update(d_frame);
-
-        ASSERT_EQ(gold_count, count);
+        d_fgd->apply(d_frame, d_foreground);
+        d_fgd->getBackgroundImage(d_background);
+        d_fgd->getForegroundRegions(foreground_regions);
+        int count = (int) foreground_regions.size();
 
         cv::Mat gold_background = cv::cvarrToMat(model->background);
         cv::Mat gold_foreground = cv::cvarrToMat(model->foreground);
 
-        if (out_cn == 3)
-            d_model.background.download(h_background3);
-        else
-        {
-            d_model.background.download(h_background);
-            cv::cvtColor(h_background, h_background3, cv::COLOR_BGRA2BGR);
-        }
-        d_model.foreground.download(h_foreground);
-
-        ASSERT_MAT_NEAR(gold_background, h_background3, 1.0);
-        ASSERT_MAT_NEAR(gold_foreground, h_foreground, 0.0);
+        ASSERT_MAT_NEAR(gold_background, d_background, 1.0);
+        ASSERT_MAT_NEAR(gold_foreground, d_foreground, 0.0);
+        ASSERT_EQ(gold_count, count);
     }
 }
 
 INSTANTIATE_TEST_CASE_P(GPU_BgSegm, FGDStatModel, testing::Combine(
     ALL_DEVICES,
-    testing::Values(std::string("768x576.avi")),
-    testing::Values(Channels(3), Channels(4))));
+    testing::Values(std::string("768x576.avi"))));
 
 #endif
 
index a9655b2..1b8e532 100644 (file)
@@ -78,7 +78,7 @@ int main(int argc, const char** argv)
     Ptr<BackgroundSubtractor> mog = gpu::createBackgroundSubtractorMOG();
     Ptr<BackgroundSubtractor> mog2 = gpu::createBackgroundSubtractorMOG2();
     Ptr<BackgroundSubtractor> gmg = gpu::createBackgroundSubtractorGMG(40);
-    FGDStatModel fgd_stat;
+    Ptr<BackgroundSubtractor> fgd = gpu::createBackgroundSubtractorFGD();
 
     GpuMat d_fgmask;
     GpuMat d_fgimg;
@@ -103,7 +103,7 @@ int main(int argc, const char** argv)
         break;
 
     case FGD_STAT:
-        fgd_stat.create(d_frame);
+        fgd->apply(d_frame, d_fgmask);
         break;
     }
 
@@ -142,9 +142,8 @@ int main(int argc, const char** argv)
             break;
 
         case FGD_STAT:
-            fgd_stat.update(d_frame);
-            d_fgmask = fgd_stat.foreground;
-            d_bgimg = fgd_stat.background;
+            fgd->apply(d_frame, d_fgmask);
+            fgd->getBackgroundImage(d_bgimg);
             break;
         }
 
index b0217c3..136a4d5 100644 (file)
@@ -1271,14 +1271,14 @@ TEST(FGDStatModel)
 {
     const std::string inputFile = abspath("768x576.avi");
 
-    cv::VideoCapture cap(inputFile);
+    VideoCapture cap(inputFile);
     if (!cap.isOpened()) throw runtime_error("can't open 768x576.avi");
 
-    cv::Mat frame;
+    Mat frame;
     cap >> frame;
 
     IplImage ipl_frame = frame;
-    cv::Ptr<CvBGStatModel> model(cvCreateFGDStatModel(&ipl_frame));
+    Ptr<CvBGStatModel> model(cvCreateFGDStatModel(&ipl_frame));
 
     while (!TestSystem::instance().stop())
     {
@@ -1297,8 +1297,10 @@ TEST(FGDStatModel)
 
     cap >> frame;
 
-    cv::gpu::GpuMat d_frame(frame);
-    cv::gpu::FGDStatModel d_model(d_frame);
+    gpu::GpuMat d_frame(frame), d_fgmask;
+    Ptr<BackgroundSubtractor> d_fgd = gpu::createBackgroundSubtractorFGD();
+
+    d_fgd->apply(d_frame, d_fgmask);
 
     while (!TestSystem::instance().stop())
     {
@@ -1307,7 +1309,7 @@ TEST(FGDStatModel)
 
         TestSystem::instance().gpuOn();
 
-        d_model.update(d_frame);
+        d_fgd->apply(d_frame, d_fgmask);
 
         TestSystem::instance().gpuOff();
     }