Monday, May 30, 2011

Next please ! Easier image iterators

The forthcoming JAI-tools version 1.2 will include several new image iterator classes. Here is a quick preview of two of them: SimpleIterator (read-only access) and WritableSimpleIterator (read-write access).

If you are used to working with the standard JAI RectIter class you probably have nested do-while loops burnt into your frontal cortex from having to write code like this countless times...
RectIter iter = ...
do {
do {
int value = iter.getSample();
// do something with value
} while (!iter.nextPixelDone());
iter.startPixels();
} while (!iter.nextLineDone());

In comparison, SimpleIterator is, well, simpler...
SimpleIterator iter = ...
do {
Number value = iter.getSample();
// do something with value
} while (iter.next());

The next() method takes care of both horizontal and vertical movement, plus it is always safe to call it speculatively. There is also a hasNext() method for convenience.

The comparison is more telling for code where you need to track the location of the image iterator. With RectIter you might write something like this...
RenderedImage image = ...
RectIter iter = ...
int x = image.getMinX();
int y = image.getMinY();
do {
do {
int value = iter.getSample();
x++ ;
// do something with value
} while (!iter.nextPixelDone());
iter.startPixels();
x = image.getMinX();
y++ ;
} while (!iter.nextLineDone());

But with SimpleIterator you can use the getPos() method...
RenderedImage image = ...
SimpleIterator iter = ...
do {
Number value = iter.getSample();
Point pos = iter.getPos();
// do something with value and position
} while (iter.next());

You might have noticed that SimpleIterator.getSample() returns a Number object rather than a primitive value. Unlike JAI's RectIter class, there are no separate getSampleFloat and getSampleDouble methods. Instead, the iterator returns image values that are either Integer, Float or Double class depending on the data type of the source image.

You can also use SimpleIterator as a replacement for JAI's RandomIter class. In fact, a SimpleIterator instance provides both sequential (X then Y) movement across an image via its next() method, plus random positioning with additional getSample methods as shown here...
// get the value of a specific position and band
int value = simpleIter.getSample(x, y, band).intValue();

// now continue from that position to the end of the iterator bounds
while (simpleIter.next()) {
value = simpleIter.getSample().intValue();
}


SimpleIterator also provides more flexible bounds handling. For example, you can set the bounds of the iterator to extend beyond those of the source image. When the iterator is positioned outside the image it will return an outside value which is set via the constructor...
// create an iterator that will return -1 when positioned outside the
// source image bounds
SimpleIterator iter = new SimpleIterator(myImage, iteratorBounds, -1);

This makes it easy to program applications that need to sample within a fixed bounding rectangle, which may or may not be contained within an image's bounds. There is no need to intersect rectangles or monitor positions in your own code.

WritableSimpleIterator provides the same methods as SimpleIterator together with the ability to set values in a writable image, either sequentially or for specified positions.

But wait - there's more ! JAI-tools version 1.2 will also include WindowIterator, to pass a client-defined moving window over an image, and ImageSetIterator, to sample multiple images simultaneously. We'll talk more about these in a subsequent article.