spyglass 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+