0

I would like to implement a configurable filter for an image processing application.

For this I have a square kernel typically this one for the first pass of a Sobel filter

-1 0 1
-2 0 2
-1 0 1

I can declare my kernel as a fixed array:

#define KERNEL_SIZE 3
int8_t kernel[][KERNEL_SIZE] = {{0,0,0},{0,0,0},{0,0,0}};

With this solution it is easy to pass the kernel to the filtering function:

void filter(char* pixels, kernel[][KERNEL_SIZE]);

However passing the kernel by value is not very wise, especially if the kernel is big and my goal is to allow variable kernel size.

The actual solution I've found is to write this:

size_t kernel_size = 3;
int8_t *kernel = malloc(sizeof(int8_t)*kernel_size*kernel_size);

void filter(char* pixels, char *kernel, size_t kernel_size);

Unfortunately I am not happy with this because I cannot easily access the kernel's rows and columns like before.

I feel this is less readable:

for(x = 0; x < kernel_size; x++)
   for(y = 0; y < kernel_size; y++)
      int8_t k = kernel[x + y * kernel_size];

than this:

for(x = 0; x < kernel_size; x++)
   for(y = 0; y < kernel_size; y++)
      int8_t k = kernel[x][y];

Also the prototype of filter does not give any clue to what the kernel is exactly. It is better if I can directly express that a kernel is a square bi-dimensional array. Unfortunately this statement below is not valid:

 void filter(char* pixels, char kernel[][size_t kernel_size]);

The alternative is to use an array of pointers:

 void filter(char* pixels, char *kernel[], size_t kernel_size);

But I doubt this solution will be more efficient that the previous one because in memory I will have my data + a pointer to each row which is not very good.

So, my question is:

How to properly pass a bi-dimensional array by reference to a function when the size of the array can be variable?

NOTE: Some might advise to use tools like ImageMagick but, here I am just playing with C and this example is pure didactic. I would like to understand more how to pass complex arrays in C

NOTE-bis: Actually the full solution to this problem would be the case of a n-dimensional array.

nowox
  • 25,978
  • 39
  • 143
  • 293
  • You can always write your own type and a few methods to abstract this functionality to a level you feel comfortable with. Something like `typedef struct Kernel { int rows, int columns, char *matrix}` and then for access `char *getCell(Kernel kernel, int x, int y)`. – Morgan Wilde May 26 '15 at 11:04
  • 2
    `void *filter(char * pixels, size_t kernel_size, char kernel[][kernel_size])`? – EOF May 26 '15 at 11:06
  • 1
    Arrays do not get passed by value; unless it's the operand of the `sizeof` or unary `&` operator, an array expression will be converted ("decay") to a pointer expression whose value is the address of the first element. Function parameter declarations of ’T a[]` and `T a[N]` are treated as `T *a`. It's only an issue if you pass a `struct` type by value and the `struct` contains a member of array type. – John Bode May 26 '15 at 11:24
  • @EOF, This is a very neat remark. I am going to test it :) – nowox May 26 '15 at 11:47

0 Answers0