Coder Social home page Coder Social logo

imglib2-ij's Introduction

Image.sc Forum developer chat

ImgLib2 is a general-purpose, multidimensional image processing library.

It provides an interface-driven design that supports numeric and non-numeric data types (8-bit unsigned integer, 32-bit floating point, etc.) in an extensible way. It implements several data sources and sample organizations, including one single primitive array, one array per plane, N-dimensional array "cells" cached to and from disk on demand, and planes read on demand from disk.

Benefits

  1. By avoiding unnecessarily complex syntax (such as nested loops) ImgLib2 allows developers to concentrate on the essence of the algorithm.

  2. By being conciser, ImgLib2 makes it much harder to write buggy code.

  3. ImgLib2 is dimension-independent. That means that you usually express your code in a way that can be applied to 2-, 3- or even 100-dimensional data.

  4. ImgLib2 has no limit on channels. You can have a fine-grained spectrum for every single pixel, if your hardware allows for that.

  5. ImgLib2 is actually not limited to images; e.g., we have examples working on RNA sequences.

  6. ImgLib2 provides transparent data access. The algorithm does not need to know that it is working on a virtual stack, and the data can actually be generated on the fly. Think about a fractal and being able to zoom in indefinitely; this is an image that you can use with any ImgLib algorithm.

  7. ImgLib2 makes it an ultra-cheap operation to work on sections of images. There is no need to copy data around.

  8. ImgLib2 is so self-contained that it could serve as the underlying data handling library for every Java-based project.

Applications

Resources

Building the source code

You can build the source from the command line using Maven:

mvn

You can also import the source into Eclipse using the m2e plugin. Download Eclipse IDE for Java Developers (3.7 Indigo or later), which comes with m2e preinstalled. Then run:

File > Import > Existing Maven Projects

Select the toplevel folder of your ImgLib working copy, and Eclipse will find all the ImgLib projects.

Both NetBeans and IntelliJ IDEA also have built-in support for Maven projects.

ImgLib1

The previous incarnation of the library, known as ImgLib1, is still available as part of Fiji. However, we strongly encourage developers to use ImgLib2 instead, and migrate existing ImgLib1 programs to ImgLib2 whenever possible.

imglib2-ij's People

Contributors

acardona avatar axtimwalde avatar bdezonia avatar ctrueden avatar dietzc avatar dprodanov avatar dscho avatar hinerm avatar hoerldavid avatar maarzt avatar mkitti avatar stephanpreibisch avatar tinevez avatar tpietzsch avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

imglib2-ij's Issues

Unnecessary type conversion when wrapping to ImagePlus

Consider the following Groovy script:

#@ DatasetIOService datasetIO
#@ UIService ui
bigCellImg = datasetIO.open("big&pixelType=uint8&axes=X,Y,Z,Time&lengths=3000,4000,5000,6000.fake")
ui.show(bigCellImg)

This pops up the huge image very quickly, which is awesome.

But now put a breakpoint at org.scijava.ui.DefaultUIService line 381 of org.scijava:scijava-common:2.73.1; this will be the line ui.show(display) inside onEvent(DisplayCreated). Run the same script above, and it will break there. Then STEP instead of CONTINUE. The step now hangs, with IterableIntervalProjector2D.map taking forever to complete. (I waited minutes, and it still was not done.)

Here are some example stack traces of what is going on during the step, retrieved from the CLI using ctrl+\:

"AWT-EventQueue-0" #21 prio=6 os_prio=31 tid=0x00007fd158950000 nid=0x6e23 runnable [0x00007000066d7000]
   java.lang.Thread.State: RUNNABLE
	at net.imglib2.type.numeric.integer.UnsignedByteType.get(UnsignedByteType.java:151)
	at net.imglib2.type.numeric.integer.UnsignedByteType.getIntegerLong(UnsignedByteType.java:168)
	at net.imglib2.type.numeric.integer.AbstractIntegerType.getRealDouble(AbstractIntegerType.java:62)
	at net.imglib2.img.display.imagej.ImageJVirtualStackUnsignedByte$ByteConverter.convert(ImageJVirtualStackUnsignedByte.java:79)
	at net.imglib2.img.display.imagej.ImageJVirtualStackUnsignedByte$ByteConverter.convert(ImageJVirtualStackUnsignedByte.java:72)
	at net.imglib2.display.projector.IterableIntervalProjector2D.map(IterableIntervalProjector2D.java:151)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getSlice(ImageJVirtualStack.java:148)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getPixels(ImageJVirtualStack.java:155)
	at net.imglib2.img.display.imagej.AbstractVirtualStack.getProcessor(AbstractVirtualStack.java:85)
	at ij.ImagePlus.setStack(ImagePlus.java:683)
	at ij.ImagePlus.<init>(ImagePlus.java:154)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:100)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:80)
	at net.imagej.legacy.translate.ImagePlusCreator.createImagePlus(ImagePlusCreator.java:121)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:98)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:87)
	at net.imagej.legacy.translate.ImageTranslator.createLegacyImage(ImageTranslator.java:74)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:267)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:254)
	at net.imagej.legacy.display.LegacyImageDisplayViewer.view(LegacyImageDisplayViewer.java:121)
	at org.scijava.ui.viewer.DisplayViewer.view(DisplayViewer.java:86)
	at net.imagej.legacy.ui.LegacyUI$1.run(LegacyUI.java:197)
	at org.scijava.thread.DefaultThreadService.invoke(DefaultThreadService.java:114)
	at net.imagej.legacy.ui.LegacyUI.show(LegacyUI.java:193)
	at org.scijava.ui.DefaultUIService.onEvent(DefaultUIService.java:381)

"AWT-EventQueue-0" #21 prio=6 os_prio=31 tid=0x00007fd158950000 nid=0x6e23 runnable [0x00007000066d7000]
   java.lang.Thread.State: RUNNABLE
	at java.lang.Double.doubleToRawLongBits(Native Method)
	at java.lang.Math.copySign(Math.java:1766)
	at java.lang.Math.signum(Math.java:1525)
	at net.imglib2.util.Util.round(Util.java:499)
	at net.imglib2.type.numeric.integer.AbstractIntegerType.setReal(AbstractIntegerType.java:74)
	at net.imglib2.img.display.imagej.ImageJVirtualStackUnsignedByte$ByteConverter.convert(ImageJVirtualStackUnsignedByte.java:84)
	at net.imglib2.img.display.imagej.ImageJVirtualStackUnsignedByte$ByteConverter.convert(ImageJVirtualStackUnsignedByte.java:72)
	at net.imglib2.display.projector.IterableIntervalProjector2D.map(IterableIntervalProjector2D.java:151)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getSlice(ImageJVirtualStack.java:148)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getPixels(ImageJVirtualStack.java:155)
	at net.imglib2.img.display.imagej.AbstractVirtualStack.getProcessor(AbstractVirtualStack.java:85)
	at ij.ImagePlus.setStack(ImagePlus.java:683)
	at ij.ImagePlus.<init>(ImagePlus.java:154)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:100)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:80)
	at net.imagej.legacy.translate.ImagePlusCreator.createImagePlus(ImagePlusCreator.java:121)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:98)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:87)
	at net.imagej.legacy.translate.ImageTranslator.createLegacyImage(ImageTranslator.java:74)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:267)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:254)
	at net.imagej.legacy.display.LegacyImageDisplayViewer.view(LegacyImageDisplayViewer.java:121)
	at org.scijava.ui.viewer.DisplayViewer.view(DisplayViewer.java:86)
	at net.imagej.legacy.ui.LegacyUI$1.run(LegacyUI.java:197)
	at org.scijava.thread.DefaultThreadService.invoke(DefaultThreadService.java:114)
	at net.imagej.legacy.ui.LegacyUI.show(LegacyUI.java:193)
	at org.scijava.ui.DefaultUIService.onEvent(DefaultUIService.java:381)

"AWT-EventQueue-0" #16 prio=6 os_prio=31 tid=0x00007fb4c4388000 nid=0xda27 runnable [0x000070000dc18000]
   java.lang.Thread.State: RUNNABLE
	at net.imglib2.view.MixedRandomAccess.get(MixedRandomAccess.java:364)
	at net.imglib2.display.projector.IterableIntervalProjector2D.map(IterableIntervalProjector2D.java:151)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getSlice(ImageJVirtualStack.java:148)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getPixels(ImageJVirtualStack.java:155)
	at net.imglib2.img.display.imagej.AbstractVirtualStack.getProcessor(AbstractVirtualStack.java:85)
	at ij.ImagePlus.setStack(ImagePlus.java:683)
	at ij.ImagePlus.<init>(ImagePlus.java:154)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:100)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:80)
	at net.imagej.legacy.translate.ImagePlusCreator.createImagePlus(ImagePlusCreator.java:121)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:98)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:87)
	at net.imagej.legacy.translate.ImageTranslator.createLegacyImage(ImageTranslator.java:74)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:267)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:254)
	at net.imagej.legacy.display.LegacyImageDisplayViewer.view(LegacyImageDisplayViewer.java:121)
	at org.scijava.ui.viewer.DisplayViewer.view(DisplayViewer.java:86)
	at net.imagej.legacy.ui.LegacyUI$1.run(LegacyUI.java:197)
	at org.scijava.thread.DefaultThreadService.invoke(DefaultThreadService.java:114)
	at net.imagej.legacy.ui.LegacyUI.show(LegacyUI.java:193)
	at org.scijava.ui.DefaultUIService.onEvent(DefaultUIService.java:381)

"AWT-EventQueue-0" #16 prio=6 os_prio=31 tid=0x00007fb4c4388000 nid=0xda27 runnable [0x000070000dc18000]
   java.lang.Thread.State: RUNNABLE
	at net.imglib2.img.array.AbstractArrayCursor.get(AbstractArrayCursor.java:123)
	at net.imglib2.img.array.AbstractArrayCursor.get(AbstractArrayCursor.java:53)
	at net.imglib2.display.projector.IterableIntervalProjector2D.map(IterableIntervalProjector2D.java:151)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getSlice(ImageJVirtualStack.java:148)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getPixels(ImageJVirtualStack.java:155)
	at net.imglib2.img.display.imagej.AbstractVirtualStack.getProcessor(AbstractVirtualStack.java:85)
	at ij.ImagePlus.setStack(ImagePlus.java:683)
	at ij.ImagePlus.<init>(ImagePlus.java:154)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:100)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:80)
	at net.imagej.legacy.translate.ImagePlusCreator.createImagePlus(ImagePlusCreator.java:121)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:98)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:87)
	at net.imagej.legacy.translate.ImageTranslator.createLegacyImage(ImageTranslator.java:74)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:267)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:254)
	at net.imagej.legacy.display.LegacyImageDisplayViewer.view(LegacyImageDisplayViewer.java:121)
	at org.scijava.ui.viewer.DisplayViewer.view(DisplayViewer.java:86)
	at net.imagej.legacy.ui.LegacyUI$1.run(LegacyUI.java:197)
	at org.scijava.thread.DefaultThreadService.invoke(DefaultThreadService.java:114)
	at net.imagej.legacy.ui.LegacyUI.show(LegacyUI.java:193)
	at org.scijava.ui.DefaultUIService.onEvent(DefaultUIService.java:381)


"AWT-EventQueue-0" #16 prio=6 os_prio=31 tid=0x00007fb4c4388000 nid=0xda27 runnable [0x000070000dc18000]
   java.lang.Thread.State: RUNNABLE
	at java.lang.Math.signum(Math.java:1525)
	at net.imglib2.util.Util.round(Util.java:499)
	at net.imglib2.type.numeric.integer.AbstractIntegerType.setReal(AbstractIntegerType.java:74)
	at net.imglib2.img.display.imagej.ImageJVirtualStackUnsignedByte$ByteConverter.convert(ImageJVirtualStackUnsignedByte.java:84)
	at net.imglib2.img.display.imagej.ImageJVirtualStackUnsignedByte$ByteConverter.convert(ImageJVirtualStackUnsignedByte.java:72)
	at net.imglib2.display.projector.IterableIntervalProjector2D.map(IterableIntervalProjector2D.java:151)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getSlice(ImageJVirtualStack.java:148)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getPixels(ImageJVirtualStack.java:155)
	at net.imglib2.img.display.imagej.AbstractVirtualStack.getProcessor(AbstractVirtualStack.java:85)
	at ij.ImagePlus.setStack(ImagePlus.java:683)
	at ij.ImagePlus.<init>(ImagePlus.java:154)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:100)
	at net.imglib2.img.display.imagej.ImgToVirtualStack.wrap(ImgToVirtualStack.java:80)
	at net.imagej.legacy.translate.ImagePlusCreator.createImagePlus(ImagePlusCreator.java:121)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:98)
	at net.imagej.legacy.translate.ImagePlusCreator.createLegacyImage(ImagePlusCreator.java:87)
	at net.imagej.legacy.translate.ImageTranslator.createLegacyImage(ImageTranslator.java:74)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:267)
	at net.imagej.legacy.LegacyImageMap.registerDisplay(LegacyImageMap.java:254)
	at net.imagej.legacy.display.LegacyImageDisplayViewer.view(LegacyImageDisplayViewer.java:121)
	at org.scijava.ui.viewer.DisplayViewer.view(DisplayViewer.java:86)
	at net.imagej.legacy.ui.LegacyUI$1.run(LegacyUI.java:197)
	at org.scijava.thread.DefaultThreadService.invoke(DefaultThreadService.java:114)
	at net.imagej.legacy.ui.LegacyUI.show(LegacyUI.java:193)
	at org.scijava.ui.DefaultUIService.onEvent(DefaultUIService.java:381)

The gist is that IterableIntervalProjector2D.map uses a ImageJVirtualStackUnsignedByte$ByteConverter to do an identity conversion from UnsignedByteType to UnsignedByteTypeโ€”i.e. no value adjustment. I am guessing that when stepping in the debugger, we do not gain the full benefits of JIT/inlining, so end up looping over all samples. Even then, it seems odd it is so slow... but regardless, this code path is highly suboptimal. Would be much better not to use the converter at all in circumstances where the source type already matches.

Signed integer Img is displayed incorrectly by ImageJFunctions.show

When displaying an IJ2 Img, say, img, of signed integral type, e.g., ByteType or IntType,
ImageJFunctions.show (img, "title"); renders negative values as zero.

This issue is also discussed in two imagej forum topics:
Signed integer Img is displayed incorrectly by ImageJFunctions.show
and
Is there a pure IJ2 mechanism for displaying images using stock Fiji?

This is presumably due to the fact that IJ1 appears not support signed integral images.
(It does support a floating-point GRAY32 image type.)

Other IJ2 Img display methods, such as DisplayService.show ("title", img); appear
to convert the signed integral Img to a FloatType / float32 Img before handing it
off to IJ1, which then displays it (correctly) as a GRAY32 image.

As long as IJ2 continues (at least in some contexts) to rely on IJ1 for image display,
the best fix would be to add signed integral display functionality to IJ1. This would
avoid the cost in time and space of the ByteType (etc.) --> FloatType conversion.
Such a fix can be arranged to be non-breaking because it only adds new functionality
to IJ1.

A more expedient fix would be to have ImageJFunctions.show mimic
DisplayService.show, and first convert signed integral images to FloatType
images before displaying them with IJ1. (Of course, if signed integral display
were added to IJ1, DisplayService.show, and similar, should be updated to
use it, as well.)

Update dependent projects.

  • Release a version of imglib2-ij with everything under package net.imglib2.ij.
  • Identify dependent projects.
  • For each dependent project: Use new imglib2-ij version in POM
  • For each dependent project: Update package for all occurrences of imglib2-ij classes.
  • For each dependent project: Create PR
  • Track PR progress until new imglib2-ij version can be propagated to pom-scijava

ImageJFunction.show can throw ArrayIndexOutOfBoundsException

From this Image.sc Forum topic: using the shearView op and then showing it as an ImagePlus using ImageJFunctions.show can throw an ArrayIndexOutOfBoundsException. Try opening the Bat Cochlea Volume sample (File โ†’ Open Samples menu), then running the following Groovy script:

#@ Img img

import net.imglib2.view.*
import bdv.util.BdvFunctions
import net.imglib2.img.display.imagej.ImageJFunctions

IntervalView imgShear12 = Views.interval( 
                Views.shear( Views.extendZero( img ), 1, 2 ),
                img );

//BdvFunctions.show( imgShear12, "shear 12" );  // looks good
ImageJFunctions.show( imgShear12 ); // CRASHES (see below)

Then move the C slider of the resultant image, and observe the message on stderr:

Exception in thread "zSelector" java.lang.ArrayIndexOutOfBoundsException

