DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Images

Table of Contents

Authors:
Tristan Roussillon, David Coeurjolly, Martial Tola
Date:
2012/12/05

Overview

The concept of point functor describe a mapping between the points of a digital space and a set of values. The only method of a point functor is the operator(), which must take a point as input parameter and must return a value.

The concept of constant image is a point functor bounded by a domain. It is thus a refinement of the concept of point functor, describing a mapping between points and values, but having in addition a domain, returned by the domain method, and a range of values (for each point of the domain), returned by the constRange method.

The concept of image, which is a refinement of the concept of constant image, provides extra services to update values. Any model of image must have a method setValue taking a point and a value as input parameters and updating the value associated with the given point with the given value. In addition, they must have a range, returned by the range method, providing output iterators.

Different models of images are available: ImageContainerBySTLVector, ImageContainerBySTLMap, and — coming soon — ImageContainerByHashTree, ImageContainerByITKImage, a wrapper for ITK images.

Let us go into details

In this section, the concepts and the main services to read and write values in images are detailed.

Concepts

Any model of the concept CPointFunctor must have two nested types:

Moreover, it must have the following method:

The concept CConstImage is a refinement of CPointFunctor. Its models must have two extra nested types:

Obviously, there are two methods that return instances of these two types:

You can see Digital Spaces, Points, Vectors and Domains for more details about spaces and domains and Ranges of values for more details about ranges in images.

The concept CImage is refinement of CConstImage. Images, instead of constant ones, provide services to update values. The main way of assigning values to points is the following method:

Moreover, in addition to the ConstRange, images must have the following inner type:

Obviously, you can get an instance of this type using the following method:

Lastly, note that the Value type in the (constant) images is expected to be at least a model of CLabel, ie. to be default-constructible, assignable and equality comparable.

Note:
In the snippets of the following subsections, the type of image used is Image and its instances are image, image1, image2.

Main methods

All models of images have a domain returned by the method domain. This domain is the set of points for which the image is defined and has values. Since a domain is a range, you can straightforwardly use it in order to iterate over the points of an image.

iterate over the points Image::Domain d = image.domain(); for (Image::Domain::ConstIterator it = d.begin(), itEnd = d.end(); it != itEnd; ++it) {}

Models of images have also two main methods in order to read or write values at a given point:

