Convert ImgLib2 array to IJ1 stack

Hello everyone,

I wrote a script that uses Image_Expression_Parser to process several stacks at once.
After completing the computation, I need to convert the result back into a 32-bit stack (I wish I have time someday to learn ImgLib2, but up to now, I’m happy with IJ1 stacks).
So I’m using:

ImagePlus resultImp = net.imglib2.img.display.imagej.ImageJFunctions.wrapFloat(result, “epsEq”)

with result, obtained from the Image_Expression_Parser, representing a 120x60x30 stack (for example).
What I get is a virtual stack 120x60 with 30 channels, instead of a single channel, 30 images stack.

What did I miss? How can I specify the output format ?

Thank you for your help, and sorry if this was already asked.

Hi @Nicolas,

I’ve sometimes had success with something like:

ImageJFunctions.wrap(Views.permute( result, 2, 3 ), "title" );

it seems that wrap puts the 3rd dimension (index 2) into “channels” and the “4th” dimension (index 3) into “z”, so that by switching them (permuting the axes), you get the right thing.

See below for more reading and details.

Let us know if that works out though,
John

More information:

Addressing this issue using an imagej2 style:

On the metadata being lost:

3 Likes

Oh one other thing -

As you noticed, the stack you get will be virtual and so you can’t be sure that writing into it will always work.

So you may run into problems you have some plugin that wants to modify that ImagePlus, in which case you may just need to make a copy.

John

1 Like

Hello @bogovicj ,

thank you for the tips and links. Actually the Groovy interpreter tells me that the number of dimensions is incorrect (ArrayIndexOutOfBoundsException: 3), but I’m confident I will find a solution when I have enough time to play with that.
Thank you.

Nicolas

1 Like

@Nicolas,

Ah, in that case, try this:

ImageJFunctions.wrap(Views.permute( Views.addDimension(result), 2, 3 ), "title" );

to add a “dummy” dimension before permuting.

John

Edit: typo
Edit2 : The above has a small error see below!!

2 Likes

Hello @bogovicj

sorry for not getting back to you earlier. Actually, with the solution you propose, one cannot wrap the “MixedTransform” into an ImagePlus:

No signature of method: static net.imglib2.img.display.imagej.ImageJFunctions.wrap() is applicable for argument types: (net.imglib2.transform.integer.MixedTransform, java.lang.String)

And and I don’t know how to convert a MixedTransform into a class that can be wrapped into an ImagePlus.

Anyway, I found a workaround by not permuting, and specifying the dimensions of the ImagePlus after wrapping (resultImp.setDimensions(1, nbSlices, 1)), so everything’s fine now.
Thank you for your help.

Nicolas

1 Like

Cool! Thanks for reporting back.

But to address your first issue

I think you mean MixedTransformView instead of MixedTransform (right?)
because it makes sense to not be able to wrap a transform as an image because its not an image…
I tried, and observed the same thing you did.

For the record (and future viewers of this thread), the missing thing in the above was two extra arguments in Views.addDimension

ImageJFunctions.wrap(Views.permute( Views.addDimension(result, 0, 0), 2, 3 ), "title" );

in imglib2 jargon, you need to make sure addDimension returns a RandomAccessibleInterval and not a plain RandomAccessible

John

2 Likes

To revive an old thread, @bogovicj could you give an example of this? I need to convert from a randomAccessibleInterval to ImagePlus (but not a virtual one!). How would I copy the randomAccessibleInterval into an imagePlus? Thanks!

1 Like

Hi @Kimberly_Meechan ,

Good question, this is how I would do it (in an imglib2-kind-of-way).

RandomAccessibleInterval< T > rai = // your rai

// This makes an ImagePlus and wraps in as an imglib2 object
// caution: only works if rai is byte, short, int, or float 
ImagePlusImg< T, ? > ipImg = new ImagePlusImgFactory<T>( Util.getTypeFromInterval( rai )).create( rai );

// copy it over
LoopBuilder.setImages( rai, ipImg ).forEachPixel( (x,y) -> y.set( x ) );

// get the ImagePlus out of the wrapper
ImagePlus imagePlus = ipImg.getImagePlus();

if instead you have an ImagePlus already, I would

Img ipImg = ImageJFunctions.wrap( myImagePlus );

then do the LoopBuilder

If your rai is not a type that an ImagePlus can handle, I would convert to something that does work like:

RandomAccessibleInterval< FloatType > raiFloat = Converters.convert(
   rai, 
   new RealFloatConverter< T >(), 
   new FloatType() );

hope that helps, and please follow up if something isn’t clear.

John

1 Like

In addition to what @bogovicj suggested, you should also be able to use ConvertService (which will first give you a virtual stack) and then call ImagePlus#duplicate() on it:

@Parameter
private ConvertService convertService;

// [...]

RandomAccessibleInterval< T > rai = // your rai

ImagePlus impVirtual = convertService.convert(rai, ImagePlus.class);

ImagePlus imp = impVirtual.duplicate();

Or, if you take that image as a Command input (via @Parameter), you can rely on the SciJava infrastructure and directly ask for the @Parameter ImagePlus.

2 Likes

Thanks both for your suggestions! I’ll give these a try