Trying to get a groovy script to work


#1

I am still trying to get a meaningful oops script to run.
I finally have a groovy script which runs properly in the script editor:

#@ ImagePlus imp
#@ ImageJ ij
#@ OpService ops
#@ CommandService cmd
#@ UIService ui

//ect1 = ij.io().open("/home/ilan/Documents/ect1/ECT1.dcm")
meta = getMeta(1)
println meta

def getMeta(int slice) {
if( imp.getImage() == null) return null;
String meta = imp.getStack().getSliceLabel(slice);
// meta will be null for SPECT studies
if (meta == null ) meta = imp.getProperty("Info");
return meta
}

I can bring up my PET data, run the above in the script editor and see the dicom tags.
The next step is to activate it from inside my java code. I would like to input to the script which image I want to use, since essentially always there are multiple images open.

Looking around I found examples of activating scripts from inside java. This one also works (although it puts out 10 pages of output in the console, so I wouldn’t say it is working properly).

double runScript() {
	try {
		final Context context = new Context(ScriptService.class);
		final ScriptService scriptService = context.getService(ScriptService.class);
		final String script = "as.integer(1) + as.integer(2)";
		final ScriptModule m = scriptService.run("add.r", script, true).get();
		final Object result = m.getReturnValue();
		String res1 = result.toString();
	} catch (Exception e) { ChoosePetCt.stackTrace2Log(e);}
	return 0;
}

I can catch it with a debugger at result.toString and see it has an array list with 1 entry of value 3.
1+2=3.
I have no idea how I would guess to use “add.r”. Another example with “add.kt” with a script of “1 + 2”
completely crashes. I would guess it doesn’t know what “add.kt” means. Neither do I.

My guess is that I should use something like
final ScriptModule m = scriptService.run(“myScript.groovy”, myect, true).get();
The script has the file name of myScript.groovy. Where would I locate this file?
Inside Fiji.app->macros? Somewhere else? Can I put more than just a single input parameter?


#2

Hello Ilan -

I don’t have an answer to your question of how to call a groovy script
from java. But I suggest the obvious alternative of using java, below.

Why not simply program the retrieval of the metadata in java?

You say you wish to activate the groovy script “from inside my java
code.” So I’m imagining that you are writing some larger processing
in java and are comfortable with some java programming. (You also
post a java snippet.)

Your getMeta code looks quite straightforward. I would be inclined
to program it in-line where it’s need in your java processing. (Or you
could package it as a java free function – oops, I meant to say a java
class with a single static method – for reuse in multiple places.)

Groovy is java-based, so the translation should be trivial.

If this doesn’t make sense for your use case, could you add some more
detail on why you want to throw groovy into the mix?

Thanks, mm


#3

Thanks for your help. I am taking the simplest thing possible as a first step. In fact the code myScript.groovy is taken from my java code. I finally learned that I need to use “def” instead of “String” which I would use in java to indicate the type of returned object.
My idea is start with the simplest example and go on from there. In oops I discovered that DefaultSpherecity can’t work under pure java, and can only work under a script. For me java is 10+ times easier, but I need to check out using real scripts. Groovy is the language which was recommended to me. If it is the easiest in some sense, that is a good enough reason for me.

So I am plugging along trying to make something which actually works. First the simplest example (which needs to include input parameters, i.e which image I want and maybe some other things as well). At least groovy now seems under control, but interfacing with it, isn’t yet under my control.

You mention I need to post a java snippet. Isn’t double runScript() a java snippet? That is what I am trying to run in my java program. It doesn’t yet have any input parameters which is a serious flaw, but I was willing to take anything as step zero. I still have to figure out how I tell the script how to use one very specific image, not just a random choice from what happens to be in memory.

Thanks again,
Ilan


#4

Hello Ilan -

First, let me apologize for being unclear. When I wrote “You also
post a java snippet,” I didn’t mean that you hadn’t posted any java,
but, rather, that the double runScript() that you posted is java,
indicating to me that you have some familiarity with java.

I believe that you should be able to access and run DefaultSphericity
from java, just like (almost) everything in ImageJ. Here is a complete
IJ1-style java plugin that calls Ops Sphericity on a (vacuous) Mesh:

import ij.IJ;
import ij.plugin.PlugIn;

import net.imagej.legacy.IJ1Helper;
import net.imagej.ops.OpService;

import net.imagej.mesh.Mesh;
import net.imagej.mesh.naive.NaiveDoubleMesh;

import net.imglib2.type.numeric.real.DoubleType;

public class My_Plugin implements PlugIn {
  public void run (String arg) {
    IJ.log ("run ops sphericity from java ...");

    // some boiler plate to get Ops ...
    OpService ops = IJ1Helper.getLegacyContext().getService(OpService.class);

    Mesh m = new NaiveDoubleMesh();  // empty mesh
    DoubleType dbl = ops.geom().sphericity (m);  // "Nan" for the result
    IJ.log ("dbl = " + dbl);
  }
}

I compile this against the jars that ship with a stock Fiji install, and
copy the jar to the Fiji plugins folder. I then run it from Fiji:
Plugins > My Plugin.

For what I imagine that you’re doing, I would suggest just using
java (especially if it’s “10+ times easier”). If you’re doing your
heavy lifting in scripts (and like it), then use scripts. If you want
to run some quick, short script from the script editor (e.g., to
avoid compiling and packaging some java code), use a script.

But if you’re doing your heavy lifting in java, it would just seem
to complicate things to carve out some “subroutine” into a script,
and then jump though hoops calling into the scripting language
from java. Just do it straight in java (especially since (almost) all
of ImageJ is written in java, so no extra “translation” is needed).

Thanks, mm


#5

Thanks mm. I wanted to take your suggestions seriously by trying to implement them in my code. I have 2 environments: ImageJ in source code which I don’t update very often and Fiji in the very latest state where I attach a debugger (when needed).

Your suggestions I decided to try under Fiji, with debugger, and my code wouldn’t work. ImageJ had no problem, at least with what I already had written.
I noticed you had used NaiveDoubleMesh() whereas I was using DefaultMesh(points). DefaultMesh had a nice advantage that I could put in the vertices at the constructor.

Finally I found the problem with the Fiji was my use of DefaultMesh which wasn’t even listed in the class overview. NaiveDoubleMesh is listed but with an empty constructor. I have a list of vertices, but it isn’t clear how to set them. With DefaultMesh there is a method to set the facets as well, if I need to do so.

In short there seem to be 2 different worlds: the one I have been playing with which includes DefaultMesh and another one where what I “knew” no longer exists. To make some progress, I need an actual mesh in the new world.

Thanks,
Ilan

P.S. I see what to do. Instead of building a list, I need to add the points directly to the mesh instead of to the list.