Command line recording of ImageJ2 plugins


I am writing code such that an ImageJ2 plugin would automatically print what would be needed for it to be run from command line, e.g.

"Plugin Name" "parameter1='1',parameter2='2"

My idea is that one can then simply put

ImageJ-binary --ij2 --run

in front of it and can run the IJ2 plugin from command line.

My issue is that I did not find an elegant way to automatically generate above parameter String, because parameter1 is the name of the java variable and not a string…

Is there a good way?

Great! I think this should even go into a scijava component to make it more generally usable. There have been plans since a long time to have a language-agnostic recorder:

So when this gets implemented, it would be straight-forward to record in any script language, or in “CLI” mode as you suggest.

This would be a great topic for the next hackathon :slight_smile:

When you have a Module m, you can query its input keys and values using m.getInputs() which will give you a Map<String,Object> that would contain parameter1 as a String key in your case.

Also, the MacroRecorderPostprocessor does something similar already, making all SciJava modules macro-recordable:

1 Like

What is the best way of making an IJ2 plugin a Module?

Normally, I am defining plugins like this:

@Plugin(type = Command.class, menuPath = "Plugins>MyPlugin) public class AnalyzeObjectsCommand implements Command

But this is not enough as Command does not implement Module. The way I did it now is by extending DynamicCommand. Is that the way to do t?

@Plugin(type = Command.class, menuPath = "Plugins>MyPlugin) public class AnalyzeObjectsCommand extends DynamicCommand

The API of ModuleService, CommandService and ScriptService is rather stable, and the modular and extensible architecture of SciJava and ImageJ ensures you can build upon this even if the actual implementation of those services is still subject to change in the future.

One way you can achieve this exists already: it’s called KNIME :wink: (and in particular the knip-imagej2 integration that is hopefully going to be replaced by an improved knip-scijava integration some time in the future, see also this GitHub issue).

Every Command you write (as long as it’s annotated with headless=true) will auto-generate its node in KNIME, and you can just chain them together. (For some very simple examples illustrating this, see the fmi-ij2-plugins repository.)

There’s of course lots of room for improvement and further development, as always.

Why don’t you describe your application more specifically, either here on the forum (in a new topic), or by creating an example repository on GitHub, so we can collaboratively solve some real-world use cases?

1 Like

Do you have also ImageJ examples (without using KNIME) about chaining Modules together into a Workflow?

I guess one would someone specify that the output of one Module is the input of the next one?

Related to this I found lines of code like below in your examples:

@Parameter(type = ItemIO.OUTPUT) private Img<T> output;

Could you explain a bit what that does?

Sorry for dropping the ball on this one until now.

Output parameters are briefly explained on the script parameters documentation page. By default, parameters are considered being INPUT, but you can annotate them as OUTPUT or BOTH as well. The definition of those is in org.scijava.ItemIO:

To see an example of using the ModuleService to run a script and get its outputs, you can have a look at this example:

that I added in response to this discussion:

Also have a look at this example notebook that can be run interactively here:

Hi Jan,

The link above regarding how to use the ModuleService does not work for me as it points to an issue, rather than to code.

The link I posted was the pull request. You can see the changed files if you click the “Files changed” tab on that page.

For your convenience, here’s the direct link to the diff of

1 Like

@ctrueden @imagejan @frauzufall @haesleinhuepf

I realized something with the IJ2 Macro Command recording, namely that it removes all capitalization in the parameters, resulting in recordings such as:

run("Elastix", "elastixdirectory=/Applications/elastix_macosx64_v4.8 workingdirectory=/Users/tischer/Desktop/elastix-tmp fixedimagefile=/Users/tischer/Desktop/elastix-output/muscles.tif-transformed.tif movingimagefile=/Users/tischer/Desktop/elastix-output/muscles.tif-transformed.tif elastixparameters=Default usemask=false useinitialtransformation=false transformationtype=Translation numiterations=1 numspatialsamples=100 gaussiansmoothingsigmas=10,10,10 bsplinegridspacing=50,50,50 finalresampler=FinalLinearInterpolator outputmodality=[Save output as Tiff]");

This is fine and works as a macro, however when trying to use this as a starting point for running the command from command line, it does not work. The reason is that on the command line the parameters do need the correct capitalization, e.g. elastixdirectory should actually be elastixDirectory, otherwise one gets an error.

Would it maybe be possible to unify this?

Hey @Christian_Tischer,

thanks for letting us know.

just out of curiousity, how do you run a command from command line?



For example:

This is described on the Scripting_Headless wiki page.

Hmm, it seems there are lurking case issues here indeed.

Consider the following script:

#@ String (value="gre") hello
#@ String (value="eti") Hello
#@ String (value="ngs") HELLO
println(hello + Hello + HELLO)

In SciJava, parameter names must be unique, but are case sensitive. So the above executes successfully from the Script Editor.

But ImageJ1 downcases parameters, meaning they must be unique and are case insensitive. If you run Plugins :arrow_forward: Macros :arrow_forward: Record… and then execute the script, the following lovely dialog appears during postprocessing:

Furthermore, right now there is no checking for multiple identical script parameters—so you can write e.g. #@ String hello on two different lines and the script will execute—but this will undoubtably cause problems in some places where we assume unique parameter names.

I filed imagej/imagej#231 to track these problems.