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 #if !defined CUDA_DISABLER
44 
45 #include "opencv2/core/cuda/common.hpp"
46 #include "opencv2/core/cuda/vec_traits.hpp"
47 #include "opencv2/core/cuda/limits.hpp"
48 
49 namespace cv { namespace cuda { namespace device {
50     namespace gmg
51     {
52         __constant__ int   c_width;
53         __constant__ int   c_height;
54         __constant__ float c_minVal;
55         __constant__ float c_maxVal;
56         __constant__ int   c_quantizationLevels;
57         __constant__ float c_backgroundPrior;
58         __constant__ float c_decisionThreshold;
59         __constant__ int   c_maxFeatures;
60         __constant__ int   c_numInitializationFrames;
61 
loadConstants(int width,int height,float minVal,float maxVal,int quantizationLevels,float backgroundPrior,float decisionThreshold,int maxFeatures,int numInitializationFrames)62         void loadConstants(int width, int height, float minVal, float maxVal, int quantizationLevels, float backgroundPrior,
63                            float decisionThreshold, int maxFeatures, int numInitializationFrames)
64         {
65             cudaSafeCall( cudaMemcpyToSymbol(c_width, &width, sizeof(width)) );
66             cudaSafeCall( cudaMemcpyToSymbol(c_height, &height, sizeof(height)) );
67             cudaSafeCall( cudaMemcpyToSymbol(c_minVal, &minVal, sizeof(minVal)) );
68             cudaSafeCall( cudaMemcpyToSymbol(c_maxVal, &maxVal, sizeof(maxVal)) );
69             cudaSafeCall( cudaMemcpyToSymbol(c_quantizationLevels, &quantizationLevels, sizeof(quantizationLevels)) );
70             cudaSafeCall( cudaMemcpyToSymbol(c_backgroundPrior, &backgroundPrior, sizeof(backgroundPrior)) );
71             cudaSafeCall( cudaMemcpyToSymbol(c_decisionThreshold, &decisionThreshold, sizeof(decisionThreshold)) );
72             cudaSafeCall( cudaMemcpyToSymbol(c_maxFeatures, &maxFeatures, sizeof(maxFeatures)) );
73             cudaSafeCall( cudaMemcpyToSymbol(c_numInitializationFrames, &numInitializationFrames, sizeof(numInitializationFrames)) );
74         }
75 
findFeature(const int color,const PtrStepi & colors,const PtrStepf & weights,const int x,const int y,const int nfeatures)76         __device__ float findFeature(const int color, const PtrStepi& colors, const PtrStepf& weights, const int x, const int y, const int nfeatures)
77         {
78             for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
79             {
80                 if (color == colors(fy, x))
81                     return weights(fy, x);
82             }
83 
84             // not in histogram, so return 0.
85             return 0.0f;
86         }
87 
normalizeHistogram(PtrStepf weights,const int x,const int y,const int nfeatures)88         __device__ void normalizeHistogram(PtrStepf weights, const int x, const int y, const int nfeatures)
89         {
90             float total = 0.0f;
91             for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
92                 total += weights(fy, x);
93 
94             if (total != 0.0f)
95             {
96                 for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
97                     weights(fy, x) /= total;
98             }
99         }
100 
insertFeature(const int color,const float weight,PtrStepi colors,PtrStepf weights,const int x,const int y,int & nfeatures)101         __device__ bool insertFeature(const int color, const float weight, PtrStepi colors, PtrStepf weights, const int x, const int y, int& nfeatures)
102         {
103             for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
104             {
105                 if (color == colors(fy, x))
106                 {
107                     // feature in histogram
108 
109                     weights(fy, x) += weight;
110 
111                     return false;
112                 }
113             }
114 
115             if (nfeatures == c_maxFeatures)
116             {
117                 // discard oldest feature
118 
119                 int idx = -1;
120                 float minVal = numeric_limits<float>::max();
121                 for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
122                 {
123                     const float w = weights(fy, x);
124                     if (w < minVal)
125                     {
126                         minVal = w;
127                         idx = fy;
128                     }
129                 }
130 
131                 colors(idx, x) = color;
132                 weights(idx, x) = weight;
133 
134                 return false;
135             }
136 
137             colors(nfeatures * c_height + y, x) = color;
138             weights(nfeatures * c_height + y, x) = weight;
139 
140             ++nfeatures;
141 
142             return true;
143         }
144 
145         namespace detail
146         {
147             template <int cn> struct Quantization
148             {
149                 template <typename T>
applycv::cuda::device::gmg::detail::Quantization150                 __device__ static int apply(const T& val)
151                 {
152                     int res = 0;
153                     res |= static_cast<int>((val.x - c_minVal) * c_quantizationLevels / (c_maxVal - c_minVal));
154                     res |= static_cast<int>((val.y - c_minVal) * c_quantizationLevels / (c_maxVal - c_minVal)) << 8;
155                     res |= static_cast<int>((val.z - c_minVal) * c_quantizationLevels / (c_maxVal - c_minVal)) << 16;
156                     return res;
157                 }
158             };
159 
160             template <> struct Quantization<1>
161             {
162                 template <typename T>
applycv::cuda::device::gmg::detail::Quantization163                 __device__ static int apply(T val)
164                 {
165                     return static_cast<int>((val - c_minVal) * c_quantizationLevels / (c_maxVal - c_minVal));
166                 }
167             };
168         }
169 
170         template <typename T> struct Quantization : detail::Quantization<VecTraits<T>::cn> {};
171 
172         template <typename SrcT>
update(const PtrStep<SrcT> frame,PtrStepb fgmask,PtrStepi colors_,PtrStepf weights_,PtrStepi nfeatures_,const int frameNum,const float learningRate,const bool updateBackgroundModel)173         __global__ void update(const PtrStep<SrcT> frame, PtrStepb fgmask, PtrStepi colors_, PtrStepf weights_, PtrStepi nfeatures_,
174                                const int frameNum, const float learningRate, const bool updateBackgroundModel)
175         {
176             const int x = blockIdx.x * blockDim.x + threadIdx.x;
177             const int y = blockIdx.y * blockDim.y + threadIdx.y;
178 
179             if (x >= c_width || y >= c_height)
180                 return;
181 
182             const SrcT pix = frame(y, x);
183             const int newFeatureColor = Quantization<SrcT>::apply(pix);
184 
185             int nfeatures = nfeatures_(y, x);
186 
187             if (frameNum >= c_numInitializationFrames)
188             {
189                 // typical operation
190 
191                 const float weight = findFeature(newFeatureColor, colors_, weights_, x, y, nfeatures);
192 
193                 // see Godbehere, Matsukawa, Goldberg (2012) for reasoning behind this implementation of Bayes rule
194                 const float posterior = (weight * c_backgroundPrior) / (weight * c_backgroundPrior + (1.0f - weight) * (1.0f - c_backgroundPrior));
195 
196                 const bool isForeground = ((1.0f - posterior) > c_decisionThreshold);
197                 fgmask(y, x) = (uchar)(-isForeground);
198 
199                 // update histogram.
200 
201                 if (updateBackgroundModel)
202                 {
203                     for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
204                         weights_(fy, x) *= 1.0f - learningRate;
205 
206                     bool inserted = insertFeature(newFeatureColor, learningRate, colors_, weights_, x, y, nfeatures);
207 
208                     if (inserted)
209                     {
210                         normalizeHistogram(weights_, x, y, nfeatures);
211                         nfeatures_(y, x) = nfeatures;
212                     }
213                 }
214             }
215             else if (updateBackgroundModel)
216             {
217                 // training-mode update
218 
219                 insertFeature(newFeatureColor, 1.0f, colors_, weights_, x, y, nfeatures);
220 
221                 if (frameNum == c_numInitializationFrames - 1)
222                     normalizeHistogram(weights_, x, y, nfeatures);
223             }
224         }
225 
226         template <typename SrcT>
update_gpu(PtrStepSzb frame,PtrStepb fgmask,PtrStepSzi colors,PtrStepf weights,PtrStepi nfeatures,int frameNum,float learningRate,bool updateBackgroundModel,cudaStream_t stream)227         void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures,
228                         int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream)
229         {
230             const dim3 block(32, 8);
231             const dim3 grid(divUp(frame.cols, block.x), divUp(frame.rows, block.y));
232 
233             cudaSafeCall( cudaFuncSetCacheConfig(update<SrcT>, cudaFuncCachePreferL1) );
234 
235             update<SrcT><<<grid, block, 0, stream>>>((PtrStepSz<SrcT>) frame, fgmask, colors, weights, nfeatures, frameNum, learningRate, updateBackgroundModel);
236 
237             cudaSafeCall( cudaGetLastError() );
238 
239             if (stream == 0)
240                 cudaSafeCall( cudaDeviceSynchronize() );
241         }
242 
243         template void update_gpu<uchar  >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
244         template void update_gpu<uchar3 >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
245         template void update_gpu<uchar4 >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
246 
247         template void update_gpu<ushort >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
248         template void update_gpu<ushort3>(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
249         template void update_gpu<ushort4>(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
250 
251         template void update_gpu<float  >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
252         template void update_gpu<float3 >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
253         template void update_gpu<float4 >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
254     }
255 }}}
256 
257 
258 #endif /* CUDA_DISABLER */
259