Home | History | Annotate | Download | only in src
      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