Commit 65abc709 authored by Alexander Alekhin's avatar Alexander Alekhin
Browse files

Merge moved code from opencv/3.4

parents f9bbe706 12ffd7f0
Loading
Loading
Loading
Loading
+280 −301
Original line number Diff line number Diff line
@@ -47,7 +47,13 @@
#include "opencv2/core/cuda/vec_math.hpp"
#include "opencv2/core/cuda/limits.hpp"

namespace cv { namespace cuda { namespace device
#include "mog2.hpp"

namespace cv
{
namespace cuda
{
namespace device
{
namespace mog2
{
@@ -104,43 +110,16 @@ namespace cv { namespace cuda { namespace device
///////////////////////////////////////////////////////////////
// MOG2

        __constant__ int           c_nmixtures;
        __constant__ float         c_Tb;
        __constant__ float         c_TB;
        __constant__ float         c_Tg;
        __constant__ float         c_varInit;
        __constant__ float         c_varMin;
        __constant__ float         c_varMax;
        __constant__ float         c_tau;
        __constant__ unsigned char c_shadowVal;

        void loadConstants(int nmixtures, float Tb, float TB, float Tg, float varInit, float varMin, float varMax, float tau, unsigned char shadowVal)
        {
            varMin = ::fminf(varMin, varMax);
            varMax = ::fmaxf(varMin, varMax);

            cudaSafeCall( cudaMemcpyToSymbol(c_nmixtures, &nmixtures, sizeof(int)) );
            cudaSafeCall( cudaMemcpyToSymbol(c_Tb, &Tb, sizeof(float)) );
            cudaSafeCall( cudaMemcpyToSymbol(c_TB, &TB, sizeof(float)) );
            cudaSafeCall( cudaMemcpyToSymbol(c_Tg, &Tg, sizeof(float)) );
            cudaSafeCall( cudaMemcpyToSymbol(c_varInit, &varInit, sizeof(float)) );
            cudaSafeCall( cudaMemcpyToSymbol(c_varMin, &varMin, sizeof(float)) );
            cudaSafeCall( cudaMemcpyToSymbol(c_varMax, &varMax, sizeof(float)) );
            cudaSafeCall( cudaMemcpyToSymbol(c_tau, &tau, sizeof(float)) );
            cudaSafeCall( cudaMemcpyToSymbol(c_shadowVal, &shadowVal, sizeof(unsigned char)) );
        }

template <bool detectShadows, typename SrcT, typename WorkT>
__global__ void mog2(const PtrStepSz<SrcT> frame, PtrStepb fgmask, PtrStepb modesUsed,
                     PtrStepf gmm_weight, PtrStepf gmm_variance, PtrStep<WorkT> gmm_mean,
                             const float alphaT, const float alpha1, const float prune)
                     const float alphaT, const float alpha1, const float prune, const Constants *const constants)
{
    const int x = blockIdx.x * blockDim.x + threadIdx.x;
    const int y = blockIdx.y * blockDim.y + threadIdx.y;

            if (x >= frame.cols || y >= frame.rows)
                return;

    if (x < frame.cols && y < frame.rows)
    {
        WorkT pix = cvt(frame(y, x));

        //calculate distances to the modes (+ sort)
@@ -153,7 +132,7 @@ namespace cv { namespace cuda { namespace device
        bool fitsPDF = false; //if it remains zero a new GMM mode will be added

        int nmodes = modesUsed(y, x);
            int nNewModes = nmodes; //current number of modes in GMM
        const int nNewModes = nmodes; //current number of modes in GMM

        float totalWeight = 0.0f;

@@ -168,20 +147,20 @@ namespace cv { namespace cuda { namespace device
            if (!fitsPDF)
            {
                //check if it belongs to some of the remaining modes
                    float var = gmm_variance(mode * frame.rows + y, x);
                const float var = gmm_variance(mode * frame.rows + y, x);

                    WorkT mean = gmm_mean(mode * frame.rows + y, x);
                const WorkT mean = gmm_mean(mode * frame.rows + y, x);

                //calculate difference and distance
                    WorkT diff = mean - pix;
                    float dist2 = sqr(diff);
                const WorkT diff = mean - pix;
                const float dist2 = sqr(diff);

                //background? - Tb - usually larger than Tg
                    if (totalWeight < c_TB && dist2 < c_Tb * var)
                if (totalWeight < constants->TB_ && dist2 < constants->Tb_ * var)
                    background = true;

                //check fit
                    if (dist2 < c_Tg * var)
                if (dist2 < constants->Tg_ * var)
                {
                    //belongs to the mode
                    fitsPDF = true;
@@ -199,8 +178,8 @@ namespace cv { namespace cuda { namespace device
                    float varnew = var + k * (dist2 - var);

                    //limit the variance
                        varnew = ::fmaxf(varnew, c_varMin);
                        varnew = ::fminf(varnew, c_varMax);
                    varnew = ::fmaxf(varnew, constants->varMin_);
                    varnew = ::fminf(varnew, constants->varMax_);

                    gmm_variance(mode * frame.rows + y, x) = varnew;

@@ -249,7 +228,7 @@ namespace cv { namespace cuda { namespace device
        if (!fitsPDF)
        {
            // replace the weakest or add a new one
                int mode = nmodes == c_nmixtures ? c_nmixtures - 1 : nmodes++;
            const int mode = nmodes == constants->nmixtures_ ? constants->nmixtures_ - 1 : nmodes++;

            if (nmodes == 1)
                gmm_weight(mode * frame.rows + y, x) = 1.f;
@@ -266,7 +245,7 @@ namespace cv { namespace cuda { namespace device
            // init

            gmm_mean(mode * frame.rows + y, x) = pix;
                gmm_variance(mode * frame.rows + y, x) = c_varInit;
            gmm_variance(mode * frame.rows + y, x) = constants->varInit_;

            //sort
            //find the new place for it
@@ -295,25 +274,25 @@ namespace cv { namespace cuda { namespace device
            // check all the components  marked as background:
            for (int mode = 0; mode < nmodes; ++mode)
            {
                    WorkT mean = gmm_mean(mode * frame.rows + y, x);
                const WorkT mean = gmm_mean(mode * frame.rows + y, x);

                    WorkT pix_mean = pix * mean;
                const WorkT pix_mean = pix * mean;

                    float numerator = sum(pix_mean);
                    float denominator = sqr(mean);
                const float numerator = sum(pix_mean);
                const float denominator = sqr(mean);

                // no division by zero allowed
                if (denominator == 0)
                    break;

                // if tau < a < 1 then also check the color distortion
                    if (numerator <= denominator && numerator >= c_tau * denominator)
                else if (numerator <= denominator && numerator >= constants->tau_ * denominator)
                {
                        float a = numerator / denominator;
                    const float a = numerator / denominator;

                    WorkT dD = a * mean - pix;

                        if (sqr(dD) < c_Tb * gmm_variance(mode * frame.rows + y, x) * a * a)
                    if (sqr(dD) < constants->Tb_ * gmm_variance(mode * frame.rows + y, x) * a * a)
                    {
                        isShadow = true;
                        break;
@@ -321,17 +300,18 @@ namespace cv { namespace cuda { namespace device
                };

                tWeight += gmm_weight(mode * frame.rows + y, x);
                    if (tWeight > c_TB)
                if (tWeight > constants->TB_)
                    break;
            }
        }

            fgmask(y, x) = background ? 0 : isShadow ? c_shadowVal : 255;
        fgmask(y, x) = background ? 0 : isShadow ? constants->shadowVal_ : 255;
    }
}

template <typename SrcT, typename WorkT>
void mog2_caller(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean,
                         float alphaT, float prune, bool detectShadows, cudaStream_t stream)
                 float alphaT, float prune, bool detectShadows, const Constants *const constants, cudaStream_t stream)
{
    dim3 block(32, 8);
    dim3 grid(divUp(frame.cols, block.x), divUp(frame.rows, block.y));
@@ -344,7 +324,7 @@ namespace cv { namespace cuda { namespace device

        mog2<true, SrcT, WorkT><<<grid, block, 0, stream>>>((PtrStepSz<SrcT>)frame, fgmask, modesUsed,
                                                            weight, variance, (PtrStepSz<WorkT>)mean,
                                                                    alphaT, alpha1, prune);
                                                            alphaT, alpha1, prune, constants);
    }
    else
    {
@@ -352,7 +332,7 @@ namespace cv { namespace cuda { namespace device

        mog2<false, SrcT, WorkT><<<grid, block, 0, stream>>>((PtrStepSz<SrcT>)frame, fgmask, modesUsed,
                                                             weight, variance, (PtrStepSz<WorkT>)mean,
                                                                    alphaT, alpha1, prune);
                                                             alphaT, alpha1, prune, constants);
    }

    cudaSafeCall(cudaGetLastError());
@@ -362,20 +342,19 @@ namespace cv { namespace cuda { namespace device
}

void mog2_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean,
                      float alphaT, float prune, bool detectShadows, cudaStream_t stream)
              float alphaT, float prune, bool detectShadows, const Constants *const constants, cudaStream_t stream)
{
            typedef void (*func_t)(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream);
    typedef void (*func_t)(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, const Constants *const constants, cudaStream_t stream);

    static const func_t funcs[] =
        {
                0, mog2_caller<uchar, float>, 0, mog2_caller<uchar3, float3>, mog2_caller<uchar4, float4>
            };
            0, mog2_caller<uchar, float>, 0, mog2_caller<uchar3, float3>, mog2_caller<uchar4, float4>};

            funcs[cn](frame, fgmask, modesUsed, weight, variance, mean, alphaT, prune, detectShadows, stream);
    funcs[cn](frame, fgmask, modesUsed, weight, variance, mean, alphaT, prune, detectShadows, constants, stream);
}

template <typename WorkT, typename OutT>
        __global__ void getBackgroundImage2(const PtrStepSzb modesUsed, const PtrStepf gmm_weight, const PtrStep<WorkT> gmm_mean, PtrStep<OutT> dst)
__global__ void getBackgroundImage2(const PtrStepSzb modesUsed, const PtrStepf gmm_weight, const PtrStep<WorkT> gmm_mean, PtrStep<OutT> dst, const Constants *const constants)
{
    const int x = blockIdx.x * blockDim.x + threadIdx.x;
    const int y = blockIdx.y * blockDim.y + threadIdx.y;
@@ -397,7 +376,7 @@ namespace cv { namespace cuda { namespace device

        totalWeight += weight;

                if(totalWeight > c_TB)
        if (totalWeight > constants->TB_)
            break;
    }

@@ -407,33 +386,33 @@ namespace cv { namespace cuda { namespace device
}

template <typename WorkT, typename OutT>
        void getBackgroundImage2_caller(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream)
void getBackgroundImage2_caller(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, const Constants *const constants, cudaStream_t stream)
{
    dim3 block(32, 8);
    dim3 grid(divUp(modesUsed.cols, block.x), divUp(modesUsed.rows, block.y));

    cudaSafeCall(cudaFuncSetCacheConfig(getBackgroundImage2<WorkT, OutT>, cudaFuncCachePreferL1));

            getBackgroundImage2<WorkT, OutT><<<grid, block, 0, stream>>>(modesUsed, weight, (PtrStepSz<WorkT>) mean, (PtrStepSz<OutT>) dst);
    getBackgroundImage2<WorkT, OutT><<<grid, block, 0, stream>>>(modesUsed, weight, (PtrStepSz<WorkT>)mean, (PtrStepSz<OutT>)dst, constants);
    cudaSafeCall(cudaGetLastError());

    if (stream == 0)
        cudaSafeCall(cudaDeviceSynchronize());
}

        void getBackgroundImage2_gpu(int cn, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream)
void getBackgroundImage2_gpu(int cn, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, const Constants *const constants, cudaStream_t stream)
{
            typedef void (*func_t)(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream);
    typedef void (*func_t)(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, const Constants *const constants, cudaStream_t stream);

    static const func_t funcs[] =
        {
                0, getBackgroundImage2_caller<float, uchar>, 0, getBackgroundImage2_caller<float3, uchar3>, getBackgroundImage2_caller<float4, uchar4>
            };
            0, getBackgroundImage2_caller<float, uchar>, 0, getBackgroundImage2_caller<float3, uchar3>, getBackgroundImage2_caller<float4, uchar4>};

            funcs[cn](modesUsed, weight, mean, dst, stream);
        }
    funcs[cn](modesUsed, weight, mean, dst, constants, stream);
}
}}}

} // namespace mog2
} // namespace device
} // namespace cuda
} // namespace cv

#endif /* CUDA_DISABLER */
+37 −0
Original line number Diff line number Diff line
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.

#ifndef OPENCV_CUDA_MOG2_H
#define OPENCV_CUDA_MOG2_H

#include "opencv2/core/cuda.hpp"

struct CUstream_st;
typedef struct CUstream_st *cudaStream_t;

namespace cv { namespace cuda {

class Stream;

namespace device { namespace mog2 {

typedef struct
{
    float Tb_;
    float TB_;
    float Tg_;
    float varInit_;
    float varMin_;
    float varMax_;
    float tau_;
    int nmixtures_;
    unsigned char shadowVal_;
} Constants;

void mog2_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, const Constants *const constants, cudaStream_t stream);
void getBackgroundImage2_gpu(int cn, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, const Constants *const constants, cudaStream_t stream);

} } } }

#endif /* OPENCV_CUDA_MOG2_H */
+176 −178
Original line number Diff line number Diff line
@@ -41,25 +41,21 @@
//M*/

#include "precomp.hpp"
#include "cuda/mog2.hpp"

using namespace cv;
using namespace cv::cuda;
using namespace cv::cuda::device::mog2;

#if !defined HAVE_CUDA || defined(CUDA_DISABLER)

Ptr<cuda::BackgroundSubtractorMOG2> cv::cuda::createBackgroundSubtractorMOG2(int, double, bool) { throw_no_cuda(); return Ptr<cuda::BackgroundSubtractorMOG2>(); }

#else

namespace cv { namespace cuda { namespace device
{
    namespace mog2
Ptr<cuda::BackgroundSubtractorMOG2> cv::cuda::createBackgroundSubtractorMOG2(int, double, bool)
{
        void loadConstants(int nmixtures, float Tb, float TB, float Tg, float varInit, float varMin, float varMax, float tau, unsigned char shadowVal);
        void mog2_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream);
        void getBackgroundImage2_gpu(int cn, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream);
    throw_no_cuda();
    return Ptr<cuda::BackgroundSubtractorMOG2>();
}
}}}

#else

namespace
{
@@ -82,6 +78,7 @@ namespace
{
public:
    MOG2Impl(int history, double varThreshold, bool detectShadows);
    ~MOG2Impl();

    void apply(InputArray image, OutputArray fgmask, double learningRate = -1) CV_OVERRIDE;
    void apply(InputArray image, OutputArray fgmask, double learningRate, Stream &stream) CV_OVERRIDE;
@@ -92,26 +89,26 @@ namespace
    int getHistory() const CV_OVERRIDE { return history_; }
    void setHistory(int history) CV_OVERRIDE { history_ = history; }

        int getNMixtures() const CV_OVERRIDE { return nmixtures_; }
        void setNMixtures(int nmixtures) CV_OVERRIDE { nmixtures_ = nmixtures; }
    int getNMixtures() const CV_OVERRIDE { return constantsHost_.nmixtures_; }
    void setNMixtures(int nmixtures) CV_OVERRIDE { constantsHost_.nmixtures_ = nmixtures; }

        double getBackgroundRatio() const CV_OVERRIDE { return backgroundRatio_; }
        void setBackgroundRatio(double ratio) CV_OVERRIDE { backgroundRatio_ = (float) ratio; }
    double getBackgroundRatio() const CV_OVERRIDE { return constantsHost_.TB_; }
    void setBackgroundRatio(double ratio) CV_OVERRIDE { constantsHost_.TB_ = (float)ratio; }

        double getVarThreshold() const CV_OVERRIDE { return varThreshold_; }
        void setVarThreshold(double varThreshold) CV_OVERRIDE { varThreshold_ = (float) varThreshold; }
    double getVarThreshold() const CV_OVERRIDE { return constantsHost_.Tb_; }
    void setVarThreshold(double varThreshold) CV_OVERRIDE { constantsHost_.Tb_ = (float)varThreshold; }

        double getVarThresholdGen() const CV_OVERRIDE { return varThresholdGen_; }
        void setVarThresholdGen(double varThresholdGen) CV_OVERRIDE { varThresholdGen_ = (float) varThresholdGen; }
    double getVarThresholdGen() const CV_OVERRIDE { return constantsHost_.Tg_; }
    void setVarThresholdGen(double varThresholdGen) CV_OVERRIDE { constantsHost_.Tg_ = (float)varThresholdGen; }

        double getVarInit() const CV_OVERRIDE { return varInit_; }
        void setVarInit(double varInit) CV_OVERRIDE { varInit_ = (float) varInit; }
    double getVarInit() const CV_OVERRIDE { return constantsHost_.varInit_; }
    void setVarInit(double varInit) CV_OVERRIDE { constantsHost_.varInit_ = (float)varInit; }

        double getVarMin() const CV_OVERRIDE { return varMin_; }
        void setVarMin(double varMin) CV_OVERRIDE { varMin_ = (float) varMin; }
    double getVarMin() const CV_OVERRIDE { return constantsHost_.varMin_; }
    void setVarMin(double varMin) CV_OVERRIDE { constantsHost_.varMin_ = ::fminf((float)varMin, constantsHost_.varMax_); }

        double getVarMax() const CV_OVERRIDE { return varMax_; }
        void setVarMax(double varMax) CV_OVERRIDE { varMax_ = (float) varMax; }
    double getVarMax() const CV_OVERRIDE { return constantsHost_.varMax_; }
    void setVarMax(double varMax) CV_OVERRIDE { constantsHost_.varMax_ = ::fmaxf(constantsHost_.varMin_, (float)varMax); }

    double getComplexityReductionThreshold() const CV_OVERRIDE { return ct_; }
    void setComplexityReductionThreshold(double ct) CV_OVERRIDE { ct_ = (float)ct; }
@@ -119,27 +116,21 @@ namespace
    bool getDetectShadows() const CV_OVERRIDE { return detectShadows_; }
    void setDetectShadows(bool detectShadows) CV_OVERRIDE { detectShadows_ = detectShadows; }

        int getShadowValue() const CV_OVERRIDE { return shadowValue_; }
        void setShadowValue(int value) CV_OVERRIDE { shadowValue_ = (uchar) value; }
    int getShadowValue() const CV_OVERRIDE { return constantsHost_.shadowVal_; }
    void setShadowValue(int value) CV_OVERRIDE { constantsHost_.shadowVal_ = (uchar)value; }

        double getShadowThreshold() const CV_OVERRIDE { return shadowThreshold_; }
        void setShadowThreshold(double threshold) CV_OVERRIDE { shadowThreshold_ = (float) threshold; }
    double getShadowThreshold() const CV_OVERRIDE { return constantsHost_.tau_; }
    void setShadowThreshold(double threshold) CV_OVERRIDE { constantsHost_.tau_ = (float)threshold; }

private:
        void initialize(Size frameSize, int frameType);
    void initialize(Size frameSize, int frameType, Stream &stream);

    Constants constantsHost_;
    Constants *constantsDevice_;

    int history_;
        int nmixtures_;
        float backgroundRatio_;
        float varThreshold_;
        float varThresholdGen_;
        float varInit_;
        float varMin_;
        float varMax_;
    float ct_;
    bool detectShadows_;
        uchar shadowValue_;
        float shadowThreshold_;

    Size frameSize_;
    int frameType_;
@@ -153,22 +144,29 @@ namespace
    GpuMat bgmodelUsedModes_;
};

    MOG2Impl::MOG2Impl(int history, double varThreshold, bool detectShadows) :
        frameSize_(0, 0), frameType_(0), nframes_(0)
MOG2Impl::MOG2Impl(int history, double varThreshold, bool detectShadows) : frameSize_(0, 0), frameType_(0), nframes_(0)
{
    history_ = history > 0 ? history : defaultHistory;
        varThreshold_ = varThreshold > 0 ? (float) varThreshold : defaultVarThreshold;
    detectShadows_ = detectShadows;

        nmixtures_ = defaultNMixtures;
        backgroundRatio_ = defaultBackgroundRatio;
        varInit_ = defaultVarInit;
        varMax_ = defaultVarMax;
        varMin_ = defaultVarMin;
        varThresholdGen_ = defaultVarThresholdGen;
    ct_ = defaultCT;
        shadowValue_ =  defaultShadowValue;
        shadowThreshold_ = defaultShadowThreshold;

    setNMixtures(defaultNMixtures);
    setBackgroundRatio(defaultBackgroundRatio);
    setVarInit(defaultVarInit);
    setVarMin(defaultVarMin);
    setVarMax(defaultVarMax);
    setVarThreshold(varThreshold > 0 ? (float)varThreshold : defaultVarThreshold);
    setVarThresholdGen(defaultVarThresholdGen);

    setShadowValue(defaultShadowValue);
    setShadowThreshold(defaultShadowThreshold);

    cudaSafeCall(cudaMalloc((void **)&constantsDevice_, sizeof(Constants)));
}

MOG2Impl::~MOG2Impl()
{
    cudaFree(constantsDevice_);
}

void MOG2Impl::apply(InputArray image, OutputArray fgmask, double learningRate)
@@ -186,7 +184,7 @@ namespace
    int work_ch = ch;

    if (nframes_ == 0 || learningRate >= 1.0 || frame.size() != frameSize_ || work_ch != mean_.channels())
            initialize(frame.size(), frame.type());
        initialize(frame.size(), frame.type(), stream);

    _fgmask.create(frameSize_, CV_8UC1);
    GpuMat fgmask = _fgmask.getGpuMat();
@@ -198,7 +196,7 @@ namespace
    CV_Assert(learningRate >= 0);

    mog2_gpu(frame, frame.channels(), fgmask, bgmodelUsedModes_, weight_, variance_, mean_,
                 (float) learningRate, static_cast<float>(-learningRate * ct_), detectShadows_, StreamAccessor::getStream(stream));
             (float)learningRate, static_cast<float>(-learningRate * ct_), detectShadows_, constantsDevice_, StreamAccessor::getStream(stream));
}

void MOG2Impl::getBackgroundImage(OutputArray backgroundImage) const
@@ -213,10 +211,10 @@ namespace
    _backgroundImage.create(frameSize_, frameType_);
    GpuMat backgroundImage = _backgroundImage.getGpuMat();

        getBackgroundImage2_gpu(backgroundImage.channels(), bgmodelUsedModes_, weight_, mean_, backgroundImage, StreamAccessor::getStream(stream));
    getBackgroundImage2_gpu(backgroundImage.channels(), bgmodelUsedModes_, weight_, mean_, backgroundImage, constantsDevice_, StreamAccessor::getStream(stream));
}

    void MOG2Impl::initialize(cv::Size frameSize, int frameType)
void MOG2Impl::initialize(cv::Size frameSize, int frameType, Stream &stream)
{
    using namespace cv::cuda::device::mog2;

@@ -226,24 +224,24 @@ namespace
    frameType_ = frameType;
    nframes_ = 0;

        int ch = CV_MAT_CN(frameType);
        int work_ch = ch;
    const int ch = CV_MAT_CN(frameType);
    const int work_ch = ch;

    // for each gaussian mixture of each pixel bg model we store ...
    // the mixture weight (w),
    // the mean (nchannels values) and
    // the covariance
        weight_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC1);
        variance_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC1);
        mean_.create(frameSize.height * nmixtures_, frameSize_.width, CV_32FC(work_ch));
    weight_.create(frameSize.height * getNMixtures(), frameSize_.width, CV_32FC1);
    variance_.create(frameSize.height * getNMixtures(), frameSize_.width, CV_32FC1);
    mean_.create(frameSize.height * getNMixtures(), frameSize_.width, CV_32FC(work_ch));

    //make the array for keeping track of the used modes per pixel - all zeros at start
    bgmodelUsedModes_.create(frameSize_, CV_8UC1);
    bgmodelUsedModes_.setTo(Scalar::all(0));

        loadConstants(nmixtures_, varThreshold_, backgroundRatio_, varThresholdGen_, varInit_, varMin_, varMax_, shadowThreshold_, shadowValue_);
    }
    cudaSafeCall(cudaMemcpyAsync(constantsDevice_, &constantsHost_, sizeof(Constants), cudaMemcpyHostToDevice, StreamAccessor::getStream(stream)));
}
} // namespace

Ptr<cuda::BackgroundSubtractorMOG2> cv::cuda::createBackgroundSubtractorMOG2(int history, double varThreshold, bool detectShadows)
{