Expression and ExpressionNT

Author: Ulf Dittmer (udittmer at yahoo dot com)

Date:4/2/2008

Description: The plugins on this page apply user-specified formulas to each pixel in an image. They can be used to alter existing images, or to create fully synthetic images.

Expression does this by interpreting the formula for each pixel; this makes it somewhat slow for complex formulas. ExpressionNT compiles the formula as a Java class and executes it; this makes for much faster execution. It also has extra functionality to generate fractal images, and supports the HLS and HSV color models. In general, you should use ExpressionNT, simply because it is so much faster.

In the presets.txt and presetsNT.txt files some formulas are predefined that should give an idea of what the plugin does. They are accessed via the Presets menu. New formulas can be given a name and stored together with the existing ones.

Filtering of ROIs and image stacks is supported, as is Undo and limited macro recording.

The plugin was inspired by Jim Bumgardners Expression plugin for Photoshop, but doesn't have as much functionality. The Photoshop plugin is described in this Word document, which is helpful reading for working with my plugin as well.

Installation: Download and unzip the ZIP archive, and put the resulting "Expression" folder into your ImageJ plugin directory. The archive contains the source and class files for both plugins, two files with predefined formulas (presets.txt and presetsNT.txt), and two LUT files (8colors.lut and 12colors.lut). It also contains this HTML file for reference. All the files should be kept together either in the plugins directory, or a subdirectory of it called "Expression".

Notes for ExpressionNT:

  • You may need to slightly adapt and recompile the source if you're using a non-Sun JDK, e.g. from IBM or Blackdown. Search for "Sun compiler" in ExpressionNT_.java, and read the comments.
  • The plugin writes temporary files to disk before compilation, so some hard disk activity is normal. This also means that you can't use it as part of an applet (unless the applet is signed).

Formulas: A number of variables and functions are available for use in the expression:
x - row coordinate
y - column coordinate
w - image width
h - image height
rw - ROI width
rh - ROI height
i - intensity of the current pixel
r - red intensity (32 bit color RGB images only), 0..255
g - green intensity (32 bit color RGB images only), 0..255
b - blue intensity (32 bit color RGB images only), 0..255
pi - 3.141592.....
e - 2.71828.....
n - when working with a stack, n is set to the number of slices; it's 1 otherwise
t - when working with a stack, t is set for each image to the images index
    in the stack (1 <= t <= n); it's 1 otherwise
maxval - maximum pixel value for this kind of image
      (255 for 8bit, 65536 for 16bit, 1 for 32bit)
p0 ... p9 - in macro mode, parameters named p0 through p9 can be passed to the plugin
	as part of the options, and can be used under those names in the expressions

+  -  *  /
% - modulo, i.e. remainder of integer division
^ - exponentiation; note that ExpressionNT recognizes the syntax "pow(x,y)"
        instead, and uses ^ for the exclusive boolean OR of x and y
sqrt(x) - square root
sin(x) - sine
cos(x) - cosine
tan(x) - tangens
asin(x) - arcus sine
acos(x) - arcus cosine
atan(x) - arcus tangens
exp(x) - exponential
ln(x) - natural logarithm (base e)
log(x) - logarithm base 10
min(x,y) - minimum of x and y (can take more than 2 parameters)
max(x,y) - maximum of x and y (can take more than 2 parameters)
floor(x) - truncates the argument to the next-lower integer
ceil(x) - truncates the argument to the next-higher integer
round(x) - truncates the argument to the closest integer
abs(x) - absolute value
d - distance from center of image
a - angle, measured from center of image; between 0 and 2*pi
? - random number between 0 and 1
if(a,b,c) - like an if/then/else switch
        a should be a boolean expression (= <> < <= > >= can be used in it);
        if a is true the result is b, otherwise c
The syntax described above is for the Expression plugin; the syntax for ExpressionNT differs as follows. If in doubt, take a look at the predefined formulas, which show just about all functions in action. In general, expressions need to conform to Java syntax.
  • Inequality is tested by "x != y", not "x <> y"
  • "if (a, b, c)" is written as "a ? b : c", which is the equivalent Java syntax.
  • min(x,y[,z]) and max(x,y[,z]) take two or three parameters, but no more
  • ? is written as "rnd()"
  • d and a are written as "d()" and "a()", respectively
  • mand() is available. It computes the Mandelbrot function, i.e. iteration depth of the complex formula z = z2 + c before the z value goes out of bounds.
    Here are example images of the predefined settings Mandel LUT and Mandel3 LUT in action with the 12colors.lut color lookup table: mand and mand(3).
  • mand(n) is similar to mand(), but uses the formula z = zn + c. Higher exponents are slower to compute. mand(2) is the same as mand().
  • i(m), r(m), g(m) and b(m) are available, with 1≤m≤n. These are the values of the pixels at the current location in all the slices, not just the current one. For m=t, these are the same as i, r, g and b. The 'Average Stack' preset shows this, as well as the "Collapse Stack" option (use with a two-image stack).
  • i(x,y), r(x,y), g(x,y) and b(x,y) can be used to access the pixel at position (x,y) in the current image. The 'Average 3x3' preset shows how to implement a 3x3 averaging filter using these functions.
  • i(x,y,m), r(x,y,m), g(x,y,m) and b(x,y,m) are available, with 1≤m≤n. These are the values of the pixels at location (x,y) in slice "m". For m=t, these are the same as i(x,y), r(x,y), g(x,y) and b(x,y).
  • All of ExpressionNTs functions are defined in the "Expr.java" file in the plugins directory. If you're proficient in Java, it's easy to add more functions.
  • In the HLS and HSV color models, the functions h(), s(), v() and l() can be used in addition to the r, g and b variables to access the color values

Input fields: R , G and B (or H , L and S or H , S and V )
For grayscale and 8 bit color images, only the first formula is used (in which case it is "I", the pixel intensity).
For 32 bit RGB images, all 3 fields are used to filter the R, G and B components, respectively. In this case, the variable "i" is either the red or the green or the blue intensity, depending on which field it is used in. If either one of the G or B fields is empty, or both, the "R" formula will be applied instead (but the "i" variable will still mean green or blue, not red). It is also possible to use the "r", "g" and "b" variables to refer to particular color components.
R , G and B should be in the range 0..maxval (unless the values in the Min and Max fields are set differently), H in the range 0..360, S, L and V in the range 0..1 .

RGB / HLS / HSV / Gray menu (ExpressionNT only)
Determines the color model in which the results are interpreted. If "RGB", the results are used unchanged; if "HLS" or "HSV", the values are converted to RGB before being displayed; if "Gray", only the first formula is evaluated, and its value is used for all 3 fields.
Note that h (Hue) has different meanings in the HLS and HSV models - color values differ by 120 from one another (see the presets 'HLS Red' and 'HSV Red' for an example).

X and Y
These are the x and y values that correspond to the upper left hand corner of the image.

Functions (ExpressionNT only)
Clicking this button opens a dialog containing a text entry area. Any functions entered in this window (in Java syntax) can be used in the expressions. The following defines a function called "funky" that squares its first parameter and adds the second:

double funky (double p1, double p2) {
	return p1 * p1 + p2;
}
Inside the function, any Java code is possible, like variable declarations, if/then/else statements etc. If you're using ImageJ 1.32c or higher, these functions are stored when the program is quit, and will be available upon restart without having to enter them again.

W and H
These are the width and height of the image. If width and height are the same values as the image's width and height in pixels, there is a 1-1 relationship between numerical coordinates and pixel coordinates.

Center
If this box is checked, the x and y values entered above are located in the center of the image, instead of the upper left hand corner. E.g., x=0 y=0 w=10 h=10 would effectively mean x=-5...5 and y=-5...5 instead of x=0...10 and y=0...10.

Min and Max
These fields are used to determine the range of results that are mapped to the intensity of each color component. E.g. for 8-bit images, if Min is 0 and Max is 255, there is a 1-1 correlation. If Max is 1000, then the result will be scaled down so that the range 0-1000 can be displayed as 0-255 levels of intensity.

