Headless execution of RoiManager(true) gives exception

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Headless execution of RoiManager(true) gives exception

Paul van Schayck
Dear all,

I'll continue sending in some reports regarding headless execution if
that's all right with you?

I'm trying to get the ROIs directly out of the ParticleAnalyzer
results. Consider the following script:

imp = IJ.openImage(path);
IJ.run(imp, "8-bit", "");
IJ.setThreshold(imp, 50, 150);

var table = ResultsTable()
var pa = ParticleAnalyzer(ParticleAnalyzer.ADD_TO_MANAGER,Measurements.CENTER_OF_MASS,
table, 100, Number.POSITIVE_INFINITY,0.1, 1.0)

var manager = new RoiManager(true)
pa.setRoiManager(manager)
pa.analyze()

return manager.getRoisAsArray()

This will give the following exception:
sun.org.mozilla.javascript.internal.WrappedException: Wrapped
java.awt.HeadlessException (<Unknown source>#24) in <Unknown source>at
line number 24

The true in the constructor of RoiManager should keep the window
hidden, but nevertheless throws this HeadlessException. A workaround
is to use doWand() on the center of mass results of the
ParticleAnalyzer, but that's less than optimal.

Thank you,

Paul

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Headless execution of RoiManager(true) gives exception

dscho
Hi Paul,

On Wed, 18 Jun 2014, Paul van Schayck wrote:

> I'll continue sending in some reports regarding headless execution if
> that's all right with you?

I think you should: bugs unbeknown to the developers have small chances to
be squashed.

> var manager = new RoiManager(true)
>
> This will give the following exception:
> sun.org.mozilla.javascript.internal.WrappedException: Wrapped
> java.awt.HeadlessException (<Unknown source>#24) in <Unknown source>at
> line number 24
>
> The true in the constructor of RoiManager should keep the window
> hidden, but nevertheless throws this HeadlessException.

The problem is pretty easy to explain; I will be a little verbose in my
explanation to maximize the benefit to all readers. First of all: have a
look at the superclass hierarchy at
http://jenkins.imagej.net/job/ImageJ1-javadoc/javadoc/ij/plugin/frame/RoiManager.html
and notice that the RoiManager is a subclass of java.awt.Frame, i.e. a
graphical window.

It is quite unfortunate that some of ImageJ 1.x' core classes -- such as
ImagePlus, and the RoiManager you pointed out -- intertwine function with
graphical user interface.

The design principle that would have helped this problem is known as
"separation of concerns": for different aspects of a given component there
should be different responsible classes, e.g. a class to show the user
interface, a container class for the current ROIs in the manager, a class
to record and replay the corresponding macros, etc.

That way, callers can pick exactly what concern they are interested in --
in your case, that would be working with ROIs, but not displaying the list
to the user or let her interact with it. There are many more benefits to
this design principle. But I digress already too much...

The conflation of function and GUI becomes more than just unfortunate when
you have to run in headless mode. The symptom is caused by the design of
the AWT (Advanced Windowing Toolkit) part of Java's classpath library:
when constructing a Frame, it asks the GUI about the dimensions of the
window title. This information is required to figure out the correct
dimensions, necessary for the layout of the window components.

The window title's dimensions are defined by the font metrics which are
provided by the operating system's graphical user interface.

The same graphical user interface that is *not* available in headless
mode.

Now, it is not a problem if you cannot construct a window in headless mode
because you do not want to display anything anyway, right? Constructing
the windows you never want to show would just be useless churn to begin with.

However, when you mix different concerns into the same class, there is no
choice: you have to construct the window if you want to work with
RoiManager's functions. If you change ImageJ 1.x' source code to *not* let
RoiManager extend the AWT Frame class, you break existing code (because it
is part of the promise known as public API that the RoiManager *is* an
AWT Frame). There is no way out.

Or is there?

Enter the headless mode by the ImageJ 1.x patcher *1*.

First of all: it is a *hack*. In other words, it works amazingly often,
but by (ImageJ 1.x') design, it cannot work in all cases.

What it does is break the contract (i.e. the public Application
Programmers' Interface) subtly: it forces the GenericDialog *not* to
extend any AWT class, putting empty methods in place of the methods
formerly inherited from the superclass.

Whenever a plugin assumes that the GenericDialog is an AWT Dialog, things
break rather badly. But most plugins are actually well-behaved and do
*not* conflate GUI with function. Those plugins work in headless mode.

Now, why do I talk about GenericDialog when your problem revolves around
the RoiManager?

The problem is exactly the same: the RoiManager conflates GUI with
function, and since you cannot instantiate AWT Window objects in headless
mode, you get neither GUI *nor function*.

If I was not so crazy busy with other problems right now that affect an
unfortunate number of users, I would try to find some time to implement
the same hack for the RoiManager as for the GenericDialog in headless
mode.

If you feel you have time to contribute to the ImageJ 1.x patcher, I would
be eager to assist you by giving you pointers where to look and what to
imitate. If you do not have the time, do not worry, I'll hopefully
eventually have time to address the issue.

Ciao,
Johannes

Footnote *1*: the headless mode was originally a fork of ImageJA (which in
turn was a project intended to improve ImageJ's applet capabilities, but
those changes were never accepted into ImageJ 1.x and eventually I just
abandoned those changes), then it was turned into a special mode of
Fiji, only to find its final home in the ImageJ 1.x patcher project:
https://github.com/imagej/ij1-patcher. This project's concern (aha!
separation of concerns!) is to apply all kinds of runtime-patches to
ImageJ 1.x: it inserts the extension points required by ImageJ2, provides
sensible ways to debug ImageJ 1.x plugins in Eclipse or Netbeans, offers
encapsulated ImageJ 1.x "instances" for use in cloud applications, and
yes, offers the headless patches.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html