How to run Register Virtual Stack Slices as a macro without user interaction?

I’ve tried recording a macro to run the Register Virtual Stack Slices plugin http://imagej.net/Register_Virtual_Stack_Slices but still have trouble setting all the inputs in a non-interactive fashion. Since I need to save the estimated transformations using the “Save transformations” option, the plugin always pops up a dialog asking which folder to use for saving the transformations. Also, a dialog asking for the reference image comes up when I run the recorded macro. It seems that interaction with these two dialogs does not get recorded into the macro in any way and so far I have found no way of specifying the transformations folder and the reference image without interacting with the GUI. The input image folder, the output folder for the aligned images and the settings used for the algorithm seem to get recorded into the macro correctly and I don’t have to interact with the corresponding menus when calling the macro. Is it even possible to run the plugin completely without user interaction via a macro?

I might add that my actual goal is to be able to call the plugin from within MATLAB using the ImageJ-Matlab interface http://imagej.net/MATLAB_Scripting. The reason for this is that I’d like to perform some analysis steps in MATLAB, run the plugin with certain parameters, run some other steps in MATLAB and then call the plugin again with different parameters (all without any interaction). The MATLAB interface itself seems to be working fine and I’m able to call the recorded macro from within MATLAB using the command:
MIJ.run('Register Virtual Stack Slices', macroParameters);
where macroParameters is a string containing the parameters which got correctly recorded into the macro, such as the one specifying the input folder as "source=D:\somefolder".

Based on the scripting example at the end of the page in http://imagej.net/Register_Virtual_Stack_Slices, it is possible to set the transforms folder and reference image without using the GUI via a jython script but I would prefer to use the MATLAB interface. If I’ve understood correctly, the MATLAB interface is only able to call the plugin via a macro and calling the Java methods directly like in the Jython example is not possible. Please correct me if I’m wrong.

Cheers,
Kimmo

Yes, this is because the plugin uses its own JFileChooser (see source) to ask for the directory. To be fully macro-recordable, this would have to be changed to a call to IJ.getDirectory().

But as you already mention the Jython example script: you could just modify this script to use Script Parameters, put it into your Fiji installation and call that one from Matlab.

Something like:

# @String source_dir
# @String target_dir
# @String transf_dir
# @String reference_name
# @boolean use_shrinking_constraint

from register_virtual_stack import Register_Virtual_Stack_MT

p = Register_Virtual_Stack_MT.Param()
# The "maximum image size":
p.sift.maxOctaveSize = 1024
# The "inlier ratio":
p.minInlierRatio = 0.05

Register_Virtual_Stack_MT.exec(source_dir, target_dir, transf_dir, reference_name, p, use_shrinking_constraint)

If you save this as e.g. Headless_RVSS.py in ./plugins/Scripts/MyScripts/, you can call it like:

MIJ.run("Headless RVSS", "source_dir=/some/path/ target_dir=/any/path/ transf_dir=/another/path reference_name=myimage use_shrinking_constraint=false");
4 Likes

@imagejan Thank you so much, your suggestion worked beautifully! I guess now I should be able to dig into the plugin’s documentation to find the rest of the tunable parameters and just add as many script parameters as necessary to the python code to be able to control all the parameters from MATLAB.

By the way, I was wrong about not being able to access the Java classes directly from MATLAB. It turned out that after starting Fiji from within MATLAB using the ImageJ-MATLAB interface, the Java classpath of Fiji is visible to MATLAB as well and you can directly use the classes contained in the register_virtual_stack package like this:

p=register_virtual_stack.Register_Virtual_Stack_MT;
p.exec(inputpath,outputpath,transformpath,referencename,1,1,0,0);

I was able to run the plugin from MATLAB using this method as well, but it seems that in MATLAB it’s quite tricky to access nested classes, so I couldn’t find a way to instantiate an object of the Register_Virtual_Stack_MT.Param class in order to tune the parameters. Rather than trying to get around this I’ll certainly stick to the python solution. Thanks again, this saved me a lot of work!

1 Like

One tool which might interest you is KNIME and its Image Processing extension. You can chain together all sorts of analysis steps from various sources including ImageJ and MATLAB, into a single reproducible workflow.

3 Likes

@ctrueden Thanks for the tip, I’ll check that out!

By the way, I ran into a bizarre problem when trying to input the rest of the parameters for the Register Virtual Stack Slices plugin using the jython solution (as in the suggestion by imagejan above). Some of the parameter values evaluated to 0 in jython (according to output of print) or did not get through at all, leading to error messages from ImageJ complaining about the corresponding parameters being required but unset. An example:

# @String source_dir
# @String target_dir
# @String transf_dir
# @String reference_name
# @boolean use_shrinking_constraint
# @double minInlierRatio

from register_virtual_stack import Register_Virtual_Stack_MT

p = Register_Virtual_Stack_MT.Param()
# The "maximum image size":
p.sift.maxOctaveSize = 1024
# The "inlier ratio":
p.minInlierRatio = minInlierRatio

# For debugging    
print minInlierRatio

Register_Virtual_Stack_MT.exec(source_dir, target_dir, transf_dir, reference_name, p, use_shrinking_constraint)

And the corresponding call in MATLAB:

MIJ.run('Headless RVSS', 'source_dir=/some/path/ target_dir=/any/path/ transf_dir=/another/path reference_name=myimage use_shrinking_constraint=false minInlierRatio=0.05');

It doesn’t matter if minInlierRatio is of type double, int or string or whatever, the problem still persists. It seems that strings evaluate to empty and numerical inputs evaluate to 0.

After some debugging, I found out that the problem goes away if I use lowercase letters only in the names of the parameters (as in imagejan’s example code). So simply changing minInlierRatio to min_inlier_ratio fixed the problem. To confirm that this is not related to the data types at all, I changed source_dir to source_Dir and again got an error message even though in lowercase this parameter worked fine. This seems really enigmatic to me and I’m wondering if this is some weird feature of jython or maybe a bug in the ImageJ-MATLAB interface, leading to loss of case-information when calling the run method. Anyway, using lowercase names for the parameters is fine for me but I just thought I’d let others know about this issue.

Kimmo

I forgot to say that you should always use the Macro recorder to get the correct code for your macro call.
The following script, e.g. Test_Recording.py:

# @String myCamelCaseVariable

print myCamelCaseVariable

will record as:

run("Test Recording", "mycamelcasevariable=[some text]");

so all macro option parameters are always lower case by convention of the ImageJ 1.x macro language.

2 Likes

@imagejan Ok, that’s certainly good to know. Thanks again for your help!

Yet another problem came up… I think this is still related so I won’t start a new thread just yet.

I was able to run the plugin via the Matlab-Jython interface using a rigid registration model. I was also successfully able to run the Transform Virtual Stack Slices plugin using the saved transformations and apply the same transformations for another stack of images. As input, I used a series of 260 images, where each image is 465 x 700 pixels (RGB, 8 bits per channel) tif image.

However, the rigid registration was just a starting point and I’d like to use the elastic registration model which is based on the bUnwarpJ algorithm. I tested the plugin (again via the Matlab-Jython interface) in the elastic registration mode with otherwise pretty much default settings. After the final image had been registered, I got a java.lang.NegativeArraySizeException and “Image failed: null” in the log window. Looking at the source code https://github.com/fiji/register_virtual_stack_slices/blob/master/src/main/java/register_virtual_stack/Register_Virtual_Stack_MT.java and based on the timing of the crash, I believe the error was encountered at the step where the plugin resizes all the images to place them on an enlarged canvas with each image having the same dimensions and then forms a virtual stack.

I then tried running the plugin via the ImageJ GUI (that is, without the Matlab-Jython interface) using the same input images and same parameters. This time the run was completed without the exception or error message. The dimensions of the output images are 6102 x 7760 and the actual tissue area only occupies a small part of the entire canvas in each image. It is thus pretty clear that my parameters are crappy and there is a lot of “section drift” as the registration errors accumulate from section to section. I’ve understood that the NegativeArraySizeException is usually a result of images exceeding 2 gigapixels http://imagej.net/Troubleshooting#NegativeArraySizeException so first I thought that the issue was simply caused by this accumulation of registration errors, leading to a hugely expanded canvas. However, I guess 6102 x 7760 should still be very much on the safe side and so far I have no idea why the exception only comes up when I’m calling the Jython code from Matlab, and not when I’m running the plugin via the ImageJ GUI.

@imagejan @iarganda Any thoughts?

Kimmo

Oh well…now that I’m taking a closer look and running the pipeline again from Matlab, it actually seems that the registered images prior to the virtual stack building/canvas enlarging step do not even look identical when running the thing from Matlab vs. ImageJ GUI. I guess this is either due to the stochastic nature of the RANSAC feature-matching step leading to different results each time I run the plugin or due to my Matlab/Jython interface still messing up some parameter values when calling the plugin. So I guess in principle it might be possible that the accumulation of registration errors from section to section, leading to enlarging of the common post-registration canvas beyond 2 gigapixels, could still be the reason for the previous NegativeArraySize exception.

I’ll triple-check my parameter values but if anyone has any comments on the possibility of error accumulation being the cause for the exception or on the deterministic/non-deterministic nature of the algorithm, I’d really appreciate them!

Kimmo

As an answer to my own question, I’m now pretty sure the NegativeArraySize exception was indeed due to the final image size growing beyond the 2 gigapixel limit. After playing around with some different parameter values for the plugin, I was able to obtain a better registration result with less “drift” and smaller output images and avoided any errors. Thanks again for the help everyone. :slight_smile:

Kimmo

2 Likes

I have modified version of 3.0.3 that delete the user interface.
You can call it from Matlab,
Please see