Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make original ImageJ commands work as SciJava modules #134

Open
hinerm opened this issue Aug 24, 2021 · 7 comments
Open

Make original ImageJ commands work as SciJava modules #134

hinerm opened this issue Aug 24, 2021 · 7 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@hinerm
Copy link
Member

hinerm commented Aug 24, 2021

[@ctrueden Edit] If we create a script wrapper for each original ImageJ command, they will be easier to use in SciJava-friendly contexts, such as napari-imagej's search bar, because the types of inputs and outputs will be properly declared. Once the script wrappers exist, we could also customize each command as needed, such as checking if headless and failing fast for commands that don't support it. The write-up below describes one possible path to automating the generation of these scripts, so that we can get an initial version of them all in existence as quickly as possible with a minimum of human error.


Goal: create a RecorderPlus object in ImageJA that operates in parallel to the IJ1 Recorder. This class would be a static singleton. This work can live on a branch in IJA as it's not meant for distribution, just a simple workflow to generate scripts.

This object should have a number of fields based on the strings that we are harvesting (e.g. a list of Strings corresponding to GenericDialog#getNextString()).

We will need to modify GenericDialog to populate our RecorderPlus object since not all information is being passed to the IJ1 Recorder.

Points of modification:

Each of these methods should be updated to populate a field of RecorderPlus with the information that would be sent to the Recorder.

Then in Recorder.saveCommand we would call into RecorderPlus to write a *.py script based on its current state (and also noting the ImagePlus parameter if present). Then we will create a new repository to house these scripts (or add it to imagej-legacy, or something..)

Finally, I think tapping into Recorder.resetCommandOptions to also clear RecorderPlus would be sufficient.

Code skeleton:

public class RecorderPlus {
	
	public static final RecorderPlus recorder = new RecorderPlus();

	//TODO add some fields, with setters, based on GenericDialog.getNextXXXXX
	
	//TODO add a reset method that clears the current fields
	
	//TODO add a "writeScript" method that outputs a script based on RecorderPlus current state
}
@ctrueden
Copy link
Member

ctrueden commented Aug 25, 2021

Before working on this automation, I suggest wrapping a couple of commands manually, to make sure that the result delivers on our requirements. (What are our requirements? We should list them.)

@elevans
Copy link
Member

elevans commented Aug 30, 2021

@ctrueden and I worked on this more earlier today and made some good progress on this. Instead of hacking getNextString, getNextNumber and the rest of the getNext methods we edited:

In each of these methods we generate the "script line" that we want as the command creates the GUI and passes all the options. For example in addChoice we added two lines to extract this data:

java.util.List<String> choices = Arrays.asList(items).stream().map(item -> "\"" + item + "\"").collect(Collectors.toList()); // convert item array to list
String label2 = label;
if (label2.indexOf('_')!=-1)
    label2 = label2.replace('_', ' ');
scriptLines.add(String.format("#@ String (label=%s, choices={%s}, value=%s) %s", label2, String.join(", ", choices), defaultItem, labelToName(label))); // create script string
...

Now when I run the Analyze Particles command the console outputs all the info we want (without even running the recorder):

#@ String (label=Size (pixel^2):, value=0-Infinity) size
#@ String (label=Circularity:, value=0.00-1.00) circularity
#@ String (label=Show:, choices={"Nothing", "Overlay", "Overlay Masks", "Outlines", "Bare Outlines", "Ellipses", "Masks", "Count Masks"}, value=Nothing) show
#@ Boolean (label=Display results, value=true) display
#@ Boolean (label=Exclude on edges, value=true) exclude
#@ Boolean (label=Clear results, value=true) clear
#@ Boolean (label=Include holes, value=true) include
#@ Boolean (label=Summarize, value=false) summarize
#@ Boolean (label=Overlay, value=false) overlay
#@ Boolean (label=Add to Manager, value=true) add
#@ Boolean (label=Composite ROIs, value=false) composite

From here we just need to grab scriptLines and save it a file. So far it works great (printing to console)! I'm still working on addRadioButtonGroup and addSlider and should be done soon. I created a new branch "scriptlines" with the changes: https://github.com/imagej/ImageJA/tree/scriptlines

@hinerm
Copy link
Member Author

hinerm commented Sep 1, 2021

Notes from talk with @ctrueden:

  • The script argline can be generated at the same time as the parameters
  • For boolean parameters use a ternary operator since the string values should be omitted when the value is false
  • Output language should be JavaScript. Note that JS uses backticks for interpolation, which is a nice way to reference the variable names
  • Need to grab the command name.. is there a place to do this in GD or does it have to come when the plugin is actually executed?
  • Name the output script file for the command, with each whitespace character replaced by an underscore
  • Folder structure under needs to match the menu structure of each command
  • Everything will be committed to imagej-legacy in src/main/resources/scripts
  • These script wrappers will collide with the original ImageJ menu items—we will probably need to tune the ImageJ Legacy menu augmentation logic not to overwrite existing built-in ImageJ 1.x commands with SciJava ones
  • Once these script wrappers are complete, we should consider removing the logic to create LegacyCommand objects based on IJ1 commands. There is a related question though about whether to worry about non-core IJ1 plugins, e.g. Fiji plugins

@ctrueden
Copy link
Member

ctrueden commented Sep 1, 2021

One other note about the menu structure for scripts, which I forgot to mention: scripts are indeed placed in the menu structure at a position matching their folder structure. So e.g. src/main/resources/scripts/Plugins/My_Awesome_Stuff/Best_Plugin_Ever.js will appear in the menus at Plugins › My Awesome Stuff › Best Plugin Ever. But with @imagejan I was also working on a new script directive #@script which would allow to declare the same script-wide pieces of metadata that you can do with @Plugin(...) in Java. So then it would become possible to write:

#@script(menuPath="Plugins>My Awesome Stuff>Best Plugin Ever")

at the top of a script and the declaration there would override the menu path.

The relevant issues are scijava/scijava-common#294 and scijava/scijava-common#344. It is past time we finish this work, and I had discussed having a pair programming session some time in September with him to do so anyway. If this work gets finished in time, then you could group all the ImageJ 1.x script wrappers in the same folder e.g. src/main/resources/scripts/legacy in imagej-legacy. On the other hand, maybe it is nice to divide the scripts into folders by their ImageJ 1.x menu structure anyway? It would be less overwhelming. What do you think?

@ctrueden ctrueden added this to the unscheduled milestone Nov 5, 2021
@ctrueden ctrueden added the enhancement New feature or request label Jun 23, 2023
@ctrueden
Copy link
Member

@gselzer Since this issue was written, you also explored wrapping the ImageJ commands as scripts, no? How far did you get? Is any work pushed anywhere? Any comments on the issue here?

@gselzer
Copy link
Contributor

gselzer commented Jun 23, 2023

@ctrueden I don't think I ever really tried, sorry.

@ctrueden
Copy link
Member

@gselzer No worries, I must have misremembered! We can circle back to this issue again in another 5 years or so 😅

@ctrueden ctrueden changed the title Create script wrappers for IJ 1.x commands Make original ImageJ commands work as SciJava modules Jun 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants