1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved. 15 // Third party copyrights are property of their respective owners. 16 // 17 // Redistribution and use in source and binary forms, with or without modification, 18 // are permitted provided that the following conditions are met: 19 // 20 // * Redistribution's of source code must retain the above copyright notice, 21 // this list of conditions and the following disclaimer. 22 // 23 // * Redistribution's in binary form must reproduce the above copyright notice, 24 // this list of conditions and the following disclaimer in the documentation 25 // and/or other materials provided with the distribution. 26 // 27 // * The name of the copyright holders may not be used to endorse or promote products 28 // derived from this software without specific prior written permission. 29 // 30 // This software is provided by the copyright holders and contributors "as is" and 31 // any express or implied warranties, including, but not limited to, the implied 32 // warranties of merchantability and fitness for a particular purpose are disclaimed. 33 // In no event shall the Intel Corporation or contributors be liable for any direct, 34 // indirect, incidental, special, exemplary, or consequential damages 35 // (including, but not limited to, procurement of substitute goods or services; 36 // loss of use, data, or profits; or business interruption) however caused 37 // and on any theory of liability, whether in contract, strict liability, 38 // or tort (including negligence or otherwise) arising in any way out of 39 // the use of this software, even if advised of the possibility of such damage. 40 // 41 //M*/ 42 43 #include "precomp.hpp" 44 45 using namespace cv; 46 using namespace cv::cuda; 47 48 #if !defined HAVE_CUDA || defined(CUDA_DISABLER) 49 50 Ptr<cuda::BackgroundSubtractorGMG> cv::cuda::createBackgroundSubtractorGMG(int, double) { throw_no_cuda(); return Ptr<cuda::BackgroundSubtractorGMG>(); } 51 52 #else 53 54 namespace cv { namespace cuda { namespace device { 55 namespace gmg 56 { 57 void loadConstants(int width, int height, float minVal, float maxVal, int quantizationLevels, float backgroundPrior, 58 float decisionThreshold, int maxFeatures, int numInitializationFrames); 59 60 template <typename SrcT> 61 void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, 62 int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); 63 } 64 }}} 65 66 namespace 67 { 68 class GMGImpl : public cuda::BackgroundSubtractorGMG 69 { 70 public: 71 GMGImpl(int initializationFrames, double decisionThreshold); 72 73 void apply(InputArray image, OutputArray fgmask, double learningRate=-1); 74 void apply(InputArray image, OutputArray fgmask, double learningRate, Stream& stream); 75 76 void getBackgroundImage(OutputArray backgroundImage) const; 77 78 int getMaxFeatures() const { return maxFeatures_; } 79 void setMaxFeatures(int maxFeatures) { maxFeatures_ = maxFeatures; } 80 81 double getDefaultLearningRate() const { return learningRate_; } 82 void setDefaultLearningRate(double lr) { learningRate_ = (float) lr; } 83 84 int getNumFrames() const { return numInitializationFrames_; } 85 void setNumFrames(int nframes) { numInitializationFrames_ = nframes; } 86 87 int getQuantizationLevels() const { return quantizationLevels_; } 88 void setQuantizationLevels(int nlevels) { quantizationLevels_ = nlevels; } 89 90 double getBackgroundPrior() const { return backgroundPrior_; } 91 void setBackgroundPrior(double bgprior) { backgroundPrior_ = (float) bgprior; } 92 93 int getSmoothingRadius() const { return smoothingRadius_; } 94 void setSmoothingRadius(int radius) { smoothingRadius_ = radius; } 95 96 double getDecisionThreshold() const { return decisionThreshold_; } 97 void setDecisionThreshold(double thresh) { decisionThreshold_ = (float) thresh; } 98 99 bool getUpdateBackgroundModel() const { return updateBackgroundModel_; } 100 void setUpdateBackgroundModel(bool update) { updateBackgroundModel_ = update; } 101 102 double getMinVal() const { return minVal_; } 103 void setMinVal(double val) { minVal_ = (float) val; } 104 105 double getMaxVal() const { return maxVal_; } 106 void setMaxVal(double val) { maxVal_ = (float) val; } 107 108 private: 109 void initialize(Size frameSize, float min, float max); 110 111 //! Total number of distinct colors to maintain in histogram. 112 int maxFeatures_; 113 114 //! Set between 0.0 and 1.0, determines how quickly features are "forgotten" from histograms. 115 float learningRate_; 116 117 //! Number of frames of video to use to initialize histograms. 118 int numInitializationFrames_; 119 120 //! Number of discrete levels in each channel to be used in histograms. 121 int quantizationLevels_; 122 123 //! Prior probability that any given pixel is a background pixel. A sensitivity parameter. 124 float backgroundPrior_; 125 126 //! Smoothing radius, in pixels, for cleaning up FG image. 127 int smoothingRadius_; 128 129 //! Value above which pixel is determined to be FG. 130 float decisionThreshold_; 131 132 //! Perform background model update. 133 bool updateBackgroundModel_; 134 135 float minVal_, maxVal_; 136 137 Size frameSize_; 138 int frameNum_; 139 140 GpuMat nfeatures_; 141 GpuMat colors_; 142 GpuMat weights_; 143 144 #if defined(HAVE_OPENCV_CUDAFILTERS) && defined(HAVE_OPENCV_CUDAARITHM) 145 Ptr<cuda::Filter> boxFilter_; 146 GpuMat buf_; 147 #endif 148 }; 149 150 GMGImpl::GMGImpl(int initializationFrames, double decisionThreshold) 151 { 152 maxFeatures_ = 64; 153 learningRate_ = 0.025f; 154 numInitializationFrames_ = initializationFrames; 155 quantizationLevels_ = 16; 156 backgroundPrior_ = 0.8f; 157 decisionThreshold_ = (float) decisionThreshold; 158 smoothingRadius_ = 7; 159 updateBackgroundModel_ = true; 160 minVal_ = maxVal_ = 0; 161 } 162 163 void GMGImpl::apply(InputArray image, OutputArray fgmask, double learningRate) 164 { 165 apply(image, fgmask, learningRate, Stream::Null()); 166 } 167 168 void GMGImpl::apply(InputArray _frame, OutputArray _fgmask, double newLearningRate, Stream& stream) 169 { 170 using namespace cv::cuda::device::gmg; 171 172 typedef void (*func_t)(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, 173 int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); 174 static const func_t funcs[6][4] = 175 { 176 {update_gpu<uchar>, 0, update_gpu<uchar3>, update_gpu<uchar4>}, 177 {0,0,0,0}, 178 {update_gpu<ushort>, 0, update_gpu<ushort3>, update_gpu<ushort4>}, 179 {0,0,0,0}, 180 {0,0,0,0}, 181 {update_gpu<float>, 0, update_gpu<float3>, update_gpu<float4>} 182 }; 183 184 GpuMat frame = _frame.getGpuMat(); 185 186 CV_Assert( frame.depth() == CV_8U || frame.depth() == CV_16U || frame.depth() == CV_32F ); 187 CV_Assert( frame.channels() == 1 || frame.channels() == 3 || frame.channels() == 4 ); 188 189 if (newLearningRate != -1.0) 190 { 191 CV_Assert( newLearningRate >= 0.0 && newLearningRate <= 1.0 ); 192 learningRate_ = (float) newLearningRate; 193 } 194 195 if (frame.size() != frameSize_) 196 { 197 double minVal = minVal_; 198 double maxVal = maxVal_; 199 200 if (minVal_ == 0 && maxVal_ == 0) 201 { 202 minVal = 0; 203 maxVal = frame.depth() == CV_8U ? 255.0 : frame.depth() == CV_16U ? std::numeric_limits<ushort>::max() : 1.0; 204 } 205 206 initialize(frame.size(), (float) minVal, (float) maxVal); 207 } 208 209 _fgmask.create(frameSize_, CV_8UC1); 210 GpuMat fgmask = _fgmask.getGpuMat(); 211 212 fgmask.setTo(Scalar::all(0), stream); 213 214 funcs[frame.depth()][frame.channels() - 1](frame, fgmask, colors_, weights_, nfeatures_, frameNum_, 215 learningRate_, updateBackgroundModel_, StreamAccessor::getStream(stream)); 216 217 #if defined(HAVE_OPENCV_CUDAFILTERS) && defined(HAVE_OPENCV_CUDAARITHM) 218 // medianBlur 219 if (smoothingRadius_ > 0) 220 { 221 boxFilter_->apply(fgmask, buf_, stream); 222 const int minCount = (smoothingRadius_ * smoothingRadius_ + 1) / 2; 223 const double thresh = 255.0 * minCount / (smoothingRadius_ * smoothingRadius_); 224 cuda::threshold(buf_, fgmask, thresh, 255.0, THRESH_BINARY, stream); 225 } 226 #endif 227 228 // keep track of how many frames we have processed 229 ++frameNum_; 230 } 231 232 void GMGImpl::getBackgroundImage(OutputArray backgroundImage) const 233 { 234 (void) backgroundImage; 235 CV_Error(Error::StsNotImplemented, "Not implemented"); 236 } 237 238 void GMGImpl::initialize(Size frameSize, float min, float max) 239 { 240 using namespace cv::cuda::device::gmg; 241 242 CV_Assert( maxFeatures_ > 0 ); 243 CV_Assert( learningRate_ >= 0.0f && learningRate_ <= 1.0f); 244 CV_Assert( numInitializationFrames_ >= 1); 245 CV_Assert( quantizationLevels_ >= 1 && quantizationLevels_ <= 255); 246 CV_Assert( backgroundPrior_ >= 0.0f && backgroundPrior_ <= 1.0f); 247 248 minVal_ = min; 249 maxVal_ = max; 250 CV_Assert( minVal_ < maxVal_ ); 251 252 frameSize_ = frameSize; 253 254 frameNum_ = 0; 255 256 nfeatures_.create(frameSize_, CV_32SC1); 257 colors_.create(maxFeatures_ * frameSize_.height, frameSize_.width, CV_32SC1); 258 weights_.create(maxFeatures_ * frameSize_.height, frameSize_.width, CV_32FC1); 259 260 nfeatures_.setTo(Scalar::all(0)); 261 262 #if defined(HAVE_OPENCV_CUDAFILTERS) && defined(HAVE_OPENCV_CUDAARITHM) 263 if (smoothingRadius_ > 0) 264 boxFilter_ = cuda::createBoxFilter(CV_8UC1, -1, Size(smoothingRadius_, smoothingRadius_)); 265 #endif 266 267 loadConstants(frameSize_.width, frameSize_.height, minVal_, maxVal_, 268 quantizationLevels_, backgroundPrior_, decisionThreshold_, maxFeatures_, numInitializationFrames_); 269 } 270 } 271 272 Ptr<cuda::BackgroundSubtractorGMG> cv::cuda::createBackgroundSubtractorGMG(int initializationFrames, double decisionThreshold) 273 { 274 return makePtr<GMGImpl>(initializationFrames, decisionThreshold); 275 } 276 277 #endif 278