3D drift correction in headless mode

Hello,

I’m trying to do 3D drift correction in Fiji/jython in headless mode.

I’m reading an image as imageplus and then would like to run the 3D drift correction with the second channel.

IJ.run(imp, "Correct 3D drift", "2")

The problem is at the beginning of the drift correction plugin:

def run():

  IJ.log("Correct_3D_Drift")
  
  imp = IJ.getImage()

Is there any way that the plugin can take an image in headless mode or is there a way to trick IJ.getImage to get an image without a window?

IJ.run method should not be called under headless mode, because it might need to get an image window, or try to update a window in the last step, which will cast error in headless mode.

To do some work in headless mode, you need to re-write your script in a way that the command goes to a more basal layer. That means you need to dip into the ij source code, and convert each command to a low-level command.

Here is an example:

if not headless
% headless mode not usable
IJ.run(ips,‘Invert’,’’);
else
% equivalemt command
ip.invert;
end

For your case, a good way is to take the run() out as your custom script and trim it for headless mode, so bypass the upper part of standard ImageJ framework, and keep the lower part, and do the same job in an invisible way pure in CPU and memory and not display any stuff on screen, including the ImageJ panel. If you can reach this step, then the headless mode can be paralleled so that you can process multiple files in large scale concurrently without showing anything on screen, and its much robust and faster.

For you example, you can start with the first line of code:
ips = ij.IJ.OpenImage(your tif stack file,…);

Then you read the run() line by line,

you can find a lot of UI dialogue, just go to a deeper layer definde in this py script, trim and re-organize all the stuff.

The best way to do this is run the code line by line in a dynamic language such as python or matlab. 90% you will succeed, but not 100%.

The key external command in this plugin is :slight_smile:

from mpicbg.imglib.image import ImagePlusAdapter
from mpicbg.imglib.algorithm.fft import PhaseCorrelation
from javax.vecmath import Point3i

def compute_stitch(imp1, imp2):
  """ Compute a Point3i that expressed the translation of imp2 relative to imp1."""
  phc = PhaseCorrelation(ImagePlusAdapter.wrap(imp1), ImagePlusAdapter.wrap(imp2), 5, True)
  phc.process()
  return Point3i(phc.getShift().getPosition())

These command only take ips object, so it determines that this plugin can be modify to a headless version. All the other parts of the code is just for user intervention or GUI window stuff, which can be removed by variables to bypass the user intervention.
This sounds just like the reverse way of writing a plugin. When writing a plugin, usually write the core , then add UI and user intervention; This is reversed: remove UI and revert to the core, which is less code and more precise.

That sounds like a sensible approach. I wasn’t sure what the philosophy of jython scripting is. If it is the most efficient way to rewrite the code for headless mode or not.

Eventually, my aim is to run these scripts on our local HPC because we have quite a lot of live cell imaging data.

Ok cool! I will give it a try. Thanks for the quick reply and for pointing out the crucial part in the code.

Is jython actually the best way to approach this? Or would I be better off going straight into java?

If you just want to do parallel work, there is no need to put it into headless mode.

Fiji usually only runs in one process, and all new trials of launching FIji will me merge to the olderst one,however, there is a way to disable it, so you can have multiple fiji running. No matter the plugin can be in headless or not, you can aloways have your macro running by Fiji from command line.So you can call Fiji many times concurrently, each process a tif file by a Macro(A). This way is much easier because you can record a macro and automatically generate a similar (from any language) macro with different image path( total 4lines,something like

-------***.ijm-------
Open(a new tif stack path)...
IJ.run...
save...
run('Quit')...
-----------------------

).The only difference for plugin headless mode compatibility is that it show up or not. If compatible, in your cmd you can add headless flag, this will be better. If not compatible, you have to let it show up, which will cause heavy load to screen because so many imageJ panel and image window pop up and you’d better no touch mouse and keyboard if multiple case has been launched. Remember better to add a line at the end of your macro to let the Fiji process quit itself, or sometimes it might stay alive doing nothing.

run(‘Quit’)

You can launch e.g. 10 task initially, and use a loop to monitor the number of imagej.exe. If less than 10, launch another one to always keep 10 task working. So you need to choose a language as your major field to launch Fiji and monitor process: Using simple scripts to call big Fiji task.

      % Wednesday, February 27, 2013
        % Running multiple instances of ImageJ
        % Multiple instances of ImageJ cannot be run, by default.
        % Try to double click on the ImageJ icon multiple times, after an instance of it is already opened, and the control will return to the already open instance.
        % To start multiple instances of ImageJ you need to
            % change a default option that allows to run a single instance listener only; you can do that under Edit -> Options -> Misc ..., where you can uncheck the box close to Run single instance listener;
            % start ImageJ by the command line with the option --allow-multiple, e.g., $ ImageJ-linux64 --allow-multiple