This may or may not actually be a bug in imglib2-ij, but I file it here in the absence of a better idea, until it gets investigated.

ImageJFunctions.wrap mixes up channels with slices, and slices with time frames

When calling ImageJFunctions.wrap( RandomAccessibleInterval ) for a RandomAccessibleInterval with 3 dimensions, the third dimension is interpreted as channels rather than Z slices. For a 4D, the 4th dimension is interpreted as stack slices (the Z axis) rather than time frames.

This issue is bad enough that I am not using wrap anymore, because it makes further work with these virtual stacks hard. For example, the ImagePlus.setPosition( channels, slices, frames ) is entirely messed up, in that one has to use channels for slices, and slices for frames.

A solution would be to edit the private method ImageJFunctions.makeImagePlus to stop interpreting the 3rd dimension as channels by default. I am not sure what motivated this, given that a wrap over an RGB image shows it as a single-slice ColorProcessor.

According to git blame, the author of ImageJFunctions.makeImagePlus is @tpietzsch . I wonder if a comment could be made about the mix up between channels and slices, and slices with frames.

I'd like to rewrite the method ImageJFunctions.makeImagePlus to do the right thing. Perhaps some of the methods that call it within ImageJFunctions could specify the number of channels that they want as an argument. Otherwise, the default number of channels should be 1, and the 3rd dimension be interpreted by default as the Z axis.

ImageJ 1.54h breaks CellImgToVirtualStackTest

$ mvn clean test -Dij.version=1.54h
...
[ERROR] net.imglib2.img.display.imagej.CellImgToVirtualStackTest.testPersistence -- Time elapsed: 0.007 s <<< FAILURE!
java.lang.AssertionError: expected:<42.0> but was:<0.0>
	...
	at net.imglib2.img.display.imagej.CellImgToVirtualStackTest.testPersistence(CellImgToVirtualStackTest.java:162)
	...

Whereas -Dij.version=1.54g works.

Cannot duplicate wrapped virtual stack

Attempting to invoke the duplicate() method of a net.imglib2.img.display.imagej virtual stack data structure does not work. This prevents some use cases e.g. Morphological Segmentation:

[ERROR] Module threw exception
java.lang.UnsupportedOperationException
	at net.imglib2.img.display.imagej.AbstractVirtualStack.duplicate(AbstractVirtualStack.java:344)
	at inra.ijpb.plugins.MorphologicalSegmentation.run(MorphologicalSegmentation.java:1624)
	at ij.IJ.runUserPlugIn(IJ.java:222)
	at ij.IJ.runPlugIn(IJ.java:186)
	at ij.IJ.runPlugIn(IJ.java:175)
	at net.imagej.legacy.command.LegacyCommand.run(LegacyCommand.java:59)
	at org.scijava.command.CommandModule.run(CommandModule.java:199)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:168)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:127)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:66)
	at org.scijava.thread.DefaultThreadService$3.call(DefaultThreadService.java:238)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

To reproduce the above exception, enable the IJBP-plugins update site, open a big cell image, then try running the "Morphological Segmentation" plugin on it.

Revise ImagePlusImg construction

ImagePlusImg constructor uses deprecated super constructor.
Hierarchy should be revised such that subclasses (ShortImagePlus etc) call super constructor with list of slices.

Also, should ImgPlusImg be abstract?

PlugInFilterRunner breaks Undo for single-image TYPE_CONVERSION

PlugInFilterRunner breaks Undo for certain code paths.

I am looking at the code in PlugInFilterRunner.java, from:

https://imagej.nih.gov/ij/developer/source/ij/plugin/filter/PlugInFilterRunner.java.html

It appears that the bug is in line 115. Lines 115--120 of the code are:

                if ((flags&PlugInFilter.NO_CHANGES)==0) {   // (filters doing no modifications don't change undo status)
                    if (snapshotDone)
                        Undo.setup(Undo.FILTER, imp);
                    else
                        Undo.reset();
                }

Line 115 tests for PlugInFilter.NO_CHANGES NOT being set, which means
that the plugin has stated that it WILL (at least potentially) change
the image. If the condition tests true (that is, NO_CHANGES is not set),
then the subsequent lines incorrectly clear the Undo information.