If you are evaluating the expression sin(x), though, the resulting values will range from -1 to +1. In this case, you should set Min to -1 and Max to 1 so the sine wave will appear as a fluctuation from black to white (unless you want to use only part of the color spectrum).

The mapping is done only when filtering in RGB or Gray mode, not for HLS or HSV. That's because in those color models the 3 fields have different ranges, while for RGB all fields have the same range.
The mapping also isn't done for 32-bit grayscale images, because their minimum and maximum values are automatically mapped to the minimum and maximum b/w intensity.

Formulas as well as numbers can be used in these fields, e.g. 2 * pi.

Wrap
If the results of the expression are outside of the Min-Max range, this setting determines how it is dealt with. If "Wrap" is unchecked the value is pinned to the Min or Max. If "Wrap" is checked, the value wraps over. This can be used to create some interesting moire effects (try the Default preset with wrap turned on and off for an example).

New Window
If this is checked the resulting image is opened in a new image window, instead of replacing the current image. The type of the new image is the same as the current one. If it is checked when filtering a stack, the scrollbar for navigating the new stack is for some reason not visible; saving and reopening the image fixes that.

Collapse Stack (ExpressionNT only)
If this is checked, and "New Window" is also checked, and the source is a stack, then the resulting image will be a single image, not a stack. In other words, the stack has been 'collapsed' into a single image. This is useful in conjunction with formulas containing any of the i(m), r(m), g(m) or b(m) functions.

Current Image Only (ExpressionNT only)
If this is checked, and the image to be filtered is a stack, only the image currently in front will be filtered, not the ones before or behind it.

Max Iter (ExpressionNT only)
This is the maximum number of iterations that is calculated for the mand() function before returning. Higher values make for a more detailed picture, but slow down the calculation. The "+" button increases the value by 50%, while the "-" buttons decreases the value by 33%.

Max is 0 (ExpressionNT only)
Checking this option will cause the mand() function always to return a value of 0 if the maximum number of iterations is reached for a particular point, instead of the actal number of iterations. This ensures that the inner regions of a Mandelbrot image always show the same color. E.g., when using one of the LUT files, these areas will always be black (the LUT can be applied to a gray-scale image by using the File/Open->LUT... menu).

Presets menu
Frequently used formulas and their settings can be stored permanently and accessed later. Simply enter a name for the formula into the 'Presets' text field, and choose 'Add' from the menu. The formula becomes part of the menu, and is also stored on disk. To remove a formula, choose it from the menu, and then choose 'Delete'. To update settings, choose it from the menu, edit the fields as desired, and choose 'Add'. This will replace the old settings. The formulas are saved in the presets.txt file (or presetsNT.txt for ExpressionNT) in the working directory (from which ImageJ was started). The file can also be edited manually, but ImageJ should be closed first to avoid any accidental loss of the changes.

Navigation Panel (ExpressionNT only)
The navigation panel can be used to pan an image and zoom in and out of it. The complete image is recomputed for each pan/zoom. For navigation to work, the X, Y, Width and Height fields may only contain numerical values, not formulas. Clicking either OK or Cancel closes the panel; while clicking OK updates the X, Y, Width and Height fields of the Expression dialog, clicking Cancel restores the original values before the navigation panel was opened. Navigation is particularly useful for Mandelbrot images.

Changes: August 2001
  • Added capability to work with stacks; the number of images and the index of the current image in the stack are available as parameters "n" and "t", respectively.
November 2001
  • Added ExpressionJEL plugin that uses the Java Expression Library (JEL) to compile expressions, and which is thus much faster than the old interpreted evaluation scheme. ExpressionJEL also adds some new options, and allows expressions to be stored persistently, and then to be accessed from a menu.
April 2002
  • ExpressionJEL has been updated to support the HLS color model in addition to RGB.
  • The result of an image operation can now be display in a new window instead of altering the current image.
