Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add converters between ImgLib2 RAI and ImageJ1 ImagePlus #229

Open
ctrueden opened this issue Dec 2, 2019 · 12 comments
Open

Add converters between ImgLib2 RAI and ImageJ1 ImagePlus #229

ctrueden opened this issue Dec 2, 2019 · 12 comments
Assignees
Milestone

Comments

@ctrueden
Copy link
Member

ctrueden commented Dec 2, 2019

There are converters for Dataset to/from ImagePlus (though see #186). But if you have e.g. an ArrayImg, you cannot currently convert it directly to ImagePlus with the ConvertService. We want this to be possible.

@imagejan
Copy link
Member

imagejan commented Dec 2, 2019

I guess this can be done with the new AbstractDelegateConverter introduced in scijava/scijava-common#366, right?

Which conversions need to be supported explicitly?

  • ArrayImg => ImagePlus
  • PlanarImg => ImagePlus
  • CellImg => ImagePlus
  • ...?

@ctrueden
Copy link
Member Author

ctrueden commented Dec 3, 2019

I think the delegate converter will be useful, yeah. Thanks for developing it.

For new converters needed:

  1. ImgPlus to ImagePlus – to map the metadata e.g. axes correctly.
  2. RandomAccessibleInterval to ImagePlus – for all other cases i.e. no metadata is available.
  3. ImagePlus to ImgPlus. We already have ImagePlus to Dataset, which extends Img, so if you request a conversion of an ImagePlus object to e.g. RandomAccessibleInterval, it should already work (though I didn't test just now). But because Dataset does not extend ImgPlus (inorite), that request would currently fail.

The above is just speculative—best would be to do some thorough TDD requesting all sorts of anticipated desirable conversions, and then implement the most general converters that also minimize information loss.

@imagejan
Copy link
Member

imagejan commented Dec 6, 2019

For the record, this Groovy script lists current support for some of the conversions:

#@ ConvertService cs

import ij.ImagePlus
import net.imagej.Dataset
import net.imagej.ImgPlus
import net.imglib2.img.Img
import net.imglib2.RandomAccessibleInterval

println cs.supports(Dataset.class, ImagePlus.class)                  // true
println cs.supports(Dataset.class, ImgPlus.class)                    // true
println cs.supports(Dataset.class, Img.class)                        // true
println cs.supports(Dataset.class, RandomAccessibleInterval.class)   // true
println ""
println cs.supports(ImagePlus.class, Dataset.class)                  // true
println cs.supports(ImagePlus.class, ImgPlus.class)                  // false
println cs.supports(ImagePlus.class, Img.class)                      // true
println cs.supports(ImagePlus.class, RandomAccessibleInterval.class) // true
println ""
println cs.supports(ImgPlus.class, Dataset.class)                    // false
println cs.supports(ImgPlus.class, ImagePlus.class)                  // false
println cs.supports(ImgPlus.class, Img.class)                        // true
println cs.supports(ImgPlus.class, RandomAccessibleInterval.class)   // true
println ""
println cs.supports(Img.class, Dataset.class)                        // false
println cs.supports(Img.class, ImagePlus.class)                      // false
println cs.supports(Img.class, ImgPlus.class)                        // true
println cs.supports(Img.class, RandomAccessibleInterval.class)       // true
println ""
println cs.supports(RandomAccessibleInterval.class, Dataset.class)   // false
println cs.supports(RandomAccessibleInterval.class, ImagePlus.class) // false
println cs.supports(RandomAccessibleInterval.class, ImgPlus.class)   // false
println cs.supports(RandomAccessibleInterval.class, Img.class)       // false

@imagejan
Copy link
Member

imagejan commented Dec 6, 2019

I started implementing a parameterized test in fb75ae4, where different types and axis orders can be defined to be tested in ImgPlus => ImagePlus conversion.

@ctrueden
Copy link
Member Author

See also imagej/imagej-common#74

@ctrueden
Copy link
Member Author

And imagej/imagej-ops#54

@imagesc-bot
Copy link

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/net-imagej-defaultdataset/37085/3

@imagesc-bot
Copy link

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/save-ilastik-hdf5-files-from-java/60194/2

@ctrueden
Copy link
Member Author

ctrueden commented May 10, 2022

I wrote a more thorough script printing supported conversions:

image-conversions.py
#@ ConvertService cs

import sys
from ij import ImagePlus
from net.imagej import Dataset, ImgPlus
from net.imagej.display import DatasetView, ImageDisplay
from net.imglib2.img import Img
from net.imglib2 import RandomAccessibleInterval

image_types = [
	ImagePlus,
	RandomAccessibleInterval,
	Img,
	ImgPlus,
	Dataset,
	DatasetView,
	ImageDisplay,
]
sys.stdout.write("              ")
for col in image_types:
	sys.stdout.write("{0: <13}".format('RAI' if col == RandomAccessibleInterval else col.__name__))
print
for row in image_types:
	sys.stdout.write("{0: <14}".format('RAI' if row == RandomAccessibleInterval else row.__name__))
	for col in image_types:
		sys.stdout.write("yes          " if cs.supports(col, row) else "NO           ")
	print

And the results as of this writing:

              ImagePlus    RAI          Img          ImgPlus      Dataset      DatasetView  ImageDisplay 
ImagePlus     yes          NO           NO           NO           yes          NO           yes          
RAI           yes          yes          yes          yes          yes          NO           NO           
Img           yes          NO           yes          yes          yes          NO           NO           
ImgPlus       NO           NO           yes          yes          yes          NO           NO           
Dataset       yes          NO           NO           NO           yes          NO           NO           
DatasetView   NO           NO           NO           NO           NO           yes          NO           
ImageDisplay  yes          NO           NO           NO           NO           NO           yes        

The PyImageJ and napari-imagej projects have to bend over backwards to support image conversions that aren't supported by the ConvertService yet, so I'm motivated to make the above grid all "yes".

@ctrueden ctrueden self-assigned this May 10, 2022
@ctrueden ctrueden added this to the m1 milestone May 10, 2022
ctrueden added a commit to imagej/imagej-common that referenced this issue Sep 27, 2022
* Dataset -> DatasetView
* RandomAccessibleInterval -> ImageDisplay

See also imagej/imagej-legacy#229.

Co-authored-by: Curtis Rueden <ctrueden@wisc.edu>
@ctrueden
Copy link
Member Author

imagej/imagej-common#102 adds new converters for Dataset to DatasetView and RAI to ImageDisplay. Updated table:

              ImagePlus    RAI          Img          ImgPlus      Dataset      DatasetView  ImageDisplay 
ImagePlus     yes          NO           NO           NO           yes          NO           yes          
RAI           yes          yes          yes          yes          yes          NO           NO           
Img           yes          NO           yes          yes          yes          NO           NO           
ImgPlus       NO           NO           yes          yes          yes          NO           NO           
Dataset       yes          NO           NO           NO           yes          NO           NO           
DatasetView   NO           NO           NO           NO           yes          yes          NO           
ImageDisplay  yes          yes          yes          yes          yes          NO           yes          

ctrueden added a commit to imagej/imagej-common that referenced this issue Nov 11, 2022
[CTR: There is one failing test... due to how SingleInputPreprocessors
work. They eagerly try to convert. Now that this commit adds so many
converters, we get a situation where e.g. the ActiveDatasetPreprocessor
takes precedence over the ActiveImageDisplayPreprocessor when filling
single ImageDisplay parameters, which is obviously bad... blargh.]

This work is a major step toward resolving imagej/imagej-legacy#229,
but does not quite do the entire job, since ij.ImagePlus is another
image type on that list, which is not available from imagej-common.
But we can add converters to imagej-legacy for ImagePlus to+from all
other image types, and then we'll have everything covered.

See also imagej/imagej-ops#54.
ctrueden added a commit to imagej/imagej-common that referenced this issue Nov 11, 2022
This work is a major step toward resolving imagej/imagej-legacy#229,
but does not quite do the entire job, since ij.ImagePlus is another
image type on that list, which is not available from imagej-common.
But we can add converters to imagej-legacy for ImagePlus to+from all
other image types, and then we'll have everything covered.

See also imagej/imagej-ops#54.

Note that these new converters triggered one failing test,
SingleInputPreprocessorTest#testSingleImageDisplay, because the
ActiveDatasetPreprocessor was getting a chance to fill the single
ImageDisplay parameter before the ActiveImageDisplayPreprocessor did,
and so the ActiveDatasetPreprocessor would wrap the active Dataset into
a *new ImageDisplay* via the newly added DatasetToImageDisplayConverter.
To avoid this issue, this commit bumps up the priorities of certain
SingleInputPreprocessors: ActiveImageDisplayPreprocessor highest, then
ActiveDatasetViewPreprocessor, then ActiveDataViewPreprocessor, then
ActiveDatasetPreprocessor. This adjustment results in all the tests
passing, but we will need to continue to be careful about the
SingleInputPreprocessor ordering. As things stand, there is probably
still some surprising behavior under the hood, because now when there is
a single Dataset input, it will be the ActiveImageDisplayPreprocessor
that fills it by unwrapping that Dataset from itself via the
ImageDisplayToDatasetConverter. We could consider removing a bunch of
no-longer-necessary SingleInputPreprocessor implementations, but for
now, I am choosing not to rock the boat further.
@ctrueden
Copy link
Member Author

With imagej/imagej-common#103, and specifically imagej/imagej-common@e67b5c9, I have now coded converters for all image types to/from all others, except for ij.ImagePlus since that's not available from imagej-common. But it gets us much closer to the above table becoming all yeses!

@imagesc-bot
Copy link

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/converting-arrayimg-to-imageplus-for-using-the-analyze-skeleton-plugin/85934/3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants