[ImageJ-devel] IJ2 Plugin Proposal

Aivar Grislis grislis at wisc.edu
Wed Nov 24 16:45:43 CST 2010


Hi Lee,

What I want to do differently is pass on the output image from a plugin 
whenever its ready.  You won't get this externally by noting that a 
member variable is annotated, the plugin has to make a call to say this 
output image is done.  In this way the plugin could produce a series of 
images one by one (rather than having to pass back an array of output 
images).

I looked at KNIME, Pipeline Pilot, and MyGrid Taverna, which were all 
mentioned in a December 2009 ImageJX discussion.  They seem overblown to 
me for what we need.  There's also licensing issues: GPL, odd 
proprietary eval/yearly lease, LPGL respectively.  Some of them involve 
authoring XML files, etc.  The annotation scheme is very lightweight.

To me the GUI drag & drop UI is mostly eye candy.  I like how 
CellProfiler sets up  workflows.  You should be able to author workflows 
by example:  you load an image, run a plugin, run another plugin, and 
that becomes a workflow.  We save the plugins used, there are inputs, 
chained output/inputs, and outputs.

Aivar



On 11/24/10 3:31 PM, Lee Kamentsky wrote:
> Hi Aivar,
> I'm sort of doing this with the @Parameter attributes now and 
> CellProfiler. I use reflection to get the class of the tagged 
> variable. The plugin's image inputs are variables of type ImagePlus 
> (and probably later, imglib's Image) that are not marked with 
> output=true and the outputs are the ones with output=true. Perhaps 
> it's a bit of a hack to infer that something is intended to be used as 
> an image by its class type, but that's what I did; the other 
> possibility would be to indicate that it is an image explicitly in 
> @Parameter.
>
> CellProfiler works beautifully with this - maybe Curtis can show you 
> how it does with ImageJ plugins.
>
> I can imagine writing your tool (or using something like Knime) with 
> the current infrastructure. You have some sort of hookup gui (and 
> Knime does this for you) that allows you to attach image inputs to 
> outputs and it's up to the tool to figure out when a plugin's inputs 
> are ready.
>
> --Lee
>
> On 11/24/2010 4:16 PM, Aivar Grislis wrote:
>> I'm proposing a more dynamic way of running plugins and sending 
>> images from one plugin to another that would lend itself to workflows 
>> and pipelines.  This could also be used within plugins and within IJ2 
>> as an architectural building block to chain chunks of image 
>> processing code together.
>>
>> Basically I propose that a plugin can have multiple named input and 
>> output images and that whenever an output image is ready it is passed 
>> on to become the input image to the next plugin in the chain.
>>
>> IMPETUS
>>
>> I feel the need for this from a couple of plugins I have worked on 
>> (actually my only plugins!).
>>
>> I worked on a Deep Zoom plugin.  This takes a huge image, tiles it, 
>> then the tiles are written out in a particular directory/file name 
>> structure.  Next we halve the original image and repeat, until the 
>> image gets halved to a miniscule size.
>>
>> While working on this plugin I thought about writing the code to 
>> halve the image and to tile it in the most general-purpose, reusable 
>> way.  Also I wanted to be memory-efficient: I didn't want to just 
>> make all the halves, then go through them and make all the tiles, 
>> then go throughout those and write out all the files.
>>
>> What I came up with at that time was a chainable plugin.  In 
>> pseudo-code:
>>
>> interface IChainablePlugin {
>>
>>   // chains one plugin to next; called from outside the plugin
>>   public chain(IChainablePlugin plugin);
>>
>>   // gets the input image; called from within plugin
>>   Image get();
>>
>>   // puts the output image; called from within plugin
>>   put(Image image);
>> }
>>
>> An abstract base class kept track of the next, chained plugin 
>> instance and handed off the output image to that next plugin, using 
>> the same thread.
>>
>> I wrote a chainable plugin class to halve the image, one to tile it, 
>> and had a third one that was just an inner class to my Deep Zoom 
>> plugin that handled the specifics of writing out the tiled image 
>> files.  Presumably the first two classes would be reusable code and 
>> the third was just specific to Deep Zoom.
>>
>> Obviously as-is this is limited to one input and one output.  I 
>> started thinking about having an image dispatcher class that would 
>> keep track of which images a plugin required and hand them off from 
>> one plugin to another.
>>
>> I'll just briefly mention the SLIM plugin I am working on.  Since the 
>> SLIM fitting process is time consuming I display a very coarse 
>> colorized version of the fitted results that is refined as the fit 
>> progresses.  So there I want to pass on my output image before the 
>> plugin finishes and I want to put out successive versions of this 
>> image.  This is similar to my wanting to process the individual tiles 
>> before the whole image is tiled.
>>
>> PROPOSAL
>>
>> We could label the input and output images using Java annotations.  
>> (Note that the current Declarative Plugin annotations allow one to 
>> label input and output image member variables but the outputs are 
>> harvested only once the plugin is finished. There is no way to put 
>> out an output image within the plugin code.)
>>
>> Here is some sample code for what I'm proposing:
>>
>> "@Input
>> @Output({ @Img(Plugin1.BLUE), @Img(Plugin1.GREEN) })
>> public class Plugin1 extends AbstractPlugin {
>>   public static final String BLUE = "Blue";
>>   public static final String GREEN = "Green";
>>
>>   void process() {
>>       Image image = get();
>>       put(BLUE, image);
>>       put(GREEN, image);
>>   }
>> }"
>>
>> Here the annotations result in an input name set of ["Default"] and 
>> an output set of ["Blue","Green"].  (If there are no parameters the 
>> default name is used.)  Of course, there could also be named input 
>> images (i.e. "get(ORANGE)") or default output images (i.e. "put()").
>>
>> Instances of plugins such as these could be chained together:
>>   plugin1.chain(Plugin1.BLUE, plugin2);  // named output goes to 
>> default input
>>   plugin1.chain(Plugin1.GREEN, plugin2, Plugin2.ORANGE); // named 
>> output goes to named input
>>   plugin2.chain(plugin3); // default output goes to default input
>>   plugin2.chain(plugin4, Plugin4.PURPLE); // default output goes to 
>> named input
>>
>> Using strings as identifiers might seem less than ideal.  However, 
>> the strings are unique to the plugin they belong to.  If they are 
>> specified as static constants, as above, that would prevent spelling 
>> mismatches.  Once a chain of plugins is established and before we run 
>> it we could make sure that all of the inputs have been chained to.  
>> We can detect if a plugin asks for an input or output that has not 
>> been annotated and warn the plugin programmer.
>>
>> Of course, once we have named input and output images we could build 
>> on that and give the IJ end-user ways to link up plugins in workflows 
>> or pipelines, a la CellProfiler.
>>
>> I have a prototype implementation of this, so the sample code above 
>> works, details upon request.
>>
>> Aivar
>>
>> (P.S. It's the Thanksgiving holiday in the U.S. so you might not hear 
>> from us until Monday.  Happy Thanksgiving!)
>>
>>
>>
>>
>>
>>
>>
>>
>> _______________________________________________
>> ImageJ-devel mailing list
>> ImageJ-devel at imagejdev.org
>> http://imagejdev.org/mailman/listinfo/imagej-devel
>
>
> _______________________________________________
> ImageJ-devel mailing list
> ImageJ-devel at imagejdev.org
> http://imagejdev.org/mailman/listinfo/imagej-devel





More information about the ImageJ-devel mailing list