Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
vibe-background-sequential.cpp 35.08 KiB
#include <assert.h>
#include <time.h>
#include "vibe-background-sequential.h"
//using namespace bgslibrary::algorithms::vibe;
namespace bgslibrary
{
namespace algorithms
{
namespace vibe
{
uint32_t distance_Han2014Improved(uint8_t pixel, uint8_t bg)
{
uint8_t min, max;
// Computes R = 0.13 min{ max[bg,26], 230}
max = 26;
if (bg > max) { max = bg; }
min = 230;
if (min > max) { min = max; }
return (uint32_t)(0.13*min);
}
static int abs_uint(const int i)
{
return (i >= 0) ? i : -i;
}
static int32_t distance_is_close_8u_C3R(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2, uint32_t threshold)
{
return (abs_uint(r1 - r2) + abs_uint(g1 - g2) + abs_uint(b1 - b2) <= 4.5 * threshold);
}
struct vibeModel_Sequential
{
/* Parameters. */
uint32_t width;
uint32_t height;
uint32_t numberOfSamples;
uint32_t matchingThreshold;
uint32_t matchingNumber;
uint32_t updateFactor;
/* Storage for the history. */
uint8_t *historyImage;
uint8_t *historyBuffer;
uint32_t lastHistoryImageSwapped;
/* Buffers with random values. */
uint32_t *jump;
int *neighbor;
uint32_t *position;
};
// -----------------------------------------------------------------------------
// Print parameters
// -----------------------------------------------------------------------------
uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model)
{
printf(
"Using ViBe background subtraction algorithm\n"
" - Number of samples per pixel: %03d\n"
" - Number of matches needed: %03d\n"
" - Matching threshold: %03d\n"
" - Model update subsampling factor: %03d\n",
libvibeModel_Sequential_GetNumberOfSamples(model),
libvibeModel_Sequential_GetMatchingNumber(model),
libvibeModel_Sequential_GetMatchingThreshold(model),
libvibeModel_Sequential_GetUpdateFactor(model)
);
return(0);
}
// -----------------------------------------------------------------------------
// Creates the data structure
// -----------------------------------------------------------------------------
vibeModel_Sequential_t *libvibeModel_Sequential_New()
{
/* Model structure alloc. */
vibeModel_Sequential_t *model = NULL;
model = (vibeModel_Sequential_t*)calloc(1, sizeof(*model));
assert(model != NULL);
/* Default parameters values. */
model->numberOfSamples = 20;
model->matchingThreshold = 20;
model->matchingNumber = 2;
model->updateFactor = 16;
/* Storage for the history. */
model->historyImage = NULL;
model->historyBuffer = NULL;
model->lastHistoryImageSwapped = 0;
/* Buffers with random values. */
model->jump = NULL;
model->neighbor = NULL;
model->position = NULL;
return(model);
}
// -----------------------------------------------------------------------------
// Some "Get-ers"
// -----------------------------------------------------------------------------
uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model)
{
assert(model != NULL); return(model->numberOfSamples);
}
uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model)
{
assert(model != NULL); return(model->matchingNumber);
}
uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model)
{
assert(model != NULL); return(model->matchingThreshold);
}
uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model)
{
assert(model != NULL); return(model->updateFactor);
}
// -----------------------------------------------------------------------------
// Some "Set-ers"
// -----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_SetMatchingThreshold(
vibeModel_Sequential_t *model,
const uint32_t matchingThreshold
) {
assert(model != NULL);
assert(matchingThreshold > 0);
model->matchingThreshold = matchingThreshold;
return(0);
}
// -----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_SetMatchingNumber(
vibeModel_Sequential_t *model,
const uint32_t matchingNumber
) {
assert(model != NULL);
assert(matchingNumber > 0);
model->matchingNumber = matchingNumber;
return(0);
}
// -----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_SetUpdateFactor(
vibeModel_Sequential_t *model,
const uint32_t updateFactor
) {
assert(model != NULL);
assert(updateFactor > 0);
model->updateFactor = updateFactor;
/* We also need to change the values of the jump buffer ! */
assert(model->jump != NULL);
/* Shifts. */
int size = (model->width > model->height) ? 2 * model->width + 1 : 2 * model->height + 1;
for (int i = 0; i < size; ++i)
model->jump[i] = (updateFactor == 1) ? 1 : (rand() % (2 * model->updateFactor)) + 1; // 1 or values between 1 and 2 * updateFactor.
return(0);
}
// ----------------------------------------------------------------------------
// Frees the structure
// ----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model)
{
if (model == NULL)
return(-1);
if (model->historyBuffer == NULL) {
free(model);
return(0);
}
free(model->historyImage);
free(model->historyBuffer);
free(model->jump);
free(model->neighbor);
free(model->position);
free(model);
return(0);
}
// -----------------------------------------------------------------------------
// Allocates and initializes a C1R model structure
// -----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_AllocInit_8u_C1R(
vibeModel_Sequential_t *model,
const uint8_t *image_data,
const uint32_t width,
const uint32_t height
) {
// Some basic checks. */
assert((image_data != NULL) && (model != NULL));
assert((width > 0) && (height > 0));
/* Finish model alloc - parameters values cannot be changed anymore. */
model->width = width;
model->height = height;
/* Creates the historyImage structure. */
model->historyImage = NULL;
model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * width * height * sizeof(*(model->historyImage)));
assert(model->historyImage != NULL);
for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
for (int index = width * height - 1; index >= 0; --index)
model->historyImage[i * width * height + index] = image_data[index];
}
/* Now creates and fills the history buffer. */
model->historyBuffer = (uint8_t*)malloc(width * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t));
assert(model->historyBuffer != NULL);
for (int index = width * height - 1; index >= 0; --index) {
uint8_t value = image_data[index];
for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) {
int value_plus_noise = value + rand() % 20 - 10;
if (value_plus_noise < 0) { value_plus_noise = 0; }
if (value_plus_noise > 255) { value_plus_noise = 255; }
model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise;
}
}
/* Fills the buffers with random values. */
int size = (width > height) ? 2 * width + 1 : 2 * height + 1;
model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump)));
assert(model->jump != NULL);
model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor)));
assert(model->neighbor != NULL);
model->position = (uint32_t*)malloc(size * sizeof(*(model->position)));
assert(model->position != NULL);
for (int i = 0; i < size; ++i) {
model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor.
model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }.
model->position[i] = rand() % (model->numberOfSamples); // Values between 0 and numberOfSamples - 1.
}
return(0);
}
// -----------------------------------------------------------------------------
// Segmentation of a C1R model
// -----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_Segmentation_8u_C1R(
vibeModel_Sequential_t *model,
const uint8_t *image_data,
uint8_t *segmentation_map
) {
/* Basic checks. */
assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL));
assert((model->width > 0) && (model->height > 0));
assert(model->historyBuffer != NULL);
assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
/* Some variables. */
uint32_t width = model->width;
uint32_t height = model->height;
uint32_t matchingNumber = model->matchingNumber;
//uint32_t matchingThreshold = model->matchingThreshold;
uint8_t *historyImage = model->historyImage;
uint8_t *historyBuffer = model->historyBuffer;
/* Segmentation. */
memset(segmentation_map, matchingNumber - 1, width * height);
/* First history Image structure. */
for (int index = width * height - 1; index >= 0; --index) {
//if (abs_uint(image_data[index] - historyImage[index]) > matchingThreshold)
if (abs_uint(image_data[index] - historyImage[index]) > distance_Han2014Improved(image_data[index], historyImage[index]))
segmentation_map[index] = matchingNumber;
}
/* Next historyImages. */
for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
uint8_t *pels = historyImage + i * width * height;
for (int index = width * height - 1; index >= 0; --index) {
// if (abs_uint(image_data[index] - pels[index]) <= matchingThreshold)
if (abs_uint(image_data[index] - pels[index]) <= distance_Han2014Improved(image_data[index], pels[index]))
--segmentation_map[index];
}
}
/* For swapping. */
model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES;
uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * width * height;
/* Now, we move in the buffer and leave the historyImages. */
int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
for (int index = width * height - 1; index >= 0; --index) {
if (segmentation_map[index] > 0) {
/* We need to check the full border and swap values with the first or second historyImage.
* We still need to find a match before we can stop our search.
*/
uint32_t indexHistoryBuffer = index * numberOfTests;
uint8_t currentValue = image_data[index];
for (int i = numberOfTests; i > 0; --i, ++indexHistoryBuffer) {
// if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= matchingThreshold) {
if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= distance_Han2014Improved(currentValue, historyBuffer[indexHistoryBuffer])) {
--segmentation_map[index];
/* Swaping: Putting found value in history image buffer. */
uint8_t temp = swappingImageBuffer[index];
swappingImageBuffer[index] = historyBuffer[indexHistoryBuffer];
historyBuffer[indexHistoryBuffer] = temp;
/* Exit inner loop. */
if (segmentation_map[index] <= 0) break;
}
} // for
} // if
} // for
/* Produces the output. Note that this step is application-dependent. */
for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask)
if (*mask > 0) *mask = COLOR_FOREGROUND;
return(0);
}
// ----------------------------------------------------------------------------
// Update a C1R model
// ----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_Update_8u_C1R(
vibeModel_Sequential_t *model,
const uint8_t *image_data,
uint8_t *updating_mask
) {
/* Basic checks . */
assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL));
assert((model->width > 0) && (model->height > 0));
assert(model->historyBuffer != NULL);
assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
/* Some variables. */
uint32_t width = model->width;
uint32_t height = model->height;
uint8_t *historyImage = model->historyImage;
uint8_t *historyBuffer = model->historyBuffer;
/* Some utility variable. */
int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
/* Updating. */
uint32_t *jump = model->jump;
int *neighbor = model->neighbor;
uint32_t *position = model->position;
/* All the frame, except the border. */
uint32_t shift, indX, indY;
unsigned int x, y;
for (y = 1; y < height - 1; ++y) {
shift = rand() % width;
indX = jump[shift]; // index_jump should never be zero (> 1).
while (indX < width - 1) {
int index = indX + y * width;
if (updating_mask[index] == COLOR_BACKGROUND) {
/* In-place substitution. */
uint8_t value = image_data[index];
int index_neighbor = index + neighbor[shift];
if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
historyImage[index + position[shift] * width * height] = value;
historyImage[index_neighbor + position[shift] * width * height] = value;
}
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[index * numberOfTests + pos] = value;
historyBuffer[index_neighbor * numberOfTests + pos] = value;
}
}
++shift;
indX += jump[shift];
}
}
/* First row. */
y = 0;
shift = rand() % width;
indX = jump[shift]; // index_jump should never be zero (> 1).
while (indX <= width - 1) {
int index = indX + y * width;
if (updating_mask[index] == COLOR_BACKGROUND) {
if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
historyImage[index + position[shift] * width * height] = image_data[index];
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[index * numberOfTests + pos] = image_data[index];
}
}
++shift;
indX += jump[shift];
}
/* Last row. */
y = height - 1;
shift = rand() % width;
indX = jump[shift]; // index_jump should never be zero (> 1).
while (indX <= width - 1) {
int index = indX + y * width;
if (updating_mask[index] == COLOR_BACKGROUND) {
if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
historyImage[index + position[shift] * width * height] = image_data[index];
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[index * numberOfTests + pos] = image_data[index];
}
}
++shift;
indX += jump[shift];
}
/* First column. */
x = 0;
shift = rand() % height;
indY = jump[shift]; // index_jump should never be zero (> 1).
while (indY <= height - 1) {
int index = x + indY * width;
if (updating_mask[index] == COLOR_BACKGROUND) {
if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
historyImage[index + position[shift] * width * height] = image_data[index];
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[index * numberOfTests + pos] = image_data[index];
}
}
++shift;
indY += jump[shift];
}
/* Last column. */
x = width - 1;
shift = rand() % height;
indY = jump[shift]; // index_jump should never be zero (> 1).
while (indY <= height - 1) {
int index = x + indY * width;
if (updating_mask[index] == COLOR_BACKGROUND) {
if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
historyImage[index + position[shift] * width * height] = image_data[index];
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[index * numberOfTests + pos] = image_data[index];
}
}
++shift;
indY += jump[shift];
}
/* The first pixel! */
if (rand() % model->updateFactor == 0) {
if (updating_mask[0] == 0) {
int position = rand() % model->numberOfSamples;
if (position < NUMBER_OF_HISTORY_IMAGES)
historyImage[position * width * height] = image_data[0];
else {
int pos = position - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[pos] = image_data[0];
}
}
}
return(0);
}
// ----------------------------------------------------------------------------
// -------------------------- The same for C3R models -------------------------
// ----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Allocates and initializes a C3R model structure
// -----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_AllocInit_8u_C3R(
vibeModel_Sequential_t *model,
const uint8_t *image_data,
const uint32_t width,
const uint32_t height
) {
/* Some basic checks. */
assert((image_data != NULL) && (model != NULL));
assert((width > 0) && (height > 0));
/* Finish model alloc - parameters values cannot be changed anymore. */
model->width = width;
model->height = height;
/* Creates the historyImage structure. */
model->historyImage = NULL;
model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * (3 * width) * height * sizeof(uint8_t));
assert(model->historyImage != NULL);
for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
for (int index = (3 * width) * height - 1; index >= 0; --index)
model->historyImage[i * (3 * width) * height + index] = image_data[index];
}
assert(model->historyImage != NULL);
/* Now creates and fills the history buffer. */
model->historyBuffer = (uint8_t *)malloc((3 * width) * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t));
assert(model->historyBuffer != NULL);
auto plus_noise = [](uint8_t value) -> int {int value_plus_noise = value + rand() % 20 - 10;
if (value_plus_noise < 0) { value_plus_noise = 0; }
if (value_plus_noise > 255) { value_plus_noise = 255; }
return value_plus_noise;};
for(int index = (3 * width) * height - 1; index >= 0; index -= 3) {
uint8_t value_1 = image_data[index];
uint8_t value_2 = image_data[index - 1];
uint8_t value_3 = image_data[index - 2];
for(int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) {
int value_plus_noise1 = plus_noise(value_1);
int value_plus_noise2 = plus_noise(value_2);
int value_plus_noise3 = plus_noise(value_3);
model->historyBuffer[(index - 2) * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x * 3 + 2] = value_plus_noise1;
model->historyBuffer[(index - 2) * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x * 3 + 1] = value_plus_noise2;
model->historyBuffer[(index - 2) * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x * 3] = value_plus_noise3;
}
}
/* Fills the buffers with random values. */
int size = (width > height) ? 2 * width + 1 : 2 * height + 1;
model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump)));
assert(model->jump != NULL);
model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor)));
assert(model->neighbor != NULL);
model->position = (uint32_t*)malloc(size * sizeof(*(model->position)));
assert(model->position != NULL);
for (int i = 0; i < size; ++i) {
model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor.
model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { width - 1, ... , width + 1 }.
model->position[i] = rand() % (model->numberOfSamples); // Values between 0 and numberOfSamples - 1.
}
return(0);
}
// -----------------------------------------------------------------------------
// Segmentation of a C3R model
// -----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_Segmentation_8u_C3R(
vibeModel_Sequential_t *model,
const uint8_t *image_data,
uint8_t *segmentation_map
) {
/* Basic checks. */
assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL));
assert((model->width > 0) && (model->height > 0));
assert(model->historyBuffer != NULL);
assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
/* Some variables. */
uint32_t width = model->width;
uint32_t height = model->height;
uint32_t matchingNumber = model->matchingNumber;
uint32_t matchingThreshold = model->matchingThreshold;
uint8_t *historyImage = model->historyImage;
uint8_t *historyBuffer = model->historyBuffer;
/* Segmentation. */
memset(segmentation_map, matchingNumber - 1, width * height);
/* First history Image structure. */
uint8_t *first = historyImage;
for (int index = width * height - 1; index >= 0; --index) {
if (
!distance_is_close_8u_C3R(
image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2],
first[3 * index], first[3 * index + 1], first[3 * index + 2], matchingThreshold
)
)
segmentation_map[index] = matchingNumber;
}
/* Next historyImages. */
for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
uint8_t *pels = historyImage + i * (3 * width) * height;
for (int index = width * height - 1; index >= 0; --index) {
if (
distance_is_close_8u_C3R(
image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2],
pels[3 * index], pels[3 * index + 1], pels[3 * index + 2], matchingThreshold
)
)
--segmentation_map[index];
}
}
// For swapping
model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES;
uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * (3 * width) * height;
// Now, we move in the buffer and leave the historyImages
int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
for (int index = width * height - 1; index >= 0; --index) {
if (segmentation_map[index] > 0) {
/* We need to check the full border and swap values with the first or second historyImage.
* We still need to find a match before we can stop our search.
*/
uint32_t indexHistoryBuffer = (3 * index) * numberOfTests;
for (int i = numberOfTests; i > 0; --i, indexHistoryBuffer += 3) {
if (
distance_is_close_8u_C3R(
image_data[(3 * index)], image_data[(3 * index) + 1], image_data[(3 * index) + 2],
historyBuffer[indexHistoryBuffer], historyBuffer[indexHistoryBuffer + 1], historyBuffer[indexHistoryBuffer + 2],
matchingThreshold
)
)
--segmentation_map[index];
/* Swaping: Putting found value in history image buffer. */
uint8_t temp_r = swappingImageBuffer[(3 * index)];
uint8_t temp_g = swappingImageBuffer[(3 * index) + 1];
uint8_t temp_b = swappingImageBuffer[(3 * index) + 2];
swappingImageBuffer[(3 * index)] = historyBuffer[indexHistoryBuffer];
swappingImageBuffer[(3 * index) + 1] = historyBuffer[indexHistoryBuffer + 1];
swappingImageBuffer[(3 * index) + 2] = historyBuffer[indexHistoryBuffer + 2];
historyBuffer[indexHistoryBuffer] = temp_r;
historyBuffer[indexHistoryBuffer + 1] = temp_g;
historyBuffer[indexHistoryBuffer + 2] = temp_b;
/* Exit inner loop. */
if (segmentation_map[index] <= 0) break;
} // for
} // if
} // for
/* Produces the output. Note that this step is application-dependent. */
for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask)
if (*mask > 0) *mask = COLOR_FOREGROUND;
return(0);
}
// ----------------------------------------------------------------------------
// Update a C3R model
// ----------------------------------------------------------------------------
int32_t libvibeModel_Sequential_Update_8u_C3R(
vibeModel_Sequential_t *model,
const uint8_t *image_data,
uint8_t *updating_mask
) {
/* Basic checks. */
assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL));
assert((model->width > 0) && (model->height > 0));
assert(model->historyBuffer != NULL);
assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
/* Some variables. */
uint32_t width = model->width;
uint32_t height = model->height;
uint8_t *historyImage = model->historyImage;
uint8_t *historyBuffer = model->historyBuffer;
/* Some utility variable. */
int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
/* Updating. */
uint32_t *jump = model->jump;
int *neighbor = model->neighbor;
uint32_t *position = model->position;
/* All the frame, except the border. */
uint32_t shift, indX, indY;
int x, y;
for (y = 1; y < height - 1; ++y) {
shift = rand() % width;
indX = jump[shift]; // index_jump should never be zero (> 1).
while (indX < width - 1) {
int index = indX + y * width;
if (updating_mask[index] == COLOR_BACKGROUND) {
/* In-place substitution. */
uint8_t r = image_data[3 * index];
uint8_t g = image_data[3 * index + 1];
uint8_t b = image_data[3 * index + 2];
int index_neighbor = 3 * (index + neighbor[shift]);
if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
historyImage[3 * index + position[shift] * (3 * width) * height] = r;
historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
historyImage[index_neighbor + position[shift] * (3 * width) * height] = r;
historyImage[index_neighbor + position[shift] * (3 * width) * height + 1] = g;
historyImage[index_neighbor + position[shift] * (3 * width) * height + 2] = b;
}
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
historyBuffer[index_neighbor * numberOfTests + 3 * pos] = r;
historyBuffer[index_neighbor * numberOfTests + 3 * pos + 1] = g;
historyBuffer[index_neighbor * numberOfTests + 3 * pos + 2] = b;
}
}
++shift;
indX += jump[shift];
}
}
/* First row. */
y = 0;
shift = rand() % width;
indX = jump[shift]; // index_jump should never be zero (> 1).
while (indX <= width - 1) {
int index = indX + y * width;
uint8_t r = image_data[3 * index];
uint8_t g = image_data[3 * index + 1];
uint8_t b = image_data[3 * index + 2];
if (updating_mask[index] == COLOR_BACKGROUND) {
if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
historyImage[3 * index + position[shift] * (3 * width) * height] = r;
historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
}
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
}
}
++shift;
indX += jump[shift];
}
/* Last row. */
y = height - 1;
shift = rand() % width;
indX = jump[shift]; // index_jump should never be zero (> 1).
while (indX <= width - 1) {
int index = indX + y * width;
uint8_t r = image_data[3 * index];
uint8_t g = image_data[3 * index + 1];
uint8_t b = image_data[3 * index + 2];
if (updating_mask[index] == COLOR_BACKGROUND) {
if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
historyImage[3 * index + position[shift] * (3 * width) * height] = r;
historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
}
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
}
}
++shift;
indX += jump[shift];
}
/* First column. */
x = 0;
shift = rand() % height;
indY = jump[shift]; // index_jump should never be zero (> 1).
while (indY <= height - 1) {
int index = x + indY * width;
uint8_t r = image_data[3 * index];
uint8_t g = image_data[3 * index + 1];
uint8_t b = image_data[3 * index + 2];
if (updating_mask[index] == COLOR_BACKGROUND) {
if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
historyImage[3 * index + position[shift] * (3 * width) * height] = r;
historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
}
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
}
}
++shift;
indY += jump[shift];
}
/* Last column. */
x = width - 1;
shift = rand() % height;
indY = jump[shift]; // index_jump should never be zero (> 1).
while (indY <= height - 1) {
int index = x + indY * width;
uint8_t r = image_data[3 * index];
uint8_t g = image_data[3 * index + 1];
uint8_t b = image_data[3 * index + 2];
if (updating_mask[index] == COLOR_BACKGROUND) {
if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
historyImage[3 * index + position[shift] * (3 * width) * height] = r;
historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
}
else {
int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
}
}
++shift;
indY += jump[shift];
}
/* The first pixel! */
if (rand() % model->updateFactor == 0) {
if (updating_mask[0] == 0) {
int position = rand() % model->numberOfSamples;
uint8_t r = image_data[0];
uint8_t g = image_data[1];
uint8_t b = image_data[2];
if (position < NUMBER_OF_HISTORY_IMAGES) {
historyImage[position * (3 * width) * height] = r;
historyImage[position * (3 * width) * height + 1] = g;
historyImage[position * (3 * width) * height + 2] = b;
}
else {
int pos = position - NUMBER_OF_HISTORY_IMAGES;
historyBuffer[3 * pos] = r;
historyBuffer[3 * pos + 1] = g;
historyBuffer[3 * pos + 2] = b;
}
}
}
return(0);
}
}
}
}