Introduction
ImageJ2 and Fiji utilize the SciJava scripting framework, which supports scripts in many languages. The mechanics — #@ parameters, script directives, services, the Script Editor — are language-agnostic; only the syntax of the host language changes. This article introduces those mechanics.
Most examples on this page are written in Groovy. They are straightforward to adapt to most other SciJava-supported languages. SciJava scripting is not part of the original ImageJ; for ImageJ 1.x macros see the macro language page and original ImageJ developer documentation.
This page is about writing scripts. For running them from the command line, see Scripting Headless.
Importing classes, services and functions
A SciJava script can access any class on the application classpath: the ImageJ and ImageJ2 APIs, SciJava services, and anything else bundled with Fiji or installed via update sites. Regular language import statements work as usual.
Services (long-lived helper objects provided by SciJava and ImageJ2) are injected into a script using the #@ notation — the same notation used for user input. For instance, PrefService is responsible for storing previously entered values in memory.
Declaring the script language
A script file is normally identified by its extension (.groovy, .py, .bsh, …). Two SciJava directives let a script declare its language explicitly, overriding (or replacing) the extension hint.
The language shebang
A #! line at the top of the script names the language directly:
The shebang takes only a language name (or extension). It must appear as the very first line.
The script directive
The more general #@script directive lets a script declare additional module metadata, including its language. The syntax is #@script(key1=value1, key2=value2, …). Supported keys include:
| name | Internal name of the script. |
| label | Human-readable label (used in menus). |
| description | Longer description (tool-tip text). |
| language | Script language by name or extension (e.g. "Python", "groovy"). |
| menuPath | Where the script appears in the menu structure; use > as separator. |
| menuRoot | Identifier of the menu the script belongs to. |
| iconPath | Path to an icon shown alongside the menu entry. |
| priority | Module priority: first, extremely-high, very-high, high, normal, low, very-low, extremely-low, last. |
| headless | Hint that the script is safe to run headlessly. Set only if the script makes no explicit AWT/Swing calls. |
| (other) | Any other key/value pair is stored as a module property. |
Example:
Operating on images
First we want to learn different ways to select an image and perform an action on it. In the original ImageJ, the image is represented by an ImagePlus object. The recommended way to select an ImagePlus object is to use Script Parameters:
Script Parameters are placed at the beginning of the script file. If only one ImagePlus is used, the front most image is selected. A second Script Parameter is used to get the radius of the gaussion filter. By using print(imp) we verify, that an ImagePlus object is assigned to the variable.
To perform an operation on the selected image, we use IJ.run(). Therefore we have to import the IJ class. There are three different versions of the run() method of these we need the one with three parameters. The first parameter is the image to perform the action on, the second parameters defines the action (called command) and the last parameter is used to configure the action (here we set the filter radius). The easiest way to find a command is to use the Recorder.
The second approach is similar to how to perform this operation using the macro language:
The first step is to select the front most image by using IJ’s method getImage(). The second step is to use the method getNumber() to show up a dialog to enter the filter radius. Running the filter is the same as in the previous example.
Finally we want to use the WindowManager to select the front most image:
This is nearly identical to the use of IJ.getImage() and therefore not recommended. The WindowManager class contains some useful methods that can be used to select more than one image (e.g. getImageTitles() and getIDList().
Opening images
In ImageJ and ImageJ2, there are several different ways to open images (or more general datasets). We want to introduce some of them.
The first example uses the DatasetIOService. It is part of SCIFIO, a flexible framework for SCientific Image Format Input and Output. Two types of image files are opened. The first one is an example image, downloaded from the Internet. The second image can be chosen by the user. Both datasets are displayed using the UIService that is part of the SciJava project.
If a script only depends on ImageJ 1.x functionality, one can use the function IJ.openImage(). It will return an ImagePlus object.
IJ.openImage() is based on the class ij.io.Opener. You can use it directly to open images and other files (e.g. text files). The example uses the class ij.io.OpenDialog to select a file. This is an alternative to the usage of the Scripting Parameter File.
ImagePlus, ImageStack and ImageProcessor Conversion
When working with the ImageJ API you will run into the problem that you have e.g. an ImageProcessor, but what you need right now is an ImagePlus.
To convert one to another use these commands:
The following scheme depicts the relations between the different classes.
Loop over ROI in ROI Manager
This small ImageJ macro scriptlet loops over the ROI in the ROI Manager, selecting one at a time.
for (i = 0; i < roiManager("count"); i++){ roiManager("Select", i); // do some operation }In Jython and other scripting languages, you can iterate over the RoiManager directly:
Calling a script from another script
There are different ways to call a script from another script. Generally, the called script is executed in the same thread than the calling script, which means that the calling script will wait that the called script terminates before going on with the rest of the execution.
Using ImageJ 1.x commands
ImageJ offers the possibility to call a plugin, macro or script within another one.
If the plugin is already part of the Menu, the simple command run(PluginName, string Arguments) (or IJ.run for other scripting languages) as returned by the macro-recorder will work.
However when one wants to call a home-made local macro that is not part of the ImageJ menu, one uses a different command (see below).
Here the example of a mainMacro calling a subMacro.
- mainMacro IJ.log("Hello world, I'm mainMacro"); runMacro("C:/structure/temp/subMacro.ijm");
- subMacro
IJ.log("Hello world, I'm subMacro");
It is also possible to pass arguments to the subMacro, it works similar to the command line execution.
The subMacro needs to use getArgument() (or IJ.imageJ.getArgs of the ImageJ API) to recover the string of argument passed to it.
- mainMacro IJ.log("Hello world, I'm mainMacro"); runMacro("C:/structure/temp/subMacro.ijm", "Arg1,Arg2");
- subMacro Arguments = getArgument() IJ.log(Arguments);
The command runMacro works only for ijm macro. To call a script written in another scripting languages, one should use the runMacroFile(PathToScript, Arguments) (respectively IJ.runMacroFile of the ImageJ API). Still using the getArgument to pass the variables from mainScript to subScript.
This first option is however limited to ImageJ 1.x code style, meaning that one cannot use script parameters, or call any service in subScript. Luckily, ImageJ2 also have is own way to call a script within a script.
Using ImageJ2 commands
One can use the ScriptService from SciJava to run a script within a script.
Here the example of a mainScript calling a subScript both in Jython.
- mainScript.py
#@ ScriptService scriptService from ij import IJ IJ.log("Hello world, I'm mainScript"); Arguments = ["some_string", "val1", "some_int", 5] scriptService.run(r"SomePath/subScript.py", True, Arguments);
- subScript.py
#@ String (label="some_string") some_string #@ Integer (label="some_int") some_int IJ.log(some_string) IJ.log(str(some_int))
subScript must use #@ Script Parameters for the inputs, and mainScript pass the arguments to subScript as a list of field, value
Calling external programs
Similar to the macro language, one can use the exec method available via java.lang.Runtime class.
In Jython this looks like: