Contenu | Menu

Last week I wrote the image structures, with 3 different structures (image_u8, image_u16, image_f32) for 3 different basic types (8bit integer, 16bit integer, 32bit floats). As I wanted a common interface to these structures, I wrote a king of "meta-structure", using C unions to make some kind of subclass design.

I still think it was a good idea, and it worked, but.... why not make it simple. KISS, Keep It Simple (Stupid!). I guess this pseudo-class design was a consequence of the previous codebase, and I used code tricks instead of imagination.

So, after a midnight revelation (yes, around 03:00, in bed...) and a few days rewriting (again...), the design is now simple, very simple:

new image design

The image definition is:

/**
 * generic image structure
 */
typedef struct s_image
{
/* TODO : add bit depth and channels */
     mw_dtype dtype;   /**< datatype of the stored values */
     uint16 ncol;      /**< number of columns */
     uint16 nrow;      /**< number of rows    */
     void * data;      /**< data array        */
} mw_image;

Yes, that's it. An image is:

Later, we may introduce some other structure fields, if they are needed my many algorithms; but the best way could be to add a simple generic pointer, and let everyone use it as they like (or even register some alloc/dealloc/copy routines).

For color images, the idea is to add a uint8 nchn field for the number of channels; then, we have the following correspondances:

But it still is possible to define a 255 channels images, if it makes sense (for the algo and for the memory space).

user interface

This generic data array can be used in different ways:

Some profiling is planned, to provide comparative measures of the performance of these levels.

code architecture

This change improves the code architecture, function calls, and dependencies. Now it's possible to implement generic image-processing algorithms without the hassle of dealing with subtypes, unions, and so on. The image file (TXT, PNG, tIFF...) read/write routines are also simplified:

mw image read.png

fast loops

By the way, the images are stored by rows, X-style ((0, 0) is the upper-left corner). So, the efficient way to pass through all the pixels is:

uint8 * data;
uint16 nrow, ncol;

data = (uint8 *) image->data;
nrow = data->nrow;
ncol = data->ncol;
for (y = 0; y < nrow; y++)
    for (x = 0; x < ncol; x++)
        do_stuff_with(data[y * ncol + x]);

This ensures a better memory localisation, less CPU cache miss, ... a faster code.

If performance is a matter, pointer arithmetics will save one sum, one product, some tests and some registers at each loop, but the code will be a bit obfuscated:

uint8 * ptr, * stop;

ptr = (uint8 *) image->data;
stop = ptr + image->ncol * image->nrow;
while (ptr < stop)
    do_stuff_with((* ptr++));