Macro-recording issue with MorpholibJ

Hi MorpholibJ fans, hi @dlegland ,

I was just macro-recording a workflow using MorphoLibJ and faced some error messages, when executing the macro. My use case is: I would like to segment the arabidopsis-embryo example image using the “Morphological Segmentation” plugin, afterwards “Remove Border Labels” and finally “Analyse Regions 3D”. This is what the recorder records:

open(".../arabidopsis-embryo.tif");
run("Morphological Segmentation");
selectWindow("Morphological Segmentation");
//setTool("multipoint");
call("inra.ijpb.plugins.MorphologicalSegmentation.segment", "tolerance=10.0", "calculateDams=true", "connectivity=6");
call("inra.ijpb.plugins.MorphologicalSegmentation.setDisplayFormat", "Catchment basins");
selectWindow("arabidopsis-embryo-catchment-basins.tif");
call("inra.ijpb.plugins.MorphologicalSegmentation.createResultImage");
run("Remove Border Labels", "left right top bottom front back");
run("Analyze Regions 3D", "volume surface_area mean_breadth sphericity euler_number bounding_box centroid equivalent_ellipsoid ellipsoid_elongations max._inscribed surface_area_method=[Crofton (13 dirs.)] euler_connectivity=C26");

And these two error messages pop up:

(Fiji Is Just) ImageJ 2.1.0/1.53c; Java 1.8.0_172 [64-bit]; Windows 10 10.0; 188MB of 11993MB (1%)
 
java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at ij.macro.Functions.call(Functions.java:4515)
	at ij.macro.Functions.getStringFunction(Functions.java:276)
	at ij.macro.Interpreter.getStringTerm(Interpreter.java:1475)
	at ij.macro.Interpreter.getString(Interpreter.java:1453)
	at ij.macro.Interpreter.doStatement(Interpreter.java:333)
	at ij.macro.Interpreter.doStatements(Interpreter.java:264)
	at ij.macro.Interpreter.run(Interpreter.java:160)
	at ij.macro.Interpreter.run(Interpreter.java:93)
	at ij.macro.Interpreter.run(Interpreter.java:104)
	at ij.plugin.Macro_Runner.runMacro(Macro_Runner.java:161)
	at ij.IJ.runMacro(IJ.java:153)
	at ij.IJ.runMacro(IJ.java:142)
	at net.imagej.legacy.IJ1Helper$3.call(IJ1Helper.java:1148)
	at net.imagej.legacy.IJ1Helper$3.call(IJ1Helper.java:1144)
	at net.imagej.legacy.IJ1Helper.runMacroFriendly(IJ1Helper.java:1095)
	at net.imagej.legacy.IJ1Helper.runMacro(IJ1Helper.java:1144)
	at net.imagej.legacy.plugin.IJ1MacroEngine.eval(IJ1MacroEngine.java:145)
	at org.scijava.script.ScriptModule.run(ScriptModule.java:157)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:165)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:124)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:63)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:225)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
	at inra.ijpb.plugins.MorphologicalSegmentation$CustomWindow.setResultDisplayOption(MorphologicalSegmentation.java:1501)
	at inra.ijpb.plugins.MorphologicalSegmentation.setDisplayFormat(MorphologicalSegmentation.java:1898)
	... 30 more

I managed to fix on of the errors by building in a wait() command. Furthermore, I switched two lines: I call createResultImage before selectWindow(result).

open(".../arabidopsis-embryo.tif");
run("Morphological Segmentation");
selectWindow("Morphological Segmentation");
wait(500);
call("inra.ijpb.plugins.MorphologicalSegmentation.segment", "tolerance=10.0", "calculateDams=true", "connectivity=6");
call("inra.ijpb.plugins.MorphologicalSegmentation.setDisplayFormat", "Catchment basins");
call("inra.ijpb.plugins.MorphologicalSegmentation.createResultImage");
selectWindow("arabidopsis-embryo-catchment-basins.tif");
run("Remove Border Labels", "left right top bottom front back");
run("Analyze Regions 3D", "volume surface_area mean_breadth sphericity euler_number bounding_box centroid equivalent_ellipsoid ellipsoid_elongations max._inscribed surface_area_method=[Crofton (13 dirs.)] euler_connectivity=C26");

