Added ocl_Mog2
authorElena Gvozdeva <elena.gvozdeva@itseez.com>
Mon, 27 Jan 2014 13:32:51 +0000 (17:32 +0400)
committerElena Gvozdeva <elena.gvozdeva@itseez.com>
Tue, 28 Jan 2014 12:23:38 +0000 (16:23 +0400)
modules/video/perf/opencl/perf_bgfg_mog2.cpp [new file with mode: 0644]
modules/video/src/bgfg_gaussmix2.cpp
modules/video/src/opencl/bgfg_mog2.cl [new file with mode: 0644]
modules/video/test/ocl/test_bgfg_mog2.cpp [new file with mode: 0644]

diff --git a/modules/video/perf/opencl/perf_bgfg_mog2.cpp b/modules/video/perf/opencl/perf_bgfg_mog2.cpp
new file mode 100644 (file)
index 0000000..b746437
--- /dev/null
@@ -0,0 +1,89 @@
+#include "perf_precomp.hpp"
+#include "opencv2/ts/ocl_perf.hpp"
+
+#ifdef HAVE_OPENCL
+
+#if defined(HAVE_XINE)     || \
+defined(HAVE_GSTREAMER)    || \
+defined(HAVE_QUICKTIME)    || \
+defined(HAVE_AVFOUNDATION) || \
+defined(HAVE_FFMPEG)       || \
+defined(WIN32)
+
+#  define BUILD_WITH_VIDEO_INPUT_SUPPORT 1
+#else
+#  define BUILD_WITH_VIDEO_INPUT_SUPPORT 0
+#endif
+
+#if BUILD_WITH_VIDEO_INPUT_SUPPORT
+
+namespace cvtest {
+namespace ocl {
+
+//////////////////////////// Mog2//////////////////////////
+
+typedef tuple<string, int> VideoMOG2ParamType;
+typedef TestBaseWithParam<VideoMOG2ParamType> MOG2_GetBackgroundImage;
+
+static void cvtFrameFmt(vector<Mat>& input, vector<Mat>& output)
+{
+    for(int i = 0; i< (int)(input.size()); i++)
+    {
+        cvtColor(input[i], output[i], COLOR_RGB2GRAY);
+    }
+}
+
+static void prepareData(VideoCapture& cap, int cn, vector<Mat>& frame_buffer)
+{
+    cv::Mat frame;
+    std::vector<Mat> frame_buffer_init;
+    int nFrame = (int)frame_buffer.size();
+    for(int i = 0; i < nFrame; i++)
+    {
+        cap >> frame;
+        ASSERT_FALSE(frame.empty());
+        frame_buffer_init.push_back(frame);
+    }
+
+    if(cn == 1)
+        cvtFrameFmt(frame_buffer_init, frame_buffer);
+    else
+        frame_buffer = frame_buffer_init;
+}
+
+OCL_PERF_TEST_P(MOG2_GetBackgroundImage, Mog2, Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), Values(1,3)))
+{
+    VideoMOG2ParamType params = GetParam();
+
+    const string inputFile = getDataPath(get<0>(params));
+
+    const int cn = get<1>(params);
+    int nFrame = 5;
+
+    vector<Mat> frame_buffer(nFrame);
+
+    cv::VideoCapture cap(inputFile);
+    ASSERT_TRUE(cap.isOpened());
+    prepareData(cap, cn, frame_buffer);
+
+    UMat u_foreground, u_background;
+
+    OCL_TEST_CYCLE()
+    {
+        Ptr<cv::BackgroundSubtractorMOG2> mog2 = createBackgroundSubtractorMOG2();
+        mog2->setDetectShadows(false);
+        u_foreground.release();
+        u_background.release();
+        for (int i = 0; i < nFrame; i++)
+        {
+            mog2->apply(frame_buffer[i], u_foreground);
+        }
+        mog2->getBackgroundImage(u_background);
+    }
+    SANITY_CHECK(u_background);
+}
+
+}}// namespace cvtest::ocl
+
+    #endif
+#endif
\ No newline at end of file
index 485e34d..cfdce37 100644 (file)
@@ -83,6 +83,7 @@
 ///////////*/
 
 #include "precomp.hpp"
