gmg.cpp 10.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

V
Vladislav Vinogradov 已提交
45 46
using namespace cv;
using namespace cv::gpu;
47

48
#if !defined HAVE_CUDA || defined(CUDA_DISABLER)
V
Vladislav Vinogradov 已提交
49 50

Ptr<gpu::BackgroundSubtractorGMG> cv::gpu::createBackgroundSubtractorGMG(int, double) { throw_no_cuda(); return Ptr<gpu::BackgroundSubtractorGMG>(); }
51 52 53

#else

54
namespace cv { namespace gpu { namespace cudev {
V
Vladislav Vinogradov 已提交
55
    namespace gmg
56 57 58 59 60
    {
        void loadConstants(int width, int height, float minVal, float maxVal, int quantizationLevels, float backgroundPrior,
                           float decisionThreshold, int maxFeatures, int numInitializationFrames);

        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
    }
}}}

V
Vladislav Vinogradov 已提交
66
namespace
67
{
V
Vladislav Vinogradov 已提交
68 69 70 71
    class GMGImpl : public gpu::BackgroundSubtractorGMG
    {
    public:
        GMGImpl(int initializationFrames, double decisionThreshold);
72

V
Vladislav Vinogradov 已提交
73 74
        void apply(InputArray image, OutputArray fgmask, double learningRate=-1);
        void apply(InputArray image, OutputArray fgmask, double learningRate, Stream& stream);
75

V
Vladislav Vinogradov 已提交
76
        void getBackgroundImage(OutputArray backgroundImage) const;
77

V
Vladislav Vinogradov 已提交
78 79
        int getMaxFeatures() const { return maxFeatures_; }
        void setMaxFeatures(int maxFeatures) { maxFeatures_ = maxFeatures; }
80

V
Vladislav Vinogradov 已提交
81 82
        double getDefaultLearningRate() const { return learningRate_; }
        void setDefaultLearningRate(double lr) { learningRate_ = (float) lr; }
83

V
Vladislav Vinogradov 已提交
84 85
        int getNumFrames() const { return numInitializationFrames_; }
        void setNumFrames(int nframes) { numInitializationFrames_ = nframes; }
86

V
Vladislav Vinogradov 已提交
87 88
        int getQuantizationLevels() const { return quantizationLevels_; }
        void setQuantizationLevels(int nlevels) { quantizationLevels_ = nlevels; }
89

V
Vladislav Vinogradov 已提交
90 91
        double getBackgroundPrior() const { return backgroundPrior_; }
        void setBackgroundPrior(double bgprior) { backgroundPrior_ = (float) bgprior; }
92

V
Vladislav Vinogradov 已提交
93 94
        int getSmoothingRadius() const { return smoothingRadius_; }
        void setSmoothingRadius(int radius) { smoothingRadius_ = radius; }
95

V
Vladislav Vinogradov 已提交
96 97
        double getDecisionThreshold() const { return decisionThreshold_; }
        void setDecisionThreshold(double thresh) { decisionThreshold_ = (float) thresh; }
98

V
Vladislav Vinogradov 已提交
99 100
        bool getUpdateBackgroundModel() const { return updateBackgroundModel_; }
        void setUpdateBackgroundModel(bool update) { updateBackgroundModel_ = update; }
101

V
Vladislav Vinogradov 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
        double getMinVal() const { return minVal_; }
        void setMinVal(double val) { minVal_ = (float) val; }

        double getMaxVal() const { return maxVal_; }
        void setMaxVal(double val) { maxVal_ = (float) val; }

    private:
        void initialize(Size frameSize, float min, float max);

        //! Total number of distinct colors to maintain in histogram.
        int maxFeatures_;

        //! Set between 0.0 and 1.0, determines how quickly features are "forgotten" from histograms.
        float learningRate_;

        //! Number of frames of video to use to initialize histograms.
        int numInitializationFrames_;

        //! Number of discrete levels in each channel to be used in histograms.
        int quantizationLevels_;

        //! Prior probability that any given pixel is a background pixel. A sensitivity parameter.
        float backgroundPrior_;

        //! Smoothing radius, in pixels, for cleaning up FG image.
        int smoothingRadius_;

        //! Value above which pixel is determined to be FG.
        float decisionThreshold_;

        //! Perform background model update.
        bool updateBackgroundModel_;

        float minVal_, maxVal_;

        Size frameSize_;
        int frameNum_;

        GpuMat nfeatures_;
        GpuMat colors_;
        GpuMat weights_;

144
#if defined(HAVE_OPENCV_GPUFILTERS) && defined(HAVE_OPENCV_GPUARITHM)
V
Vladislav Vinogradov 已提交
145 146
        Ptr<gpu::Filter> boxFilter_;
        GpuMat buf_;
147
#endif
148 149
    };

V
Vladislav Vinogradov 已提交
150 151 152 153 154 155 156 157 158 159 160 161
    GMGImpl::GMGImpl(int initializationFrames, double decisionThreshold)
    {
        maxFeatures_ = 64;
        learningRate_ = 0.025f;
        numInitializationFrames_ = initializationFrames;
        quantizationLevels_ = 16;
        backgroundPrior_ = 0.8f;
        decisionThreshold_ = (float) decisionThreshold;
        smoothingRadius_ = 7;
        updateBackgroundModel_ = true;
        minVal_ = maxVal_ = 0;
    }
162

V
Vladislav Vinogradov 已提交
163
    void GMGImpl::apply(InputArray image, OutputArray fgmask, double learningRate)
164
    {
V
Vladislav Vinogradov 已提交
165
        apply(image, fgmask, learningRate, Stream::Null());
166 167
    }

V
Vladislav Vinogradov 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
    void GMGImpl::apply(InputArray _frame, OutputArray _fgmask, double newLearningRate, Stream& stream)
    {
        using namespace cv::gpu::cudev::gmg;

        typedef void (*func_t)(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures,
                               int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
        static const func_t funcs[6][4] =
        {
            {update_gpu<uchar>, 0, update_gpu<uchar3>, update_gpu<uchar4>},
            {0,0,0,0},
            {update_gpu<ushort>, 0, update_gpu<ushort3>, update_gpu<ushort4>},
            {0,0,0,0},
            {0,0,0,0},
            {update_gpu<float>, 0, update_gpu<float3>, update_gpu<float4>}
        };

        GpuMat frame = _frame.getGpuMat();

        CV_Assert( frame.depth() == CV_8U || frame.depth() == CV_16U || frame.depth() == CV_32F );
        CV_Assert( frame.channels() == 1 || frame.channels() == 3 || frame.channels() == 4 );

        if (newLearningRate != -1.0)
        {
            CV_Assert( newLearningRate >= 0.0 && newLearningRate <= 1.0 );
            learningRate_ = (float) newLearningRate;
        }

        if (frame.size() != frameSize_)
        {
            double minVal = minVal_;
            double maxVal = maxVal_;
199

V
Vladislav Vinogradov 已提交
200 201 202 203 204
            if (minVal_ == 0 && maxVal_ == 0)
            {
                minVal = 0;
                maxVal = frame.depth() == CV_8U ? 255.0 : frame.depth() == CV_16U ? std::numeric_limits<ushort>::max() : 1.0;
            }
205

V
Vladislav Vinogradov 已提交
206 207 208 209 210 211 212 213 214 215 216
            initialize(frame.size(), (float) minVal, (float) maxVal);
        }

        _fgmask.create(frameSize_, CV_8UC1);
        GpuMat fgmask = _fgmask.getGpuMat();

        fgmask.setTo(Scalar::all(0), stream);

        funcs[frame.depth()][frame.channels() - 1](frame, fgmask, colors_, weights_, nfeatures_, frameNum_,
                                                   learningRate_, updateBackgroundModel_, StreamAccessor::getStream(stream));

217
#if defined(HAVE_OPENCV_GPUFILTERS) && defined(HAVE_OPENCV_GPUARITHM)
V
Vladislav Vinogradov 已提交
218 219 220 221 222 223 224 225
        // medianBlur
        if (smoothingRadius_ > 0)
        {
            boxFilter_->apply(fgmask, buf_, stream);
            const int minCount = (smoothingRadius_ * smoothingRadius_ + 1) / 2;
            const double thresh = 255.0 * minCount / (smoothingRadius_ * smoothingRadius_);
            gpu::threshold(buf_, fgmask, thresh, 255.0, THRESH_BINARY, stream);
        }
226
#endif
V
Vladislav Vinogradov 已提交
227 228 229 230

        // keep track of how many frames we have processed
        ++frameNum_;
    }
231

V
Vladislav Vinogradov 已提交
232
    void GMGImpl::getBackgroundImage(OutputArray backgroundImage) const
233
    {
V
Vladislav Vinogradov 已提交
234 235
        (void) backgroundImage;
        CV_Error(Error::StsNotImplemented, "Not implemented");
236
    }
237

V
Vladislav Vinogradov 已提交
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
    void GMGImpl::initialize(Size frameSize, float min, float max)
    {
        using namespace cv::gpu::cudev::gmg;

        CV_Assert( maxFeatures_ > 0 );
        CV_Assert( learningRate_ >= 0.0f && learningRate_ <= 1.0f);
        CV_Assert( numInitializationFrames_ >= 1);
        CV_Assert( quantizationLevels_ >= 1 && quantizationLevels_ <= 255);
        CV_Assert( backgroundPrior_ >= 0.0f && backgroundPrior_ <= 1.0f);

        minVal_ = min;
        maxVal_ = max;
        CV_Assert( minVal_ < maxVal_ );

        frameSize_ = frameSize;

        frameNum_ = 0;

        nfeatures_.create(frameSize_, CV_32SC1);
        colors_.create(maxFeatures_ * frameSize_.height, frameSize_.width, CV_32SC1);
        weights_.create(maxFeatures_ * frameSize_.height, frameSize_.width, CV_32FC1);

        nfeatures_.setTo(Scalar::all(0));

262
#if defined(HAVE_OPENCV_GPUFILTERS) && defined(HAVE_OPENCV_GPUARITHM)
V
Vladislav Vinogradov 已提交
263 264
        if (smoothingRadius_ > 0)
            boxFilter_ = gpu::createBoxFilter(CV_8UC1, -1, Size(smoothingRadius_, smoothingRadius_));
265
#endif
V
Vladislav Vinogradov 已提交
266 267 268 269

        loadConstants(frameSize_.width, frameSize_.height, minVal_, maxVal_,
                      quantizationLevels_, backgroundPrior_, decisionThreshold_, maxFeatures_, numInitializationFrames_);
    }
270 271
}

V
Vladislav Vinogradov 已提交
272
Ptr<gpu::BackgroundSubtractorGMG> cv::gpu::createBackgroundSubtractorGMG(int initializationFrames, double decisionThreshold)
273
{
V
Vladislav Vinogradov 已提交
274
    return new GMGImpl(initializationFrames, decisionThreshold);
275 276
}

277
#endif