vil : Core image library

A set of classes to represent and manipulate images

Introduction

Broadly there are two sorts of image one is interested in - images in memory (all parts of which can be accessed directly) and external images (eg in files) which can only be accessed indirectly. In most cases images in files are loaded into memory in one go, where they can then be manipulated. However, for some very large images this is not possible or desirable. In this case it is useful to be able to load in a sub-section of the image, manipulate it, and possible write it out again. vil supports both memory images and external images.

The core class is vil_image_view<T> which gives a view of an image in memory. The only way to get at the pixel data in an image is through a vil_image_view<T>.

Large images (in files) can be accessed through the vil_image_resource class, but one can only get at the data by asking for a view of it, which loads the requested section into memory and creates a suitable vil_image_view<T>.

Images

The vil_image_view<T> represents a view of a multi-plane image of given type. A pointer is stored to the top-left pixel in the first plane of the image (top_left_ptr()) and integers indicating how to get to neighbours in the i (istep()), j (jstep()) and plane (planestep()) directions.

The advantages of this approach are

Note that the same colour image can either be viewed as a one plane image with RGB pixels (using vil_image_view<vil_rgb<vxl_byte> >) or as a 3 plane byte image (using vil_image_view<vxl_byte> with nplanes() == 3).

vil_image_view<vil_rgb<vxl_byte> > rgb_image;
rgb_image = vil_load("my_image.jpg");

// Create a 3 plane view of rgb
vil_image_view<vxl_byte > three_plane_image =  rgb_image;
// or explicitly
three_plane_image =  vil_view_as_planes(rgb_image);
// or with less typing
three_plane_image = vil_load("my_image.jpg");

// Now create rgb view of 3 plane image (note: will set view to empty if not possible)
vil_image_view<vil_rgb<vxl_byte> > rgb_image2 = three_plane_image;
// or explicitly
rgb_image2 = vil_view_as_rgb(three_plane_image);

// If you want a greyscale image no matter whether the underlying image is rgb or grey
vil_image_view<vxl_byte> image2 = vil_convert_to_grey_using_average<vxl_byte>(vil_load("my_image.jpg"),vxl_byte());

There are some conversions that will try a fast view conversion only.

There are some conversions that will process each pixel to do a conversion.

Copying

Since the vil_image_view<T> is a `view' of the actual image data, copying one only copies the `view', not the image data itself - you get two views looking at the same chunk of memory. Some cunning smart pointer stuff is used to ensure that the actual data remains as long as a valid view is looking at it. (Note that this may not always be the case, since the view can be of a chunk of memory that the view does not have direct control of, such as a video buffer). This view copying will work between different types of view if it is possible to reconfigure the view very cheaply. If you wish to copy the image data itself, then use the vil_copy_deep(src_im) function. This copies the raw data into a newly created space, and returns a new view of it. Alternatively, use the method dest_im.deep_copy(src_im), or the function vil_copy_reformat(src_im, dest_im).

Example of loading, copying then processing:

vil_image_view<vxl_byte> image;
image = vil_load("test_image.jpg");
vil_image_view<vxl_byte> image2 = vil_copy_deep(image);
my_invert_image(image2);
vil_save(image2,"output_image.jpg");

Example of creating an image in memory

unsigned ni=256;
unsigned nj=256;
unsigned nplanes=3;
vil_image_view<vxl_byte> image(ni,nj,nplanes);
for (unsigned p=0;p<nplanes;++p)
  for (unsigned j=0;j<nj;++j)
    for (unsigned i=0;i<ni;++i)
      image(i,j,p) = vxl_byte(i+j+p);

Example of creating an image in memory, using pointer arithmetic

  unsigned ni=256;
  unsigned nj=256;
  unsigned nplanes=3;
  vil_image_view<vxl_byte> image(ni,nj,nplanes);
  vxl_byte* plane = image.top_left_ptr();
  for (unsigned p=0;p<nplanes;++p,plane += image.planestep())
  {
    vxl_byte* row = plane;
    for (unsigned j=0;j<nj;++j,row += image.jstep())
    {
      vxl_byte* pixel = row;
      for (unsigned i=0;i<ni;++i,pixel+=image.istep())
        *pixel = vxl_byte(i+10*j+100*p);
    }
  }