The result image “arabidopsis-embryo-catchment-basins.tif” still doesn’t show up. Can you give me a hint @dlegland ?

Thanks!

Cheers,
Robert

Ok, I managed it by adding more wait() commands:

// load data
open(".../arabidopsis-embryo.tif");

// start MorpholibJ plugin
run("Morphological Segmentation");
wait(1000);
// execute segmentation
call("inra.ijpb.plugins.MorphologicalSegmentation.segment", "tolerance=10.0", "calculateDams=true", "connectivity=6");
wait(1000);
// set output format
call("inra.ijpb.plugins.MorphologicalSegmentation.setDisplayFormat", "Catchment basins");
wait(1000);
// output label image
call("inra.ijpb.plugins.MorphologicalSegmentation.createResultImage");
selectWindow("arabidopsis-embryo-catchment-basins.tif");

// remove objects on image edge
run("Remove Border Labels", "left right top bottom front back");

// analyse
run("Analyze Regions 3D", "volume surface_area mean_breadth sphericity euler_number bounding_box centroid equivalent_ellipsoid ellipsoid_elongations max._inscribed surface_area_method=[Crofton (13 dirs.)] euler_connectivity=C26");

// save table to disc
saveAs("Results", ".../arabidopsis-embryo-catchment-basins-killBorders-morpho.csv");

However, if there is a better way for approaching this, I would be happy to learn :slight_smile:

3 Likes

I guess it’s the same story as for the other plugins (co-)authored by @iarganda (e.g. Trainable Weka Segmentation [TWS]): the custom GUI makes these plugins interactive and user friendly, but at the same time they’re a nightmare to call by macro (from a programmer’s perspective), forcing you to add wait() statements to wait for GUI processes to finish…

On the other hand, both TWS and MorphoLibJ provide an excellent Java API, and their use via scripting (in Beanshell) is excellently documented:


For the best IJ1 macro experience, I would actually suggest to save a script similar to the example script into e.g.

./Fiji.app/scripts/Plugins/Segmentation/MorphoLibJ_Segmentation_(macro_recordable).bsh

… and then run that script with the macro recorder active, which should a single line such as:

run("MorphoLibJ Segmentation (macro recordable)", "radius=2 tolerance=3 strconn=6, dams=true");

What do you think?

2 Likes

Great idea, thanks! However, not so helpful for showing MorpholibJ in a Macro-course :slightly_smiling_face:

Anyway, I guess the lesson that wait() commands can solve problems of that kind is part of the learning process.

I’m also wondering if there might be a general solution. I have the suspicion that these issues could be fixed within the call() command…

2 Likes

I think I am having a somewhat similar issue but with Plot.create.

This macro will create a plot called “Plot”:

yValues = newArray(0, 0.7, 2.3, 2.8, 1, 0.5);
Plot.create("Plot", "X", "Y", yValues);

But this macro sadly doesn’t (even with a wait command):

yValues = newArray(0, 0.7, 2.3, 2.8, 1, 0.5);
Plot.create("Plot", "X", "Y", yValues);

wait(2000);
selectWindow("Plot");

image

So I am not sure how one would fix this?

Thanks

1 Like

Hey @LPUoO ,

have you tried Plot.show();?

2 Likes

Hey @imagejan and CC-Hi @dlegland ,

I just tried the strategy you mentioned and get different results when calling the macro-recordable example script.

open("C:/structure/data/arabidopsis-embryo.tif");
run("MorphoLibJ Segmentation (macro recordable)", "radius=1 tolerance=10 strconn=6 dams=true");
run("glasbey_on_dark");

This is the result of the script:
image

And to compare, this is my result when using the user interface:

Do you have any ideas why?

Thanks a lot!

Best,
Robert

1 Like

Hi @haesleinhuepf,

just a guess:

by specifying radius=1, you’re telling the example script to compute a Morphology.gradient on the image, i.e. you’re treating the image as an Object Image, whereas in the user interface you seem to have selected Border Image (which suppresses gradient computation).

You could try to set radius=0 which should omit the gradient computation in the example script.

1 Like