* The command recorder:
Recording commands is a great idea. Currently, the output is one of
the these two:
- directly as macro language, which is has great utility on the user end
- as events from the ij.CommandListener, which is currently very
limited: only the command, not the arguments neither the image over
which the command has been applied.
Generalizing the command recorder could lead to automatic code
generation in any scripting language of choice, including java.
* The min and max: a call to setMinAndMax on a GRAY8 or COLOR_RGB
image has the effect of expanding the desired range to the 8-bit range
of the grey or each color channel. Not so for GRAY16 or GRAY32. The
result is that a number of successive calls to setMinAndMax with the
same min, max values has different effects on each image, depending on
type.
* The severe lack of thread safety. I have patched some of that over
the last year with the addition of Thread-local ij.Macro.getOptions()
and in Thread-local ij.WindowManager.getCurrentImage(). Yet, there are
numerous other places affected: for example, numerous ij.plugin.* java
files use static fields to store the parameters as edited from a
GenericDialog, be it from a user-driven dialog or from a macro-driven
dialog. The result is a collision: different threads calling the same
class with different macro arguments for the dialogs result in
unexpected parameters being used in computations.
This design error should not be repeated, in view of the increasingly
multi-core of CPUs.
* The lack of multidimensional data representation. The current adhoc,
limited solutions, namly hyperstacks and CompositeImage, are, I'm
sorry to say, horrendous. They fix the immediate problem, but they
introduce numerous others, particularly: inconsistency in dimension
handling, and extra complexity in core classes like ImagePlus.
To this effect, I would create a proper data structure that can handle
any number of dimensions, i.e. a so-called tensor representation.
Which leads to:
** The difficulty in managing stacks programmatically. The
ImageStack fails me every time I need to manipulate its pixels. Even
simple tasks like duplicating a stack are not trivial. The
ij.plugin.CanvasResizer has somewhat helped in at least resizing the
2D dimensions of a stack, but there is no way to resize it in 3D for
example. Proper tensor implementation ought to enable resizing in any
dimensions, and provide trivial copy mechanisms of any subpart.
** The limitations in ImageProcessor: it's only 2D, and completely
unware of the third and other dimensions. Numerous plugins, like
current TransformJ package, perform operations purely on 2D, even if
they can handle stacks.
** The lack of image source abstraction. Does it matter if an image
lives in a database, in an url, in a text file, in a series of paged
blocks (2D like mipmaps, or 3D in an octree of diminishing cube edge
length), in a remote server, or as an actual file? It should not
matter at all. The current ij.io.FileInfo manages the file and the url
cases, but the model is not extensible.
Just to say that we within the Fiji project have started a general
implementation for tensors, with pixel iterators optimized for each
data source type (2D sections like ImageProcessor, or paged cubes,
etc; even handling complex numbers for 3D FFT; mostly the work of
Stephan Preibisch).
* The difficulty in calling plugins from other plugins. The current
model uses ij.IJ.run("Name", "arguments"); or as of recently and
because of improved Thread isolation capabilities,
ij.IJ.run(imageplus, "Name", "arguments");
Still, there is no generic way to express the need to suppress calls
to ImagePlus.show() in plugins and instead gather the otherwise shown
images for the caller plugin to use.
What I think we are seeing here is the use of a java plugin as a
script, if we define script as "a small program to do one relatively
simple task using mostly high-level commands and not intended to be
reused by other plugins." For this purpose, the current javascript
support is great. But actual java plugins ought to be more expressive
and controlable. I would like to see more expressive PlugIn-like
interfaces.
* The current practice of not packaging plugins; i.e. a "Class_Name"
instead of a "org.my.Class_Name". Which leads to very undesirable name
collisions and on occasions incomprehensible errors when compiling
other plugins. The plugin-from-plugin call problem is aggravated by
this problem as well.
* The presence of public fields, like the ImagePlus.changes. These are
the least friendly at all for a program to manage or listen to. Such
practice should be banned outright; sharing state publically in a
non-final way is the antithesis of concurrent programming (aka Thread
safety).
* The lack of an event system. The current ImageListener interface is
a start, but very insufficient. Ideally I want to listen to anything
that occurs to an image. I suspect the duality between ImagePlus and
ImageProcessor, which sometimes suplant each other in current ImageJ,
is part of the problem.
* The inability to insert plugins as commands anywhere in the menus.
The current ij.Menus is a mess that I gave up on fixing. Johannes
Schindelin gave it a long shot and came up with a cleanup, which
enabled adding commands just about anywhere in the menus. Such
cleaned-up class is part of the ImageJA/fiji branch that we use as the
source for the core ij.jar of Fiji.
* The lack of a plugin manager, resulting in fragmented documentation,
difficulty in finding plugins, imposibility of finding plugin source
code on occasions. The lack of a plugin manager is very related to the
lack of a centralized set of tested, safety-verified plugins. We are
aiming at solving this problem within Fiji, with institutional support
from the Max Plank in Dresden, Germany.
* Numerous inconsistencies in the API. Simple, small gotchas like the
setMinAndMax that I explained above are abundant. For example:
** The ROI exists in the ImagePlus and in the ImageProcessor, but
could be programmatically two different ROI if one is to set it
directly to the ImageProcessor. This is part of the duality between
ImageProcessor and ImagePlus, which must be resolved one what or
another.
** Calling ImageProcessor.fill() has different effects depending
upon the type of ROI present in the ImageProcessor. For a correct
fill, one must call ImageProcessor.fill(mask), where mask is the
ImageProcessor mask of the ROI when the ROI is not a ij.gui.Roi (a
Rectangle).
* The GUI classes. As others and myself pointed out, the GUI classes
are a mixture of GUI, control and data representation. This leads to:
** Inability to run ImageJ headless, without a virtual screen
buffer, even if no GUI classes are instantiated at all (but are
present within the import list of some class that is instantiated).
** The sometimes not small problem of avoiding null pointers in
ImageCanvas when not contained in an ImageWindow.
** Lack of flexibility with a GUI toolkit. I don't think Swing is
great (I use it for TrakEM2, but it's a headache), but java3d and jogl
are nice alternatives. The hoops and workarounds to make java3d work
with ImageJ are enormous, and result in, for example, Bene Schmid's 3D
Viewer basically reinventing its own data structures and delegating
some calls to an ImageCanvas and ImageWindow for ROI and ImageJ
interaction.
I am sure I'm missing a few of my informal list of grievances with
current ImageJ. As I said, ImageJ works and its great, but all the
above are limiting us in what we can do in our application fields.
I would love to see what other aspects of ImageJ you consider in need
of attention, or expansions on the above.
Albert