+#include "opencl_kernels.hpp"
 
 namespace cv
 {
@@ -141,6 +142,8 @@ public:
         fCT = defaultfCT2;
         nShadowDetection =  defaultnShadowDetection2;
         fTau = defaultfTau;
+
+        opencl_ON = true;
     }
     //! the full constructor that takes the length of the history,
     // the number of gaussian mixtures, the background ratio parameter and the noise strength
@@ -165,6 +168,8 @@ public:
         nShadowDetection =  defaultnShadowDetection2;
         fTau = defaultfTau;
         name_ = "BackgroundSubtractor.MOG2";
+
+        opencl_ON = true;
     }
     //! the destructor
     ~BackgroundSubtractorMOG2Impl() {}
@@ -184,14 +189,44 @@ public:
         int nchannels = CV_MAT_CN(frameType);
         CV_Assert( nchannels <= CV_CN_MAX );
 
-        // for each gaussian mixture of each pixel bg model we store ...
-        // the mixture weight (w),
-        // the mean (nchannels values) and
-        // the covariance
-        bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + nchannels), CV_32F );
-        //make the array for keeping track of the used modes per pixel - all zeros at start
-        bgmodelUsedModes.create(frameSize,CV_8U);
-        bgmodelUsedModes = Scalar::all(0);
+        if (ocl::useOpenCL() && opencl_ON)
+        {
+            kernel_apply.create("mog2_kernel", ocl::video::bgfg_mog2_oclsrc, format("-D CN=%d -D NMIXTURES=%d", nchannels, nmixtures));
+            kernel_getBg.create("getBackgroundImage2_kernel", ocl::video::bgfg_mog2_oclsrc, format( "-D CN=%d -D NMIXTURES=%d", nchannels, nmixtures));
+
+            if (kernel_apply.empty() || kernel_getBg.empty())
+                opencl_ON = false;
+        }
+        else opencl_ON = false;
+
+        if (opencl_ON)
+        {
+            u_weight.create(frameSize.height * nmixtures, frameSize.width, CV_32FC1);
+            u_weight.setTo(Scalar::all(0));
+
+            u_variance.create(frameSize.height * nmixtures, frameSize.width, CV_32FC1);
+            u_variance.setTo(Scalar::all(0));
+
+            if (nchannels==3)
+                nchannels=4;
+            u_mean.create(frameSize.height * nmixtures, frameSize.width, CV_32FC(nchannels)); //4 channels
+            u_mean.setTo(Scalar::all(0));
+
+            //make the array for keeping track of the used modes per pixel - all zeros at start
+            u_bgmodelUsedModes.create(frameSize, CV_32FC1);
+            u_bgmodelUsedModes.setTo(cv::Scalar::all(0));
+        }
+        else
+        {
+            // for each gaussian mixture of each pixel bg model we store ...
+            // the mixture weight (w),
+            // the mean (nchannels values) and
+            // the covariance
+            bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + nchannels), CV_32F );
+            //make the array for keeping track of the used modes per pixel - all zeros at start
+            bgmodelUsedModes.create(frameSize,CV_8U);
+            bgmodelUsedModes = Scalar::all(0);
+        }
     }
 
     virtual AlgorithmInfo* info() const { return 0; }
@@ -271,6 +306,19 @@ protected:
     int frameType;
     Mat bgmodel;
     Mat bgmodelUsedModes;//keep track of number of modes per pixel
+
+    //for OCL
+
+    mutable bool opencl_ON;
+
+    UMat u_weight;
+    UMat u_variance;
+    UMat u_mean;
+    UMat u_bgmodelUsedModes;
+
+    mutable ocl::Kernel kernel_apply;
+    mutable ocl::Kernel kernel_getBg;
+
     int nframes;
     int history;
     int nmixtures;
@@ -321,6 +369,9 @@ protected:
     //See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
 
     String name_;
+
+    bool ocl_getBackgroundImage(OutputArray backgroundImage) const;
+    bool ocl_apply(InputArray _image, OutputArray _fgmask,  bool  needToInitialize, double learningRate=-1);
 };
 
 struct GaussBGStatModel2Params
@@ -685,14 +736,78 @@ public:
     uchar shadowVal;
 };
 
+bool BackgroundSubtractorMOG2Impl::ocl_apply(InputArray _image, OutputArray _fgmask, bool  needToInitialize, double learningRate)
+{
+    ++nframes;
+    learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( 2*nframes, history );
+    CV_Assert(learningRate >= 0);
+
+    UMat fgmask(_image.size(), CV_32SC1);
+
+    fgmask.setTo(cv::Scalar::all(1));
+
+    const float alpha1 = 1.0f - learningRate;
+
+    int detectShadows_flag = 0;
+    if(bShadowDetection)
+        detectShadows_flag = 1;
+
+    UMat frame = _image.getUMat();
+
+    float varMax = MAX(fVarMin, fVarMax);
+    float varMin = MIN(fVarMin, fVarMax);
+
+    int idxArg = 0;
+    idxArg = kernel_apply.set(idxArg, ocl::KernelArg::ReadOnly(frame));
+    idxArg = kernel_apply.set(idxArg, ocl::KernelArg::ReadWriteNoSize(u_bgmodelUsedModes));
+    idxArg = kernel_apply.set(idxArg, ocl::KernelArg::ReadWriteNoSize(u_weight));
+    idxArg = kernel_apply.set(idxArg, ocl::KernelArg::ReadWriteNoSize(u_mean));
+    idxArg = kernel_apply.set(idxArg, ocl::KernelArg::ReadWriteNoSize(u_variance));
+    idxArg = kernel_apply.set(idxArg, ocl::KernelArg::WriteOnlyNoSize(fgmask));
+
+    idxArg = kernel_apply.set(idxArg, (float)learningRate);        //alphaT
+    idxArg = kernel_apply.set(idxArg, (float)alpha1);
+    idxArg = kernel_apply.set(idxArg, (float)(-learningRate*fCT));   //prune
+    idxArg = kernel_apply.set(idxArg, detectShadows_flag);
+
+    idxArg = kernel_apply.set(idxArg, (float)varThreshold); //c_Tb
+    idxArg = kernel_apply.set(idxArg, backgroundRatio);     //c_TB
+    idxArg = kernel_apply.set(idxArg, varThresholdGen);     //c_Tg
+    idxArg = kernel_apply.set(idxArg, varMin);
+    idxArg = kernel_apply.set(idxArg, varMax);
+    idxArg = kernel_apply.set(idxArg, fVarInit);
+    idxArg = kernel_apply.set(idxArg, fTau);
+    idxArg = kernel_apply.set(idxArg, nShadowDetection);
+
+    size_t globalsize[] = {frame.cols, frame.rows, 1};
+
+    if (!(kernel_apply.run(2, globalsize, NULL, true)))
+        return false;
+
+    _fgmask.create(_image.size(),CV_8U);
+    UMat temp = _fgmask.getUMat();
+    fgmask.convertTo(temp, CV_8U);
+
+    return true;
+}
+
 void BackgroundSubtractorMOG2Impl::apply(InputArray _image, OutputArray _fgmask, double learningRate)
 {
-    Mat image = _image.getMat();
-    bool needToInitialize = nframes == 0 || learningRate >= 1 || image.size() != frameSize || image.type() != frameType;
+    bool needToInitialize = nframes == 0 || learningRate >= 1 || _image.size() != frameSize || _image.type() != frameType;
 
     if( needToInitialize )
-        initialize(image.size(), image.type());
+        initialize(_image.size(), _image.type());
 
+    if (opencl_ON)
+    {
+        if (ocl_apply(_image,_fgmask, needToInitialize, learningRate))
+            return;
+        else
+            initialize(_image.size(), _image.type());
+    }
+    opencl_ON = false;
+
+    Mat image = _image.getMat();
     _fgmask.create( image.size(), CV_8U );
     Mat fgmask = _fgmask.getMat();
 
@@ -712,8 +827,36 @@ void BackgroundSubtractorMOG2Impl::apply(InputArray _image, OutputArray _fgmask,
                               image.total()/(double)(1 << 16));
 }
 
+bool BackgroundSubtractorMOG2Impl::ocl_getBackgroundImage(OutputArray _backgroundImage) const
+{
+    CV_Assert(frameType == CV_8UC1 || frameType == CV_8UC3);
+
+    _backgroundImage.create(frameSize, frameType);
+    UMat dst = _backgroundImage.getUMat();
+
+    int idxArg = 0;
+    idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::ReadOnly(u_bgmodelUsedModes));
+    idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::ReadOnlyNoSize(u_weight));
+    idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::ReadOnlyNoSize(u_mean));
+    idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::WriteOnlyNoSize(dst));
+    idxArg = kernel_getBg.set(idxArg, backgroundRatio);
+
+    size_t globalsize[2] = {u_bgmodelUsedModes.cols, u_bgmodelUsedModes.rows};
+
+    return kernel_getBg.run(2, globalsize, NULL, false);
+}
+
 void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImage) const
 {
+    if (opencl_ON)
+    {
+        if (ocl_getBackgroundImage(backgroundImage));
+            return;
+        
+        opencl_ON = false;
+        return;
+    }
+
     int nchannels = CV_MAT_CN(frameType);
     CV_Assert( nchannels == 3 );
     Mat meanBackground(frameSize, CV_8UC3, Scalar::all(0));
@@ -765,7 +908,6 @@ void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImag
     }
 }
 