Resizing

When one resizes (using set_size) a vil_image_view<T> the view disconnects from the data (which may then be deleted if no other views are connected), allocates a new chunk of memory for the new image and sets the view to look at it.

Note that if the set_size does not change the image size, then nothing is done and the view remains unchanged.

Manipulating Views

There are a variety of ways one can view the same data, allowing one to appear to change the data simply by changing ones view of it.

For instance one can obtain a transposed view of an image simply by swapping ni-nj and istep-jstep. This is particularly useful when implementing decomposable filters, as one need only write it for one direction, then can apply it to the original image and its transpose.

vil_image_view<vxl_byte> src_image = vil_load("image_file.jpg");
vil_image_view<vxl_byte> tmp_image1, tmp_image2;
vil_exp_filter_i(src_image, tmp_image1, 2.0);  // Apply filter to rows of src_image
vil_exp_filter_i(vil_transpose(tmp_image1), tmp_image2, 2.0);  // Apply filter to cols of tmp_image1
vil_image_view<vxl_byte> filtered_image = vil_transpose(tmp_image2);
// Note that
// vil_exp_filter_i(vil_transpose(tmp_image1),vil_transpose(filtered_image),2.0)
// would only work correctly if filtered_image was already the correct size.
// If it isn't, then the view created by vil_transpose(filtered_image) would
// be resized, and disconnected from filtered_image itself, which would remain
// unchanged.

View manipulations include:

Operations on Views

Useful simple operations on views include

vil_image_view_base_sptr

vil_image_view_base_sptr is used internally by vil, and is not intended for users of vil. Anywhere you see a function returning one of these, (e.g. vil_load() ) you can assign it directly to a vil_image_view<T>. If you want a pixel-type independent image container, see vil_memory_image below.

Image resources

The vil_image_resource class is an abstract base class for image data, views of which can be obtained (or changed) with the get_view()/put_view() functions. You cannot directly construct one of these vil_image_resource classes. Instead you use a helper function, which will return a smart pointer - expect to see lots of vil_image_resource_sptr objects. The types of derived classes, and means of creating them are

vil_image_resource objects in most cases only deal with scalar-type pixels. Of course once you get a view of real image data in memory, you can easily convert a multi-planar view into a multi-component view.

interfaces

There are two reasons to still use vil1 (currently core/vil1)

There are several functions to convert between the various types of vil1 and vil images.

Reporting

Currently most error reporting either happens by calling vcl_abort, or by returning a null image. The null images reporting in particular will transition to exception-based reporting. You can retain the old behaiour by setting VXL_LEGACY_ERROR_REPORTING with CMake.

Mathematics on images

Functions to evaluate image properties:

Functions to modify images:

Other related maths functions

Interpolating images

Bilinear interpolation (of single planes of scalar types) can be obtained using

Other methods of sampling with bilinear interpolation include:

Bicubic interpolation: For each of the bilinear interpolation functions there is a corresponding bicubic interpolation function. Just use "bicub" instead of "bilin" in the name.


vil_algo : Computational Imaging Library

A core level 2 library containing some simple algorithms for manipulating images. Note that the argument order is typically of the form vil_f(src_im,dest_im,params). Examples include

See also the vipl library for a more generic image processing interface and more image processing algorithms.

Morphological functions (using vil_structuring_element)

Other related maths functions

Region finding

The boundaries of thresholded regions can be found using

General utilities

Parameter Conventions

For your ease of use, all vil functions and methods adhere to the following parameter conventions:

Examples

There are plenty of working examples in the examples subdirectory - these can be treated as a mini-tutorial.

Lead

Ian Scott is responsible for co-ordinating significant changes to vil. http://sourceforge.net/sendmessage.php?touser=261110