J Image Tutorial
J Image Tutorial
Werner Bailer∗
ijtutorial@fh-hagenberg.at†
Version 1.71
Based on ImageJ Release 1.36
July 2, 2006
Contents
1 Getting Started 3
1.1 About ImageJ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 About this Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Setting up your Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 Updating ImageJ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1
Version 1.71
4.3 Processors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.4 Accessing Pixel Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.5 Regions of Interest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.6 Creating New Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.7 Displaying Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.8 Image Type Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.9 ColorInverter PlugIn (Example) . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.10 Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.11 StackAverage PlugIn (Example) . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.12 Additional Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
6 Windows 38
6.1 GenericDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.2 FrameDemo PlugIn (Example) . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.3 ImageWindow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.4 ImageCanvas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.5 Subclasses of ImageWindow . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.6 Event Handling (Example) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
7 Advanced Topics 46
7.1 Importing/Exporting Movies . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.2 Writing I/O plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7.3 Using the ImageJ Library outside ImageJ . . . . . . . . . . . . . . . . . . . . 51
8 Troubleshooting 54
8.1 ImageJ runs out of memory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
8.2 A plugin is not displayed in ImageJ’s plugins menu. . . . . . . . . . . . . . . 54
8.3 When you call the “Plugins/Compile and Run ...” menu . . . . . . . . . . . . . 55
8.4 ImageJ throws an exception in a web application (Unix/Linux) . . . . . . . . 55
10 Further Resources 56
10.1 API Documentation, Source Code . . . . . . . . . . . . . . . . . . . . . . . . 56
10.2 Plugins Page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
10.3 ImageJ Mailing List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
10.4 Java Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
10.5 Image Processing Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
1 Getting Started
1.1 About ImageJ1
ImageJ is a public domain Java image processing program inspired by NIH Image for the
Macintosh. It runs, either as an online applet or as a downloadable application, on any
computer with a Java 1.1 or later virtual machine. Downloadable distributions are available
for Windows, Mac OS, Mac OS X and Linux.
It can display, edit, analyze, process, save and print 8-bit, 16-bit and 32-bit images. It
can read many image formats including TIFF, GIF, JPEG, BMP, DICOM, FITS and “raw”.
It supports “stacks”, a series of images that share a single window. It is multithreaded, so
time-consuming operations such as image file reading can be performed in parallel with other
operations.
It can calculate area and pixel value statistics of user-defined selections. It can measure
distances and angles. It can create density histograms and line profile plots. It supports
standard image processing functions such as contrast manipulation, sharpening, smoothing,
edge detection and median filtering.
It does geometric transformations such as scaling, rotation and flips. Image can be zoomed
up to 32:1 and down to 1:32. All analysis and processing functions are available at any
magnification factor. The program supports any number of windows (images) simultaneously,
limited only by available memory.
Spatial calibration is available to provide real world dimensional measurements in units
such as millimeters. Density or gray scale calibration is also available.
ImageJ was designed with an open architecture that provides extensibility via Java plu-
gins. Custom acquisition, analysis and processing plugins can be developed using ImageJ’s
built in editor and Java compiler. User-written plugins make it possible to solve almost any
image processing or analysis problem.
ImageJ is being developed on Mac OS X using its built in editor and Java compiler,
plus the BBEdit editor and the Ant build tool. The source code is freely available. The
author, Wayne Rasband (wayne@codon.nih.gov), is at the Research Services Branch, National
Institute of Mental Health, Bethesda, Maryland, USA.
2.6 Interfaces
2.6.1 PlugIn
This interface has just one method:
2.6.2 PlugInFilter
This interface also has a method
void run(ImageProcessor ip)
This method runs the plugin, what you implement here is what the plugin actually
does. It takes the image processor it works on as an argument. The processor can
be modified directly or a new processor and a new image can be based on its data,
so that the original image is left unchanged. The original image is locked while the
plugin is running. In contrast to the PlugIn interface the run method does not take
a string argument. The argument can be passed using
int setup(java.lang.String arg, ImagePlus imp)
This method sets up the plugin filter for use. The arg string has the same function
as in the run method of the PlugIn interface. You do not have to care for the
argument imp—this is handled by ImageJ and the currently active image is passed.
The setup method returns a flag word that represents the filters capabilities (i.e.
which types of images it can handle).
2.7 PlugInFrame
A PlugInFrame is a subclass of an AWT frame that implements the PlugIn interface. Your
plugin will be implemented as a subclass of PlugInFrame.
There is one constructor for a PlugInFrame. It receives the title of the window as argument:
PlugInFrame(java.lang.String title)
As this class is a plugin, the method
void run(java.lang.String arg)
declared in the PlugIn interface is implemented and can be overwritten by your
plugin’s run method.
Of course all methods declared in java.awt.Frame and its superclasses can be overwritten.
For details consult the Java AWT API documentation.
import ij.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.*;
The packages of the ImageJ API are discussed in Section 3. Depending on the type of
plugin, the package in the last import statement is ij.plugin.*, ij.plugin.filter.* or
ij.plugin.frame.*.
2.8.1 PlugIn
For each plugin a new class is created, which implements the interface of the respective plugin
type:
In this sample code, a utility method is called, which displays a message box.
2.8.2 PlugInFilter
Similarly, a filter plugin implements the appropriate interface:
// ...
}
In addition, the plugin declares an instance variable, which will hold the image on which
the filter plugin works. The setup method is called when the plugin is instantiated. An
argument string and an image are passed:
In the method’s code, the image argument is stored in the instance variable, and the capability
flag of the filter plugin is returned. The following capability flags are defined in PlugInFilter:
static int DOES 16 The plugin filter handles 16 bit grayscale images.
static int DOES 32 The plugin filter handles 32 bit floating point grayscale images.
static int DOES 8C The plugin filter handles 8 bit color images.
static int DOES 8G The plugin filter handles 8 bit grayscale images.
static int DOES ALL The plugin filter handles all types of images.
static int DOES RGB The plugin filter handles RGB images.
static int DOES STACKS The plugin filter supports stacks, ImageJ will call it for each slice
in a stack.
static int DONE If the setup method returns DONE the run method will not be called.
static int NO CHANGES The plugin filter does not change the pixel data.
static int NO IMAGE REQUIRED The plugin filter does not require an image to be open.
static int NO UNDO The plugin filter does not support undo.
static int ROI REQUIRED The plugin filter requires a region of interest (ROI).
static int SUPPORTS MASKING Plugin filters always work on the bounding rectangle of the
ROI. If this flag is set and there is a non-rectangular ROI, ImageJ will restore the pixels
that are inside the bounding rectangle but outside the ROI.
The run method receives the image processor (cf. Section 4.3) of the image and performs
the actual function of the plugin:
The example code inverts the image, updates the display, waits for a half second, and again
inverts the image and updates the display.
2.8.3 PlugInFrame
The frame plugin extends the PlugInFrame class, which implements the PlugIn interface:
A PlugInFrame is derived from a Java AWT window. In the sample code the constructor for
the class is implemented:
public My_Plugin_Frame() {
super("Plugin_Frame");
TextArea ta = new TextArea(15, 50);
add(ta);
pack();
GUI.center(this);
show();
}
First, the constructor of the base class is called with the title of the window as argument.
Then a text area is created and added to the window, and the window is displayed.
import ij.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*;
import java.awt.*;
Note: Do not use a package statement inside plugin classes—they have to be in the default
package!
The name of this plugin has the necessary underscore appended. It needs an image as input,
so it has to implement PlugInFilter:
What comes next is the method for setting up the plugin. For the case that we get
“about” as argument, we call the method showAbout that displays an about dialog. In that
case we return DONE because we do not want the run method to be called. In any other case
we return the capability flags for this plugin: It works on 8 bit grayscale images, also on
stacks and in the case that there is a ROI (region of interest) defined the plugin will just
work on the masked region (ROI).
The run method implements the actual function of the plugin. We get the processor of
the original image. Then we get the image as an array of pixels from the processor—as it is
a 8 bit grayscale image (= 256 possible values) we can use a byte array. Note that the pixel
array is one-dimensional, containing one scan line after the other. Then we read the width
of the image (because we need to know the length of a scan line) and the bounding rectangle
of the ROI.
NewImage
A class for creating a new image of a certain type from scratch.
Roi
A class representing a region of interest of an image. If supported by a plugin, it
can process just the ROI and not the whole image. There are several subclasses for
specific types of ROIs, which are discussed in 4.5.
ImageCanvas
A canvas derived from java.awt.Canvas on which an image is painted (see Section
6).
ImageWindow
A frame derived from java.awt.Frame that displays an image (see Section 6).
StackWindow
An ImageWindow designed for displaying stacks (see Section 6).
HistogramWindow
An ImageWindow designed for displaying histograms (see Section 6).
PlotWindow
An ImageWindow designed for displaying plots (see Section 6).
ij.io
This package contains classes for reading/decoding and writing/encoding image files.
ij.macro
The package implements the parser for the macro language and the built-in macro func-
tions.
ij.measure
Most ImageJ menu commands are implemented as plugins and can therefore be
found in the classes of ij.plugin and its subpackages.
PlugIn
This interface has to be implemented by plugins, that do not require an image as
input (see Section 2).
Converter
Implements a method for conveniently converting an ImagePlus from one type to
another (see Section 4.8)
ij.plugin.filter
PlugInFilter
This interface has to be implemented by plugins, that require an image as input (see
Section 2).
ij.plugin.frame
PlugInFrame
A window class that can be subclassed by a plugin (see Section 2).
ij.process
ImageConverter
A class that contains methods for converting images from one image type to another.
ImageProcessor
An abstract superclass of the image processors for certain image types. An image
processor provides methods for actually working on the image data (see Section 4).
StackConverter
A class for converting stacks from one image type to another.
StackProcessor
A class for processing image stacks.
8 bit grayscale images can display 256 grayscales, a pixel is represented by a byte vari-
able.
8 bit color images can display 256 colors that are specified in a lookup table (LUT), a
pixel is represented by a byte variable.
16 bit grayscale images can display 65, 536 grayscales, a pixel is represented by a short
variable.
RGB color images can display 256 values per channel, a pixel is represented by an int
variable.
32 bit images are floating point grayscale images, a pixel is represented by a float variable.
For information about conversion between different image types, see Section 4.8. D. Sage
and M. Unser (Biomedical Imaging Group, Swiss Federal Institute of Technology Lausanne)
contributed a package called ImageAccess, which unifies access to images regardless of data
types.2
2
More information can be found at http://bigwww.epfl.ch/teaching/iplabsite/.
4.2 Images
An ImagePlus is an object that represents an image. It is based on an ImageProcessor,
a class that holds the pixel array and does the actual work on the image. The type of the
ImageProcessor used depends on the type of the image. The image types are represented
by constants declared in ImagePlus:
ImageJ displays images using a class called ImageWindow. It handles repainting, zooming,
changing masks etc.
To construct an ImagePlus use one of the following constructors:
ImagePlus()
Default constructor, creates a new empty ImagePlus and does no initialization.
ImagePlus(java.lang.String pathOrURL)
Constructs a new ImagePlus, loading the Image from the path or URL specified.
ImagePlus(java.lang.String title, java.awt.Image img)
Constructs a new ImagePlus based on a Java AWT image. The first argument is
the title of the ImageWindow that displays the image.
ImagePlus(java.lang.String title, ImageProcessor ip)
Constructs a new ImagePlus that uses the specified ImageProcessor. The first
argument is the title of the ImageWindow that displays the image.
ImagePlus(java.lang.String title, ImageStack stack)
Constructs a new ImagePlus from an ImageStack. The first argument is the title
of the ImageWindow that displays the image.
The type of an ImagePlus can be retrieved using
int getType()
Similar methods exist for getting the image dimension, the title (i.e. name of the Image-
Window that displays this image), the AWT image that represents the ImagePlus and the file
information:
int getHeight()
int getWidth()
java.lang.String getTitle()
java.awt.Image getImage()
ij.io.FileInfo getFileInfo()
The AWT image on which the ImagePlus is based and the image’s title title can be set using
void setImage(java.awt.Image img)
void setTitle(java.lang.String title)
An ImagePlus can have a list of additional properties that can be defined by the user. They
are indexed using a string and can be any type of object. These properties can be read and
set using the methods:
java.util.Properties getProperties()
Returns this image’s Properties.
java.lang.Object getProperty(java.lang.String key)
Returns the property associated with key.
void setProperty(java.lang.String key, java.lang.Object value)
Adds a key-value pair to this image’s properties.
4.3 Processors
Each image is based on an image processor. The type of the processor depends on the type of
the image. You can get and set the image processor using these two methods of an ImagePlus:
ImageProcessor getProcessor()
Returns a reference to the image’s ImageProcessor.
void setProcessor(java.lang.String title, ImageProcessor ip)
Sets the image processor to the one specified.
When working with plugin filters you do not have to care about retrieving the processor
from the ImagePlus, it is passed as argument to the run method.
ImageProcessor is an abstract class. Depending on the type of the image we use a subclass
of ImageProcessor. There are five of them:
ByteProcessor
Used for 8 bit grayscale and color images. It has a subclass called BinaryProcessor
for grayscale images that only contain the pixel values 0 and 255.
ShortProcessor
Used for 16 bit grayscale images.
ColorProcessor
Used for 32 bit integer images (RGB with 8 bit per channel).
FloatProcessor
Used for 32 bit floating point images.
This example would work for an RGB image. As you have noticed we get back a one-
dimensional array. It contains the image scanline by scanline. To convert a position in this
array to a (x,y) coordinate in an image, we need at least the width of a scanline.
The width and height of an ImageProcessor can be retrieved using these methods:
int getHeight()
int getWidth()
Now we have everything to iterate through the pixel array. As you have seen in the sample
plugin code this can be done using two nested loops.
Some cases need a bit more explanation: Reading pixels from ByteProcessor, Short-
Processor and from ColorProcessor.
Java’s byte data type is signed and has values ranging from −128 to 127, while we would
expect a 8 bit grayscale image to have values from 0 to 255. If we cast a byte variable to
another type we have to make sure, that the sign bit is eliminated. This can be done using
a binary AND operation (&):
It’s the same with Java’s short data type, which is also signed and has values ranging
from −32, 768 to 32, 767, while we would expect a 16 bit grayscale image to have values from
0 to 65, 535. If we cast a short variable to another type we have to make sure that the sign
bit is eliminated. This can again be done using a binary AND operation:
ColorProcessors return the pixel array as an int[]. The values of the three color
components are packed into one int variable. They can be accessed as follows:
The pixel array you work on is a reference to the ImageProcessor’s pixel array. So any
modifications effect the ImageProcessor immediately. However, if you want the Image-
Processor to use another (perhaps newly created) array, you can do this using
void setPixels(java.lang.Object pixels)
You do not always have to retrieve or set the whole pixel array. ImageProcessor offers
some other methods for retrieving or setting pixel values:
int getPixel(int x, int y)
Returns the value of the specified pixel.
void putPixel(int x, int y, int value)
Sets the pixel at (x,y) to the specified value.
The methods listed above are also available on the ImagePlus object, which has in addition
the method
Roi getRoi()
Returns a ROI object representing the current selection.
The classes representing the different types of ROIs can be found in ij.gui. These classes
are:
• Line
• OvalROI
• PolygonRoi, with subclasses FreehandRoi and PointRoi
• ShapeRoi
• TextRoi
There are two methods to copy pixel values between different ImageProcessors:
void insert(ImageProcessor ip, int xloc, int yloc)
Inserts the image contained in ip at (xloc, yloc).
void copyBits(ImageProcessor ip, int xloc, int yloc, int mode)
Copies the image represented by ip to xloc, yloc using the specified blitting mode.
The blitting mode is one of the following constants defined in the interface Blitter:
If you need a Java AWT image, you can retrieve it from the ImageProcessor using
java.awt.Image createImage()
To scale to 0−255 when converting short or float images to byte images and to 0−65535
when converting float to short images set scaling true using
public static void setDoScaling(boolean scaleConversions)
public static boolean getDoScaling()
returns true if scaling is enabled.
ImageConverter does not convert stacks, you can use StackConverter for this purpose. An
instance of this class can be created using
StackConverter(ImagePlus img)
It has the following methods:
void convertToGray8()
Converts this stack to 8-bit grayscale.
void convertToGray16()
Converts this stack to 16-bit grayscale.
void convertToGray32()
Converts this stack to 32-bit (float) grayscale.
void convertToRGB()
Converts the stack to RGB.
void convertToIndexedColor(int nColors)
Converts the stack to 8-bits indexed color. nColors must be greater than 1 and less
than or equal to 256.
import ij.*;
import ij.gui.*;
import ij.process.*;
import ij.plugin.filter.PlugInFilter;
import java.awt.*;
Don’t forget to rename the file to ColorInverter .java, otherwise you won’t be able to
compile it!
We want to handle RGB files, we do not want to apply it to stacks, we want to support
non-rectangular ROIs and because we display the results in a new image we do not modify
the original, so we change the capabilities returned by the setup method to DOES RGB +
SUPPORTS MASKING + NO CHANGES.
First we save the dimension and the ROI of the original image to local variables.
int w = ip.getWidth();
int h = ip.getHeight();
Rectangle roi = ip.getRoi();
We want to have the result written to a new image, so we create a new RGB image of the
same size, with one slice and initially black and get the new image’s processor.
Then we copy the image from the original ImageProcessor to (0,0) in the new image, using
COPY blitting mode (this mode just overwrites the pixels in the destination processor). We
then get the pixel array of the new image (which is of course identical to the old one). It’s a
RGB image, so we get an int array.
inv_ip.copyBits(ip,0,0,Blitter.COPY);
int[] pixels = (int[]) inv_ip.getPixels();
We now go through the bounding rectangle of the ROI with two nested loops. The outer
one runs through the lines in the ROI, the inner one through the columns in each line. The
offset in the one-dimensional array is the start of the current line (= width of the image ×
number of scanlines).
In the inner loop we calculate the position of the current pixel in the one-dimensional array
(we save it in a variable because we need it twice). We then get the value of the current
pixel. Note that we can access the pixel array of the new image, as it contains a copy of the
old one.
We invert each component by subtracting it’s value from 255. Then we pack the modified
color components into an integer again.
r=255-r;
g=255-g;
b=255-b;
pixels[pos] = ((r & 0xff) << 16) +
((g & 0xff) << 8) +
(b & 0xff);
}
}
We have now done all necessary modifications to the pixel array. Our image is still not visible,
so we call show to open an ImageWindow that displays it. Then we call updateAndDraw to
force the pixel array to be read and the image to be updated.
inverted.show();
inverted.updateAndDraw();
}
}
4.10 Stacks
ImageJ supports expandable arrays of images called image stacks, that consist of images
(slices) of the same size. In a plugin filter you can access the currently open stack by retrieving
it from the current ImagePlus using
ImageStack getStack()
ImagePlus also offers a method for creating a new stack:
ImageStack createEmptyStack()
Returns an empty image stack that has the same width, height and color table as
this image.
Alternatively you can create an ImageStack using one of these constructors:
ImageStack(int width, int height)
Creates a new, empty image stack with specified height and width.
ImageStack(int width, int height, java.awt.image.ColorModel cm)
Creates a new, empty image stack with specified height, width and color model.
To set the newly created stack as the stack of an ImagePlus use its method
void setStack(java.lang.String title, ImageStack stack)
The number of slices of a stack can be retrieved using the method
int getSize()
of class ImageStack or with the methods
int getStackSize()
int getImageStackSize()
of class ImagePlus.
The currently displayed slice of an ImagePlus can be retrieved and set using
int getCurrentSlice()
void setSlice(int index)
A stack offers several methods for retrieving and setting its properties:
int getHeight()
Returns the height of the stack.
int getWidth()
Returns the width of the stack.
java.lang.Object getPixels(int n)
Returns the pixel array of the specified slice, where n is a number from 1 to the
number of slices. See also Section 4.4.
void setPixels(java.lang.Object pixels, int n)
Assigns a pixel array to the specified slice, where n is a number from 1 to the number
of slices. See also Section 4.4.
ImageProcessor getProcessor(int n)
Returns an ImageProcessor for the specified slice, where n is a number from 1 to
the number of slices. See also Section 4.3.
java.lang.String getSliceLabel(int n)
Returns the label of the specified slice, where n is a number from 1 to the number
of slices.
void setSliceLabel(java.lang.String label, int n)
Sets the label of the specified slice, where n is a number from 1 to the number of
slices.
java.awt.Rectangle getRoi()
Returns the bounding rectangle of the stack’s ROI. For more information on ROIs,
see Section 4.5.
void setRoi(java.awt.Rectangle roi)
Sets the stacks ROI to the specified rectangle. For more information on ROIs, see
Section 4.5.
Slices can be added to and removed from the ImageStack using these methods:
void addSlice(java.lang.String sliceLabel, ImageProcessor ip)
Adds the image represented by ip to the end of the stack.
void addSlice(java.lang.String sliceLabel, ImageProcessor ip, int n)
Adds the image represented by ip to the stack following slice n.
void addSlice(java.lang.String sliceLabel, java.lang.Object pixels)
Adds an image represented by its pixel array to the end of the stack.
void deleteLastSlice()
Deletes the last slice in the stack.
void deleteSlice(int n)
Deletes the specified slice, where n is in the range 1 . . .number of slices.
import ij.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*;
We define the stack as instance variable because we will retrieve it in setup and use it in
run.
In this method we get the stack from the current image and return the plugin’s capabilities—
in this case we indicate that it handles 8 bit grayscale images and requires a stack as input.
In the run method we declare a byte array that will hold the pixels of the current slice. Then
we get width and height of the stack and calculate the length of the pixel array of each slice
as the product of width and height. sum is the array to hold the summed pixel values.
In the outer loop we iterate through the slices of the stack and get the pixel array from each
slice. In the inner loop we go through the pixel array of the current slice and add the pixel
value to the corresponding pixel in the sum array.
We have now gone through the whole stack. The image containing the averages will be a
8 bit grayscale image again, so we create a byte array for it. Then we iterate through the
pixels in the sum array and divide each of them through the number of slices to get pixel
values in the range 0 . . . 255.
Finally we add a new slice to the stack. It is called “Average” and represented by the pixel
array that contains the average values.
stack.addSlice("Average",average);
}
4.12.1 ImagePlus
Windows
void setWindow(ImageWindow win)
Sets the window that displays the image.
ImageWindow getWindow()
Gets the window that is used to display the image.
void mouseMoved(int x, int y)
Displays the cursor coordinates and pixel value in the status bar.
Multithreading
boolean lock()
Locks the image so that it cannot be accessed by another thread.
boolean lockSilently()
Similar to lock, but doesn’t beep and display an error message if the attempt to lock
the image fails.
void unlock()
Unlocks the image.
Lookup Tables
LookUpTable createLut()
Creates a LookUpTable based on the image.
Statistics
ij.process.ImageStatistics getStatistics()
Returns an ImageStatistics object generated using the standard measurement
options (area, mean, mode, min and max).
ij.process.ImageStatistics getStatistics(int mOptions)
Returns an ImageStatistics object generated using the specified measurement
options.
ij.process.ImageStatistics getStatistics(int mOptions, int nBins)
Returns an ImageStatistics object generated using the specified measurement
options and number of histogram bins.
Calibration
void setCalibration(ij.measure.Calibration cal)
Sets this image’s calibration.
void setGlobalCalibration(ij.measure.Calibration global)
Sets the system-wide calibration.
ij.measure.Calibration getCalibration()
Returns this image’s calibration.
void copyScale(ImagePlus imp)
Copies the calibration from the specified image.
4.12.2 ImageProcessor
Geometric Transforms
void flipHorizontal()
Flips the image horizontally.
void flipVertical()
Flips the image vertically.
void rotate(double angle)
Rotates the image angle degrees clockwise.
void scale(double xScale, double yScale)
Scales the image by the specified factors.
ImageProcessor crop()
Crops the image to the bounding rectangle of the current ROI. Returns a new image
processor that represents the cropped image.
ImageProcessor resize(int dstWidth, int dstHeight)
Resizes the image to the specified destination size. Returns a new image processor
that represents the resized image.
ImageProcessor rotateLeft()
Rotates the image 90 degrees counter-clockwise. Returns a new image processor
that represents the rotated image.
ImageProcessor rotateRight()
Rotates the image 90 degrees clockwise. Returns a new image processor that repre-
sents the rotated image.
void setInterpolate(boolean interpolate)
Setting interpolate to true causes scale(), resize() and rotate() to do bilinear
interpolation, otherwise nearest-neighbor interpolation is used.
Filters
void convolve3x3(int[] kernel)
Convolves the image with the specified 3×3 convolution matrix.
void convolve(float[] kernel, int kernelWidth, int kernelHeight)
Convolves the image with the specified convolution kernelWidth×kernelHeight
matrix.
void sharpen()
Sharpens the image using a 3×3 convolution kernel.
void smooth()
Replaces each pixel with the 3×3 neighborhood mean.
void noise(double range)
Adds random noise (random numbers within range) to the image.
void filter(int type)
A 3×3 filter operation, the argument defines the filter type.
void dilate()
Dilates the image using a 3×3 minimum filter.
void erode()
Erodes the image using a 3×3 maximum filter.
void findEdges()
Finds edges using a Sobel operator.
void medianFilter()
A 3×3 median filter.
void gamma(double value)
A gamma correction.
void invert()
Inverts an image.
void add(int value)
Adds the argument to each pixel value.
void add(double value)
Adds the argument to each pixel value.
void multiply(double value)
Multiplies each pixel value with the argument.
void sqr()
Squares each pixel value.
void sqrt()
Calculates the square root of each pixel value.
void and(int value)
Binary AND of each pixel value with the argument.
void or(int value)
Binary OR of each pixel value with the argument.
void xor(int value)
Binary exclusive OR of each pixel value with the argument.
void log()
Calculates pixel values on a logarithmic scale.
Drawing
void setColor(java.awt.Color color)
Sets the foreground color. This will set the default fill/draw value to the pixel value
that represents this color.
void setValue(double value)
Sets the default fill/draw value.
void setLineWidth(int width)
Sets the line width.
void moveTo(int x, int y)
Sets the current drawing location to (x,y).
void lineTo(int x2, int y2)
Draws a line from the current drawing location to (x2,y2).
void drawPixel(int x, int y)
Sets the pixel at (x,y) to the current drawing color.
void drawDot(int xcenter, int ycenter)
Draws a dot using the current line width and color.
void drawDot2(int x, int y)
Draws a 2×2 dot in the current color.
void drawPolygon(java.awt.Polygon p)
Draws the specified polygon.
void drawRect(int x, int y, int width, int height)
Draws the specified rectangle.
void fill()
Fills the current rectangular ROI with the current drawing color.
void fillPolygon(java.awt.Polygon p)
Fills the specified polygon with the current drawing color.
void fill(int[] mask)
Fills pixels that are within the current ROI and part of the mask (i. e. pixels that
have value 0 (= black) in the mask array).
void drawString(java.lang.String s)
Draws the string s at the current location with the current color.
int getStringWidth(java.lang.String s)
Returns the width of the specified string in pixels.
Colors
int getBestIndex(java.awt.Color c)
Returns the LUT index that matches the specified color best.
java.awt.image.ColorModel getColorModel()
Returns this processor’s color model.
void invertLut()
Inverts the values in the lookup table.
Minimum, Maximum and Threshold
double getMin()
Returns the smallest displayed pixel value.
double getMax()
Returns the largest displayed pixel value.
void setMinAndMax(double min, double max)
Maps the pixels in this image from min. . .max to the value range of this type of
image.
void resetMinAndMax()
For short and float images, recalculates the minimum and maximum image val-
ues needed to correctly display the image (i. e. maps the color values to the 255
displayable grayscales.
void autoThreshold()
Calculates the auto threshold of an image and applies it.
double getMinThreshold()
Returns the minimum threshold.
double getMaxThreshold()
Returns the maximum threshold.
void setThreshold(double minThreshold, double maxThreshold, int lutUpdate)
Sets the minimum and maximum threshold levels, the third parameters specifies if
the lookup table will be recalculated.
Histograms
int[] getHistogram()
Returns the histogram of the image. This method will return a luminosity histogram
for RGB images and null for floating point images.
int getHistogramSize()
The size of the histogram is 256 for 8 bit and RGB images and max-min+1 for 16
bit integer images.
Snapshots (Undo)
void snapshot()
Saves the current state of the processor as snapshot.
java.lang.Object getPixelsCopy()
Returns a reference to this image’s snapshot (undo) array, i. e. the pixel array before
the last modification.
void reset()
Resets the processor to the state saved in the snapshot.
void reset(int[] mask)
Resets the processor to the state saved in the snapshot, excluding pixels that are
part of mask.
4.12.3 Stacks
Accessing Images
java.lang.Object[] getImageArray()
Returns the stack as an array of ImagePlus objects.
java.lang.Object getPixels(int n)
Returns the pixel array for the specified slice (1 <= n <= nr slices).
Color
boolean isHSB()
Returns true, if this is a 3-slice HSB stack.
boolean isRGB()
Returns true, if this is a 3-slice RGB stack.
java.awt.image.ColorModel getColorModel()
Returns the stack’s color model.
void setColorModel(java.awt.image.ColorModel cm)
Assigns a new color model to the stack.
Figure 1: The ImageJ main window and its components: Menu bar, tool bar and status bar.
Figure 2: The ImageJ results window displays messages, measurements, etc. It opens auto-
matically, when text is written to it.
You will often want to displays numbers, which you can format for output using
static java.lang.String d2s(double n)
Converts a number to a formatted string using two digits to the right of the decimal
point.
static java.lang.String d2s(double n, int precision)
Converts a number to a rounded formatted string.
import ij.*;
import ij.plugin.PlugIn;
All we have to implement is the run method. We do not need the argument, so we ignore
it. First of all we display a string in the status bar that informs the user that the plugin was
started. Then we set the progress bar to 0% and show an error message.
We want the user to input a string and set the progress bar to 50% after that. Then we
write a message into the main window saying that we were going to start the sample plugin
Red And Blue (this is one of the plugins that come with ImageJ and displays a new image
with a red/blue gradient) and run the plugin. Finally we set the progress bar to 100% and
show a custom message box.
6 Windows
By default, plugins work with ImagePlus objects displayed in ImageWindows. They can
output information to the ImageJ window but they cannot control a window. Sometimes
this can be necessary, especially for getting user input.
One option is to create a plugin, that has its own window. This can be done using the
PlugInFrame class, that has been discussed in 2.5.
6.1 GenericDialog
In Section 5.3 we saw a very simple way of getting user input. If you need more user input
than just one string or number, GenericDialog helps you build a modal AWT dialog, i. e.
the programs only proceeds after the user has answered the dialog. The GenericDialog can
be built on the fly and you don’t have to care about event handling.
There are two constructors:
GenericDialog(java.lang.String title)
Creates a new GenericDialog with the specified title.
We import the ij and ij.process package, the ij.gui package, where GenericDialog
is located and the classes PlugInFrame and AWT label.
import ij.*;
import ij.gui.*;
import ij.plugin.frame.PlugInFrame;
import java.awt.Label;
Our plugin is a subclass of PlugInFrame which implements the PlugIn interface, so we don’t
have to implement an interface here.
We overwrite the default constructor of the new class. If we wouldn’t do that, the superclass’
default constructor PlugInFrame() would be called, which does not exist. So we have to call
the superclass’ constructor and specify a title for the new frame.
public FrameDemo_() {
super("FrameDemo");
}
In the run method we create a GenericDialog with the title “FrameDemo settings”. Then
we add two 3 digit numeric fields with a default value of 200.
We display the dialog. As it is modal, the program is stopped until the user closes the dialog.
If the user clicks “Cancel‘” we display an error message and leave the run method.
gd.showDialog();
if (gd.wasCanceled()) {
IJ.error("PlugIn canceled!");
return;
}
Here we get the values of the numeric fields with two calls of getNextNumber(). We set the
size of the FrameDemo window to these values and add a centered AWT label with the text
“PlugInFrame demo”. Finally we show the frame.
6.3 ImageWindow
An ImageWindow is a frame (derived from java.awt.Frame) that displays an ImagePlus.
The frame contains an ImageCanvas on which the image is painted and a line of information
text on top. Each ImagePlus is associated with an ImageWindow, which is created when the
image’s show() method is called for the first time. ImageWindows can also be created using
one of the constructors:
ImageWindow(ImagePlus imp)
Creates a new ImageWindow that contains the specified image.
ImageWindow(ImagePlus imp, ImageCanvas ic)
Creates a new ImageWindow that contains the specified image which will be painted
on the specified canvas.
ImageJ maintains the list of open windows using the WindowManager class. When the con-
structor of ImageWindow is called, the window is added to the list of open windows.
boolean close()
Closes the window and removes it from the list. If the image has been changed, this
method will ask the user whether the image displayed in this window shall be saved.
If the user wants to save the image the method returns false. Otherwise it returns
true and the image is deleted.
boolean isClosed()
Returns true if close() has already been called, false otherwise.
The image displayed in an ImageWindow and the canvas on which the image is drawn can be
accessed using
ImagePlus getImagePlus()
ImageCanvas getCanvas()
ImageWindow provides methods for the cut, copy and paste command:
void copy(boolean cut)
Copies the current ROI (which has to be rectangular) to the clipboard. If the
argument cut is true the ROI is cut and not copied.
void paste()
Pastes the content of the clipboard into the current image. The content of the
clipboard may not be larger than the current image and must be the same type.
Like an ImagePlus an ImageWindow has a method
void mouseMoved(int x, int y)
This method displays the specified coordinates and the pixel value of the image in
this window in the status bar of the ImageJ window.
ImageWindow has also a useful public boolean variable called running, which is set to
false if the user presses escape or closes the window. This can be used in a plugin like
shown in the following fragment to give the user a possibility to interrupt a plugin.
...
win.running = true;
while (win.running) {
// do computation
}
The variable running2 has a similar function as running, but is also set to false if the
user clicks in the image window.
6.4 ImageCanvas
Each ImageWindow has an ImageCanvas on which the image is drawn. This is a subclass
of java.awt.Canvas and also implements a MouseListener and a MouseMotionListener
(for more information see the Java API documentation, package java.awt.event). It can
therefore be useful for event handling, e. g. by subclassing it. Additionally it can be used to
get information on how the image is displayed and to modify this. Some useful methods of
ImageCanvas are listed here:
java.awt.Point getCursorLoc()
Returns the current cursor location.
double getMagnification()
Returns the current magnification factor of the image.
void setMagnification(double magnification)
Sets new magnification factor for image.
java.awt.Rectangle getSrcRect()
The surrounding rectangle of the image with current magnification.
int offScreenX(int x)
Converts a screen x-coordinate to an offscreen x-coordinate.
int offScreenY(int y)
Converts a screen y-coordinate to an offscreen y-coordinate.
int screenX(int x)
Converts an offscreen x-coordinate to a screen x-coordinate.
int screenY(int y)
Converts an offscreen y-coordinate to a screen y-coordinate.
void setCursor(int x, int y)
Sets the cursor based on the current tool and cursor location.
void setImageUpdated()
ImagePlus.updateAndDraw calls this method to get the paint method to update
the image from the ImageProcessor.
void zoomIn(int x, int y)
Zooms in by making the window bigger.
void zoomOut(int x, int y)
Zooms out by making srcRect bigger.
6.5.3 PlotWindow
This is a subclass of ImageWindow designed for displaying plots in a (x, y)-plane
PlotWindow(java.lang.String title, java.lang.String xLabel,
java.lang.String yLabel, double[] xValues, double[] yValues)
Constructs a new plot window with specified title, labels for x- and y- axis and adds
points with specified (x,y)-coordinates.
void addLabel(double x, double y, java.lang.String label)
Adds a new label with the specified text at position (x,y).
void addPoints(double[] x, double[] y, int shape)
This methods adds points with specified (x, y) coordinates to the plot. The number
of points is given by the length of the array. The argument shape determines the
shape of a point. Currently only circles are supported, which is specified by passing
the constant PlotWindow.CIRCLE.
void setLimits(double xMin, double xMax, double yMin, double yMax)
Sets the limits of the plotting plane.
Event handling in Java AWT is based on interfaces called listeners. There is a listener
interface for each type of event. A class implementing a listener interface is able to react on
a certain type of event. The class can be added to a component’s list of listeners and will be
notified when an event that it can handle occurs.
A plugin that has to react on a certain type of event can implement the appropriate
interface. It can access the window of the image it works on and the canvas on which the
image is painted. So it can be added as a listener to these components.
For example, we want to write a plugin that reacts to mouse clicks on the image it works
on. The listener interfaces are defined in java.awt.event, so we import this package.
import ij.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*; import ij.gui.*;
import java.awt.event.*;
We have to access the image and the canvas in more than one method, so we declare them
as instance variables:
ImagePlus img;
ImageCanvas canvas;
In the setup method we have access to the ImagePlus so we save it to the instance variable.
We also set the plugin’s capabilities.
In the run method we get the ImageWindow that displays the image and the canvas on which
it is drawn. We want the plugin to be notified when the user clicks on the canvas so we add
the plugin to the canvas’ MouseListeners.
To implement the interface we have to implement the five methods it declares. We only want
to react on clicks so we can leave the others empty. We get the coordinates of the point of the
mouse click from the event object that is passed to the method. The image could be scaled
in the window so we use the offScreenX() and offScreenY() method of ImageCanvas to
receive the true coordinates.
A more advanced mouse listener (which avoids assigning the listener to the same image twice)
and a similar example that reacts on keyboard events can be found at the ImageJ plugins
page (cf. Section 10).
Like mouse and key listeners a plugin can implement any event listener, e. g. a mouse
motion listener. For adding a mouse motion listener, the following changes of the mouse
listener plugin are necessary:
The class has to implement the event listener interface:
In the setup method, we add the plugin as listener to the image canvas.
canvas.addMouseMotionListener(this);
For details about listener interfaces, their methods and the events passed please see the Java
AWT documentation.
7 Advanced Topics
7.1 Importing/Exporting Movies
Because of its capability to handle image stacks ImageJ can be used to process movies.
Import and export plugins for a number of common movie formats are available, for example
• Read the image metadata (size, pixel type, etc.) and data from the file. If a Java
library is available for this file format, consider using it for this step.
• Write the image metadata (size, pixel type, etc.) and data to the file. If a Java library
is available for this file format, consider using it for this step.
0 1 3 7 15 31 63 127 255
0 1 3 7 15 31 63 127 255
0 1 3 7 15 31 63 127 255
0 1 3 7 15 31 63 127 255
0 1 3 7 15 31 63 127 255
0 1 3 7 15 31 63 127 255
0 1 3 7 15 31 63 127 255
0 1 3 7 15 31 63 127 255
0 1 3 7 15 31 63 127 255
The reader plugin does not need an image as input, so we implement the PlugIn interface,
and we keep an ImagePlus as instance variable that will hold the image we read from file:
import java.io.*;
import ij.*;
import ij.io.*;
import ij.gui.*;
import ij.plugin.*;
import ij.process.*;
import java.util.*;
ImagePlus img;
public Simple_ASCII_Reader() {
img = null;
}
The run method displays a file open dialog and gets the directory and file name the
user has selected. In the case that the user has not selected a file (i.e. cancelled), we return.
Otherwise we call the read method of our plugin (see below) and – in the case that a non-null
image is returned – show the new image.
read(directory,fileName);
if (img==null) return;
img.show();
}
The actual functionality for reading the file is implemented in the read method of our
plugin. It makes use of a utility method called getLineAsArray, that takes one line of file,
tokenizes it and returns the values as a short array (as the values in the file are unsigned
and thus outside the byte value range):
int i = 0;
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
values[i] = (new Short(token)).shortValue();
i++;
}
return values;
Now we can look at the read method. It opens a BufferedReader, and reads the lines
of the file into a vector.
Then we have to determine the metadata of our image, in order to know how we have to
create the new ImagePlus. In most real file formats you will find this information in some
header structure of the image file. We know that our simple ASCII format represents a 8 bit
graycale image with one slice, so we just need to get the width and height of the image. The
height is the number of lines we have read and the width is the number of values in the first
line. Then we can create the new image and get its pixel array.
Then we can iterate through the lines we have read, and copy the pixels from the array
of each line to the pixel array of the image (converting them to byte). The rest of the code
is just for exception handling (e.g. in the case that reading from the file fails).
public Simple_ASCII_Writer() {
img = null;
ip = null;
}
The run method displays a file save dialog, and – in case the user did not cancel – calls
the write method of our plugin, which does the actual work.
The write method opens a BufferedWriter and gets the pixel array of the image.
Then we iterate through the pixel array and write the values to the file. We need to
convert the numeric values to strings and write a space (except for the last one). Similarly,
we write a line feed after each of the lines, except for the last one.
offset = j*img.getWidth();
for (int i=0;i<img.getWidth();i++) {
pos = offset = i;
bw.write(new Integer(pixels[pos] & 0xff).toString());
if (i<img.getWidth()-1) bw.write(" ");
}
if (j<img.getHeight()-1) bw.write("\n");
}
The rest of the code just closes the writer and does the exception handling.
bw.close();
} catch (Exception e) {
IJ.error("Simple ASCII Writer", e.getMessage());
return;
}
}
Of course it would be possible to combine both plugins into one (using the PlugInFilter
interface), using the argument to determine whether the plugin should read an image or write
the currently active one.
Java 1.1.
Java 2 introduced many improvements concerning image processing with Java. But many
users still use browsers that only have a Java 1.1 virtual machine and only a minority uses
Sun’s Java plugin. Java 2 support may also be not available on less widespread platforms.
ImageJ still supports Java 1.1 and is therefore a good choice especially for applets.
ImagePlus as internal image format.
You will probably need an internal image representation format for your application. It
is convenient to use ImagePlus and ImageProcessor for this purpose, as a lot of basic
functionality (reading/writing pixel values, scaling, etc.) is already available.
Plugins and Macros.
If you decide to use ImagePlus as your internal image format you can also use all plugins
and macros from the ImageJ distribution as well as all other ImageJ plugins.
File I/O.
You can use the ImageJ file input/output plugins for reading and writing files in a variety of
formats.
Of course there are some other useful Java based imaging toolkits and libraries besides
ImageJ. The ImageJ links page at http://rsb.info.nih.gov/ij/links.html lists some of them.
As display format you often have only the choice between JPEG, GIF or PNG in web
applications. The output will not be written to a file but to the response stream of the
servlet/JSP. You can use ImageJ’s file encoders for this purpose or use e. g. Sun’s JPEG
encoder. The following servlet sample code illustrates how to load a file (in any format that
can be read by ImageJ) and send it as a JPEG stream to the user’s browser. The name of
the image will be specified as parameter image of a GET request. A call of the servlet could
look like
http://www.myserver.com/servlet/ShowImage?image=/images/picture.tif
We assume in this example that the image loaded is a RGB color image. Here is the
complete code (requires Java 2):
First we import the servlet packages, the AWT image subpackage, the required ImageJ
packages and the Sun JPEG encoder:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.awt.image.*;
import ij.*;
import ij.io.*;
import ij.process.*;
import com.sun.image.codec.jpeg.*;
We implement the method for handling a GET request, which gets the HTTP request
and response as parameters. First we read the parameter containing the image URL from the
request and open the ImageJ using ImageJ’s Opener. As we assumed to open a color image,
we can now get its ColorProcessor, create a new BufferedImage and store the image’s pixel
array in it.
String inputURL=request.getParameter("image");
Opener opener = new Opener();
ImagePlus image = opener.openURL(inputURL);
As we want to return a JPEG image, we set the appropriate MIME type for the HTTP
response. We get the response’s binary output stream and open a JPEG encoder on it. To get
best quality, we disable subsampling and set the JPEG quality parameters to the maximum.
Finally we encode the image with the specified parameters and clean up by flushing and
closing the output stream.
response.setContentType("image/jpeg");
8 Troubleshooting
8.1 ImageJ runs out of memory.
This can be solved by making more memory available to the Java Runtime Environment.
As virtual memory is significantly slower than real RAM, you should try to assign not more
than 2/3 of your real RAM to the Java virtual machine.
If you are using Mac OS X or a Windows version installed with the installer, you can
set the maximum memory using the “Edit/Options/Memory” menu command. The changes
will take effect after you restart ImageJ.
Otherwise change the -mx option passed to the Java virtual machine, e.g. -xm256m to set
the memory to 256MB. The operating system specific instructions for setting the memory
size can be found at http://rsb.info.nih.gov/ij/install.
• The plugin may not be in the plugin directory or one of its subdirectories.
• If you did not compile the plugin inside ImageJ, make sure that the compilation was
successful and a class file has been created.
8.3 When you call the “Plugins/Compile and Run ...” menu, you get the
message: “This JVM appears not to include the javac compiler. [...]”
If you are using Mac OS, you need the MRJ SDK in addition to the MRJ (Macintosh Runtime
for Java).
If you experience this problem when using the Windows or Linux distribution including a
Java compiler, make sure
• that the tools library (tools11.jar if you are using JRE/JDK 1.1, tools.jar if you
are using Java 2 (JRE/JDK 1.2 or higher)) is in the classpath, and
• that you are using the right Java environment if you have more than one installed.
Specify the path to the Java Virtual Machine you want to use explicitly.
images.location=http://www.mymirror.com/ij/images/
plug-in08="Plugin",ij.plugin.Plugin_
10 Further Resources
10.1 API Documentation, Source Code
The ImageJ API documentation is available online at
http://rsb.info.nih.gov/ij/developer/api/.
The browsable source code is available at http://rsb.info.nih.gov/ij/developer/source.
API documentation and source code are available for download at
http://rsb.info.nih.gov/ij/download.html.
• JavaWorld: http://www.javaworld.com
• DocJava: http://www.DocJava.com
• java.net: http://www.java.net
10.4.2 Books
Java in a Nutshell
by David Flanagan
1252 pages, 5th edition (March 2005)
O’Reilly & Associates
ISBN: 0-596-00773-6
Learning Java
by Patrick Niemeyer and Jonathan Knudsen
724 pages, 1st edition (May 2000)
O’Reilly & Associates
ISBN: 1-56592-718-4