Loading modules/cudabgsegm/src/cuda/mog2.cu +280 −301 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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) Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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; Loading @@ -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)); Loading @@ -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 { Loading @@ -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()); Loading @@ -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; Loading @@ -397,7 +376,7 @@ namespace cv { namespace cuda { namespace device totalWeight += weight; if(totalWeight > c_TB) if (totalWeight > constants->TB_) break; } Loading @@ -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 */ modules/cudabgsegm/src/cuda/mog2.hpp 0 → 100644 +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 */ modules/cudabgsegm/src/mog2.cpp +176 −178 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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; Loading @@ -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; } Loading @@ -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_; Loading @@ -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) Loading @@ -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(); Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading Loading
modules/cudabgsegm/src/cuda/mog2.cu +280 −301 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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) Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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; Loading @@ -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)); Loading @@ -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 { Loading @@ -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()); Loading @@ -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; Loading @@ -397,7 +376,7 @@ namespace cv { namespace cuda { namespace device totalWeight += weight; if(totalWeight > c_TB) if (totalWeight > constants->TB_) break; } Loading @@ -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 */
modules/cudabgsegm/src/cuda/mog2.hpp 0 → 100644 +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 */
modules/cudabgsegm/src/mog2.cpp +176 −178 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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; Loading @@ -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; } Loading @@ -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_; Loading @@ -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) Loading @@ -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(); Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading