mog2.cpp 10.3 KB
Newer Older
V
Vladislav Vinogradov 已提交
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 47
using namespace cv;
using namespace cv::gpu;

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

V
Vladislav Vinogradov 已提交
50
Ptr<gpu::BackgroundSubtractorMOG2> cv::gpu::createBackgroundSubtractorMOG2(int, double, bool) { throw_no_cuda(); return Ptr<gpu::BackgroundSubtractorMOG2>(); }
V
Vladislav Vinogradov 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63

#else

namespace cv { namespace gpu { namespace cudev
{
    namespace mog2
    {
        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);
    }
}}}

V
Vladislav Vinogradov 已提交
64
namespace
V
Vladislav Vinogradov 已提交
65 66 67 68 69 70 71 72 73 74 75 76
{
    // default parameters of gaussian background detection algorithm
    const int defaultHistory = 500; // Learning rate; alpha = 1/defaultHistory2
    const float defaultVarThreshold = 4.0f * 4.0f;
    const int defaultNMixtures = 5; // maximal number of Gaussians in mixture
    const float defaultBackgroundRatio = 0.9f; // threshold sum of weights for background test
    const float defaultVarThresholdGen = 3.0f * 3.0f;
    const float defaultVarInit = 15.0f; // initial variance for new components
    const float defaultVarMax = 5.0f * defaultVarInit;
    const float defaultVarMin = 4.0f;

    // additional parameters
V
Vladislav Vinogradov 已提交
77 78 79
    const float defaultCT = 0.05f; // complexity reduction prior constant 0 - no reduction of number of components
    const unsigned char defaultShadowValue = 127; // value to use in the segmentation mask for shadows, set 0 not to do shadow detection
    const float defaultShadowThreshold = 0.5f; // Tau - shadow threshold, see the paper for explanation
V
Vladislav Vinogradov 已提交
80

V
Vladislav Vinogradov 已提交
81 82 83 84
    class MOG2Impl : public gpu::BackgroundSubtractorMOG2
    {
    public:
        MOG2Impl(int history, double varThreshold, bool detectShadows);
V
Vladislav Vinogradov 已提交
85

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

V
Vladislav Vinogradov 已提交
89 90
        void getBackgroundImage(OutputArray backgroundImage) const;
        void getBackgroundImage(OutputArray backgroundImage, Stream& stream) const;
V
Vladislav Vinogradov 已提交
91

V
Vladislav Vinogradov 已提交
92 93
        int getHistory() const { return history_; }
        void setHistory(int history) { history_ = history; }
V
Vladislav Vinogradov 已提交
94

V
Vladislav Vinogradov 已提交
95 96
        int getNMixtures() const { return nmixtures_; }
        void setNMixtures(int nmixtures) { nmixtures_ = nmixtures; }
V
Vladislav Vinogradov 已提交
97

V
Vladislav Vinogradov 已提交
98 99
        double getBackgroundRatio() const { return backgroundRatio_; }
        void setBackgroundRatio(double ratio) { backgroundRatio_ = (float) ratio; }
V
Vladislav Vinogradov 已提交
100

V
Vladislav Vinogradov 已提交
101 102
        double getVarThreshold() const { return varThreshold_; }
        void setVarThreshold(double varThreshold) { varThreshold_ = (float) varThreshold; }
V
Vladislav Vinogradov 已提交
103

V
Vladislav Vinogradov 已提交
104 105
        double getVarThresholdGen() const { return varThresholdGen_; }
        void setVarThresholdGen(double varThresholdGen) { varThresholdGen_ = (float) varThresholdGen; }
V
Vladislav Vinogradov 已提交
106

V
Vladislav Vinogradov 已提交
107 108
        double getVarInit() const { return varInit_; }
        void setVarInit(double varInit) { varInit_ = (float) varInit; }
V
Vladislav Vinogradov 已提交
109

V
Vladislav Vinogradov 已提交
110 111
        double getVarMin() const { return varMin_; }
        void setVarMin(double varMin) { varMin_ = (float) varMin; }
V
Vladislav Vinogradov 已提交
112

V
Vladislav Vinogradov 已提交
113 114
        double getVarMax() const { return varMax_; }
        void setVarMax(double varMax) { varMax_ = (float) varMax; }
V
Vladislav Vinogradov 已提交
115

V
Vladislav Vinogradov 已提交
116 117
        double getComplexityReductionThreshold() const { return ct_; }
        void setComplexityReductionThreshold(double ct) { ct_ = (float) ct; }
V
Vladislav Vinogradov 已提交
118

V
Vladislav Vinogradov 已提交
119 120
        bool getDetectShadows() const { return detectShadows_; }
        void setDetectShadows(bool detectShadows) { detectShadows_ = detectShadows; }
V
Vladislav Vinogradov 已提交
121

V
Vladislav Vinogradov 已提交
122 123
        int getShadowValue() const { return shadowValue_; }
        void setShadowValue(int value) { shadowValue_ = (uchar) value; }
V
Vladislav Vinogradov 已提交
124

V
Vladislav Vinogradov 已提交
125 126
        double getShadowThreshold() const { return shadowThreshold_; }
        void setShadowThreshold(double threshold) { shadowThreshold_ = (float) threshold; }
V
Vladislav Vinogradov 已提交
127

V
Vladislav Vinogradov 已提交
128 129
    private:
        void initialize(Size frameSize, int frameType);
V
Vladislav Vinogradov 已提交
130

V
Vladislav Vinogradov 已提交
131 132 133 134 135 136 137 138 139 140 141 142
        int history_;
        int nmixtures_;
        float backgroundRatio_;
        float varThreshold_;
        float varThresholdGen_;
        float varInit_;
        float varMin_;
        float varMax_;
        float ct_;
        bool detectShadows_;
        uchar shadowValue_;
        float shadowThreshold_;
V
Vladislav Vinogradov 已提交
143

V
Vladislav Vinogradov 已提交
144 145 146
        Size frameSize_;
        int frameType_;
        int nframes_;
V
Vladislav Vinogradov 已提交
147

V
Vladislav Vinogradov 已提交
148 149 150
        GpuMat weight_;
        GpuMat variance_;
        GpuMat mean_;
V
Vladislav Vinogradov 已提交
151

V
Vladislav Vinogradov 已提交
152 153 154
        //keep track of number of modes per pixel
        GpuMat bgmodelUsedModes_;
    };
V
Vladislav Vinogradov 已提交
155

V
Vladislav Vinogradov 已提交
156 157 158 159 160 161 162 163 164 165 166 167 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
    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;
    }

    void MOG2Impl::apply(InputArray image, OutputArray fgmask, double learningRate)
    {
        apply(image, fgmask, learningRate, Stream::Null());
    }

    void MOG2Impl::apply(InputArray _frame, OutputArray _fgmask, double learningRate, Stream& stream)
    {
        using namespace cv::gpu::cudev::mog2;

        GpuMat frame = _frame.getGpuMat();

        int ch = frame.channels();
        int work_ch = ch;

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

        _fgmask.create(frameSize_, CV_8UC1);
        GpuMat fgmask = _fgmask.getGpuMat();
V
Vladislav Vinogradov 已提交
193

V
Vladislav Vinogradov 已提交
194
        fgmask.setTo(Scalar::all(0), stream);
V
Vladislav Vinogradov 已提交
195

V
Vladislav Vinogradov 已提交
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
        ++nframes_;
        learningRate = learningRate >= 0 && nframes_ > 1 ? learningRate : 1.0 / std::min(2 * nframes_, history_);
        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));
    }

    void MOG2Impl::getBackgroundImage(OutputArray backgroundImage) const
    {
        getBackgroundImage(backgroundImage, Stream::Null());
    }

    void MOG2Impl::getBackgroundImage(OutputArray _backgroundImage, Stream& stream) const
    {
        using namespace cv::gpu::cudev::mog2;

        _backgroundImage.create(frameSize_, frameType_);
        GpuMat backgroundImage = _backgroundImage.getGpuMat();

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

    void MOG2Impl::initialize(cv::Size frameSize, int frameType)
    {
        using namespace cv::gpu::cudev::mog2;

        CV_Assert( frameType == CV_8UC1 || frameType == CV_8UC3 || frameType == CV_8UC4 );

        frameSize_ = frameSize;
        frameType_ = frameType;
        nframes_ = 0;

        int ch = CV_MAT_CN(frameType);
        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));

        //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_);
    }
}

Ptr<gpu::BackgroundSubtractorMOG2> cv::gpu::createBackgroundSubtractorMOG2(int history, double varThreshold, bool detectShadows)
{
    return new MOG2Impl(history, varThreshold, detectShadows);
V
Vladislav Vinogradov 已提交
251 252 253
}

#endif