# Efficient image padding in C

I am currently implementing pyramids in Lucas Kanade algorithm for optical flow. To be able to build pyramids, I need to pad the images (mirror edge matrix elements) for the required amount of rows/cols determined by parameter half_window.

I have written this code which works but I am new to C programming and it looks overly complex to me. How would an experienced C programmer write this?

image_t is a struct for storing image data I am required to use. Rest is my code. It first adjusts sizes of output which is a pointer to struct image_t object. Then it builds padded image row by row as follows:

• skip first half_window rows
• mirror first half_window columns of the row
• copy original elements of that row
• mirror the last half_window columns of the row
• skip last half_window rows

Then

• mirror first half_window rows with memcpy
• mirror last half_window rows with memcpy

struct image_t {
enum image_type type;   // The image type
uint16_t w;             // Image width
uint16_t h;             // Image height
struct timeval ts;      // The timestamp of creation

uint8_t buf_idx;        // Buffer index for V4L2 freeing
uint32_t buf_size;      // The buffer size
void *buf;              // Image buffer (depending on the image_type)
};

void pad_image(struct image_t *input, struct image_t *output, uint8_t half_window)
{
uint8_t *input_buf = (uint8_t *)input->buf;

output->h = input->h + 2*half_window;
output->w = input->w + 2*half_window;
output->buf_size = sizeof(uint8_t) * output->h * output->w;
free(output->buf);
output->buf = malloc(output->buf_size);
uint8_t *output_buf = (uint8_t*)output->buf;

for (int i = half_window; i != (output->h-half_window); i++){

for (int j=0; j!=half_window; j++)
output_buf[i*output->w + (half_window -1 - j)] = input_buf[(i-half_window)*input->w + j];

for (int j=half_window; j!=output->w-half_window;j++)
output_buf[i*output->w + j] = input_buf[(i-half_window)*input->w + (j - half_window)];

for (int j=0; j!=half_window;j++)
output_buf[i*output->w + output->w - half_window + j] = output_buf[i*output->w + output->w - half_window -1 - j];
}

for (int i=0; i!=half_window; i++){
memcpy(&output_buf[(half_window-1)*output->w - i*output->w], &output_buf[half_window*output->w + i*output->w], sizeof(uint8_t)*output->w);
memcpy(&output_buf[(output->h - half_window)*output->w + i*output->w], &output_buf[(output->h-half_window-1)*output->w - i*output->w], sizeof(uint8_t)*output->w);

}
}


Input:

   1    2    3    4
5    6    7    8
9   10   11   12
13   14   15   16


Expected output for half_window = 2:

   6    5    5    6    7    8    8    7
2    1    1    2    3    4    4    3
2    1    1    2    3    4    4    3
6    5    5    6    7    8    8    7
10    9    9   10   11   12   12   11
14   13   13   14   15   16   16   15
14   13   13   14   15   16   16   15
10    9    9   10   11   12   12   11


I have made some changes to the code I feel make things more clear, I will post them here in case someone needs something similar.

Code below is used in my function and is work of Freek van Tienen (part of open source software Paparazzi):

struct image_t {
enum image_type type;   ///< The image type
uint16_t w;             ///< Image width
uint16_t h;             ///< Image height
struct timeval ts;      ///< The timestamp of creation

uint8_t buf_idx;        ///< Buffer index for V4L2 freeing
uint32_t buf_size;      ///< The buffer size
void *buf;              ///< Image buffer (depending on the image_type)
};

void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
{
// Set the variables
img->type = type;
img->w = width;
img->h = height;

// Depending on the type the size differs
if (type == IMAGE_YUV422) {
img->buf_size = sizeof(uint8_t) * 2 * width * height;
} else if (type == IMAGE_JPEG) {
img->buf_size = sizeof(uint8_t) * 2 * width * height;  // At maximum quality this is enough
} else if (type == IMAGE_GRADIENT) {
img->buf_size = sizeof(int16_t) * width * height;
} else {
img->buf_size = sizeof(uint8_t) * width * height;
}

img->buf = malloc(img->buf_size);
}


void pad_image(struct image_t *input, struct image_t *output, uint8_t expand)
{
image_create(output, input->w + 2 * expand, input->h + 2 * expand, input->type);

uint8_t *input_buf = (uint8_t *)input->buf;
uint8_t *output_buf = (uint8_t *)output->buf;

// Skip first expand rows, iterate through next input->h rows
for (uint16_t i = expand; i != (output->h - expand); i++){

// Mirror first expand columns
for (uint8_t j = 0; j != expand; j++)
output_buf[i * output->w + (expand - 1 - j)] = input_buf[(i - expand) * input->w + j];

// Copy corresponding row values from input image
memcpy(&output_buf[i * output->w + expand], &input_buf[(i - expand) * input->w], sizeof(uint8_t) * input->w);

// Mirror last expand columns
for (uint8_t j = 0; j != expand; j++)
output_buf[i * output->w + output->w - expand + j] = output_buf[i * output->w + output->w - expand -1 - j];
}

// Mirror first expand and last expand rows
for (uint8_t i = 0; i != expand; i++){
memcpy(&output_buf[(expand - 1) * output->w - i * output->w], &output_buf[expand * output->w + i * output->w], sizeof(uint8_t) * output->w);
memcpy(&output_buf[(output->h - expand) * output->w + i * output->w], &output_buf[(output->h - expand - 1) * output->w - i * output->w], sizeof(uint8_t) * output->w);
}
}

• Does this answer your question? In that case, it is perfectly OK to self-accept your own answer. If it doesn't answer your question, you should possibly close off this entire question, and repost a new question with updated information. – holroy Feb 27 '16 at 19:58