4
\$\begingroup\$

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
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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);
}

My code for image padding:

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);
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ 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. \$\endgroup\$
    – holroy
    Feb 27, 2016 at 19:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.