process the values Image::Domain d = image.domain(); for (Image::Domain::ConstIterator it = d.begin(), itEnd = d.end(); it != itEnd; ++it) { Image::Value v = image( *it ); v += 5; //adding 5 to all values image.setValue( v ); }

Note that this method of iterating over the values of an image is not always the fastest and that is why we also provide ranges.

Ranges of values

Constant images provide a constant range of values returned by the constRange method. As every model of CConstBidirectionalRange, it provides begin, end, rbegin and rend methods returning constant iterators to iterate over the values in the forward or backward direction.

iterate over the values Image::ConstRange r = image.constRange(); for (Image::ConstRange::ConstIterator it = r.begin(), itEnd = r.end(); it != itEnd; ++it) {}

However, this range is also a model of CConstBidirectionalRangeFromPoint, which is a refinement of CConstBidirectionalRange. That is why it also has overloaded versions of the begin and rbegin methods taking a point as input argument. This provides a way of iterating on sub-ranges defined from points.

iterator on the origin (0, ... , 0) Image::ConstRange::ConstIterator it = r.begin( Image::Point::diagonal(0) )

Note that if the point does not belong to the domain, the returned iterators (resp. reverse iterators) must be equal to the end (resp. rend) methods.

ASSERT( image.constRange().begin( image.domain().end() ) == image.constRange().end() )

Images provide in addition to a constant range, a richer range returned by the range method. This range is not only a model of CBidirectionalRangeFromPoint, but also a model of CBidirectionalOutputRangeFromPoint. That is why, it must have two methods: outputIterator and routputIterator returning output iterators. Moreover, it must have overloaded versions of these methods taking a point as input argument. Thus, these output iterators are useful in order to incrementaly fill (a part of) an image. For instance, you can fill an image from the values of another one (assumed to have the same domain) as follows:

Image::Range r1 = image1.range(); 
Image::ConstRange r2 = image2.constRange(); 
std::copy( r2.begin(), r2.end(), r1.outputIterator() ); 

Main models

Different models of images are available: ImageContainerBySTLVector, ImageContainerBySTLMap, and — coming soon — ImageContainerByHashTree, ImageContainerByITKImage, a wrapper for ITK images.

ImageContainerBySTLVector

ImageContainerBySTLVector is a model of CImage that inherits the STL vector class. The hyper-rectangular domain, which the only model of domain accepted, is linearized so that each point is mapped, from its coordinates, into an index and each index is mapped into a unique value, as in any one-dimensional array.

Let \( n \) be the domain size (the number of points). At construction all the needed space is allocated and filled with a default value (0) in \( O(n) \) space and time. After that, you can access to the value associated to any point at any time. Each access for reading (operator()) or writing ('setValue`) values is in \( O(1) \).

The (constant) range of this class only used the built-in iterators of the underlying STL vector. It is therefore a fast way of iterating over the values of the image.

ImageContainerBySTLMap

ImageContainerBySTLMap is a model of CImage that inherits the STL map class. The domain can be any set of points. Values are stored and associated to points in pairs point-value. The set of points stored in this way may be any domain subset. A default value (user-defined) is automatically associated to each point of the domain that does not belong the subset for which values are known. Once constructed (in \( O(1) \)), the image is valid and every point of the image domain has a value, which can be read and overwritten.

The pairs point-value are stored in a red-black tree, where the points are used as keys, so that each access for reading (operator()) or writing (setValue) values is in \( O(log m) \), where \( m \) is the cardinal of the subset for which values are known (less or equal to the domain size \( n \)).

The (constant) range of this class adapts the domain iterators in order to deal with values instead of points. The operator* of the iterators provided by the range calls the operator() and use the setValue method of the class.

ImageContainerByHashTree

Note:
Todo

Image Adapter classes

ImageAdapter, ConstImageAdapter are perfect swiss-nifes to transform and adapt images (change their domain definition, change their value types, ...). These classses are parametrized by several types and functor in order to adapt the behavior of image getters/setters (operator() and setValue methods). These adapted behaviors are computed on-the-fly when calling these methods.

ConstImageAdapter requires several types and functors to create a "read-only" adapted image (operator(), constRange(), ...)

ImageAdapter requires a supplementary functor and allows write access to the image (setValue methods, range(), ... )

Note:
Functors used to convert domains or values may be complex. Keep in mind that each time operator() or setValue() methods are called, such functors are evaluated (with potential side-effects depending on the functors).

ConstImageAdapter

ConstImageAdapter is a small class that adapts any (constant or not) image into a constant one, which provides a virtual view (so read-only) of the true values contained in the adapted image. The class is parametrized by several template arguments: TImageContainer: the type of image to adapt. TNewDomain: the type of the new domain. TFunctorD: type of functor used to convert image domain points to new domain points TNewValue: type of the new image value type. TFucntorV: functor to convert values.

The values associated to access the point values are adapted with a functor g and a functor f given at construction so that operator() calls f(img(g(aPoint))), instead of calling directly operator() of the underlying image img.

Functor g (and/or functor f) can be a default functor, i.e. a simple functor that just returns its argument.

In order to illustrate the next ConstImageAdapter usage samples, we are going a) to use these includes:

#include "DGtal/io/colormaps/HueShadeColorMap.h"
#include "DGtal/io/colormaps/GrayscaleColorMap.h"
#include "DGtal/images/ImageContainerBySTLVector.h"
#include "DGtal/images/ConstImageAdapter.h"

b) then define these types and variables:

typedef HueShadeColorMap<unsigned char> HueShade; // a simple HueShadeColorMap varying on 'unsigned char' values
typedef HueShadeColorMap<double> HueShadeDouble; // a simple HueShadeColorMap varying on 'double' values
typedef GrayscaleColorMap<unsigned char> Gray; // a simple GrayscaleColorMap varying on 'unsigned char' values
DefaultFunctor df; // a simple functor that just returns its argument

c) then define a simple 16x16 (1,1) to (16,16) image (of 'unsigned char' type):

typedef ImageContainerBySTLVector<Domain, unsigned char> Image;
Domain domain(Point(1,1), Point(16,16));
Image image(domain);

filled with 0 to 255 values like that:

unsigned char i = 0;
for (Image::Iterator it = image.begin(); it != image.end(); ++it)
*it = i++;

