Tuesday, April 5, 2011

JAI-tools version 1.1.1 and Jiffle version 0.1.0 released

The JAI-tools team is pleased to announce the combined release of new versions of JAI-tools and Jiffle. This is the first release since Jiffle moved into a separate project with its own versioning (see previous post).

The new versions are now available from the Maven Central repository and mirror sites.

You can checkout the sources from:
http://jai-tools.googlecode.com/svn/tags/1.1.1
http://jiffle.googlecode.com/svn/tags/0.1.0

To search for particular changes of interest go to the issue tracker for each project.

Thanks to Andrea Aime and Daniele Romagnoli for their work on this release, and also Ian Turton and Manuel Bossant for contributions and bug spotting.

JAI-tools version 1.1.1

This is a minor release which includes bug fixes and improvements, but also some new features. Notable items:
  • ROIGeometry now has more methods implemented and improved performance.
  • Problems with clipping and setting rendering hints have been fixed in the DiskMemImageGraphics class.
  • KernelFactory has been expanded and can now generate many standard kernel types including cosine, Gaussian, Epanechnikov and quartic.
  • Improvements to the utility Swing widgets.
  • A new CompareOp class for comparison of double and float values taking into account absolute or proportional tolerance.

Jiffle version 0.1.0

This is the first release of the Jiffle scripting language under its own version numbering. The new jars are jt-jiffle-language-0.1.0.jar and jt-jiffle-demo-0.1.0.jar.

The main change from the version that was included with JAI-tools 1.1.0 is support for user-defined coordinates. This separates the bounds and resolution of the processing area from those of the source and destination images. It means that within your Jiffle script, you can work with whatever type of coordinates are best suited to your application, e.g. geographic, proportional, or arbitrary cartesian coordinates. When running a script, CoordinateTransform objects are used to convert between user coordinates and pixel positions in each source and destination image.

The separation of processing and image coordinates can be handy even when you are working directly with pixel positions. You can use it to deal with non-overlapping source and destination images, or as a device to sub-sample or over-sample source images.

As well as the new coordinate support, there have been some small extensions to Jiffle's syntax and a general tidy-up of the code base and javadocs.

Share and enjoy.

Tuesday, March 22, 2011

Jiffle leaves home to grow up

Although it's usually the other way around (grow up then leave home) sometimes things don't turn out as planned...

For Jiffle, the scripting language developed as part of JAI-tools, what was originally planned was compatibility with the r.mapcalc raster algebra language used in GRASS GIS, but recently we decided that this was too limiting and it would be better to set Jiffle free and have its development driven purely by our brilliant ideas (plus the moderating influence of user feedback).

Like all great ambitions, this one quickly ran aground on the rocks of practical constraint. Being a module in a Maven-based project, Jiffle had the same version number as all of the other JAI-tools modules, but this didn't fit well with allowing Jiffle's syntax and code-base to be more fluid (ie. lots of changes breaking backwards-compatibility). So it was decided to separate Jiffle out from the JAI-tools project.

Jiffle now has its own site: http://code.google.com/p/jiffle/ and it's been re-versioned to 0.1.x to make it clear to users that substantial changes can be expected. Despite leaving home, Jiffle will retain its close relationship to JAI-tools, with the same project team developing both.

Unfortunately, this has created a certain amount of version chaos. At Maven Central you can find:
  • jt-jiffle-1.1.0.jar (as part of the most recent JAI-tools release)
  • jiffle-1.0.1.jar (from the previous release before the "jt-" prefix was adopted)
  • And soon: jt-jiffle-language-0.1.0.jar (the new jar name being required to avoid future clashes with previous versions)
It's hard to see how we could have made it much more confusing.

Here's what to do:
  • For JAI-tools version 1.1.0, use jt-jiffle-1.1.0
  • With later JAI-tools releases, swap over to the most recent version of jt-jiffle-language
If you you use Maven as your build tool it will cut through much of this confusion for you because the dependency relationship between different versions of JAI-tools and Jiffle will be contained in each project's pom.xml file.

The next post will show off some of the new Jiffle language features to prove that all of this chaos has been worth it :)

Monday, March 7, 2011

JAI-tools version 1.1.0

The JAI-tools project team is pleased to announce the release of version 1.1.0 of the library. This is a bumper issue with many new features plus major improvements to existing features. Highlights (described below) include new image operators Contour, Vectorize and VectorBinarize; a new ROI class capable of handling massive images; and a performance boost for the Jiffle scripting language.

The release is now available from the Maven Central repository and mirror sites. Maven users should read the notes below (Library setup) about new module names and the option of using a single jar.

You can checkout the sources for this release from:

http://jai-tools.googlecode.com/svn/tags/1.1.0

To search for particular changes of interest go to the issue tracker.

Many thanks to team members Andrea Aime, Andrea Antonello and Simone Giannecchini for all of their work and advice over the last year.

Summary of new features and changes

New image operators

Contour

Generates vector contours from raster image values. The contour levels can be specified explicitly or as the interval between levels. Selective contouring can be done by defining particular image values or ranges of values as NoData to be ignored by the operator. The generated contours are returned as JTS LineString objects, suitable for plotting as well as further manipulation or analysis. Here are a couple of examples of the operator in action courtesy of GeoSolutions:


Vectorize

Generates vector boundaries (as JTS Polygons) for regions of uniform value in a raster image. This complements the JAI-tools Regionalize and RangeLookup operators. Here is an example, where an image has first been classified into two uniform ranges using RangeLookup and then vectorized into polygons using Vectorize:

VectorBinarize

An alternative to the standard JAI Binarize operation. The destination image is backed by a JTS Geometry object rather than a raster. This makes it possible to binarize massive images with only small memory usage.

New ROI class

The new ROIGeometry class can be used as a replacement for the standard JAI ROIShape class. It is backed by a JTS Geometry object rather than an image to minimize memory overhead and it works in conjunction with the VectorBinarize operator, making it possible to define ROIs over massive image areas. It also offers the choice of using pixel corner or center coordinates which is particularly useful for geospatial applications.

Jiffle

The Jiffle image scripting language has been almost completely rewritten for this new version, as previewed in previous posts here and here.

It's faster

Jiffle scripts are now translated to Java source and then compiled to executable bytecode using the Janino in-memory compiler. As a result, scripts now run hundreds of times faster than was the case in version 1.0. The generated Java source can be saved for later use and the compiled objects can be used as any other Java class.

It's easier

A new JiffleBuilder class makes it easier to compile and run scripts with a minimum of key strokes. It can also create a destination image for you ready to receive the results of the script.

It's multi-tasking

The JiffleExecutor class allows you to run one or more Jiffle scripts on background threads. The progress of each task can be monitored and results are passed back to the caller via a simple event system.

It has more bits

The Jiffle language itself has been extended and now provides support for multi-band source images, scoped variables, loop constructs and simple lists.

And it's coming to a program near you

Jiffle can be integrated into applications as an analysis engine. It has been used in JGrass and is about to appear in the upcoming spatial toolbox OmsBox in the uDig GIS application.


As well as Jiffle, OmsBox will include many other features from JAI-tools such as the contour extractor:



To learn more about Jiffle, have a look at the new collection of example programs.

Library setup

Module names

All module names are now prefixed with "jt-" to make it easier to spot them when you're working with a large number of other dependencies. If you use Maven, this means you'll need to edit both the name and the version of JAI-tools modules in your existing pom.xml files.

One jar fits all

You now have the option of using a single jar for JAI-tools. Maven users just need to include jt-all as a dependency in the pom.xml file. If you don't use Maven you can download and add jt-all-1.1.0.jar to your project manually. This combined jar includes all JAI-tools modules other than jt-demo (the example applications).

Monday, February 21, 2011

Jiffle plays the Game of Life


After showing off with fractals in the last Jiffle demo, it seemed only natural to delve back in time for another classic to illustrate new features and uses of the language. And nothing could be more classic than John Conway's Game of Life: a cellular simulation with simple rules that can display exceptionally complex behaviour. If you're not familiar with Life, this Wikipedia article is a good place to start. You can also marvel at the compendious collection of Life patterns at LifeWiki:

The Java Swing program shown in the screen-shot above uses a Jiffle runtime object as a simulation engine to play Life. Two different Jiffle scripts are used: one which simulates a world with edges; and a second where the world is a toroid, ie. opposite edges of the image are joined to form a continuous surface. In both scripts the world is an image where an unoccupied location is represented by pixel value 0 and an occupied location by pixel value 1.

Here is the entire script for the world with edges:

options { outside = 0; }

n = 0;
foreach (iy in -1:1) {
foreach (ix in -1:1) {
n += world[ix, iy];
}
}

n -= world;
nextworld = (n == 3) || (world && n==2);

The expression world[ix, iy] accesses a relative neighbour location. For example world[-1, 1] would get the value of a pixel at (x-1, y+1) where x and y are the ordinates of the current pixel.

The two foreach loops use integer sequence syntax, startValue:endValue, to iterate over the 3x3 neighbourhood centred on the current pixel and count the number of occupied cells (those with a value of 1). The rules of Life are expressed only in terms of the number of neighbouring cells occupied, so we adjust the value of n by subtracting the value of the current pixel.

The options block at the top of the script sets a value to be returned for any neighbour positions that are beyond the bounds of the image. Without this option, the runtime object would throw an Exception at the very first pixel when trying to access the relative neighbour position world[-1, -1].

The final line of the script expresses all of the Game of Life rules in a single statement ! It uses naked conditional statements which return 1 or 0.

A second Jiffle script provides an alternative version of the simulation, where the image representing the world is treated as a toroid:

n = 0;
foreach (iy in -1:1) {
yy = y() + iy;
yy = if (yy < 0, height() - 1, yy);
yy = if (yy >= height(), 0, yy);

foreach (ix in -1:1) {
xx = x() + ix;
xx = if (xx < 0, width()-1, xx);
xx = if (xx >= width(), 0, xx);
n += world[$xx, $yy];
}
}

n -= world;
nextworld = (n == 3) || (world && n==2);


This script works with absolute rather than relative neighbour positions. These are indicated by the $ prefix. When a neighbour position is beyond an edge, it is adjusted to the corresponding position at the opposite edge. Note that we don't need the outside option in this script.

The Game of Life is an iterative simulation where the output for time t becomes the input for time t+1. To accomplish this, the demo program caches the runtime objects compiled from the Jiffle scripts, and uses them repeatedly with two images which are represented by the variables world and nextworld in the scripts. These images are simply swapped between source and destination roles at each time step as shown in this code fragment...

activeRuntime.setSourceImage(WORLD_NAME, curWorld);
activeRuntime.setDestinationImage(NEXT_WORLD_NAME, nextWorld);
activeRuntime.evaluateAll(null);

TiledImage temp = curWorld;
curWorld = nextWorld;
nextWorld = temp;

You can view and download the complete source code for this program from the JAI-tools web site.

Monday, February 14, 2011

Jiffle meets Mandelbrot


The Jiffle scripting language has been getting some new bells and whistles recently. While the idea is still to keep the language small and simple, by adding a few extra constructs it becomes much more flexible.

Above is the JiffleDemo application showing a script that uses two of these new constructs, scoped variables and loops, to generate a binary image of the Mandelbrot set. Below is the script itself (it is one of the examples distributed with JAI-tools).

The "init" block is where you declare variables that you want to remain in scope throughout processing. Jiffle calls these image-scope variables. Variables declared outside this block are termed pixel-scope, ie. their values are discarded after each pixel is processed. In the Java runtime class that the Jiffle compiler creates, the image-scope variables are class fields while the pixel-scope variables are local to the evaluate method called to process each destination image pixel. The runtime class is also provided with a getter method for the image-scope variables so you can retrieve them after running the script. You could use this, for instance, to count pixels that are in a certain value range.

The script below uses an until-loop (lifted from Ruby) for the iterative calculation. Jiffle also offers a while-loop and I'm musing about adding some kind of for-loop syntax as well.

/*
* An example Jiffle script: draws a binary
* image of the Mandelbrot set. Adapted from
* C code at http://warp.povusers.org/Mandelbrot/
*
* Author: Michael Bedward
*/

/* We declare variables that we want to remain
* in scope between pixels in the 'init' block.
* The functions width() and height() return
* the dimensions of the destination area.
*/
init {
MaxIter = 30;
MinRe = -2.0;
MaxRe = 1.0;
MinIm = -1.2;
MaxIm = MinIm + (MaxRe-MinRe) * height() / width();
Re_scale = (MaxRe-MinRe)/(width()-1);
Im_scale = (MaxIm-MinIm)/(height()-1);
}

/* Calculations performed for each pixel.
* The functions x() and y() return current
* pixel coordinates.
*/
c_im = MaxIm - y()*Im_scale;
c_re = MinRe + x()*Re_scale;

Z_re = c_re;
Z_im = c_im;

outside = 0;
n = 0;

/* Jiffle has an 'until' loop construct */
until (n >= MaxIter || outside) {
Z_re2 = Z_re*Z_re;
Z_im2 = Z_im*Z_im;
outside = if (Z_re2 + Z_im2 > 4);
Z_im = 2*Z_re*Z_im + c_im;
Z_re = Z_re2 - Z_im2 + c_re;
n++ ;
}

/* The variable 'result' represents the
* destination image (you can use any name
* you like in your own scripts).
*/
result = outside;

As an aside, I recall using much the same algorithm, though in FORTRAN, to generate Mandelbrot set images on an 80286 PC last century. Some people never change...

Wednesday, February 9, 2011

Continuous JAI-tools builds

Now that the project is getting bigger and (gasp) actually being used it was time to get more organized about our build process, or rather, to actually have one. To date we've relied on an ad hoc process of people checking out the sources, building them on their local system, and then reporting that Michael has broken the build again.

Now, courtesy of the kind folks at OpenGeo, in particular Justin Deoliveira, JAI-tools has entered the world of continuous integration. OpenGeo's Hudson server now builds the development code (ie. sources from trunk the project's subversion repository) and you can check the status of the builds at http://hudson.opengeo.org/hudson/view/jai-tools/. If you are subscribed to the project discussion list you will also be sent notices of any build failures.

Thanks to Justin and Andrea Aime for organizing all of this.

Thursday, January 13, 2011

Images in a jiffy: speeding up Jiffle with Janino

Jiffle is a scripting language for raster algebra dreamed up by myself and Andrea Antonello. You can use it to create, combine and analyse raster (pixel) images. It's based on the r.mapcalc language for map calculations in the GRASS GIS program.

The idea of Jiffle is to let you concentrate on the interesting bits rather than having to write the incredibly tedious boiler plate code that is normally required to work with image data using Java. The image here of a simple trigonometric function was created with this script...
    xc = width() / 2
    yc = height() / 2
    dx = (x()-xc)/xc
    dy = (y()-yc)/yc
    d = sqrt(dx^2 + dy^2)
    outImg = sin(8 * PI * d)

The Jiffle parser, developed using ANTLR, converts a script like the one above into a tree representation of the expressions (Abstract Syntax Tree or AST). Up until now, running the script involved walking this tree multiple times (once per destination image pixel) and executing the expression like an interpreter. While this worked, it was much too slow to process large images.

Enter Janino, which advertises itself (quite accurately) as a "super-small, super-fast Java™ compiler". One of things you can do with Janino is to compile source and load the resulting bytecode in-memory. To apply this to Jiffle, I first replaced the ANTLR grammar for the run-time tree walker with one that translates an AST into a Java method body. For example, the script above is translated to this...

double xc=_width / 2.0;
double yc=_height / 2.0;
double dx=(_x - xc) / xc;
double dy=(_y - yc) / yc;
double d=Math.sqrt(Math.pow(dx, 2.0) + Math.pow(dy, 2.0));
writeToImage("out", _x, _y, _band, Math.sin(25.132741228718345 * d));

Next, I created a new interface JiffleRuntime and a template for an implementing class that looks like this...

import jaitools.jiffle.runtime.JiffleRuntime;

import java.awt.image.RenderedImage;
import java.awt.image.WritableRenderedImage;
import java.util.HashMap;
import java.util.Map;
import javax.media.jai.iterator.RandomIter;
import javax.media.jai.iterator.RandomIterFactory;
import javax.media.jai.iterator.WritableRandomIter;

public class JiffleRuntimeImpl implements JiffleRuntime {

/*
* Note not using generics here because they are not
* supported by Janino.
*/
private Map images = new HashMap();
private Map readers = new HashMap();
private Map writers = new HashMap();

private double _width;
private double _height;

public void evaluate(int _x, int _y, int _band) {
// COMPILER_BREAK

throw new UnsupportedOperationException("Method body to be provided by Jiffle compiler");

// COMPILER_RESUME
}

public double readFromImage(String imageName, int x, int y, int band) {
RandomIter iter = (RandomIter) readers.get(imageName);
return iter.getSampleDouble(x, y, band);
}

public void writeToImage(String imageName, int x, int y, int band, double value) {
WritableRandomIter iter = (WritableRandomIter) writers.get(imageName);
iter.setSample(x, y, band, value);
}

public void setDestinationImage(String imageName, WritableRenderedImage image) {
images.put(imageName, image);

if (images.size() == 1) {
_width = image.getWidth();
_height = image.getHeight();
}

writers.put(imageName, RandomIterFactory.createWritable(image, null));
}

public void setSourceImage(String imageName, RenderedImage image) {
images.put(imageName, image);
readers.put(imageName, RandomIterFactory.create(image, null));
}

}

The Jiffle compiler inserts the generated statements into the evaluate method of this class...

public void evaluate(int _x, int _y, int _band) {
double xc=_width / 2.0;
double yc=_height / 2.0;
double dx=(_x - xc) / xc;
double dy=(_y - yc) / yc;
double d=Math.sqrt(Math.pow(dx, 2.0) + Math.pow(dy, 2.0));
writeToImage("out", _x, _y, _band, Math.sin(25.132741228718345 * d));
}

Now we have the run-time class source as a String in memory, we compile it with Janino's SimpleCompiler class and retrieve the resulting executable bytecode as shown here...

SimpleCompiler compiler = new SimpleCompiler();
compiler.cook(runtimeSource);
Class clazz = compiler.getClassLoader().loadClass(PACKAGE_NAME + "." + RUNTIME_CLASS_NAME);
runtimeInstance = (JiffleRuntime) clazz.newInstance();

And voila ! The Jiffle script has now been compiled into a form that will run at the speed of the JVM, hundreds of time faster than the original tree walking approach.

Janino doesn't handle generic collections or var-arg method calls so some work-arounds were required in the parser grammars and Jiffle's run-time support classes to deal with this. For example, instead of generating this source...

double foo = JiffleFunctions.median(x1, x2, x3, x4, x5);

We change the median method to expect a Double array and have the compiler generate this...

double foo = JiffleFunctions.median(new Double[]{x1, x2, x3, x4, x5});