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-&gt;buf;

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

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

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

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

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

    for (int i=0; i!=half_window; i++){
        memcpy(&amp;output_buf[(half_window-1)*output-&gt;w - i*output-&gt;w], &amp;output_buf[half_window*output-&gt;w + i*output-&gt;w], sizeof(uint8_t)*output-&gt;w);
        memcpy(&amp;output_buf[(output-&gt;h - half_window)*output-&gt;w + i*output-&gt;w], &amp;output_buf[(output-&gt;h-half_window-1)*output-&gt;w - i*output-&gt;w], sizeof(uint8_t)*output-&gt;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;   ///&lt; The image type
  uint16_t w;             ///&lt; Image width
  uint16_t h;             ///&lt; Image height
  struct timeval ts;      ///&lt; The timestamp of creation

  uint8_t buf_idx;        ///&lt; Buffer index for V4L2 freeing
  uint32_t buf_size;      ///&lt; The buffer size
  void *buf;              ///&lt; 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-&gt;type = type;
  img-&gt;w = width;
  img-&gt;h = height;


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

  img-&gt;buf = malloc(img-&gt;buf_size);
}


My code for image padding:

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

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

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

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

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

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

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