[ImageJ-devel] Status and API of ROIs in ImageJ2 ?

Curtis Rueden ctrueden at wisc.edu
Thu Sep 24 12:04:51 CDT 2015


Hi Adrian,

> It's as if the ImageDisplay parameter was getting populated by the
> image before cropping

It seems that the ROI syncing between IJ1 and IJ2 is not happening as
expected. When your command runs, a sync is supposed to happen during
preprocessing because you have a Dataset parameter. But maybe the sync is
incomplete for some reason. Sorry I don't have time to investigate it right
now, though.

> What are those WARNINGs printed upon plugin invokation ?

Those were debugging statements, which were erroneously set to log.warn. I
fixed it [1].

Regards,
Curtis

[1]
https://github.com/imagej/imagej-legacy/commit/2015336482fe284954d2603fede892d616d20960

On Fri, Sep 4, 2015 at 2:29 PM, Adrian Daerr <
adrian.daerr at univ-paris-diderot.fr> wrote:

> Hi Curtis,
>
> OverlayService.getSelectionBounds seems to behave stranger yet. Take the
> Foo_Bar test plugin source from my previous post, compile it and place it
> in ImageJ's plugins directory. Start ImageJ, create a new image (say
> 400x400 8bpp), draw a rectangular selection inside and invoke Foo_Bar: as
> reported in my last mail it will report a getSelectionBounds of 399x399
> instead of the expected dimension of the rectangular selection. Now crop
> the image to the rectangular selection via Image->Crop, and invoke Foo_Bar
> again. It will report the same getSelectionBounds (width 399, height 399)
> although the active image is now strictly smaller. It's as if the
> ImageDisplay parameter was getting populated by the image before cropping
> (and of course still without rectangular selection).
>
> How is one supposed to use OverlayService.getSelectionBounds ?
> What are those WARNINGs printed upon plugin invokation ?
>
> [WARNING] ====> Roi class = ij.gui.Roi
> [WARNING] ====> RECTANGLE: Roi[Rectangle, x=76, y=92, width=209,
> height=160]
>
> cheers,
> Adrian
>
>
> On Tue, 01 Sep 2015 20:41:30 +0200
>
>  "Adrian Daerr" <adrian.daerr at univ-paris-diderot.fr> wrote:
>
>> Hi Curtis, hi all,
>>
>> If all you care about is the bounding box of the active selection, you
>>> can just do it the same way as the ImageJ2 CropImageJ command:
>>> by calling OverlayService.getSelectionBounds. Then you would
>>> avoid some of the current weirdness associated with Overlay
>>> parameters.
>>>
>>
>> This was working fine with a programmatically added rectangular
>> overlay/selection, but when I call getSelectionBounds on an image with an
>> interactively created rectangular selection it returns the whole image
>> dimension. It does not seem to be aware of the ROI. Below is a MVCE to
>> reproduce. After compiling and placing it in the plugins folder, I start
>> imagej, create a new image, draw a rectangular selection using ImageJ's
>> leftmost tool and then invoque the plugin. It logs the following to the
>> console:
>>
>> [WARNING] ====> Roi class = ij.gui.Roi
>> [WARNING] ====> RECTANGLE: Roi[Rectangle, x=100, y=163, width=196,
>> height=112]
>> [INFO] image: plugin:class net.imagej.display.DefaultImageDisplay:
>> type=interface net.imagej.display.DataView, name=Untitled,
>> objects={net.imagej.display.DefaultDatasetView at 757dbeaf,
>> net.imagej.display.DefaultOverlayView at 2198a037}
>> [INFO] region: +0.0 +0.0, 559.0 x 559.0
>>
>> I expected the region in the last line (that obtained through
>> OverlayService.getSelectionBounds) to coincide with the Roi mentionned in
>> the WARNING.
>>
>> The CropImage command you mentionned does not do anything either before
>> calling getSelectionBounds, and cropping works fine. Do you understand what
>> is going on ?
>>
>> Cheers,
>> Adrian
>>
>>
>> import net.imagej.display.ImageDisplay;
>> import net.imagej.display.OverlayService;
>>
>> import org.scijava.command.Command;
>> import org.scijava.log.LogService;
>> import org.scijava.plugin.Parameter;
>> import org.scijava.plugin.Plugin;
>> import org.scijava.util.RealRect;
>>
>> @Plugin(type = Command.class, menuPath = "Plugins>Foo_Bar")
>> public class Foo_Bar implements Command {
>>
>>     @Parameter
>>     private ImageDisplay display;
>>
>>     @Parameter
>>     private OverlayService overlayService;
>>
>>     @Parameter
>>     private LogService log;
>>
>>     @Override
>>     public void run() {
>>         RealRect r = overlayService.getSelectionBounds(display);
>>         log.info("image: "+display);
>>         log.info("region: +" + r.x + " +" +  r.y
>>                  + ", " +  r.width + " x " + r.height);
>>     }
>> }
>>
>>
>>
>>
>> On Mon, 24 Aug 2015 16:22:15 -0500
>>  Curtis Rueden <ctrueden at wisc.edu> wrote:
>>
>>> Hi Adrian,
>>>
>>> Glad to hear you found a working solution!
>>>
>>> The short answer about ROIs is that they have not been a focus of ImageJ2
>>> or ImgLib2 development in recent years. Support for labelings (highly
>>> related to ROIs) was rewritten this January [1], but a rewrite of the
>>> core
>>> ImgLib2 ROI library [2] is still pending. And there is a substantial
>>> pending redesign of the ImageJ Common data model planned as well --
>>> though
>>> it is unlikely anyone will work on it this year.
>>>
>>> At this juncture, the most effective balance for most plugin developers
>>> is
>>> probably to use parameterized commands and/or scripts, but with the
>>> ImageJ1
>>> data structures (ij.ImagePlus, etc.) -- unless you need access to a new
>>> capability that ImageJ2 + ImgLib2 make possible (>5D images, very large
>>> image planes, very large numbers of image planes, dynamically generated
>>> images, images stored in places besides disk, cell-based image caching,
>>> image types beyond uint8/uint16/float32, etc.).
>>>
>>> That said, your feedback is very much appreciated.
>>>
>>> And some issues will be ironed out in the next couple of weeks as we
>>> revamp
>>> the tutorials for the upcoming ImageJ conference.
>>>
>>> The easiest way to give a plugin a (rectangular) roi is to ... just
>>>> declare a net.imagej.overlay.RectangularOverlay as an input parameter.
>>>> It is properly populated by the origin and extent of a rectangular
>>>> selection drawn on the active image.
>>>>
>>>
>>> If all you care about is the bounding box of the active selection, you
>>> can
>>> just do it the same way as the ImageJ2 CropImageJ command: by calling
>>> OverlayService.getSelectionBounds [3]. Then you would avoid some of the
>>> current weirdness associated with Overlay parameters.
>>>
>>> If I launch the default UI, then the ROI will not show, but the plugin
>>>> can launch. If on the other hand I launch the "swing" UI as in the
>>>> tutorial, I do see the ROI
>>>>
>>>
>>> Yes, that tutorial was written when the ImageJ2 Swing UI was still the
>>> default. It is not tested/working with the Legacy UI (which is now the
>>> default). I will try to remedy that very soon.
>>>
>>> (not until I call Image>Adjust>Brightness/Contrast..., but that's a
>>>> minor detail),
>>>>
>>>
>>> Yes, that annoying bug has been around for quite a while. Many things
>>> that
>>> refresh the display will do, such as pressing + then - to zoom in/out.
>>>
>>> but now the invocation of the plugin at the end of main() will throw a
>>>> MethodCallException with the stackTrace pasted below. How can the
>>>> choice of a UI make the plugin execution fail ?
>>>>
>>> ...
>>>
>>>> Caused by: java.lang.NullPointerException
>>>>         at Goutte_pendante.initTitle(Goutte_pendante.java:94)
>>>>
>>>
>>> In 2014, we made a conscious decision to support the ImageJ 1.x classes
>>> _only_ from the legacy UI. You cannot use them from the Swing UI. In your
>>> case: the ActiveImagePlusPreprocessor cannot set the active ImagePlus
>>> because WindowManager.getCurrentImage() returns null [4], because no
>>> ImageJ
>>> 1.x user interface exists. So it stays null and then your initializer
>>> throws the NPE.
>>>
>>> Regards,
>>> Curtis
>>>
>>> [1]
>>>
>>> https://github.com/imglib/imglib2-roi/tree/imglib2-roi-0.3.2/src/main/java/net/imglib2/labeling
>>>
>>> [2] https://github.com/imglib/imglib2-roi
>>>
>>> [3]
>>>
>>> https://github.com/imagej/imagej-plugins-commands/blob/imagej-plugins-commands-0.5.1/src/main/java/net/imagej/plugins/commands/imglib/CropImage.java#L104
>>>
>>> [4]
>>>
>>> https://github.com/imagej/imagej-legacy/blob/imagej-legacy-0.17.1/src/main/java/net/imagej/legacy/plugin/ActiveImagePlusPreprocessor.java#L49-L52
>>>
>>>
>>> On Sun, Aug 23, 2015 at 6:30 AM, Adrian Daerr <
>>> adrian.daerr at univ-paris-diderot.fr> wrote:
>>>
>>> Hello,
>>>>
>>>> While I am still interested in answers concerning the status/API/roadmap
>>>> for ROIs and overlays beyond what's on http://imagej.net/ROIs, I have
>>>> solved the problem at hand which was keeping me from making progress,
>>>> so I
>>>> post the (rather obvious, once I found the net.imagej.overlay package)
>>>> solution here for the record and to close this thread.
>>>>
>>>> The easiest way to give a plugin a (rectangular) roi is to ...
>>>> just declare a net.imagej.overlay.RectangularOverlay as an input
>>>> parameter. It is properly populated by the origin and extent of a
>>>> rectangular selection drawn on the active image.
>>>>
>>>> cheers,
>>>> Adrian
>>>>
>>>>
>>>> On Wed, 19 Aug 2015 17:10:06 +0200
>>>>
>>>>  "Adrian Daerr" <adrian.daerr at univ-paris-diderot.fr> wrote:
>>>>
>>>>
>>>>> Dear ImageJ developers,
>>>>>
>>>>> I have included code from the AddROIs tutorial into the main()
>>>>> method of my plugin (for the moment essentially one of Curtis'
>>>>> commands-with-preview example), to select a Rectangle before
>>>>> calling the plugin. The source is available here:
>>>>>
>>>>> https://gitlab.com/pendant-drop/pendant-drop
>>>>> (in Goutte_pendante.java)
>>>>>
>>>>> If I launch the default UI, then the ROI will not show, but the
>>>>> plugin can launch. If on the other hand I launch the "swing" UI
>>>>> as in the tutorial, I do see the ROI (not until I call
>>>>> Image>Adjust>Brightness/Contrast..., but that's a minor detail),
>>>>> but now the invocation of the plugin at the end of main() will
>>>>> throw a MethodCallException with the stackTrace pasted below. How
>>>>> can the choice of a UI make the plugin execution fail ?
>>>>>
>>>>> Is there any other way that main can set a ROI on a loaded image
>>>>> that the plugin, which still uses an ImagePlus as input
>>>>> parameter, will see when calling imp.getProcessor().getRoi() ?
>>>>>
>>>>> TIA
>>>>> Adrian
>>>>>
>>>>>
>>>>> $> mvn package
>>>>> $> fiji --class-path target/pendant_drop-2.0.0-SNAPSHOT.jar
>>>>> Goutte_pendante.class
>>>>> [INFO] Overriding About Pendant Drop; identifier:
>>>>> command:About_Pendant_Drop; jar:
>>>>>
>>>>> file:/home/adrian/Programmes/plugins_ImageJ_src/Traitement_Gouttes/target/pendant_drop-2.0.0-SNAPSHOT.jar
>>>>> [INFO] Overriding Pendant Drop; identifier: command:Goutte_pendante;
>>>>> jar:
>>>>>
>>>>> file:/home/adrian/Programmes/plugins_ImageJ_src/Traitement_Gouttes/target/pendant_drop-2.0.0-SNAPSHOT.jar
>>>>> [INFO] Populating metadata
>>>>> [INFO] Populating metadata
>>>>> [INFO] Found 10 JHotDraw adapters.
>>>>> org.scijava.module.MethodCallException: Error executing method:
>>>>> Goutte_pendante#initTitle
>>>>>         at org.scijava.module.MethodRef.execute(MethodRef.java:73)
>>>>>         at
>>>>>
>>>>> org.scijava.module.AbstractModuleItem.initialize(AbstractModuleItem.java:199)
>>>>>         at
>>>>> org.scijava.module.AbstractModule.initialize(AbstractModule.java:86)
>>>>>         at
>>>>> org.scijava.command.CommandModule.initialize(CommandModule.java:147)
>>>>>         at
>>>>>
>>>>> org.scijava.module.process.InitPreprocessor.process(InitPreprocessor.java:60)
>>>>>         at
>>>>> org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:104)
>>>>>         at org.scijava.module.ModuleRunner.run(ModuleRunner.java:156)
>>>>>         at org.scijava.module.ModuleRunner.call(ModuleRunner.java:126)
>>>>>         at org.scijava.module.ModuleRunner.call(ModuleRunner.java:65)
>>>>>         at
>>>>>
>>>>> org.scijava.thread.DefaultThreadService$2.call(DefaultThreadService.java:191)
>>>>>         at
>>>>> java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
>>>>>         at java.util.concurrent.FutureTask.run(FutureTask.java:138)
>>>>>         at
>>>>>
>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
>>>>>         at
>>>>>
>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
>>>>>         at java.lang.Thread.run(Thread.java:662)
>>>>> Caused by: java.lang.reflect.InvocationTargetException
>>>>>         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>>>         at
>>>>>
>>>>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>>>>>         at
>>>>>
>>>>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>>>>         at java.lang.reflect.Method.invoke(Method.java:597)
>>>>>         at org.scijava.module.MethodRef.execute(MethodRef.java:69)
>>>>>         ... 14 more
>>>>> Caused by: java.lang.NullPointerException
>>>>>         at Goutte_pendante.initTitle(Goutte_pendante.java:94)
>>>>>         ... 19 more
>>>>> [ERROR] Module threw exception
>>>>> java.lang.NullPointerException
>>>>>         at Goutte_pendante.cancel(Goutte_pendante.java:87)
>>>>>         at
>>>>> org.scijava.command.CommandModule.cancel(CommandModule.java:140)
>>>>>         at
>>>>>
>>>>> org.scijava.module.ModuleRunner.cleanupAndBroadcastCancelation(ModuleRunner.java:189)
>>>>>         at org.scijava.module.ModuleRunner.run(ModuleRunner.java:161)
>>>>>         at org.scijava.module.ModuleRunner.call(ModuleRunner.java:126)
>>>>>         at org.scijava.module.ModuleRunner.call(ModuleRunner.java:65)
>>>>>         at
>>>>>
>>>>> org.scijava.thread.DefaultThreadService$2.call(DefaultThreadService.java:191)
>>>>>         at
>>>>> java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
>>>>>         at java.util.concurrent.FutureTask.run(FutureTask.java:138)
>>>>>         at
>>>>>
>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
>>>>>         at
>>>>>
>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
>>>>>         at java.lang.Thread.run(Thread.java:662)
>>>>>
>>>>>
>>>>>
>>>>> On Sat, 15 Aug 2015 13:14:13 +0200
>>>>>  Adrian Daerr <adrian.daerr at univ-paris-diderot.fr> wrote:
>>>>>
>>>>> Hello,
>>>>>>
>>>>>> I am seizing a major rewrite of a plugin as an opportunity to switch
>>>>>> from ImageJ1 to ImageJ2, also to avoid concurrency issues[*], and now
>>>>>> lots of questions come up. Some concern the way ROIs are handled. What
>>>>>> has happened in this regard since
>>>>>>   http://imagej.net/ROIs
>>>>>> was last updated ?
>>>>>>
>>>>>> [*] cf discussion on the ImageJ list archived at
>>>>>>
>>>>>>
>>>>>> http://imagej.1557.x6.nabble.com/ExtendedPlugInFilter-GenericDialog-and-synchronization-td5013333.html
>>>>>>
>>>>>> Here are two concrete questions:
>>>>>>
>>>>>> 1) My plugin relies on a rectangular ROI being drawn on the image to
>>>>>> know which area to include in the computation. How do I draw this ROI
>>>>>> once I have loaded the image as a dataset in the main() method that is
>>>>>> used for testing purposes ?
>>>>>>
>>>>>> public static void main(final String... args) throws Exception {
>>>>>>     final String testImagePath = "testImage.jpg";
>>>>>>
>>>>>>     // Launch ImageJ as usual.
>>>>>>     final ImageJ ij = net.imagej.Main.launch(args);
>>>>>>
>>>>>>     // Open test image.
>>>>>>     final Dataset dataset = ij.dataset().open(testImagePath);
>>>>>>
>>>>>>     // display the dataset
>>>>>>     ij.ui().show(dataset);
>>>>>>
>>>>>>     // create rectangular ROI
>>>>>>     //imp.setRoi(120,60,340,420);// How to do this on a dataset ?
>>>>>>
>>>>>>     // Launch the "Foo_Bar" command.
>>>>>>     ij.command().run(Foo_Bar.class, true);
>>>>>> }
>>>>>>
>>>>>> (alternatively, how would I generate a new dataset, or I guess
>>>>>> something
>>>>>> like a "View" in ImageJ2 terminology, of the ROI sub-image of the
>>>>>> original
>>>>>> dataset ? I could then substitute the original dataset with this
>>>>>> sub-image
>>>>>> and have the plugin operate on the whole image by default)
>>>>>>
>>>>>> 2) The plugin preview generates overlays using java.awt.geom.Path2D,
>>>>>> java.awt.geom.Area and java.awt.Shape, which are then converted via
>>>>>> ij.gui.ShapeRoi() and ij.gui.Overlay(), assembled with overlay.add(),
>>>>>> and drawn using imp.setOverlay(). Is there a new IJ2-way to do this
>>>>>> (especially since the cited web page (rightly) insists on separation
>>>>>> of selection and visualisation shapes) ?
>>>>>>
>>>>>> TIA,
>>>>>> Adrian
>>>>>>
>>>>>> _______________________________________________
>>>>>> ImageJ-devel mailing list
>>>>>> ImageJ-devel at imagej.net
>>>>>> http://imagej.net/mailman/listinfo/imagej-devel
>>>>>>
>>>>>>
>>>>> --
>>>>> http://www.msc.univ-paris-diderot.fr/~daerr/
>>>>>
>>>>> _______________________________________________
>>>>> ImageJ-devel mailing list
>>>>> ImageJ-devel at imagej.net
>>>>> http://imagej.net/mailman/listinfo/imagej-devel
>>>>>
>>>>>
>>>> --
>>>> http://www.msc.univ-paris-diderot.fr/~daerr/
>>>>
>>>> _______________________________________________
>>>> ImageJ-devel mailing list
>>>> ImageJ-devel at imagej.net
>>>> http://imagej.net/mailman/listinfo/imagej-devel
>>>>
>>>>
>> --
>> http://www.msc.univ-paris-diderot.fr/~daerr/
>>
>
> --
> http://www.msc.univ-paris-diderot.fr/~daerr/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://imagej.net/pipermail/imagej-devel/attachments/20150924/8e34a019/attachment-0001.html>


More information about the ImageJ-devel mailing list