Difference between revisions of "Scripting basics"

m (Loop over Roi in Roi Manager: Add scripting version)
m (Loop over Roi in Roi Manager: fix code formating)
 
(7 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
{{Learn | scripting}}
 
{{Learn | scripting}}
  
== Introduction ==
+
= Introduction =
  
 
ImageJ and Fiji are able to run scripts written in [https://imagej.net/Scripting#Supported_languages different languages]. Besides all the differences the approach on how to use the [http://javadoc.imagej.net/ API of ImageJ] is similar for all of them. This article will introduce the basic concepts and is valid for all scripting languages.
 
ImageJ and Fiji are able to run scripts written in [https://imagej.net/Scripting#Supported_languages different languages]. Besides all the differences the approach on how to use the [http://javadoc.imagej.net/ API of ImageJ] is similar for all of them. This article will introduce the basic concepts and is valid for all scripting languages.
  
{{Notice|The examples are written in Groovy, but they are easy to adapt for any other scripting language ImageJ supports.}}
+
{{Notice|The examples are written in Groovy, but they are easy to adapt for any other scripting language ImageJ supports. For the ImageJ1 macro language, refer to the dedicated section in Languages.}}
  
== Get an image and perform an action ==
+
= Importing classes, services and functions =
 +
Using scripting, one can access a huge number of classes and functions available in Fiji.<br>
 +
The most common ones are provided by the ImageJ and ImageJ2 API.<br>
 +
To access them, one use classical <code>import</code> statements (see below).<br>
 +
In Fiji, some functionalities are also provided by so-called Services from scijava, which can be  accessed using the <code>#@</code> notations (also used to collect some input from the user).<br>
 +
For instance you might come across the <code>PrefService</code> responsible for the storage in memory of previously entered values.
 +
 
 +
<source lang='java'>
 +
#@ PrefService pref // Importing the prefservice under the variable name pref
 +
#@ ImagePlus imp    // Assigning the currently opened image to variable imp
 +
 
 +
import ij.IJ // classical ImageJ1 import statement
 +
</source>
 +
 
 +
= Get an image and perform an action =
  
 
First we want to learn different ways to select an image and perform an action on it. In [[ImageJ1]] the image is represented by an [http://javadoc.imagej.net/ImageJ1/ij/ImagePlus.html ImagePlus] object. The recommended way to select an ImagePlus object is to use [[Script_parameters|Script Parameters]]:
 
First we want to learn different ways to select an image and perform an action on it. In [[ImageJ1]] the image is represented by an [http://javadoc.imagej.net/ImageJ1/ij/ImagePlus.html ImagePlus] object. The recommended way to select an ImagePlus object is to use [[Script_parameters|Script Parameters]]:
Line 51: Line 65:
 
This is nearly identical to the use of <code>IJ.getImage()</code> and therefore not recommended. The WindowManager class contains some useful methods that can be used to select more than one image (e.g. <code>getImageTitles()</code> and <code>getIDList()</code>.
 
This is nearly identical to the use of <code>IJ.getImage()</code> and therefore not recommended. The WindowManager class contains some useful methods that can be used to select more than one image (e.g. <code>getImageTitles()</code> and <code>getIDList()</code>.
  
== Opening images ==
+
= Opening images =
  
 
In ImageJ there are many different ways to open images (or more general datasets). We want to introduce some of them.
 
In ImageJ there are many different ways to open images (or more general datasets). We want to introduce some of them.
Line 101: Line 115:
 
</source>
 
</source>
  
== ImagePlus, ImageStack and ImageProcessor Conversion ==
+
= ImagePlus, ImageStack and ImageProcessor Conversion =
  
 
When working with the ImageJ API you will run into the problem that you have e.g. a ImageProcessor, but what you need right now is a ImagePlus.   
 
When working with the ImageJ API you will run into the problem that you have e.g. a ImageProcessor, but what you need right now is a ImagePlus.   
Line 131: Line 145:
 
[[Image:Image_Class_Hierarchy.png|600px|center]]
 
[[Image:Image_Class_Hierarchy.png|600px|center]]
  
== Loop over Roi in Roi Manager ==
+
= Loop over Roi in Roi Manager =
 
This small IJmacro scriptlet loops over the roi in the Roi Manager, selecting one at a time.
 
This small IJmacro scriptlet loops over the roi in the Roi Manager, selecting one at a time.
  
Line 143: Line 157:
 
In Jython and other scripting languages this looks like.
 
In Jython and other scripting languages this looks like.
  
<source lang='java'>
+
<source lang='python'>
 
from ij.plugin.frame import RoiManager
 
from ij.plugin.frame import RoiManager
  
 
# Get number of ROIs
 
# Get number of ROIs
RM = RoiManager.getRoiManager()
+
RM = RoiManager.getInstance()
 
n = RM.getCount()
 
n = RM.getCount()
  
Line 154: Line 168:
 
</source>
 
</source>
  
== Links ==
+
Since version 1.52v11 of ImageJ, one can directly loop over the roi in a RoiManager as followed
 +
 
 +
<source lang='python'>
 +
from ij.plugin.frame import RoiManager
 +
 
 +
# Assume a RoiManager is opened
 +
for roi in RoiManager.getInstance():
 +
print roi
 +
</source>
 +
 
 +
= Calling a script from another script =
 +
There are different ways to call a script from another script.<br>
 +
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 ImageJ1 commands ==
 +
ImageJ offers the possibility to call a plugin, macro or script within another one.<br>
 +
If the plugin is already part of the Menu, the simple command <code>run(PluginName, string Arguments)</code> (or <code>IJ.run</code> 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).<br>
 +
Here the example of a mainMacro calling a subMacro.
 +
 
 +
- mainMacro
 +
<source lang='java'>
 +
IJ.log("Hello world, I'm mainMacro");
 +
runMacro("C:/structure/temp/subMacro.ijm");
 +
</source>
 +
 
 +
- subMacro
 +
<source lang='java'>
 +
IJ.log("Hello world, I'm subMacro");
 +
</source>
 +
 
 +
It is also possible to pass arguments to the subMacro, it works similar to the command line execution.<br>
 +
The subMacro needs to use <code>getArgument()</code> (or <code>IJ.imageJ.getArgs</code> of the ImageJ API) to recover the string of argument passed to it.
 +
 
 +
- mainMacro
 +
<source lang='java'>
 +
IJ.log("Hello world, I'm mainMacro");
 +
runMacro("C:/structure/temp/subMacro.ijm", "Arg1,Arg2");
 +
</source>
 +
 
 +
- subMacro
 +
<source lang='java'>
 +
Arguments = getArgument()
 +
IJ.log(Arguments);
 +
</source>
 +
 
 +
The command <code>runMacro</code> works only for ijm macro.<br>
 +
To call a script written in another scripting languages, one should use the <code>runMacroFile(PathToScript, Arguments)</code> (respectively <code>IJ.runMacroFile</code> of the ImageJ API). Still using the <code>getArgument</code> to pass the variables from mainScript to subScript.
 +
 
 +
This 1st option is however limited to ImageJ1 code style, meaning that one cannot use script parameters, or call any service in subScript.<br>
 +
Luckily ImageJ2 also have is own way to call a script within a script.
 +
 
 +
== Using ImageJ2 command ==
 +
One can use the ScriptService from scijava to run a script within a script.<br>
 +
Here the example of a mainScript calling a subScript both in Jython.
 +
 
 +
- mainScript.py
 +
<source lang='python'>
 +
#@ 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);
 +
</source>
 +
 
 +
- subScript.py
 +
<source lang='python'>
 +
#@ String (label="some_string") some_string
 +
#@ Integer (label="some_int") some_int
 +
IJ.log(some_string)
 +
IJ.log(str(some_int))
 +
</source>
 +
 
 +
subScript must use #@ Script Parameters for the inputs, and mainScript pass the arguments to subScript as a list of <code>field, value</code>
 +
 
 +
= Calling external programs =
 +
Similar to the macro language, one can use the <code>exec</code> method available via [https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html java.lang.Runtime] class.<br>
 +
Note that the code below execute the external program and directly execute the rest of the script. It does not wait for the external process to finish (which is also possible by doing some extra command on the <code>proc</code> object).<br>
 +
In Jython this looks like:
 +
 
 +
<source lang='python'>
 +
from java.lang import Runtime
 +
 
 +
run = Runtime.getRuntime()
 +
 
 +
# Option 1: provide a single string command
 +
proc = run.exec("someCommand")
 +
 
 +
# Option 2: Provide a string array of command and argument
 +
proc = run.exec(["someExe", "Arg1", "Arg2"])
 +
 
 +
print("Done")
 +
</source>
 +
 
 +
= Links =
 
* [https://imagej.net/Developing_Plugins_for_ImageJ_1.x#ImageJ.27s_API ImageJ API examples]
 
* [https://imagej.net/Developing_Plugins_for_ImageJ_1.x#ImageJ.27s_API ImageJ API examples]
 
* [https://github.com/imagej/tutorials/tree/master/howtos/src/main/java/howto  ImageJ tutorials repository]
 
* [https://github.com/imagej/tutorials/tree/master/howtos/src/main/java/howto  ImageJ tutorials repository]

Latest revision as of 05:13, 1 April 2020

Learn
Topics
Introduction
Getting Started
User Guides
Tutorials
Tips and Tricks
Presentations
Plugins
Techniques
All Techniques
Colocalization
Deconvolution
Registration
Segmentation
Stitching
Tracking
Visualization
Scripting
Overview
User input
Basics of script writing
How to use the Javadoc
Batch processing
Script Editor
Auto Imports
Templates
Running headlessly
Comparisons
Toolbox
Multithreading in Clojure
Multithreading in JavaScript
Chess in Jython
Languages
BeanShell
Groovy
ImageJ Macro
JavaScript
Lisp (Clojure)
MATLAB
Python (Jython)
R (Renjin)
Ruby (JRuby)
Scala


Introduction

ImageJ and Fiji are able to run scripts written in different languages. Besides all the differences the approach on how to use the API of ImageJ is similar for all of them. This article will introduce the basic concepts and is valid for all scripting languages.



Importing classes, services and functions

Using scripting, one can access a huge number of classes and functions available in Fiji.
The most common ones are provided by the ImageJ and ImageJ2 API.
To access them, one use classical import statements (see below).
In Fiji, some functionalities are also provided by so-called Services from scijava, which can be accessed using the #@ notations (also used to collect some input from the user).
For instance you might come across the PrefService responsible for the storage in memory of previously entered values.

#@ PrefService pref // Importing the prefservice under the variable name pref
#@ ImagePlus imp    // Assigning the currently opened image to variable imp

import ij.IJ // classical ImageJ1 import statement

Get an image and perform an action

First we want to learn different ways to select an image and perform an action on it. In ImageJ1 the image is represented by an ImagePlus object. The recommended way to select an ImagePlus object is to use Script Parameters:

#@ ImagePlus imp
#@ Integer(label='Filter radius',description='The sigma of the gaussian filter.',value=2) sig

print(imp)

import ij.IJ

IJ.run(imp, "Gaussian Blur...", "sigma=" + sig)

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 class IJ. 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:

import ij.IJ

imp = IJ.getImage()
sig = IJ.getNumber('Filter radius:', 2)
IJ.run(imp, "Gaussian Blur...", "sigma=" + sig)

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:

import ij.IJ
import ij.WindowManager

imp = WindowManager.getCurrentImage()
sig = IJ.getNumber('Filter radius:', 2)
IJ.run(imp, "Gaussian Blur...", "sigma=" + sig)

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 there are many 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.

#@ DatasetIOService ds
#@ UIService ui
#@ String(label='Image URL', value='http://wsr.imagej.net/images/clown.jpg') fileUrl
#@ File(label='local image') file

// Load a sample file from the internet and a local file of your choice.
dataset1 = ds.open(fileUrl)
dataset2 = ds.open(file.getAbsolutePath())
// Display the datasets.
ui.show(dataset1)
ui.show(dataset2)

If a script only depends on ImageJ1 functionality, one can use the function IJ.openImage(). It will return an ImagePlus object.

#@ String(label='Image URL', value='http://wsr.imagej.net/images/clown.jpg') fileUrl
#@ File(label='local image') file

import ij.IJ

// Load a sample file from the internet and a local file of your choice.
imagePlus1 = IJ.openImage(fileUrl)
imagePlus2 = IJ.openImage(file.getAbsolutePath())
// Display the datasets.
imagePlus1.show()
imagePlus2.show()

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.

import ij.io.Opener
import ij.io.OpenDialog

// Use the OpenDialog to select a file.
filePath = new OpenDialog('Select an image file').getPath()
// Open the selected file.
imagePlus = new Opener().openImage(filePath)
// Display the ImagePlus.
imagePlus.show()

ImagePlus, ImageStack and ImageProcessor Conversion

When working with the ImageJ API you will run into the problem that you have e.g. a ImageProcessor, but what you need right now is a ImagePlus.

To convert one to another use these commands:


// ImagePlus to ImageProcessor:
ip = imp.getProcessor()

// ImageProcessor to ImagePlus:
imp = new ImagePlus('title', ip)

// ImagePlus to ImageStack:
stack = imp.getImageStack()

// ImageStack to ImagePlus:
imp = ImagePlus('title', stack)

// ImageStack to ImageProcessor:
ip = stack.getProcessor(nframe)

// ImageProcessor to ImageStack:
stack.addSlice(ip)

The following scheme depicts the relations between the different classes.

Image Class Hierarchy.png

Loop over Roi in Roi Manager

This small IJmacro 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 this looks like.

from ij.plugin.frame import RoiManager

# Get number of ROIs
RM = RoiManager.getInstance()
n = RM.getCount()

for i in range(n):
   roi = RM.getRoi(i)

Since version 1.52v11 of ImageJ, one can directly loop over the roi in a RoiManager as followed

from ij.plugin.frame import RoiManager

# Assume a RoiManager is opened
for roi in RoiManager.getInstance():
	print roi

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 ImageJ1 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 1st option is however limited to ImageJ1 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 command

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.
Note that the code below execute the external program and directly execute the rest of the script. It does not wait for the external process to finish (which is also possible by doing some extra command on the proc object).
In Jython this looks like:

from java.lang import Runtime

run = Runtime.getRuntime()

# Option 1: provide a single string command
proc = run.exec("someCommand")

# Option 2: Provide a string array of command and argument
proc = run.exec(["someExe", "Arg1", "Arg2"]) 

print("Done")

Links