have a look at post:

======
Above is a simple and intuitive mode of paralleling Fiji (A).
If you just want to automate and process image in tandem way without the need to parallel, there is also a setbactchmode in Macro(B), or you can also do a simple file loop in a Macro©.

You can also split your image into 10 list, each list generate a long Macro, and launch 10 fiji process, each do one Macro, i.e., each process have its own list of images to do. This sounds better, no need to monitor process.

You can also using mode C, just split your image into 10 folders, and do a file looping in a macro. You can even compose the 10 command and hand run it ten times from windows command line (with macro argument as one of the folder path), if you like.

You can also … as you can imagine

Apart from the above ABC mode, there is another more sophisticated mode(D) to do automation and parallel Fiji work in Matlab. This need absolute headless mode, and is more tricky and low success rate. However, if succeed, there will be much more power, because all the whole above stuff can be modulized as a tiny amount of a much larger project. In that way you can have inner and coherent access to every pixel value of every imageplus object anytime (instead of just launch from command line, surrender task to windows to execute it, has nothing to get ,nothing to set, no handle/connectivity to any object at all).

@mendel I will run the code on our HPC - there is no GUI. So, I will need to use headless.

I’m a bit stuck to find the way ImageJ interprets the run method. If I say:

IJ.run("Median...", "1")

How do I find out what the actual function call is in the Java API? And how do I then convert this reference to a Jython call?

One of the reasons of Fiji’s existence is actually because it does make it possible to run IJ.run() calls and all kind of plugins runnable in headless mode (thanks to runtime patching of the ImageJ1 classes that otherwise don’t have a good separation between UI and functionality).

There is no problem with running this headless in Fiji, in particular because it uses the signature of IJ.run() that takes an ImagePlus as first argument.

The reason why you’d sometimes like to use a lower-level API call instead of the high-level IJ.run is because some plugins rely on the current active image (such as IJ.getImage() or WindowManager.getCurrentImage() ) which might not be thread-safe and therefore not suitable for parallelization.


The easiest way to find the underlying Java code call is using the search bar:

If you press the Source button, it will show you the RankFilters class implementation in the imagej1 repository.

After digging a bit through its code, you might find that you can call the RankFilters.rank method to directly filter an ImageProcessor:

As you see, it’s not entirely trivial to find… You might be fine with just leaving the command as recorded by the recorder:

IJ.run(imp, "Median...", "radius=2");

The IJ.run can work in headless in Macro (call imagej.exe from cmd line with headless flag), but if called from other programming language such as Matlab in headless mode(in worker, such as using parfor), error appears:

  Java exception occurred:
    java.awt.HeadlessException

    	at java.awt.GraphicsEnvironment.checkHeadless(Unknown Source)

    	at java.awt.MenuComponent.<init>(Unknown Source)

    	at java.awt.MenuItem.<init>(Unknown Source)

    	at java.awt.MenuItem.<init>(Unknown Source)

    	at java.awt.Menu.<init>(Unknown Source)

    	at java.awt.Menu.<init>(Unknown Source)

    	at ij.Menus.getMenu(Menus.java:831)

    	at ij.Menus.getMenu(Menus.java:821)

    	at ij.Menus.addMenuBar(Menus.java:109)

    	at ij.IJ.init(IJ.java:385)

    	at ij.IJ.run(IJ.java:372)

So at some level, run imageJ in Matlab’s parallel headless mode encounter some error. However, if I change the line:

IJ.run(ips,'Invert','');
to
ip.invert;

Then this problem was solved.

This code runs in headless mode.

*ip is imageplus object.*
*ip is imageprocessor.*
filterType = 4;
radius = 50;
aFilter = ij.plugin.filter.RankFilters;
aFilter.setup('median',ips);
aFilter.rank(ip,radius,filterType);

* now the ips is updated. you can save it:
ij.IJ.save(ips,path);

As imagejan said, you can also use IJ.run in a macro to run in headless. This image-embedded plugins (filters) are safe. Only some otherplugins need GUI and may encounter problem in headless.

The deeper level code is for headless mode in non-Macro language/interface.