spyglass 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,77 @@
1
+ /*
2
+ This file is part of BGSLibrary.
3
+
4
+ BGSLibrary is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ BGSLibrary is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ /****************************************************************************
18
+ *
19
+ * Image.hpp
20
+ *
21
+ * Purpose: C++ wrapper for OpenCV IplImage which supports simple and
22
+ * efficient access to the image data
23
+ *
24
+ * Author: Donovan Parks, September 2007
25
+ *
26
+ * Based on code from:
27
+ * http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.hpptml
28
+ ******************************************************************************/
29
+
30
+ #include "bgslib_image.h"
31
+
32
+ ImageBase::~ImageBase()
33
+ {
34
+ if(imgp != NULL && m_bReleaseMemory)
35
+ cvReleaseImage(&imgp);
36
+ imgp = NULL;
37
+ }
38
+
39
+ void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue)
40
+ {
41
+ for(int r = 1; r < image.Ptr()->height-1; ++r)
42
+ {
43
+ for(int c = 1; c < image.Ptr()->width-1; ++c)
44
+ {
45
+ int count = 0;
46
+ if(image(r,c) == fgValue)
47
+ {
48
+ if(image(r-1,c-1) == fgValue)
49
+ count++;
50
+ if(image(r-1,c) == fgValue)
51
+ count++;
52
+ if(image(r-1,c+1) == fgValue)
53
+ count++;
54
+ if(image(r,c-1) == fgValue)
55
+ count++;
56
+ if(image(r,c+1) == fgValue)
57
+ count++;
58
+ if(image(r+1,c-1) == fgValue)
59
+ count++;
60
+ if(image(r+1,c) == fgValue)
61
+ count++;
62
+ if(image(r+1,c+1) == fgValue)
63
+ count++;
64
+
65
+ if(count < minDensity)
66
+ filtered(r,c) = 0;
67
+ else
68
+ filtered(r,c) = fgValue;
69
+ }
70
+ else
71
+ {
72
+ filtered(r,c) = 0;
73
+ }
74
+ }
75
+ }
76
+ }
77
+
@@ -0,0 +1,365 @@
1
+ /*
2
+ This file is part of BGSLibrary.
3
+
4
+ BGSLibrary is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ BGSLibrary is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ /****************************************************************************
18
+ *
19
+ * Image.h
20
+ *
21
+ * Purpose: C++ wrapper for OpenCV IplImage which supports simple and
22
+ * efficient access to the image data
23
+ *
24
+ * Author: Donovan Parks, September 2007
25
+ *
26
+ * Based on code from:
27
+ * http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html
28
+ ******************************************************************************/
29
+
30
+ #ifndef _IMAGE_H_
31
+ #define _IMAGE_H_
32
+
33
+ #include <opencv/cv.h>
34
+ #include <opencv/cxcore.h>
35
+
36
+ // --- Image Iterator ---------------------------------------------------------
37
+
38
+ template <class T>
39
+ class ImageIterator
40
+ {
41
+ public:
42
+ ImageIterator(IplImage* image, int x=0, int y=0, int dx= 0, int dy=0) :
43
+ i(x), j(y), i0(0)
44
+ {
45
+ data = reinterpret_cast<T*>(image->imageData);
46
+ step = image->widthStep / sizeof(T);
47
+
48
+ nl= image->height;
49
+ if ((y+dy)>0 && (y+dy) < nl)
50
+ nl= y+dy;
51
+
52
+ if (y<0)
53
+ j=0;
54
+
55
+ data += step*j;
56
+
57
+ nc = image->width;
58
+ if ((x+dx) > 0 && (x+dx) < nc)
59
+ nc = x+dx;
60
+
61
+ nc *= image->nChannels;
62
+ if (x>0)
63
+ i0 = x*image->nChannels;
64
+ i = i0;
65
+
66
+ nch = image->nChannels;
67
+ }
68
+
69
+
70
+ /* has next ? */
71
+ bool operator!() const { return j < nl; }
72
+
73
+ /* next pixel */
74
+ ImageIterator& operator++()
75
+ {
76
+ i++;
77
+ if (i >= nc)
78
+ {
79
+ i=i0;
80
+ j++;
81
+ data += step;
82
+ }
83
+ return *this;
84
+ }
85
+
86
+ ImageIterator& operator+=(int s)
87
+ {
88
+ i+=s;
89
+ if (i >= nc)
90
+ {
91
+ i=i0;
92
+ j++;
93
+ data += step;
94
+ }
95
+ return *this;
96
+ }
97
+
98
+ /* pixel access */
99
+ T& operator*() { return data[i]; }
100
+
101
+ const T operator*() const { return data[i]; }
102
+
103
+ const T neighbor(int dx, int dy) const
104
+ {
105
+ return *(data+dy*step+i+dx);
106
+ }
107
+
108
+ T* operator&() const { return data+i; }
109
+
110
+ /* current pixel coordinates */
111
+ int column() const { return i/nch; }
112
+ int line() const { return j; }
113
+
114
+ private:
115
+ int i, i0,j;
116
+ T* data;
117
+ int step;
118
+ int nl, nc;
119
+ int nch;
120
+ };
121
+
122
+ // --- Constants --------------------------------------------------------------
123
+
124
+ const unsigned char NUM_CHANNELS = 3;
125
+
126
+ // --- Pixel Types ------------------------------------------------------------
127
+
128
+ class RgbPixel
129
+ {
130
+ public:
131
+ RgbPixel() {;}
132
+ RgbPixel(unsigned char _r, unsigned char _g, unsigned char _b)
133
+ {
134
+ ch[0] = _r; ch[1] = _g; ch[2] = _b;
135
+ }
136
+
137
+ RgbPixel& operator=(const RgbPixel& rhs)
138
+ {
139
+ ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2];
140
+ return *this;
141
+ }
142
+
143
+ inline unsigned char& operator()(const int _ch)
144
+ {
145
+ return ch[_ch];
146
+ }
147
+
148
+ inline unsigned char operator()(const int _ch) const
149
+ {
150
+ return ch[_ch];
151
+ }
152
+
153
+ unsigned char ch[3];
154
+ };
155
+
156
+ class RgbPixelFloat
157
+ {
158
+ public:
159
+ RgbPixelFloat() {;}
160
+ RgbPixelFloat(float _r, float _g, float _b)
161
+ {
162
+ ch[0] = _r; ch[1] = _g; ch[2] = _b;
163
+ }
164
+
165
+ RgbPixelFloat& operator=(const RgbPixelFloat& rhs)
166
+ {
167
+ ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2];
168
+ return *this;
169
+ }
170
+
171
+ inline float& operator()(const int _ch)
172
+ {
173
+ return ch[_ch];
174
+ }
175
+
176
+ inline float operator()(const int _ch) const
177
+ {
178
+ return ch[_ch];
179
+ }
180
+
181
+ float ch[3];
182
+ };
183
+
184
+ // --- Image Types ------------------------------------------------------------
185
+
186
+ class ImageBase
187
+ {
188
+ public:
189
+ ImageBase(IplImage* img = NULL) { imgp = img; m_bReleaseMemory = true; }
190
+ ~ImageBase();
191
+
192
+ void ReleaseMemory(bool b) { m_bReleaseMemory = b; }
193
+
194
+ IplImage* Ptr() { return imgp; }
195
+ const IplImage* Ptr() const { return imgp; }
196
+
197
+ void ReleaseImage()
198
+ {
199
+ cvReleaseImage(&imgp);
200
+ }
201
+
202
+ void operator=(IplImage* img)
203
+ {
204
+ imgp = img;
205
+ }
206
+
207
+ // copy-constructor
208
+ ImageBase(const ImageBase& rhs)
209
+ {
210
+ // it is very inefficent if this copy-constructor is called
211
+ assert(false);
212
+ }
213
+
214
+ // assignment operator
215
+ ImageBase& operator=(const ImageBase& rhs)
216
+ {
217
+ // it is very inefficent if operator= is called
218
+ assert(false);
219
+
220
+ return *this;
221
+ }
222
+
223
+ virtual void Clear() = 0;
224
+
225
+ protected:
226
+ IplImage* imgp;
227
+ bool m_bReleaseMemory;
228
+ };
229
+
230
+ class RgbImage : public ImageBase
231
+ {
232
+ public:
233
+ RgbImage(IplImage* img = NULL) : ImageBase(img) { ; }
234
+
235
+ virtual void Clear()
236
+ {
237
+ cvZero(imgp);
238
+ }
239
+
240
+ void operator=(IplImage* img)
241
+ {
242
+ imgp = img;
243
+ }
244
+
245
+ // channel-level access using image(row, col, channel)
246
+ inline unsigned char& operator()(const int r, const int c, const int ch)
247
+ {
248
+ return (unsigned char &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels+ch];
249
+ }
250
+
251
+ inline const unsigned char& operator()(const int r, const int c, const int ch) const
252
+ {
253
+ return (unsigned char &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels+ch];
254
+ }
255
+
256
+ // RGB pixel-level access using image(row, col)
257
+ inline RgbPixel& operator()(const int r, const int c)
258
+ {
259
+ return (RgbPixel &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels];
260
+ }
261
+
262
+ inline const RgbPixel& operator()(const int r, const int c) const
263
+ {
264
+ return (RgbPixel &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels];
265
+ }
266
+ };
267
+
268
+ class RgbImageFloat : public ImageBase
269
+ {
270
+ public:
271
+ RgbImageFloat(IplImage* img = NULL) : ImageBase(img) { ; }
272
+
273
+ virtual void Clear()
274
+ {
275
+ cvZero(imgp);
276
+ }
277
+
278
+ void operator=(IplImage* img)
279
+ {
280
+ imgp = img;
281
+ }
282
+
283
+ // channel-level access using image(row, col, channel)
284
+ inline float& operator()(const int r, const int c, const int ch)
285
+ {
286
+ return (float &)imgp->imageData[r*imgp->widthStep+(c*imgp->nChannels+ch)*sizeof(float)];
287
+ }
288
+
289
+ inline float operator()(const int r, const int c, const int ch) const
290
+ {
291
+ return (float)imgp->imageData[r*imgp->widthStep+(c*imgp->nChannels+ch)*sizeof(float)];
292
+ }
293
+
294
+ // RGB pixel-level access using image(row, col)
295
+ inline RgbPixelFloat& operator()(const int r, const int c)
296
+ {
297
+ return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels*sizeof(float)];
298
+ }
299
+
300
+ inline const RgbPixelFloat& operator()(const int r, const int c) const
301
+ {
302
+ return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels*sizeof(float)];
303
+ }
304
+ };
305
+
306
+ class BwImage : public ImageBase
307
+ {
308
+ public:
309
+ BwImage(IplImage* img = NULL) : ImageBase(img) { ; }
310
+
311
+ virtual void Clear()
312
+ {
313
+ cvZero(imgp);
314
+ }
315
+
316
+ void operator=(IplImage* img)
317
+ {
318
+ imgp = img;
319
+ }
320
+
321
+ // pixel-level access using image(row, col)
322
+ inline unsigned char& operator()(const int r, const int c)
323
+ {
324
+ return (unsigned char &)imgp->imageData[r*imgp->widthStep+c];
325
+ }
326
+
327
+ inline unsigned char operator()(const int r, const int c) const
328
+ {
329
+ return (unsigned char)imgp->imageData[r*imgp->widthStep+c];
330
+ }
331
+ };
332
+
333
+ class BwImageFloat : public ImageBase
334
+ {
335
+ public:
336
+ BwImageFloat(IplImage* img = NULL) : ImageBase(img) { ; }
337
+
338
+ virtual void Clear()
339
+ {
340
+ cvZero(imgp);
341
+ }
342
+
343
+ void operator=(IplImage* img)
344
+ {
345
+ imgp = img;
346
+ }
347
+
348
+ // pixel-level access using image(row, col)
349
+ inline float& operator()(const int r, const int c)
350
+ {
351
+ return (float &)imgp->imageData[r*imgp->widthStep+c*sizeof(float)];
352
+ }
353
+
354
+ inline float operator()(const int r, const int c) const
355
+ {
356
+ return (float)imgp->imageData[r*imgp->widthStep+c*sizeof(float)];
357
+ }
358
+ };
359
+
360
+ // --- Image Functions --------------------------------------------------------
361
+
362
+ void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue);
363
+
364
+ #endif
365
+
@@ -0,0 +1,276 @@
1
+ /*
2
+ This file is part of BGSLibrary.
3
+
4
+ BGSLibrary is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ BGSLibrary is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ /****************************************************************************
18
+ *
19
+ * PratiMediodBGS.h
20
+ *
21
+ * Purpose: Implementation of the temporal median background
22
+ * subtraction algorithm described in:
23
+ *
24
+ * [1] "Detecting Moving Objects, Shosts, and Shadows in Video Stream"
25
+ * by R. Cucchiara et al (2003)
26
+ *
27
+ * [2] "Reliable Background Suppression for Complex Scenes"
28
+ * by S. Calderara et al (2006)
29
+ *
30
+ * Author: Donovan Parks, September 2007
31
+ *
32
+ * Please note that this is not an implementation of the complete system
33
+ * given in the above papers. It simply implements the temporal media background
34
+ * subtraction algorithm.
35
+ ******************************************************************************/
36
+
37
+ #include "bgslib_prati_mediod_bgs.h"
38
+
39
+ using namespace Algorithms::BackgroundSubtraction;
40
+
41
+ PratiMediodBGS::PratiMediodBGS()
42
+ {
43
+ m_median_buffer = NULL;
44
+ }
45
+
46
+ PratiMediodBGS::~PratiMediodBGS()
47
+ {
48
+ if(m_median_buffer != NULL)
49
+ delete[] m_median_buffer;
50
+ }
51
+
52
+ void PratiMediodBGS::Initalize(const BgsParams& param)
53
+ {
54
+ m_params = (PratiParams&)param;
55
+
56
+ m_mask_low_threshold = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
57
+ m_mask_high_threshold = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
58
+
59
+ m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
60
+
61
+ m_median_buffer = new MEDIAN_BUFFER[m_params.Size()];
62
+ }
63
+
64
+ void PratiMediodBGS::InitModel(const RgbImage& data)
65
+ {
66
+ // there is no need to initialize the mode since it needs a buffer of frames
67
+ // before it can performing background subtraction
68
+ }
69
+
70
+ void PratiMediodBGS::Update(int frame_num, const RgbImage& data, const BwImage& update_mask)
71
+ {
72
+ // update the image buffer with the new frame and calculate new median values
73
+ if(frame_num % m_params.SamplingRate() == 0)
74
+ {
75
+ if(m_median_buffer[0].dist.size() == m_params.HistorySize())
76
+ {
77
+ // subtract distance to sample being removed from all distances
78
+ for(unsigned int r = 0; r < m_params.Height(); ++r)
79
+ {
80
+ for(unsigned int c = 0; c < m_params.Width(); ++c)
81
+ {
82
+ int i = r*m_params.Width()+c;
83
+
84
+ if(update_mask(r,c) == BACKGROUND)
85
+ {
86
+ int oldPos = m_median_buffer[i].pos;
87
+ for(unsigned int s = 0; s < m_median_buffer[i].pixels.size(); ++s)
88
+ {
89
+ int maxDist = 0;
90
+ for(int ch = 0; ch < NUM_CHANNELS; ++ch)
91
+ {
92
+ int tempDist = abs(m_median_buffer[i].pixels.at(oldPos)(ch)
93
+ - m_median_buffer[i].pixels.at(s)(ch));
94
+ if(tempDist > maxDist)
95
+ maxDist = tempDist;
96
+ }
97
+
98
+ m_median_buffer[i].dist.at(s) -= maxDist;
99
+ }
100
+
101
+ int dist;
102
+ UpdateMediod(r, c, data, dist);
103
+ m_median_buffer[i].dist.at(oldPos) = dist;
104
+ m_median_buffer[i].pixels.at(oldPos) = data(r,c);
105
+ m_median_buffer[i].pos++;
106
+ if(m_median_buffer[i].pos >= m_params.HistorySize())
107
+ m_median_buffer[i].pos = 0;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ else
113
+ {
114
+ // calculate sum of L-inf distances for new point and
115
+ // add distance from each sample point to this point to their L-inf sum
116
+ int dist;
117
+ for(unsigned int r = 0; r < m_params.Height(); ++r)
118
+ {
119
+ for(unsigned int c = 0; c < m_params.Width(); ++c)
120
+ {
121
+ int index = r*m_params.Width()+c;
122
+ UpdateMediod(r, c, data, dist);
123
+ m_median_buffer[index].dist.push_back(dist);
124
+ m_median_buffer[index].pos = 0;
125
+ m_median_buffer[index].pixels.push_back(data(r,c));
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ void PratiMediodBGS::UpdateMediod(int r, int c, const RgbImage& new_frame, int& dist)
133
+ {
134
+ // calculate sum of L-inf distances for new point and
135
+ // add distance from each sample point to this point to their L-inf sum
136
+ unsigned int i = (r*m_params.Width()+c);
137
+
138
+ m_median_buffer[i].medianDist = INT_MAX;
139
+
140
+ int L_inf_dist = 0;
141
+ for(unsigned int s = 0; s < m_median_buffer[i].dist.size(); ++s)
142
+ {
143
+ int maxDist = 0;
144
+ for(int ch = 0; ch < NUM_CHANNELS; ++ch)
145
+ {
146
+ int tempDist = abs(m_median_buffer[i].pixels.at(s)(ch) - new_frame(r,c,ch));
147
+ if(tempDist > maxDist)
148
+ maxDist = tempDist;
149
+ }
150
+
151
+ // check if point from this frame in the image buffer is the median
152
+ m_median_buffer[i].dist.at(s) += maxDist;
153
+ if(m_median_buffer[i].dist.at(s) < m_median_buffer[i].medianDist)
154
+ {
155
+ m_median_buffer[i].medianDist = m_median_buffer[i].dist.at(s);
156
+ m_median_buffer[i].median = m_median_buffer[i].pixels.at(s);
157
+ }
158
+
159
+ L_inf_dist += maxDist;
160
+ }
161
+
162
+ dist = L_inf_dist;
163
+
164
+ // check if the new point is the median
165
+ if(L_inf_dist < m_median_buffer[i].medianDist)
166
+ {
167
+ m_median_buffer[i].medianDist = L_inf_dist;
168
+ m_median_buffer[i].median = new_frame(r,c);
169
+ }
170
+ }
171
+
172
+ void PratiMediodBGS::Combine(const BwImage& low_mask, const BwImage& high_mask, BwImage& output)
173
+ {
174
+ for(unsigned int r = 0; r < m_params.Height(); ++r)
175
+ {
176
+ for(unsigned int c = 0; c < m_params.Width(); ++c)
177
+ {
178
+ output(r,c) = BACKGROUND;
179
+
180
+ if(r == 0 || c == 0 || r == m_params.Height()-1 || c == m_params.Width()-1)
181
+ continue;
182
+
183
+ if(high_mask(r,c) == FOREGROUND)
184
+ {
185
+ output(r,c) = FOREGROUND;
186
+ }
187
+ else if(low_mask(r,c) == FOREGROUND)
188
+ {
189
+ // consider the pixel to be a F/G pixel if it is 8-connected to
190
+ // a F/G pixel in the high mask
191
+ // check if there is an 8-connected foreground pixel
192
+ if(high_mask(r-1,c-1))
193
+ output(r,c) = FOREGROUND;
194
+ else if(high_mask(r-1,c))
195
+ output(r,c) = FOREGROUND;
196
+ else if(high_mask(r-1,c+1))
197
+ output(r,c) = FOREGROUND;
198
+ else if(high_mask(r,c-1))
199
+ output(r,c) = FOREGROUND;
200
+ else if(high_mask(r,c+1))
201
+ output(r,c) = FOREGROUND;
202
+ else if(high_mask(r+1,c-1))
203
+ output(r,c) = FOREGROUND;
204
+ else if(high_mask(r+1,c))
205
+ output(r,c) = FOREGROUND;
206
+ else if(high_mask(r+1,c+1))
207
+ output(r,c) = FOREGROUND;
208
+ }
209
+ }
210
+ }
211
+ }
212
+
213
+ void PratiMediodBGS::CalculateMasks(int r, int c, const RgbPixel& pixel)
214
+ {
215
+ int pos = r*m_params.Width()+c;
216
+
217
+ // calculate l-inf distance between current value and median value
218
+ unsigned char dist = 0;
219
+ for(int ch = 0; ch < NUM_CHANNELS; ++ch)
220
+ {
221
+ int tempDist = abs(pixel(ch) - m_median_buffer[pos].median(ch));
222
+ if(tempDist > dist)
223
+ dist = tempDist;
224
+ }
225
+ m_background(r,c) = m_median_buffer[pos].median;
226
+
227
+ // check if pixel is a B/G or F/G pixel according to the low threshold B/G model
228
+ m_mask_low_threshold(r,c) = BACKGROUND;
229
+ if(dist > m_params.LowThreshold())
230
+ {
231
+ m_mask_low_threshold(r,c) = FOREGROUND;
232
+ }
233
+
234
+ // check if pixel is a B/G or F/G pixel according to the high threshold B/G model
235
+ m_mask_high_threshold(r,c)= BACKGROUND;
236
+ if(dist > m_params.HighThreshold())
237
+ {
238
+ m_mask_high_threshold(r,c) = FOREGROUND;
239
+ }
240
+ }
241
+
242
+ ///////////////////////////////////////////////////////////////////////////////
243
+ //Input:
244
+ // data - a pointer to the data of a RGB image of the same size
245
+ //Output:
246
+ // output - a pointer to the data of a gray value image of the same size
247
+ // values: 255-foreground, 0-background
248
+ ///////////////////////////////////////////////////////////////////////////////
249
+ void PratiMediodBGS::Subtract(int frame_num, const RgbImage& data,
250
+ BwImage& low_threshold_mark, BwImage& high_threshold_mark)
251
+ {
252
+ if(frame_num < m_params.HistorySize())
253
+ {
254
+ low_threshold_mark.Clear();
255
+ high_threshold_mark.Clear();
256
+ return;
257
+ }
258
+
259
+ // update each pixel of the image
260
+ for(unsigned int r = 0; r < m_params.Height(); ++r)
261
+ {
262
+ for(unsigned int c = 0; c < m_params.Width(); ++c)
263
+ {
264
+ // need at least one frame of data before we can start calculating the masks
265
+ CalculateMasks(r, c, data(r,c));
266
+ }
267
+ }
268
+
269
+ // combine low and high threshold masks
270
+ Combine(m_mask_low_threshold, m_mask_high_threshold, low_threshold_mark);
271
+ Combine(m_mask_low_threshold, m_mask_high_threshold, high_threshold_mark);
272
+ }
273
+
274
+
275
+
276
+