which looks like that with a simple HueShadeColorMap varying from 0 to 255 and with (1,1) the first bottom-left point:

image.png
(1) simple 16x16 image: (1,1) to (16,16) drawn with a simple HueShadeColorMap varying from 0 to 255.

Here is now the construction of a simple image adapter that use a subdomain of the initial image domain to access the first bottom-left 8x8 image:

typedef ConstImageAdapter<Image, Domain, DefaultFunctor, Image::Value, DefaultFunctor > ConstImageAdapterForSubImage;
Domain subDomain(Point(1,1), Point(8,8));
ConstImageAdapterForSubImage subImage(image, subDomain, df, df);

and here is the result:

subImage.png
(2) first bottom-left 8x8 image: (1,1) to (8,8) adapted from image (1) with a subdomain.

Here is then the construction of an image adapter that use a specific domain: here, only one pixel on two in x and y coordinates, created like that:

DigitalSet set(domain);
for( unsigned int y=0; y < 17; y++)
for( unsigned int x=0; x < 17; x++)
if ((x%2) && (y%2))
set.insertNew(Point(x,y));
DigitalSetDomain<DigitalSet> specificDomain(set);

from the initial image domain.

typedef ConstImageAdapter<Image, DigitalSetDomain<DigitalSet>, DefaultFunctor, Image::Value, DefaultFunctor > ConstImageAdapterForSpecificImage;
ConstImageAdapterForSpecificImage specificImage(image, specificDomain, df, df);

Here is the result:

specificImage.png
(3) 16x16 image: (1,1) to (16,16) adapted from image (1) with a specific domain.

Here is now the construction of an image adapter that is a thresholded view of the initial scalar image:

typedef ConstImageAdapter<Image, Domain, DefaultFunctor, bool, Thresholder<Image::Value> > ConstImageAdapterForThresholderImage;
Thresholder<Image::Value> t(127);
ConstImageAdapterForThresholderImage thresholderImage(image, domain, df, t);

and here is the result with a simple GrayscaleColorMap varying from 0 to 1:

thresholderImage.png
(4) 16x16 image: (1,1) to (16,16) adapted from image (1) with a thresholder set to 127.

Here is finally the construction of an image adapter that use a functor to change 'unsigned char' values to 'double' values using a log scale functor defined like that:

template <typename Scalar>
double operator()(const Scalar &a) const
{
return std::log( 1 + NumberTraits<Scalar>::castToDouble(a) );
}
};

defined from the initial image:

typedef ConstImageAdapter<Image, Domain, DefaultFunctor, double, LogScaleFunctor<Image::Value> > ConstImageAdapterForLogScale;
ConstImageAdapterForLogScale logImage(image, domain, df, logScale);

and here is the result with a simple HueShadeColorMap varying from 0. to logScale(255):

logImage.png
(5) 16x16 image: (1,1) to (16,16) adapted from image (1) with a log scale functor.

ImageAdapter

ImageAdapter is a small class that adapts an image (like ConstImageAdapter) but provides a virtual access (reading and writing) of the true values contained in the adapted image. It uses a given Domain (i.e. a subdomain) but work directly (for reading and writing processes) thanks to an alias (i.e. a pointer) on the original Image given in argument.

This class requires an additional templare paremter: TFunctoVm1: functor to convert adapted image values to the original image values.

The values associated to accessing the point values are adapted with a functor g and a functor f given at construction so that operator() calls f(img(g(aPoint))), instead of calling directly operator() of the underlying image img.

The values associated to writing the points are adapted with a functor g and a functor \( f^{-1}\) given at construction so that setValue() is img.setValue(g(aPoint), f-1(aValue)).

The use is the same that for ConstImageAdapter.

Useful classes and functions

In addition to the image containers and the image adapters described in the previous sections, there are also image proxys:

Image is a light proxy on image containers based on a COW pointer. It can be constructed, copied, assigned, deleted without any special care.

Moreover, in ImageHelper.h, many useful functions are provided.

  1. Conversely, others convert images into digital sets with value comparators: setFromPointsRangeAndPredicate, setFromPointsRangeAndFunctor, setFromImage.
  1. Some of them convert digital sets into images, imageFromRangeAndValue assigns a given value in an image to each point of a given range.
  1. Lastly, some functions are available to fastly fill images from point functors or other images: imageFromFunctor and imageFromImage.