1 /* Copyright - Benjamin Laugraud <blaugraud@ulg.ac.be> - 2016
2 * Copyright - Marc Van Droogenbroeck <m.vandroogenbroeck@ulg.ac.be> - 2016
4 * ViBe is covered by a patent (see http://www.telecom.ulg.ac.be/research/vibe).
6 * Permission to use ViBe without payment of fee is granted for nonprofit
7 * educational and research purposes only.
9 * This work may not be copied or reproduced in whole or in part for any
12 * Copying, reproduction, or republishing for any purpose shall require a
13 * license. Please contact the authors in such cases. All the code is provided
14 * without any guarantee.
20 @brief Template-based C++ implementation of the ViBe algorithm.
22 @author Benjamin Laungraud and Marc Van Droogenbroeck
28 Full documentation is available online at:
29 http://www.telecom.ulg.ac.be/research/vibe/doc2
32 #ifdef _LIB_VIBE_XX_VIBE_H_
34 /* ========================================================================== *
35 * ViBeSequential<Channels, Distance> *
36 * ========================================================================== */
38 template <int32_t Channels, class Distance>
39 ViBeSequential<Channels, Distance>::ViBeSequential(
50 /******************************************************************************/
52 template <int32_t Channels, class Distance>
53 void ViBeSequential<Channels, Distance>::_CRTP_segmentation(
54 const uint8_t* buffer,
55 uint8_t* segmentationMap
59 throw; // TODO Exception
61 if (segmentationMap == NULL)
62 throw; // TODO Exception
65 /* Even though those variables/contents are redundant with the variables of
66 * ViBeBase, they avoid additional dereference instructions.
68 static const uint32_t NUMBER_OF_HISTORY_IMAGES =
69 this->NUMBER_OF_HISTORY_IMAGES;
71 static const uint8_t FOREGROUND = this->FOREGROUND;
73 uint32_t pixels = this->pixels;
74 uint32_t numValues = this->numValues;
75 uint32_t matchingNumber = this->matchingNumber;
76 uint32_t matchingThreshold = this->matchingThreshold;
78 uint8_t* historyImage = this->historyImage;
79 uint8_t* historyBuffer = this->historyBuffer;
81 /* Initialize segmentation map. */
82 memset(segmentationMap, matchingNumber - 1, pixels);
84 /* First history Image structure. */
85 for (int32_t index = pixels - 1; index >= 0; --index) {
88 buffer + (Channels * index),
89 historyImage + (Channels * index),
93 segmentationMap[index] = matchingNumber;
96 /* Next historyImages. */
97 for (uint32_t i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
98 uint8_t* pels = historyImage + i * numValues;
100 for (int32_t index = pixels - 1; index >= 0; --index) {
103 buffer + (Channels * index),
104 pels + (Channels * index),
108 --segmentationMap[index];
113 this->lastHistoryImageSwapped =
114 (this->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES;
116 uint8_t* swappingImageBuffer =
117 historyImage + (this->lastHistoryImageSwapped) * numValues;
119 /* Now, we move in the buffer and leave the historyImages. */
120 int32_t numberOfTests = (this->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
122 for (int32_t index = pixels - 1; index >= 0; --index) {
123 if (segmentationMap[index] > 0) {
124 /* We need to check the full border and swap values with the first or
125 * second historyImage. We still need to find a match before we can stop
128 uint32_t indexHistoryBuffer = (Channels * index) * numberOfTests;
129 uint8_t currentValue[Channels];
131 internals::CopyPixel<Channels>::copy(
133 buffer + (Channels * index)
136 for (int i = numberOfTests; i > 0; --i, indexHistoryBuffer += Channels) {
140 historyBuffer + indexHistoryBuffer,
144 --segmentationMap[index];
146 /* Swaping: Putting found value in history image buffer. */
147 internals::SwapPixels<Channels>::swap(
148 swappingImageBuffer + (Channels * index),
149 historyBuffer + indexHistoryBuffer
152 /* Exit inner loop. */
153 if (segmentationMap[index] <= 0)
160 /* Produces the output. Note that this step is application-dependent. */
162 uint8_t* mask = segmentationMap;
163 mask < segmentationMap + pixels;
171 /******************************************************************************/
173 template <int32_t Channels, class Distance>
174 void ViBeSequential<Channels, Distance>::_CRTP_update(
175 const uint8_t* buffer,
176 uint8_t* updatingMask
180 throw; // TODO Exception
182 if (updatingMask == NULL)
183 throw; // TODO Exception
186 /* Some variables. */
187 static const uint32_t NUMBER_OF_HISTORY_IMAGES =
188 this->NUMBER_OF_HISTORY_IMAGES;
190 static const uint8_t BACKGROUND = this->BACKGROUND;
192 uint32_t height = this->height;
193 uint32_t width = this->width;
194 uint32_t numValues = this->numValues;
196 uint8_t* historyImage = this->historyImage;
197 uint8_t* historyBuffer = this->historyBuffer;
199 /* Some utility variable. */
200 int numberOfTests = (this->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
202 uint32_t* jump = this->jump;
203 int32_t* neighbor = this->neighbor;
204 uint32_t* position = this->position;
206 /* All the frame, except the border. */
207 uint32_t shift, indX, indY;
210 for (y = 1; y < height - 1; ++y) {
211 shift = rand() % width;
212 indX = jump[shift]; // index_jump should never be zero (> 1).
214 while (indX < width - 1) {
215 int index = indX + y * width;
217 if (updatingMask[index] == BACKGROUND) {
218 /* In-place substitution. */
219 uint8_t currentValue[Channels];
221 internals::CopyPixel<Channels>::copy(
223 buffer + (Channels * index)
226 int indexNeighbor = Channels * (index + neighbor[shift]);
228 if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
229 internals::CopyPixel<Channels>::copy(
230 historyImage + (Channels * index + position[shift] * numValues),
234 internals::CopyPixel<Channels>::copy(
235 historyImage + (indexNeighbor + position[shift] * numValues),
240 int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
242 internals::CopyPixel<Channels>::copy(
244 (Channels * index) * numberOfTests + Channels * pos
249 internals::CopyPixel<Channels>::copy(
250 historyBuffer + (indexNeighbor * numberOfTests + Channels * pos),
263 shift = rand() % width;
264 indX = jump[shift]; // index_jump should never be zero (> 1).
266 while (indX <= width - 1) {
267 int index = indX + y * width;
269 if (updatingMask[index] == BACKGROUND) {
270 if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
271 internals::CopyPixel<Channels>::copy(
272 historyImage + (Channels * index + position[shift] * numValues),
273 buffer + (Channels * index)
277 int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
279 internals::CopyPixel<Channels>::copy(
280 historyBuffer + ((Channels * index) * numberOfTests + Channels * pos),
281 buffer + (Channels * index)
292 shift = rand() % width;
293 indX = jump[shift]; // index_jump should never be zero (> 1).
295 while (indX <= width - 1) {
296 int index = indX + y * width;
298 if (updatingMask[index] == BACKGROUND) {
299 if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
300 internals::CopyPixel<Channels>::copy(
301 historyImage + (Channels * index + position[shift] * numValues),
302 buffer + (Channels * index)
306 int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
308 internals::CopyPixel<Channels>::copy(
309 historyBuffer + ((Channels * index) * numberOfTests + Channels * pos),
310 buffer + (Channels * index)
321 shift = rand() % height;
322 indY = jump[shift]; // index_jump should never be zero (> 1).
324 while (indY <= height - 1) {
325 int index = x + indY * width;
327 if (updatingMask[index] == BACKGROUND) {
328 if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
329 internals::CopyPixel<Channels>::copy(
330 historyImage + (Channels * index + position[shift] * numValues),
331 buffer + (Channels * index)
335 int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
337 internals::CopyPixel<Channels>::copy(
338 historyBuffer + ((Channels * index) * numberOfTests + Channels * pos),
339 buffer + (Channels * index)
350 shift = rand() % height;
351 indY = jump[shift]; // index_jump should never be zero (> 1).
353 while (indY <= height - 1) {
354 int index = x + indY * width;
356 if (updatingMask[index] == BACKGROUND) {
357 if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
358 internals::CopyPixel<Channels>::copy(
359 historyImage + (Channels * index + position[shift] * numValues),
360 buffer + (Channels * index)
364 int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
366 internals::CopyPixel<Channels>::copy(
367 historyBuffer + ((Channels * index) * numberOfTests + Channels * pos),
368 buffer + (Channels * index)
377 /* The first pixel! */
378 if (rand() % this->updateFactor == 0) {
379 if (updatingMask[0] == 0) {
380 uint32_t position = rand() % this->numberOfSamples;
382 if (position < NUMBER_OF_HISTORY_IMAGES) {
383 internals::CopyPixel<Channels>::copy(
384 historyImage + (position * numValues),
389 int pos = position - NUMBER_OF_HISTORY_IMAGES;
391 internals::CopyPixel<Channels>::copy(
392 historyBuffer + (Channels * pos),
400 #endif /* _LIB_VIBE_XX_VIBE_H_ */