May 2003
  • The new ExpressionNT plugin replaces the one that utilized the JEL library. JEL was proving troublesome to integrate with ImageJ, due to ImageJ and JEL both using ClassLoaders; those were interfering with each other.

    I have tested the plugins on MacOS 9 and X and Windows 2000 and XP. I'd be interested to hear about experiences on other operating systems. The original Expression plugin shouldn't have problems on any platform, though.

June 2003
  • Added the generalized Mandelbrot function mand(n) to ExpressionNT
  • Added support for the HSV color model to ExpressionNT, and h(), s(), v() and l() functions for use with the HLS and HSV color models
August 2003
  • The Undo menu can now be used to reverse image filtering. Undo does nothing if "New Window" was checked, because the window can simply be closed. It also doesn't work for the zooming and panning done from the Navigation panel in ExpressionNT.
  • Added partial support for macro recording and playback. It is possible to choose a function from the Presets menu and apply it to an image. The macro syntax for Expression is:
    run("Expression ", "preset='Default'");
    and for ExpressionNT:
    run("ExpressionNT ", "preset='Default'");
    where 'Default' should be replaced by the name of the preset as it appears in the popup menu. Selecting a function and clicking the "Apply Expression" button is also recorded as such in the Macro Recorder. Note that manual changes to any of the parameters will not be recorded.
    If the plugins are called in this fashion, the dialog window is not shown.
  • Optimized mand() to be about 10% faster than mand(2).
January 2004
  • A warning message is shown if the presets file is not found, but the plugin will now work regardless (used to throw an exception).
February 2004
  • When working with stacks in ExpressionNT, it is possible to 'collapse' them. That means to calculate only a single resulting image instead of a full stack. It is also possible to access the values of all pixels at the current (x,y) location in all slices, not just the current one.
  • Pixel values of floating-point (32-bit) images are no longer scaled to be between the Min and Max values, because ImageJ does that automatically.
  • In Macro mode it is now possible to pass arbitrary parameters to the plugin.
    Thanks to Rudolf Oldenbourg for these suggestions.
  • The plugin files, including the presets, can now reside in a subdirectory of the plugins directory. Incompatible change: The presets files must be in the same directory as the other files. They can no longer be kept in the ImageJ directory (where they had to be in previous versions).
March 2004
  • It is possible to define new functions in ExpressionNT.
  • Non-rectangular ROIs are now supported.
March 2005
  • Added checkbox to only filter the current image of a stack. Thanks to Jerry LeCarpentier for the suggestion.
  • Fixed problem with saving of Java functions on Windows.
  • Fixed incorrect setup of Undo.
  • Better recovery from a compilation error.
  • No longer filters 8-bit color LUT images, unless they have a pseudo-color LUT or a greyscale LUT. These images should be converted to RGB color first.
  • Fixed race condition in cases where the filtering takes very little time.
May 2005
  • In ExpressionNT it is now possible to access all pixels in all images using the following notation:
    i(t) - the value of the pixel at the current (x,y) position in slice t (1 ≤ t ≤ n)
    i(x,y) - the value of the pixel at position (x,y) in the current image
    i(x,y,t) - the value of the pixel at position (x,y) in slice t (1 ≤ t ≤ n)
    In addition, the same functions named "r", "g" and "b" are available for accessing the individual color components of RGB images. Incompatible change: The I[n] notation for accessing the pixel at the current (x,y) position in the other images no longer works. Use i(n) instead.
    Caution: When using these functions, you probably want to check the "New Window" option, because the values returned are retrieved from the currently active image objects. That means that the values will have changed for all pixels for which the expression has already been evaluated. Most likely, that's not what you want.
    Thanks to Marek Gorywoda for the suggestion.
July 2005 April 2007
  • underwearfiend blogs about how to alter pictures using some advanced expressions: part 1, part 2
June 2007
  • Fixed a bug (reported by Harry Parker) where an exception would be thrown if a macro tried to select a non-existing preset. Now a warning message is shown.
April 2008
  • ExpressionNT now reports any compiler errors it encounters.


Back To ImageJ Plugin Page | Back To Home Page