-
 Ptr<BackgroundSubtractorMOG2> createBackgroundSubtractorMOG2(int _history, double _varThreshold,
                                                              bool _bShadowDetection)
 {
@@ -774,4 +916,4 @@ Ptr<BackgroundSubtractorMOG2> createBackgroundSubtractorMOG2(int _history, doubl
 
 }
 
-/* End of file. */
+/* End of file. */
\ No newline at end of file
diff --git a/modules/video/src/opencl/bgfg_mog2.cl b/modules/video/src/opencl/bgfg_mog2.cl
new file mode 100644 (file)
index 0000000..6ae278b
--- /dev/null
@@ -0,0 +1,272 @@
+#if CN==1
+
+#define T_MEAN float
+#define F_ZERO (0.0f)
+#define cnMode 1
+
+#define frameToMean(a, b) (b) = *(a);
+#define meanToFrame(a, b) *b = convert_uchar_sat(a);
+
+inline float sqr(float val)
+{
+    return val * val;
+}
+
+inline float sum(float val)
+{
+    return val;
+}
+
+#else
+
+#define T_MEAN float4
+#define F_ZERO (0.0f, 0.0f, 0.0f, 0.0f)
+#define cnMode 4
+
+#define meanToFrame(a, b)\
+    b[0] = convert_uchar_sat(a.x); \
+    b[1] = convert_uchar_sat(a.y); \
+    b[2] = convert_uchar_sat(a.z);
+
+#define frameToMean(a, b)\
+    b.x = a[0]; \
+    b.y = a[1]; \
+    b.z = a[2]; \
+    b.w = 0.0f;
+
+inline float sqr(const float4 val)
+{
+    return val.x * val.x + val.y * val.y + val.z * val.z;
+}
+
+inline float sum(const float4 val)
+{
+    return (val.x + val.y + val.z);
+}
+
+inline void swap4(__global float4* ptr, int x, int y, int k, int rows, int ptr_step)
+{
+    float4 val = ptr[(k * rows + y) * ptr_step + x];
+    ptr[(k * rows + y) * ptr_step + x] = ptr[((k + 1) * rows + y) * ptr_step + x];
+    ptr[((k + 1) * rows + y) * ptr_step + x] = val;
+}
+
+#endif
+
+inline void swap(__global float* ptr, int x, int y, int k, int rows, int ptr_step)
+{
+    float val = ptr[(k * rows + y) * ptr_step + x];
+    ptr[(k * rows + y) * ptr_step + x] = ptr[((k + 1) * rows + y) * ptr_step + x];
+    ptr[((k + 1) * rows + y) * ptr_step + x] = val;
+}
+
+__kernel void mog2_kernel(__global const uchar* frame, int frame_step, int frame_offset, int frame_row, int frame_col, //uchar || uchar3
+                          __global uchar* modesUsed, int modesUsed_step, int modesUsed_offset,                         //int
+                          __global uchar* weight, int weight_step, int weight_offset,                                  //float
+                          __global uchar* mean, int mean_step, int mean_offset,                                        //T_MEAN=float || float4
+                          __global uchar* variance, int var_step, int var_offset,                                      //float
+                          __global uchar* fgmask, int fgmask_step, int fgmask_offset,                                  //int
+                          float alphaT, float alpha1, float prune,
+                          int detectShadows_flag, 
+                          float c_Tb, float c_TB, float c_Tg, float c_varMin,                     //constants
+                          float c_varMax, float c_varInit, float c_tau, uchar c_shadowVal)
+{
+    int x = get_global_id(0);
+    int y = get_global_id(1);
+
+    weight_step/= sizeof(float);
+    var_step   /= sizeof(float);
+    mean_step  /= (sizeof(float)*cnMode);
+
+    if( x < frame_col && y < frame_row)
+    {
+        __global const uchar* _frame = (frame + mad24( y, frame_step, x*CN + frame_offset));
+        T_MEAN pix;
+        frameToMean(_frame, pix);
+
+        bool background = false; // true - the pixel classified as background
+
+        bool fitsPDF = false; //if it remains zero a new GMM mode will be added
+
+        __global int* _modesUsed = (__global int*)(modesUsed + mad24( y, modesUsed_step, x*(int)(sizeof(int))));
+        int nmodes = _modesUsed[0];
+        int nNewModes = nmodes; //current number of modes in GMM
+
+        float totalWeight = 0.0f;
+
+        __global float* _weight = (__global float*)(weight);
+        __global float* _variance = (__global float*)(variance);
+        __global T_MEAN* _mean = (__global T_MEAN*)(mean);
+
+        for (int mode = 0; mode < nmodes; ++mode)
+        {
+
+            float c_weight = alpha1 * _weight[(mode * frame_row + y) * weight_step + x] + prune;
+
+            if (!fitsPDF)
+            {
+                float c_var = _variance[(mode * frame_row + y) * var_step + x];
+
+                T_MEAN c_mean = _mean[(mode * frame_row + y) * mean_step + x];
+
+                T_MEAN diff = c_mean - pix;
+                float dist2 = sqr(diff);
+
+                if (totalWeight < c_TB && dist2 < c_Tb * c_var)
+                    background = true;
+
+                if (dist2 < c_Tg * c_var)
+                {
+                    fitsPDF = true;
+                    c_weight += alphaT;
+                    float k = alphaT / c_weight;
+
+                    _mean[(mode * frame_row + y) * mean_step + x] = c_mean - k * diff;
+
+                    float varnew = c_var + k * (dist2 - c_var);
+                    varnew = fmax(varnew, c_varMin);
+                    varnew = fmin(varnew, c_varMax);
+
+                    _variance[(mode * frame_row + y) * var_step + x] = varnew;
+                    for (int i = mode; i > 0; --i)
+                    {
+                        if (c_weight < _weight[((i - 1) * frame_row + y) * weight_step + x])
+                            break;
+                        swap(_weight, x, y, i - 1, frame_row, weight_step);
+                        swap(_variance, x, y, i - 1, frame_row, var_step);
+                        #if (CN==1)
+                        swap(_mean, x, y, i - 1, frame_row, mean_step);
+                        #else
+                        swap4(_mean, x, y, i - 1, frame_row, mean_step);
+                        #endif
+                    }
+                }
+            } // !fitsPDF
+
+            if (c_weight < -prune)
+            {
+                c_weight = 0.0f;
+                nmodes--;
+            }
+
+            _weight[(mode * frame_row + y) * weight_step + x] = c_weight; //update weight by the calculated value
+            totalWeight += c_weight;
+        }
+
+        totalWeight = 1.f / totalWeight;
+        for (int mode = 0; mode < nmodes; ++mode)
+            _weight[(mode * frame_row + y) * weight_step + x] *= totalWeight;
+
+        nmodes = nNewModes;
+
+        if (!fitsPDF)
+        {
+            int mode = nmodes == (NMIXTURES) ? (NMIXTURES) - 1 : nmodes++;
+
+            if (nmodes == 1)
+                _weight[(mode * frame_row + y) * weight_step + x] = 1.f;
+            else
+            {
+                _weight[(mode * frame_row + y) * weight_step + x] = alphaT;
+
+                for (int i = 0; i < nmodes - 1; ++i)
+                    _weight[(i * frame_row + y) * weight_step + x] *= alpha1;
+            }
+
+            _mean[(mode * frame_row + y) * mean_step + x] = pix;
+            _variance[(mode * frame_row + y) * var_step + x] = c_varInit;
+
+            for (int i = nmodes - 1; i > 0; --i)
+            {
+                if (alphaT < _weight[((i - 1) * frame_row + y) * weight_step + x])
+                    break;
+
+                swap(_weight, x, y, i - 1, frame_row, weight_step);
+                swap(_variance, x, y, i - 1, frame_row, var_step);
+                #if (CN==1)
+                swap(_mean, x, y, i - 1, frame_row, mean_step);
+                #else
+                swap4(_mean, x, y, i - 1, frame_row, mean_step);
+                #endif
+            }
+        }
+
+        _modesUsed[0] = nmodes;
+        bool isShadow = false;
+        if (detectShadows_flag && !background)
+        {
+            float tWeight = 0.0f;
+
+            for (int mode = 0; mode < nmodes; ++mode)
+            {
+                T_MEAN c_mean = _mean[(mode * frame_row + y) * mean_step + x];
+
+                T_MEAN pix_mean = pix * c_mean;
+
+                float numerator = sum(pix_mean);
+                float denominator = sqr(c_mean);
+
+                if (denominator == 0)
+                    break;
+
+                if (numerator <= denominator && numerator >= c_tau * denominator)
+                {
+                    float a = numerator / denominator;
+
+                    T_MEAN dD = a * c_mean - pix;
+
+                    if (sqr(dD) < c_Tb * _variance[(mode * frame_row + y) * var_step + x] * a * a)
+                    {
+                        isShadow = true;
+                        break;
+                    }
+                }
+
+                tWeight += _weight[(mode * frame_row + y) * weight_step + x];
+                if (tWeight > c_TB)
+                    break;
+            }
+        }
+        __global int* _fgmask = (__global int*)(fgmask + mad24(y, fgmask_step, x*(int)(sizeof(int)) + fgmask_offset));
+        *_fgmask = background ? 0 : isShadow ? c_shadowVal : 255;
+    }
+}
+
+__kernel void getBackgroundImage2_kernel(__global const uchar* modesUsed, int modesUsed_step, int modesUsed_offset, int modesUsed_row, int modesUsed_col,
+                                         __global const uchar* weight, int weight_step, int weight_offset,
+                                         __global const uchar* mean, int mean_step, int mean_offset,
+                                         __global uchar* dst, int dst_step, int dst_offset,
+                                         float c_TB)
+{
+    int x = get_global_id(0);
+    int y = get_global_id(1);
+
+    if(x < modesUsed_col && y < modesUsed_row)
+    {
+        __global int* _modesUsed = (__global int*)(modesUsed + mad24( y, modesUsed_step, x*(int)(sizeof(int))));
+        int nmodes = _modesUsed[0];
+
+        T_MEAN meanVal = (T_MEAN)F_ZERO;
+
+        float totalWeight = 0.0f;
+
+        for (int mode = 0; mode < nmodes; ++mode)
+        {
+            __global const float* _weight = (__global const float*)(weight + mad24(mode * modesUsed_row + y, weight_step, x*(int)(sizeof(float))));
+            float c_weight = _weight[0];
+
+            __global const T_MEAN* _mean = (__global const T_MEAN*)(mean + mad24(mode * modesUsed_row + y, mean_step, x*(int)(sizeof(float))*cnMode));
+            T_MEAN c_mean = _mean[0];
+            meanVal = meanVal + c_weight * c_mean;
+
+            totalWeight += c_weight;
+
+            if(totalWeight > c_TB)
+                break;
+        }
+
+        meanVal = meanVal * (1.f / totalWeight);
+        __global uchar* _dst = dst + y * dst_step + x*CN + dst_offset;
+        meanToFrame(meanVal, _dst);
+    }
+}
\ No newline at end of file
diff --git a/modules/video/test/ocl/test_bgfg_mog2.cpp b/modules/video/test/ocl/test_bgfg_mog2.cpp
new file mode 100644 (file)
index 0000000..a0d811b
--- /dev/null
@@ -0,0 +1,125 @@
+#include "test_precomp.hpp"
+#include "opencv2/ts/ocl_test.hpp"
+
+#ifdef HAVE_OPENCL
+
+#if defined(HAVE_XINE)     || \
+defined(HAVE_GSTREAMER)    || \
+defined(HAVE_QUICKTIME)    || \
+defined(HAVE_AVFOUNDATION) || \
+defined(HAVE_FFMPEG)       || \
+defined(WIN32)
+
+#  define BUILD_WITH_VIDEO_INPUT_SUPPORT 1
+#else
+#  define BUILD_WITH_VIDEO_INPUT_SUPPORT 0
+#endif
+
+#if BUILD_WITH_VIDEO_INPUT_SUPPORT
+
+namespace cvtest {
+namespace ocl {
+
+////////////////////////// MOG2///////////////////////////////////
+
+namespace
+{
+    IMPLEMENT_PARAM_CLASS(UseGray, bool)
+    IMPLEMENT_PARAM_CLASS(DetectShadow, bool)
+}
+
+PARAM_TEST_CASE(Mog2, UseGray, DetectShadow, bool)
+{
+    bool useGray;
+    bool detectShadow;
+    bool useRoi;
+    virtual void SetUp()
+    {
+        useGray = GET_PARAM(0);
+        detectShadow = GET_PARAM(1);
+        useRoi = GET_PARAM(2);
+    }
+};
+
+OCL_TEST_P(Mog2, Update)
+{
+    string inputFile = string(TS::ptr()->get_data_path()) + "video/768x576.avi";
+    VideoCapture cap(inputFile);
+    ASSERT_TRUE(cap.isOpened());
+
+    Ptr<BackgroundSubtractorMOG2> mog2_cpu = createBackgroundSubtractorMOG2();
+    Ptr<BackgroundSubtractorMOG2> mog2_ocl = createBackgroundSubtractorMOG2();
+
+    mog2_cpu->setDetectShadows(detectShadow);
+    mog2_ocl->setDetectShadows(detectShadow);
+
+    Mat frame, foreground;
+    UMat u_foreground;
+
+    for (int i = 0; i < 10; ++i)
+    {
+        cap >> frame;
+        ASSERT_FALSE(frame.empty());
+
+        if (useGray)
+        {
+            Mat temp;
+            cvtColor(frame, temp, COLOR_BGR2GRAY);
+            swap(temp, frame);
+        }
+
+        OCL_OFF(mog2_cpu->apply(frame, foreground));
+        OCL_ON (mog2_ocl->apply(frame, u_foreground));
+
+        if (detectShadow)
+            EXPECT_MAT_SIMILAR(foreground, u_foreground, 15e-3)
+        else
+            EXPECT_MAT_NEAR(foreground, u_foreground, 0);
+    }
+}
+
+OCL_TEST_P(Mog2, getBackgroundImage)
+{
+    if (useGray)
+        return;
+
+    string inputFile = string(TS::ptr()->get_data_path()) + "video/768x576.avi";
+    VideoCapture cap(inputFile);
+    ASSERT_TRUE(cap.isOpened());
+
+    Ptr<BackgroundSubtractorMOG2> mog2_cpu = createBackgroundSubtractorMOG2();
+    Ptr<BackgroundSubtractorMOG2> mog2_ocl = createBackgroundSubtractorMOG2();
+
+    mog2_cpu->setDetectShadows(detectShadow);
+    mog2_ocl->setDetectShadows(detectShadow);
+
+    Mat frame, foreground;
+    UMat u_foreground;
+
+    for (int i = 0; i < 10; ++i)
+    {
+        cap >> frame;
+        ASSERT_FALSE(frame.empty());
+
+        OCL_OFF(mog2_cpu->apply(frame, foreground));
+        OCL_ON (mog2_ocl->apply(frame, u_foreground));
+    }
+
+    Mat background;
+    OCL_OFF(mog2_cpu->getBackgroundImage(background));
+
+    UMat u_background;
+    OCL_ON (mog2_ocl->getBackgroundImage(u_background));
+
+    EXPECT_MAT_NEAR(background, u_background, 1.0);
+}
+
+OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2, Combine(
+                                    Values(UseGray(true), UseGray(false)),
+                                    Values(DetectShadow(true), DetectShadow(false)),
+                                    Bool())
+                           );
+}}// namespace cvtest::ocl
+
+    #endif
+#endif