I do not understand all of the code paths here, but, simplistically,
it would appear that replacing line 115 with:

                if ((flags&PlugInFilter.NO_CHANGES)!=0) {   // (filters doing no modifications don't change undo status)

would fix the bug.

As a workaround, a (single-image) TYPE_CONVERSION PlugInFilter can
return, e.g.:

   return DOES_8G | NO_CHANGES;

from its setup() method (falsely saying that it won't change the
image), in effect, reversing the incorrect NO_CHANGES test in
PlugInFilterRunner, and preventing PlugInFilterRunner from clearing
the Undo information.

Here is code for a plugin that illustrates the bug and the
workaround (but not the proposed actual fix):

// PlugInFilterUndo.java

// contents of plugins.config file:
//
// MM, "PlugInFilterUndo", mm.PlugInFilterUndo("")
// MM, "PlugInFilterUndo -- NO_CHANGES", mm.PlugInFilterUndo("NO_CHANGES")

package mm;

import ij.ImagePlus;
import ij.Undo;
import ij.plugin.filter.PlugInFilter;
import ij.process.ImageProcessor;
import ij.process.ShortProcessor;

/**
 * example for broken undo in PlugInFilterRunner
 */

public class PlugInFilterUndo implements PlugInFilter {

  private ImagePlus imp = null;

  public int setup (String arg, ImagePlus image) {
    imp = image;  // remember image for run method
    if (arg.equals ("NO_CHANGES"))  return DOES_8G | NO_CHANGES;
    else                            return DOES_8G;
  }

  public void run (ImageProcessor ip) {
    ShortProcessor sp = imp.getProcessor().convertToShortProcessor();
    short pixels[] = (short[]) sp.getPixels();
    for (int i = 0; i < pixels.length; i++)
      pixels[i] = (short) (((i / 32) % 2 == 0) ? 16384 : 49152);
    Undo.setup (Undo.TYPE_CONVERSION, imp);
    imp.setProcessor (sp);
    return;
  }

}

To run this code, build and install the plugin (including the
plugins.config given as comments in the above java code.) Then
open (or create) an 8-bit image and run the command:

MM > PlugInFilterUndo -- NO_CHANGES

This version uses the "NO_CHANGES" workaround, and will convert
the image to a 16-bit image (and change the values of the pixels).
Now running:

Edit > Undo

will revert the image back to the 8-bit original.

Contrariwise, running the version without the workaround:

MM > PlugInFilterUndo

will perform the same conversion to a 16-bit image, but, because
of the PlugInFilterRunner bug, subsequently running:

Edit > Undo

will now not work.

This is all analyzed and tested with:

ImageJ 2.0.0-rc-65/1.52b; Java 1.8.0_66 [64-bit]; Linux 4.4.0-121-generic;

on:

ubuntu 16.04 LTS, 64-bit

Thanks, mm

Revise package structure to avoid split packages

See PR #20

The packages net.imglib2.img net.imglib2.display.projector and net.imglib2.img.display are already contained in imglib2, therefore they should not be used here. By adding the common ij infix to the package names this is avoided for current and future packages.

getVoxels unimplemented in AbstractVirtualStack

Consider this Groovy script:

image = net.imglib2.img.array.ArrayImgs.unsignedBytes(10, 10, 10)
imp = net.imglib2.img.display.imagej.ImageJFunctions.wrap(image, "Image")
ij.IJ.run(imp, "Gaussian Blur 3D...", "x=10 y=2 z=2")

Running it results in the following exception:

java.lang.UnsupportedOperationException
	at net.imglib2.img.display.imagej.AbstractVirtualStack.getVoxels(AbstractVirtualStack.java:351)
	at ij.plugin.GaussianBlur3D.blurZ(GaussianBlur3D.java:72)
	at ij.plugin.GaussianBlur3D.blur(GaussianBlur3D.java:55)
	at ij.plugin.GaussianBlur3D.run(GaussianBlur3D.java:20)
	at ij.IJ.runPlugIn(IJ.java:198)
	at ij.Executer.runCommand(Executer.java:137)
	at ij.Executer.run(Executer.java:66)
	at ij.IJ.run(IJ.java:308)
	at ij.IJ.run(IJ.java:364)
	at ij.IJ$run.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:141)
	at Script8.run(Script8.groovy:6)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.