contributed by Nicolas Wiest-Daesslé

This is a short tutorial for ImLib3D, a C++ templated library for three dimensional image processing and manipulation. The library relies heavily on templates, in a similar manner as the Standard Template Library does.

As a user of the library one should have a little knowledge on how to use the STL and its iterators.

First Steps

Here we require that imlib3d already be compiled, and that all issues concerning its installation or its compilation already be solved. Using ImLib3D then only requires the user to know how to compile a c++ file.

The following shell commands should be available, and their output should be similar to this:

[user@localhost]$ pkg-config --modversion imlib3d

[user@localhost]$ pkg-config --cflags imlib3d
-I/usr/include/ImLib3D-0.9.2 -I/usr/include/libxml++-2.6 -I/usr/lib/libxml++-2.6/include
-I/usr/include/libxml2 -I/usr/include/glibmm-2.4 -I/usr/lib/glibmm-2.4/include -I/usr/include/sigc++-2.0 
-I/usr/lib/sigc++-2.0/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include

[user@localhost]$ pkg-config --libs imlib3d
-lImLib3D -lavwio -lxml++-2.6 -lgsl -lgslcblas -lfftw3 -lfftw3f -lxml2 -lpthread -lz -lm 
-lglibmm-2.4 -lgobject-2.0 -lsigc-2.0 -lglib-2.0

If the output is not similar to that, you should consider modifying your PKG_CONFIG_PATH, PATH and LD_LIBRARY_PATH environment variables (or your Operating System relevant user definable library path, like DYLD_LIBRARY_PATH for Darwin/OSX).

Now we will try to get an example up and running. Let's take the file Example1.cpp from ImLib3D example directory:

#include <ImLib3D/ImLib3D.hpp>
#include <ImLib3D/TestPatterns.hpp>

// Basic creation, access, file 

main(int argc,char **argv)
    // Declare a floating point image. Images are initialized with 0 size
    Image3Df image;

    // create a uniform noise image of size 100x100x100

    // Change some arbitrary values

    // Write the image to a file

This file is quite simple in fact,
#include <ImLib3D/ImLib3D.hpp> this gives access to basic ImLib3D functionality
#include <ImLib3D/TestPatterns.hpp> this is required in our example because we want to build an image filled with noise.

Now we enter the main function.
Image3Df image; this defines an ImLib3D image containing floating point data.
IP3D::NoiseUniform(Size3D(100,100,100),image); this statement is a call to a the NoiseUniform function from the namespace IP3D, it takes two arguments: a Size3D object, and an image.

So now we have an image at our disposal, with dimension 100 ³ filled with uniform noise. We can now, access some pixels in the image using the "(" ")" operators : image(20,10,30)=.5;

The last line, image.WriteToFile("example1.im3D"); writes the image to a file (ImLib3D format: xml header + binary data).

The next step is compiling the stuff so that we will get a program:

g++ -Wall Example1.cpp -o example1 `pkg-config --cflags --libs imlib3d`
Now we can launch the new example1 program (remember that on Unix systems we should launch it with ./example1).


Right now you are able to build some application with only a few lines, but nothing really useful for image processing, let's dig a little further.

ImLib3D is like the Standard Template Library: it uses iterators to walk through its data. This looks like what we did in good old C with pointers, but this is done in a more controlled manner, or in a not so ``simple way''.

let's say we have the following code:

#include <ImLib3D/ImLib3D.hpp>

void ExampleFunction()
  Image3Df image;
this gives us access to ImLib3D core, and it also gave us an image. Let's update the code so that we'll get a new image 128 ³ voxels.
#include <ImLib3D/ImLib3D.hpp>

void ExampleFunction()
  // First Way
  Image3Df image(128,128,128);
  /* we could have done it that way:
  Image3Df image;

  /* or that way
  Size3D size(128,128,128);
  Image3Df image(size);  

Now you should be wondering "how the hell can I walk through that image!"

Let's do it!


#include <ImLib3D/ImLib3D.hpp>

void ExampleFunction()
  // Our image
  Image3Df image(128,128,128);

  // Good old C programmer would do so:
  for (int i = 0; i < image.Width(); ++i)
    for (int j = 0; j < image.Height(); ++j)
      for (int k = 0; k < image.Depth(); ++k)
        image(i,j,k) = 0;

  //  That's ok, but  how do you know what the order of the data in
  //  memory is? Is this the fastest way to do walk the data, or should
  //  the k loop be before the j loop...?
  //  Let's do the same thing, the STL way!

  for (Image3Df::iterator it = image.begin(); it != image.end(); ++it)
    *it = 0;

Here we have two ways of iterating through the image, but the STL way is more efficient, requires less code, and has a syntax that can be generalized to more complex ways of walking through the image.

but one would say: ``hey stop! how do we know the position I'm at!''

well, there's two answers to that.

First: are you sure you need it? Many simple operations in image processing do not really require for the algorithm to know the coordinates of the pixel it is processing. If you don't need this information use the standard iterator. It's really fast.

Second: if you do need the coordinates, then use iteratorXYZ instead of plain iterator. This iterator has x,y,z coordinates: in the previous example, you could now write "it.x" or "it.z"... (this iterator is only slightly slower than the previous iterator).

exercise: Implement a threshold function.

There can be multiple way of walking through an image, so the user can rely on multiple types of iterators like the following ones:

iterator, the standard one
iteratorFast, same as iterator, only a synonym
iteratorXYZ, iterator that keeps track of x,y,z position
iteratorZone, iterator for walking through a rectangular portion
iteratorFastMasked, ignore certain points of the image, as specified by a mask image
iteratorXYZMasked, same thing.