+ * Under the hood, each {@link ij.process.ImageProcessor}'s backing array is + * wrapped into an {@link ArrayDataAccess}. The resulting {@link List} of + * {@link ArrayDataAccess}es is used to form a {@link PlanarImg}. + *
+ * + * @param imp the {@link ImagePlus} to wrap + * @return a {@link PlanarImg} directly wrapping {@code imp} + */ + public static PlanarImg< ?, ? > wrapDirect(final ImagePlus imp ) { switch ( imp.getType() ) { case ImagePlus.GRAY8: - return wrapByte( imp ); + return wrapByteDirect( imp ); case ImagePlus.GRAY16: - return wrapShort( imp ); + return wrapShortDirect( imp ); case ImagePlus.GRAY32: - return wrapFloat( imp ); + return wrapFloatDirect( imp ); case ImagePlus.COLOR_RGB: - return wrapRGBA( imp ); + return wrapRGBADirect( imp ); default: throw new RuntimeException( "Only 8, 16, 32-bit and RGB supported!" ); } } - public static PlanarImg< UnsignedByteType, ? > wrapByte(final ImagePlus imp ) + /** + * Wraps an {@link ImagePlus} into a {@link PlanarImg} of unsigned bytes. + *+ * Under the hood, each {@link ij.process.ImageProcessor}'s backing array is + * wrapped into an {@link ByteArray}. The resulting {@link List} of + * {@link ArrayDataAccess}es is used to form a {@link PlanarImg}. + *
+ * + * @param imp the {@link ImagePlus} to wrap + * @return a {@link PlanarImg} of unsigned bytes directly wrapping {@code imp} + */ + public static PlanarImg< UnsignedByteType, ? > wrapByteDirect(final ImagePlus imp ) { if ( imp.getType() != ImagePlus.GRAY8 ) - return null; + throw new IllegalArgumentException(imp + " does not contain unsigned bytes!"); final ByteImagePlus< UnsignedByteType > container = new ByteImagePlus<>( imp ); @@ -100,10 +125,21 @@ public class ImagePlusToImg return container; } - public static PlanarImg< UnsignedShortType, ? > wrapShort(final ImagePlus imp ) + /** + * Wraps an {@link ImagePlus} into a {@link PlanarImg} of unsigned shorts. + *+ * Under the hood, each {@link ij.process.ImageProcessor}'s backing array is + * wrapped into an {@link ShortArray}. The resulting {@link List} of + * {@link ArrayDataAccess}es is used to form a {@link PlanarImg}. + *
+ * + * @param imp the {@link ImagePlus} to wrap + * @return a {@link PlanarImg} of unsigned shorts directly wrapping {@code imp} + */ + public static PlanarImg< UnsignedShortType, ? > wrapShortDirect(final ImagePlus imp ) { if ( imp.getType() != ImagePlus.GRAY16 ) - return null; + throw new IllegalArgumentException(imp + " does not contain unsigned shorts!"); final ShortImagePlus< UnsignedShortType > container = new ShortImagePlus<>( imp ); @@ -116,26 +152,21 @@ public class ImagePlusToImg return container; } - public static PlanarImg< UnsignedIntType, ? > wrapInt(final ImagePlus imp ) - { - if( imp.getType() != ImagePlus.COLOR_RGB ) - return null; - - final IntImagePlus< UnsignedIntType > container = new IntImagePlus<>( imp ); - - // create a Type that is linked to the container - final UnsignedIntType linkedType = new UnsignedIntType( container ); - - // pass it to the DirectAccessContainer - container.setLinkedType( linkedType ); - - return container; - } - - public static PlanarImg< ARGBType, ? > wrapRGBA( final ImagePlus imp ) + /** + * Wraps an {@link ImagePlus} into a {@link PlanarImg} of RGBA tuples. + *+ * Under the hood, each {@link ij.process.ImageProcessor}'s backing array is + * wrapped into an {@link IntArray}. The resulting {@link List} of + * {@link ArrayDataAccess}es is used to form a {@link PlanarImg}. + *
+ * + * @param imp the {@link ImagePlus} to wrap + * @return a {@link PlanarImg} of ARGB tuples directly wrapping {@code imp} + */ + public static PlanarImg< ARGBType, ? > wrapRGBADirect(final ImagePlus imp ) { if ( imp.getType() != ImagePlus.COLOR_RGB ) - return null; + throw new IllegalArgumentException(imp + " does not contain RGB tuples!"); final IntImagePlus< ARGBType > container = new IntImagePlus<>( imp ); @@ -148,10 +179,21 @@ public class ImagePlusToImg return container; } - public static PlanarImg< FloatType, ? > wrapFloat(final ImagePlus imp ) + /** + * Wraps an {@link ImagePlus} into a {@link PlanarImg} of floats. + *+ * Under the hood, each {@link ij.process.ImageProcessor}'s backing array is + * wrapped into an {@link FloatArray}. The resulting {@link List} of + * {@link ArrayDataAccess}es is used to form a {@link PlanarImg}. + *
+ * + * @param imp the {@link ImagePlus} to wrap + * @return a {@link PlanarImg} of floats directly wrapping {@code imp} + */ + public static PlanarImg< FloatType, ? > wrapFloatDirect(final ImagePlus imp ) { if ( imp.getType() != ImagePlus.GRAY32 ) - return null; + throw new IllegalArgumentException(imp + " does not contain floats!"); final FloatImagePlus< FloatType > container = new FloatImagePlus<>( imp ); @@ -164,61 +206,99 @@ public class ImagePlusToImg return container; } - public static PlanarImg< FloatType, ? > convertFloat( final ImagePlus imp ) + /** + * Wraps an 8 bit {@link ImagePlus}, into an {@link PlanarImg}, that is backed + * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if + * needed, and caches them. + * @param image the {@link ImagePlus} to wrap. Must contain unsigned bytes. + * @return a {@link PlanarImg} wrapping {@code image}. + */ + public static PlanarImg< UnsignedByteType, ByteArray > wrapByteCached(final ImagePlus image ) { - - switch ( imp.getType() ) - { - case ImagePlus.GRAY8: - return convertToFloat( wrapByte( imp ), new NumberToFloatConverter< UnsignedByteType >() ); - case ImagePlus.GRAY16: - return convertToFloat( wrapShort( imp ), new NumberToFloatConverter< UnsignedShortType >() ); - case ImagePlus.GRAY32: - return wrapFloat( imp ); - case ImagePlus.COLOR_RGB: - return convertToFloat( wrapRGBA( imp ), new ARGBtoFloatConverter() ); - default: - throw new RuntimeException( "Only 8, 16, 32-bit and RGB supported!" ); - } + return internWrap( image, ImagePlus.GRAY8, new UnsignedByteType(), array -> new ByteArray( ( byte[] ) array ) ); } - static private class ARGBtoFloatConverter implements Converter< ARGBType, FloatType > + /** + * Wraps a 16 bit {@link ImagePlus}, into an {@link PlanarImg}, that is backed + * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if + * needed, and caches them. + * @param image the {@link ImagePlus} to wrap. Must contain unsigned shorts. + * @return a {@link PlanarImg} wrapping {@code image}. + */ + public static PlanarImg< UnsignedShortType, ShortArray > wrapShortCached(final ImagePlus image ) { - /** Luminance times alpha. */ - @Override - public void convert( final ARGBType input, final FloatType output ) - { - final int v = input.get(); - output.setReal( ( ( v >> 24 ) & 0xff ) * ( ( ( v >> 16 ) & 0xff ) * 0.299 + ( ( v >> 8 ) & 0xff ) * 0.587 + ( v & 0xff ) * 0.144 ) ); - } + return internWrap( image, ImagePlus.GRAY16, new UnsignedShortType(), array -> new ShortArray( ( short[] ) array ) ); } - static private class NumberToFloatConverter< T extends ComplexType< T > > implements Converter< T, FloatType > + /** + * Wraps a 32 bit {@link ImagePlus}, into an {@link PlanarImg}, that is backed + * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if + * needed, and caches them. + * @param image the {@link ImagePlus} to wrap. Must contain floats. + * @return a {@link PlanarImg} wrapping {@code image}. + */ + public static PlanarImg< FloatType, FloatArray > wrapFloatCached(final ImagePlus image ) { - @Override - public void convert( final T input, final FloatType output ) - { - output.setReal( input.getRealFloat() ); - } + return internWrap( image, ImagePlus.GRAY32, new FloatType(), array -> new FloatArray( ( float[] ) array ) ); } - protected static < T extends Type< T > > PlanarImg< FloatType, ?> convertToFloat( - final Img< T > input, final Converter< T, FloatType > c ) + /** + * Wraps a 24 bit {@link ImagePlus}, into an {@link PlanarImg}, that is backed + * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if + * needed, and caches them. + * @param image the {@link ImagePlus} to wrap. Must contain RGB tuples. + * @return a {@link PlanarImg} wrapping {@code image}. + */ + public static PlanarImg< ARGBType, IntArray > wrapRGBACached(final ImagePlus image ) { - final ImagePlusImg< FloatType, ? > output = new ImagePlusImgFactory<>( new FloatType() ).create( input ); - - final Cursor< T > in = input.cursor(); - final Cursor< FloatType > out = output.cursor(); + return internWrap( image, ImagePlus.COLOR_RGB, new ARGBType(), array -> new IntArray( ( int[] ) array ) ); + } - while ( in.hasNext() ) + /** + * Wraps an {@link ImagePlus}, into an {@link PlanarImg}, that is backed by a + * {@link PlanarImg}. The {@link PlanarImg} loads the planes only if needed, + * and caches them. The pixel type of the returned image depends on the type + * of the ImagePlus. + * @param image the {@link ImagePlus} to wrap + * @return a {@link PlanarImg} wrapping {@code image}. + */ + public static PlanarImg< ?, ? > wrapCached(final ImagePlus image ) + { + switch ( image.getType() ) { - in.fwd(); - out.fwd(); - - c.convert( in.get(), out.get() ); + case ImagePlus.GRAY8: + return wrapByteCached( image ); + case ImagePlus.GRAY16: + return wrapShortCached( image ); + case ImagePlus.GRAY32: + return wrapFloatCached( image ); + case ImagePlus.COLOR_RGB: + return wrapRGBACached( image ); } + throw new RuntimeException( "Only 8, 16, 32-bit and RGB supported!" ); + } - return output; + private static < T extends NativeType< T >, A extends ArrayDataAccess< A > > PlanarImg< T, A > internWrap( + final ImagePlus image, + final int expectedType, + final T type, + final Function< Object, A > createArrayAccess + ) { + if ( image.getType() != expectedType ) + throw new IllegalArgumentException(); + final ImagePlusLoader< A > loader = new ImagePlusLoader<>( image, createArrayAccess ); + final long[] dimensions = getNonTrivialDimensions( image ); + final PlanarImg< T, A > cached = new PlanarImg<>( loader, dimensions, new Fraction() ); + cached.setLinkedType( ( (NativeTypeFactory< T, A >) type.getNativeTypeFactory() ).createLinkedType( cached ) ); + // TODO: Preserve metadata + return cached; + } + + private static long[] getNonTrivialDimensions(final ImagePlus image ) + { + final LongStream xy = LongStream.of( image.getWidth(), image.getHeight() ); + final LongStream czt = LongStream.of( image.getNChannels(), image.getNSlices(), image.getNFrames() ); + return LongStream.concat( xy, czt.filter( x -> x > 1 ) ).toArray(); } private static class ImagePlusLoader< A extends ArrayDataAccess< A >> extends AbstractList< A > @@ -260,6 +340,4 @@ public int size() return image.getStackSize(); } } - - // } diff --git a/src/main/java/net/imglib2/imagej/ImagePlusToImgPlus.java b/src/main/java/net/imglib2/imagej/ImagePlusToImgPlus.java deleted file mode 100644 index 4d473fe..0000000 --- a/src/main/java/net/imglib2/imagej/ImagePlusToImgPlus.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * #%L - * ImgLib2: a general-purpose, multidimensional image processing library. - * %% - * Copyright (C) 2009 - 2025 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, - * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, - * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, - * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, - * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, - * Jean-Yves Tinevez and Michael Zinsmaier. - * %% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * #L% - */ - -package net.imglib2.imagej; - -import ij.ImagePlus; -import net.imagej.ImgPlus; -import net.imagej.axis.CalibratedAxis; -import net.imglib2.cache.Cache; -import net.imglib2.cache.ref.SoftRefLoaderCache; -import net.imglib2.imagej.img.CalibrationUtils; -import net.imglib2.img.basictypeaccess.array.*; -import net.imglib2.img.planar.PlanarImg; -import net.imglib2.type.NativeType; -import net.imglib2.type.NativeTypeFactory; -import net.imglib2.type.numeric.ARGBType; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.type.numeric.integer.UnsignedIntType; -import net.imglib2.type.numeric.integer.UnsignedShortType; -import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.util.Fraction; - -import java.util.AbstractList; -import java.util.concurrent.ExecutionException; -import java.util.function.Function; -import java.util.stream.LongStream; - -/** - * Provides convenience functions to wrap ImageJ 1.x data structures as ImageJ ones. - * Many functions wrap lazily, using imglib2-caches. These functions load - * planes on-demand, which is especially useful when wrapping a virtual stack. - * - * - * @author Stephan Preibisch - * @author Stephan Saalfeld - * @author Matthias Arzt - */ -public class ImagePlusToImgPlus -{ - - /** - * Wraps a 8 bit {@link ImagePlus}, into an {@link ImgPlus}, that is backed - * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if - * needed, and caches them. The axes of the returned image are set according - * to the calibration of the given image. - */ - public static ImgPlus< UnsignedByteType > wrapByte(final ImagePlus image ) - { - return internWrap( image, ImagePlus.GRAY8, new UnsignedByteType(), array -> new ByteArray( ( byte[] ) array ) ); - } - - /** - * Wraps a 16 bit {@link ImagePlus}, into an {@link ImgPlus}, that is backed - * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if - * needed, and caches them. The axes of the returned image are set according - * to the calibration of the given image. - */ - public static ImgPlus< UnsignedShortType > wrapShort(final ImagePlus image ) - { - return internWrap( image, ImagePlus.GRAY16, new UnsignedShortType(), array -> new ShortArray( ( short[] ) array ) ); - } - - /** - * Wraps a 32 bit {@link ImagePlus}, into an {@link ImgPlus}, that is backed - * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if - * needed, and caches them. The axes of the returned image are set according - * to the calibration of the given image. - */ - public static ImgPlus< FloatType > wrapFloat(final ImagePlus image ) - { - return internWrap( image, ImagePlus.GRAY32, new FloatType(), array -> new FloatArray( ( float[] ) array ) ); - } - - /** - * Wraps a 32 bit {@link ImagePlus}, into an {@link ImgPlus}, that is backed - * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if - * needed, and caches them. The axes of the returned image are set according - * to the calibration of the given image. - */ - public static ImgPlus< UnsignedIntType > wrapInt(final ImagePlus image ) - { - return internWrap( image, ImagePlus.COLOR_RGB, new UnsignedIntType(), array -> new IntArray( ( int[] ) array ) ); - } - - /** - * Wraps a 24 bit {@link ImagePlus}, into an {@link ImgPlus}, that is backed - * by a {@link PlanarImg}. The {@link PlanarImg} loads the planes only if - * needed, and caches them. The axes of the returned image are set according - * to the calibration of the given image. - */ - public static ImgPlus< ARGBType > wrapRGBA(final ImagePlus image ) - { - return internWrap( image, ImagePlus.COLOR_RGB, new ARGBType(), array -> new IntArray( ( int[] ) array ) ); - } - - /** - * Wraps an {@link ImagePlus}, into an {@link ImgPlus}, that is backed by a - * {@link PlanarImg}. The {@link PlanarImg} loads the planes only if needed, - * and caches them. The pixel type of the returned image depends on the type - * of the ImagePlus. The axes of the returned image are set according to the - * calibration of the given image. - */ - public static ImgPlus< ? > wrap(final ImagePlus image ) - { - switch ( image.getType() ) - { - case ImagePlus.GRAY8: - return wrapByte( image ); - case ImagePlus.GRAY16: - return wrapShort( image ); - case ImagePlus.GRAY32: - return wrapFloat( image ); - case ImagePlus.COLOR_RGB: - return wrapRGBA( image ); - } - throw new RuntimeException( "Only 8, 16, 32-bit and RGB supported!" ); - } - - private static < T extends NativeType< T >, A extends ArrayDataAccess< A > > ImgPlus< T > internWrap(final ImagePlus image, final int expectedType, final T type, final Function< Object, A > createArrayAccess ) - { - if ( image.getType() != expectedType ) - throw new IllegalArgumentException(); - final ImagePlusLoader< A > loader = new ImagePlusLoader<>( image, createArrayAccess ); - final long[] dimensions = getNonTrivialDimensions( image ); - final PlanarImg< T, A > cached = new PlanarImg<>( loader, dimensions, new Fraction() ); - cached.setLinkedType( ( (NativeTypeFactory< T, A >) type.getNativeTypeFactory() ).createLinkedType( cached ) ); - final CalibratedAxis[] axes = CalibrationUtils.getNonTrivialAxes( image ); - return new ImgPlus<>( cached, image.getTitle(), axes ); - } - - private static long[] getNonTrivialDimensions(final ImagePlus image ) - { - final LongStream xy = LongStream.of( image.getWidth(), image.getHeight() ); - final LongStream czt = LongStream.of( image.getNChannels(), image.getNSlices(), image.getNFrames() ); - return LongStream.concat( xy, czt.filter( x -> x > 1 ) ).toArray(); - } - - private static class ImagePlusLoader< A extends ArrayDataAccess< A >> extends AbstractList< A > - { - private final ImagePlus image; - - private final Cache< Integer, A > cache; - - private final Function< Object, A > arrayFactory; - - public ImagePlusLoader( final ImagePlus image, final Function< Object, A > arrayFactory ) - { - this.arrayFactory = arrayFactory; - this.image = image; - cache = new SoftRefLoaderCache< Integer, A >().withLoader( this::load ); - } - - @Override - public A get( final int key ) - { - try - { - return cache.get( key ); - } - catch ( final ExecutionException e ) - { - throw new RuntimeException( e ); - } - } - - private A load( final Integer key ) - { - return arrayFactory.apply( image.getStack().getPixels( key + 1 ) ); - } - - @Override - public int size() - { - return image.getStackSize(); - } - } - - // -} diff --git a/src/main/java/net/imglib2/imagej/ImgPlusToImagePlus.java b/src/main/java/net/imglib2/imagej/ImgPlusToImagePlus.java deleted file mode 100644 index 99941ec..0000000 --- a/src/main/java/net/imglib2/imagej/ImgPlusToImagePlus.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * #%L - * ImgLib2: a general-purpose, multidimensional image processing library. - * %% - * Copyright (C) 2009 - 2025 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, - * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, - * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, - * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, - * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, - * Jean-Yves Tinevez and Michael Zinsmaier. - * %% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * #L% - */ - -package net.imglib2.imagej; - -import java.util.Arrays; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import net.imagej.ImgPlus; -import net.imagej.axis.Axes; -import net.imagej.axis.AxisType; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.imagej.img.*; -import net.imglib2.transform.integer.MixedTransform; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.ARGBType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.MixedTransformView; -import net.imglib2.view.Views; - -import ij.ImagePlus; - -public class ImgPlusToImagePlus -{ - // TODO move to image-legacy - public static ImagePlus wrap( final ImgPlus< ? extends RealType< ? > > imgPlus, final boolean mergeRGB ) - { - final ImgPlus< ? > imgPlus2 = mergeRGB && ImgPlusViews.canFuseColor( imgPlus ) ? ImgPlusViews.fuseColor( imgPlus ) : imgPlus; - return wrap( imgPlus2 ); - } - - /** - * Wraps an {@link ImgPlus} into an {@link ImagePlus}. The image can be - * {@link RealType} or {@link ARGBType}. The {@link ImagePlus} is backed by - * a special {@link ij.VirtualStack}, which copies an plane from the given - * image, instead of it plane from a file. - *- * Only up to five dimensions are support. Axes can might be arbitrary. The - * image title and calibration are derived from the given image. - * - * @see ArrayImgToImagePlus - * @see ImgPlusToImagePlus - */ - public static ImagePlus wrap( final ImgPlus< ? > imgPlus ) - { - return wrap( imgPlus, ImgPlusToImagePlus::createVirtualStack ); - } - - /** - * Similar to {@link #wrap(ImgPlus)}, but works only for {@link ImgPlus} of - * {@link BitType}. The pixel values of 0 and 1 are scaled to 0 and 255. - * - * @see ArrayImgToImagePlus - * @see ImgPlusToImagePlus - */ - public static ImagePlus wrapAndScaleBitType( final ImgPlus< BitType > imgPlus ) - { - return wrap( imgPlus, ImgPlusToImagePlus::createVirtualStackBits ); - } - - private static < T > ImagePlus wrap( ImgPlus< T > imgPlus, final Function< RandomAccessibleInterval< T >, ImageJVirtualStack>> imageStackWrapper ) - { - imgPlus = ImgPlusViews.fixAxes( imgPlus ); - final RandomAccessibleInterval< T > sorted = ensureXYCZT( imgPlus ); - final ImageJVirtualStack> stack = imageStackWrapper.apply( sorted ); - final ImagePlus result = new ImagePlus( imgPlus.getName(), stack ); - // NB: setWritable after the ImagePlus is created. Otherwise a useless stack.setPixels(...) call would be performed. - stack.setWritable( true ); - result.setDimensions( ( int ) sorted.dimension( 2 ), ( int ) sorted.dimension( 3 ), ( int ) sorted.dimension( 4 ) ); - CalibrationUtils.copyCalibrationToImagePlus( imgPlus, result ); - return result; - } - - private static ImageJVirtualStack> createVirtualStackBits( final RandomAccessibleInterval< BitType > sorted ) - { - return ImageJVirtualStackUnsignedByte.wrapAndScaleBitType( sorted ); - } - - private static ImageJVirtualStack> createVirtualStack( final RandomAccessibleInterval< ? > rai ) - { - final Object type = rai.randomAccess().get(); - if ( type instanceof RealType ) - return createVirtualStackRealType( cast( rai ) ); - if ( type instanceof ARGBType ) - return ImageJVirtualStackARGB.wrap( cast( rai ) ); - throw new IllegalArgumentException( "Unsupported type" ); - } - - private static < T > T cast( final Object in ) - { - @SuppressWarnings( "unchecked" ) - final - T out = ( T ) in; - return out; - } - - private static ImageJVirtualStack< ? > createVirtualStackRealType( final RandomAccessibleInterval< ? extends RealType< ? > > rai ) - { - final RealType< ? extends RealType< ? > > type = rai.randomAccess().get(); - final int bitDepth = type.getBitsPerPixel(); - final boolean isSigned = type.getMinValue() < 0; - - if ( bitDepth <= 8 && !isSigned ) - return ImageJVirtualStackUnsignedByte.wrap( rai ); - if ( bitDepth <= 16 && !isSigned ) - return ImageJVirtualStackUnsignedShort.wrap( rai ); - - // other types translated as 32-bit float data - return ImageJVirtualStackFloat.wrap( rai ); - } - - private static < T > RandomAccessibleInterval< T > ensureXYCZT( final ImgPlus< T > imgPlus ) - { - final int[] axes = getPermutation( getAxes( imgPlus ) ); - return permute( imgPlus, axes ); - } - - private static int[] getPermutation( final List< AxisType > axes ) - { - return axes.stream().mapToInt( axis -> { - final int index = imagePlusAxisOrder.indexOf( axis ); - if ( index < 0 ) - throw new IllegalArgumentException( "Unsupported axis type: " + axis ); - return index; - } ).toArray(); - } - - private static List< AxisType > getAxes( final ImgPlus< ? > imgPlus ) - { - return IntStream.range( 0, imgPlus.numDimensions() ) - .mapToObj( i -> imgPlus.axis( i ).type() ) - .collect( Collectors.toList() ); - } - - private static < T > RandomAccessibleInterval< T > permute( final ImgPlus< T > imgPlus, int[] axes ) - { - boolean inNaturalOrder = true; - final boolean[] matchedDimensions = new boolean[ 5 ]; - final long[] min = new long[ 5 ], max = new long[ 5 ]; - for ( int d = 0; d < axes.length; d++ ) - { - final int index = axes[ d ]; - matchedDimensions[ index ] = true; - min[ index ] = imgPlus.min( d ); - max[ index ] = imgPlus.max( d ); - if ( index != d ) - inNaturalOrder = false; - } - - if ( imgPlus.numDimensions() != 5 ) - inNaturalOrder = false; - if ( inNaturalOrder ) - return imgPlus; - - axes = Arrays.copyOf( axes, 5 ); - RandomAccessibleInterval< T > rai = imgPlus; - // pad the image to at least 5D - for ( int i = 0; i < 5; i++ ) - { - if ( matchedDimensions[ i ] ) - continue; - axes[ rai.numDimensions() ] = i; - min[ i ] = 0; - max[ i ] = 0; - rai = Views.addDimension( rai, 0, 0 ); - } - - // permute the axis order to XYCZT... - final MixedTransform t = new MixedTransform( rai.numDimensions(), 5 ); - t.setComponentMapping( axes ); - return Views.interval( new MixedTransformView<>( rai, t ), min, max ); - } - - private static final List< AxisType > imagePlusAxisOrder = - Arrays.asList( Axes.X, Axes.Y, Axes.CHANNEL, Axes.Z, Axes.TIME ); -} diff --git a/src/main/java/net/imglib2/imagej/ImgPlusViews.java b/src/main/java/net/imglib2/imagej/ImgPlusViews.java deleted file mode 100644 index 909f242..0000000 --- a/src/main/java/net/imglib2/imagej/ImgPlusViews.java +++ /dev/null @@ -1,220 +0,0 @@ -/*- - * #%L - * ImgLib2: a general-purpose, multidimensional image processing library. - * %% - * Copyright (C) 2009 - 2025 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, - * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, - * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, - * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, - * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, - * Jean-Yves Tinevez and Michael Zinsmaier. - * %% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * #L% - */ -package net.imglib2.imagej; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.function.IntUnaryOperator; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import net.imagej.ImgPlus; -import net.imagej.axis.Axes; -import net.imagej.axis.AxisType; -import net.imagej.axis.CalibratedAxis; -import net.imglib2.RandomAccessible; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.converter.Converters; -import net.imglib2.img.Img; -import net.imglib2.img.ImgView; -import net.imglib2.type.Type; -import net.imglib2.type.numeric.ARGBType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.util.Util; -import net.imglib2.view.Views; -import net.imglib2.view.composite.Composite; - -// TODO: migrate to imagej-common -public class ImgPlusViews -{ - /** - * Same as {@link Views#hyperSlice(RandomAccessible, int, long)}. But works - * on {@link ImgPlus} and manages axes information too. - */ - public static < T extends Type< T > > ImgPlus< T > hyperSlice( final ImgPlus< T > image, final int d, final long position ) - { - final IntUnaryOperator axesMapping = i -> ( i < d ) ? i : i + 1; - return newImgPlus( image, Views.hyperSlice( image.getImg(), d, position ), axesMapping ); - } - - /** - * Same as {@link Views#permute(RandomAccessible, int, int)}. But works on - * {@link ImgPlus}. But works on {@link ImgPlus} and manages axes - * information too. - */ - public static < T extends Type< T > > ImgPlus< T > permute( final ImgPlus< T > image, final int fromAxis, final int toAxis ) - { - if ( fromAxis == toAxis ) - return image; - final IntUnaryOperator axesMapping = i -> { - if ( i == fromAxis ) - return toAxis; - if ( i == toAxis ) - return fromAxis; - return i; - }; - return newImgPlus( image, Views.permute( image.getImg(), fromAxis, toAxis ), axesMapping ); - } - - /** - * Permutes the axes of the image. One axis is moved, while the order of the - * other axes is preserved. If an image has axis order XYCZT, fromAxis=2 and - * toAxis=4, then the returned axis order is XYZTC. - */ - public static < T extends Type< T > > ImgPlus< T > moveAxis( final ImgPlus< T > image, final int fromAxis, final int toAxis ) - { - if ( fromAxis == toAxis ) - return image; - final int direction = toAxis > fromAxis ? 1 : -1; - ImgPlus< T > res = image; - for ( int i = fromAxis; i != toAxis; i += direction ) - res = permute( res, i, i + direction ); - return res; - } - - /** - * Indicates it {@link #fuseColor(ImgPlus)} can by used. - */ - public static boolean canFuseColor( final ImgPlus< ? extends RealType< ? > > image ) - { - final int d = image.dimensionIndex( Axes.CHANNEL ); - return d >= 0 && image.dimension( d ) == 3; - } - - /** - * Generates a color image from a gray scale image that has a color axes of - * dimension 3. - */ - public static ImgPlus< ARGBType > fuseColor( final ImgPlus< ? extends RealType< ? > > image ) - { - final int d = image.dimensionIndex( Axes.CHANNEL ); - final RandomAccessibleInterval< ARGBType > colors = fuseColor( image.getImg(), d ); - final IntUnaryOperator axisMapping = i -> ( i < d ) ? i : i + 1; - return newImgPlus( image, colors, axisMapping ); - } - - private static RandomAccessibleInterval< ARGBType > fuseColor( final Img< ? extends RealType< ? > > image, final int d ) - { - if ( d < 0 || image.dimension( d ) != 3 ) - throw new IllegalArgumentException(); - return Converters.convert( - Views.collapse( Views.moveAxis( image, d, image.numDimensions() - 1 ) ), - ImgPlusViews::convertToColor, - new ARGBType() ); - } - - /** - * Change the axis types of an image, such that each axis is uniquely typed - * as X, Y, Z, channel or time. Existing unique axis of type: X, Y, Z, - * channel or time are preserved. - */ - public static < T > ImgPlus< T > fixAxes( final ImgPlus< T > in ) - { - final List< AxisType > newAxisTypes = fixAxes( getAxes( in ) ); - final CalibratedAxis[] newAxes = IntStream.range( 0, in.numDimensions() ).mapToObj( i -> { - final CalibratedAxis newAxis = in.axis( i ).copy(); - newAxis.setType( newAxisTypes.get( i ) ); - return newAxis; - } ).toArray( CalibratedAxis[]::new ); - return new ImgPlus<>( in.getImg(), in.getName(), newAxes ); - } - - // -- Helper methods -- - - private static < T extends Type< T > > ImgPlus< T > newImgPlus( final ImgPlus< ? > image, final RandomAccessibleInterval< T > newContent, final IntUnaryOperator axesMapping ) - { - final T type = Util.getTypeFromInterval( newContent ); - final Img< T > newImg = ImgView.wrap( newContent, image.factory().imgFactory( type ) ); - final ImgPlus< T > result = new ImgPlus<>( newImg, image.getName() ); - for ( int i = 0; i < result.numDimensions(); i++ ) - result.setAxis( image.axis( axesMapping.applyAsInt( i ) ).copy(), i ); - return result; - } - - private static void convertToColor( final Composite< ? extends RealType< ? > > in, final ARGBType out ) - { - out.set( ARGBType.rgba( toInt( in.get( 0 ) ), toInt( in.get( 1 ) ), toInt( in.get( 2 ) ), 255 ) ); - } - - private static int toInt( final RealType< ? > realType ) - { - return ( int ) realType.getRealFloat(); - } - - private static final List< AxisType > imagePlusAxisOrder = - Arrays.asList( Axes.X, Axes.Y, Axes.CHANNEL, Axes.Z, Axes.TIME ); - - private static List< AxisType > fixAxes( final List< AxisType > in ) - { - final List< AxisType > unusedAxis = new ArrayList<>( imagePlusAxisOrder ); - unusedAxis.removeAll( in ); - final Predicate< AxisType > isDuplicate = createIsDuplicatePredicate(); - final Predicate< AxisType > replaceIf = axis -> isDuplicate.test( axis ) || !imagePlusAxisOrder.contains( axis ); - final Iterator< AxisType > iterator = unusedAxis.iterator(); - final Supplier< AxisType > replacements = () -> iterator.hasNext() ? iterator.next() : Axes.unknown(); - return replaceMatches( in, replaceIf, replacements ); - } - - // NB: Package-private to allow tests. - static List< AxisType > getAxes( final ImgPlus< ? > in ) - { - return IntStream.range( 0, in.numDimensions() ) - .mapToObj( in::axis ).map( CalibratedAxis::type ) - .collect( Collectors.toList() ); - } - - // NB: Package-private to allow tests. - static < T > Predicate< T > createIsDuplicatePredicate() - { - final Set< T > before = new HashSet<>(); - return element -> { - final boolean isDuplicate = before.contains( element ); - if ( !isDuplicate ) - before.add( element ); - return isDuplicate; - }; - } - - // NB: Package-private to allow tests. - static < T > List< T > replaceMatches( final List< T > in, final Predicate< T > predicate, final Supplier< T > replacements ) - { - return in.stream().map( value -> predicate.test( value ) ? replacements.get() : value ).collect( Collectors.toList() ); - } -} diff --git a/src/main/java/net/imglib2/imagej/RAIToImagePlus.java b/src/main/java/net/imglib2/imagej/RAIToImagePlus.java index 0ce5fa3..4440336 100644 --- a/src/main/java/net/imglib2/imagej/RAIToImagePlus.java +++ b/src/main/java/net/imglib2/imagej/RAIToImagePlus.java @@ -2,35 +2,42 @@ import ij.ImagePlus; import ij.VirtualStack; -import net.imagej.ImgPlus; import net.imglib2.Dimensions; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.Sampler; import net.imglib2.converter.ComplexPowerGLogFloatConverter; import net.imglib2.converter.Converter; import net.imglib2.converter.Converters; -import net.imglib2.converter.RealUnsignedByteConverter; +import net.imglib2.converter.readwrite.SamplerConverter; import net.imglib2.imagej.img.*; +import net.imglib2.img.basictypeaccess.IntAccess; +import net.imglib2.type.BooleanType; +import net.imglib2.type.NativeType; import net.imglib2.type.logic.BitType; import net.imglib2.type.numeric.*; import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.type.numeric.integer.UnsignedShortType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.util.Cast; +import net.imglib2.view.Views; +import net.imglib2.view.composite.Composite; +import net.imglib2.view.composite.GenericComposite; import java.util.concurrent.ExecutorService; +import java.util.function.Function; /** * Utilities for wrapping {@link RandomAccessibleInterval}s * into {@link ImagePlus}es. *
- * Under the hood, conversion utilizes {@link ImageJVirtualStack}, - * meaning the resulting objects are read-only unless - * {@link ImageJVirtualStack#setWritable(boolean)} is called. + * Under the hood, conversion utilizes {@link ImageJVirtualStack}, allowing + * read/write operations to the backing {@link RandomAccessibleInterval}. *
* * @author Tobis Pietzsch * @author Stephan Preibisch * @author Stephan Saalfeld + * @author Gabriel Selzer */ public class RAIToImagePlus { @@ -44,6 +51,7 @@ private RAIToImagePlus() {} * or ImagePlus.COLOR_RGB) is inferred from the generic type of the input * {@link RandomAccessibleInterval}. * + * @param+ * Note that this method scales the result such that {@code true} values in {@code img} are mapped to {@code 255} in the resulting {@code ImagePlus}. + *
+ * + * @param element type in source image + * @param img the {@link RandomAccessibleInterval} to wrap + * @param title the name assigned to the resulting {@link ImagePlus} + * @param service the {@link ExecutorService} used for processing. + * @return an {@link ImagePlus} wrapping {@code img} + * @see #wrapBoolean(RandomAccessibleInterval, String, ExecutorService) for wrapping without scaling. + */ + public static < B extends BooleanType > ImagePlus wrapAndScaleBoolean( + final RandomAccessibleInterval img, + final String title, + final ExecutorService service ) + { + return internalWrap( // + img, // + ImageJVirtualStackUnsignedByte::wrapAndScaleBoolean, // + title, // + service // + ); + } + + /** + * Create a single channel 8-bit unsigned integer {@link ImagePlus} from a + * {@link BooleanType} {@link RandomAccessibleInterval} using a custom + * {@link Converter}. + *+ * Note that this method scales the result such that {@code true} values in {@code img} are mapped to {@code 255} in the resulting {@code ImagePlus}. + *
+ * + * @param element type in source image + * @param img the {@link RandomAccessibleInterval} to wrap + * @param title the name assigned to the resulting {@link ImagePlus} + * @return an {@link ImagePlus} wrapping {@code img} + * @see #wrapBoolean(RandomAccessibleInterval, String) for wrapping without scaling. + */ + public static < B extends BooleanType > ImagePlus wrapAndScaleBoolean( + final RandomAccessibleInterval img, + final String title ) + { + return wrapAndScaleBoolean( img, title, null ); + } + + private static
+ * Only up to five dimensions are supported. Axes can might be arbitrary. The
+ * image title and calibration are derived from the given image.
+ *
+ * @param rai the {@link RandomAccessibleInterval} to convert
+ * @param title the title to assign to the output
+ * @return an {@link ImagePlus} wrapping {@code rai}
+ * @see ArrayImgToImagePlus
+ */
+ public static ImagePlus wrapVirtualStack(final RandomAccessibleInterval< ? > rai, final String title )
+ {
+ return wrapVirtualStack( rai, title, RAIToImagePlus::createVirtualStack );
+ }
+
+ /**
+ * Similar to {@link #wrapVirtualStack(RandomAccessibleInterval, String)}, but works only
+ * for {@link RandomAccessibleInterval}s of {@link BitType}. The pixel values
+ * of 0 and 1 are scaled to 0 and 255.
+ *
+ * @param rai the {@link RandomAccessibleInterval} to convert. Must contain bits.
+ * @param title the title to assign to the output
+ * @return an {@link ImagePlus} wrapping {@code rai}
+ * @see ArrayImgToImagePlus
+ */
+ public static > ImagePlus wrapVirtualStackAndScaleBooleanType(final RandomAccessibleInterval< B > rai , final String title )
+ {
+ return wrapVirtualStack( rai, title, RAIToImagePlus::createVirtualStackBools);
+ }
+
+ private static < T > ImagePlus wrapVirtualStack(RandomAccessibleInterval< T > rai, final String title, final Function< RandomAccessibleInterval< T >, ImageJVirtualStack>> imageStackWrapper )
+ {
+ final ImageJVirtualStack> stack = imageStackWrapper.apply( rai );
+ final ImagePlus result = new ImagePlus( title, stack );
+ // NB: setWritable after the ImagePlus is created. Otherwise a useless stack.setPixels(...) call would be performed.
+ stack.setWritable( true );
+ return result;
+ }
+
+ private static > ImageJVirtualStack> createVirtualStackBools(final RandomAccessibleInterval< B > sorted )
+ {
+ return ImageJVirtualStackUnsignedByte.wrapAndScaleBoolean( sorted );
+ }
+
+ private static ImageJVirtualStack> createVirtualStack(final RandomAccessibleInterval< ? > rai )
+ {
+ final Object type = rai.randomAccess().get();
+ if ( type instanceof RealType )
+ return createVirtualStackRealType( cast( rai ) );
+ if ( type instanceof ARGBType )
+ return ImageJVirtualStackARGB.wrap( cast( rai ) );
+ throw new IllegalArgumentException( "Unsupported type" );
+ }
+
+ private static < T > T cast(final Object in )
+ {
+ @SuppressWarnings( "unchecked" )
+ final
+ T out = ( T ) in;
+ return out;
+ }
+
+ private static ImageJVirtualStack< ? > createVirtualStackRealType(final RandomAccessibleInterval< ? extends RealType< ? > > rai )
+ {
+ final RealType< ? extends RealType< ? > > type = rai.randomAccess().get();
+ final int bitDepth = type.getBitsPerPixel();
+ final boolean isSigned = type.getMinValue() < 0;
+
+ if ( bitDepth <= 8 && !isSigned )
+ return ImageJVirtualStackUnsignedByte.wrap( rai );
+ if ( bitDepth <= 16 && !isSigned )
+ return ImageJVirtualStackUnsignedShort.wrap( rai );
+
+ // other types translated as 32-bit float data
+ return ImageJVirtualStackFloat.wrap( rai );
+ }
+
+ private static class RGBAConverter
- * (in ImageJ that would be a hyperstack of {@link ByteProcessor}s)
- *
- * (in ImageJ that would be a hyperstack of {@link ByteProcessor}s)
- *
- * (in ImageJ that would be a hyperstack of {@link ShortProcessor}s)
- *
- * (in ImageJ that would be a hyperstack of {@link ShortProcessor}s)
- *
- * (In ImageJ that would be a hyperstack of {@link ColorProcessor}s. The
- * integers, however, would be displayed as ARGB unsigned byte channels and
- * thus look weird.)
- *
- * (In ImageJ that would be a hyperstack of {@link ColorProcessor}s. The
- * integers, however, would be displayed as ARGB unsigned byte channels and
- * thus look weird.)
- *
- * (in ImageJ that would be a hyperstack of {@link FloatProcessor}s)
- *
- * (in ImageJ that would be a hyperstack of {@link ColorProcessor}s)
- *
- * (In ImageJ that would be a hyperstack of {@link FloatProcessor}s with
- * real and imaginary numbers interleaved in the plane. That means it would
- * look weird.)
- *
* The returned {@link ImagePlus} uses the same pixel buffer as the given
* image. Changes to the {@link ImagePlus} are therefore correctly reflected
- * in the {@link ImgPlus}. The title and calibration are derived from the
+ * in the {@link ArrayImg}. The title and calibration are derived from the
* given image.
*
- * Use {@link #isSupported(ImgPlus)} to check if an {@link ImagePlus} is
+ * Use {@link #isSupported(Object)} to check if an {@link ImagePlus} is
* supported.
*
+ * @param img the {@link ArrayImg} to convert
+ * @param name the {@link String} title to assign to the result
+ * @return an {@link ImagePlus} wrapping the data in {@code img}
* @see PlanarImgToImagePlus
- * @see ImgPlusToImagePlus
+ * @see CellImgToImagePlus
*/
- public static ImagePlus wrap( ImgPlus< ? > imgPlus )
+ public static ImagePlus wrap(ArrayImg< ?, ? extends ArrayDataAccess> > img, String name)
{
- imgPlus = ImgPlusViews.fixAxes( imgPlus );
- final Img< ? > img = imgPlus.getImg();
- if ( !( img instanceof ArrayImg ) )
- throw new IllegalArgumentException( "Expecting ArrayImg" );
- final ArrayImg< ?, ArrayDataAccess< ? > > arrayImg = ( ArrayImg< ?, ArrayDataAccess< ? > > ) img;
final int sizeX = ( int ) img.dimension( 0 );
final int sizeY = ( int ) img.dimension( 1 );
- final Object pixels = arrayImg.update( null ).getCurrentStorageArray();
+ final Object pixels = img.update( null ).getCurrentStorageArray();
final ImageProcessor processor = ImageProcessorUtils.createImageProcessor( pixels, sizeX, sizeY, null );
- final ImagePlus imagePlus = new ImagePlus( imgPlus.getName(), processor );
- CalibrationUtils.copyCalibrationToImagePlus( imgPlus, imagePlus );
- return imagePlus;
- }
-
- private static boolean checkAxis( final List< AxisType > axes )
- {
- return axes.size() == 2 && axes.get( 0 ) == Axes.X && axes.get( 1 ) == Axes.Y;
- }
-
- private static List< AxisType > getAxes( final ImgPlus< ? > img )
- {
- return IntStream.range( 0, img.numDimensions() ).mapToObj( img::axis ).map( CalibratedAxis::type ).collect( Collectors.toList() );
+ return new ImagePlus( name, processor );
}
}
diff --git a/src/main/java/net/imglib2/imagej/img/CalibrationUtils.java b/src/main/java/net/imglib2/imagej/img/CalibrationUtils.java
deleted file mode 100644
index bc222c0..0000000
--- a/src/main/java/net/imglib2/imagej/img/CalibrationUtils.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*-
- * #%L
- * ImgLib2: a general-purpose, multidimensional image processing library.
- * %%
- * Copyright (C) 2009 - 2025 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
- * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
- * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
- * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
- * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
- * Jean-Yves Tinevez and Michael Zinsmaier.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package net.imglib2.imagej.img;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import net.imagej.ImgPlus;
-import net.imagej.axis.Axes;
-import net.imagej.axis.CalibratedAxis;
-import net.imagej.axis.DefaultLinearAxis;
-
-import ij.ImagePlus;
-import ij.measure.Calibration;
-
-public class CalibrationUtils
-{
- /**
- * Sets the {@link Calibration} data on the provided {@link ImagePlus}.
- */
- public static void copyCalibrationToImagePlus( final ImgPlus< ? > imgPlus, final ImagePlus imp )
- {
- final Calibration calibration = imp.getCalibration();
- final int xIndex = imgPlus.dimensionIndex( Axes.X );
- final int yIndex = imgPlus.dimensionIndex( Axes.Y );
- final int zIndex = imgPlus.dimensionIndex( Axes.Z );
- final int tIndex = imgPlus.dimensionIndex( Axes.TIME );
-
- if ( xIndex >= 0 )
- {
- calibration.pixelWidth = imgPlus.averageScale( xIndex );
- final CalibratedAxis axis = imgPlus.axis( xIndex );
- calibration.xOrigin = axis.calibratedValue( 0 );
- calibration.setXUnit( axis.unit() );
- }
- if ( yIndex >= 0 )
- {
- calibration.pixelHeight = imgPlus.averageScale( yIndex );
- final CalibratedAxis axis = imgPlus.axis( yIndex );
- calibration.yOrigin = axis.calibratedValue( 0 );
- calibration.setYUnit( axis.unit() );
- }
- if ( zIndex >= 0 )
- {
- calibration.pixelDepth = imgPlus.averageScale( zIndex );
- final CalibratedAxis axis = imgPlus.axis( zIndex );
- calibration.zOrigin = axis.calibratedValue( 0 );
- calibration.setZUnit( axis.unit() );
- }
- if ( tIndex >= 0 )
- {
- calibration.frameInterval = imgPlus.averageScale( tIndex );
- calibration.setTimeUnit( imgPlus.axis( tIndex ).unit() );
- }
- }
-
- public static CalibratedAxis[] getNonTrivialAxes( final ImagePlus image )
- {
- final List< CalibratedAxis > result = new ArrayList<>();
- final Calibration calibration = image.getCalibration();
- result.add( new DefaultLinearAxis( Axes.X, calibration.getXUnit(), calibration.pixelWidth, calibration.xOrigin ) );
- result.add( new DefaultLinearAxis( Axes.Y, calibration.getYUnit(), calibration.pixelHeight, calibration.yOrigin ) );
- if ( image.getNChannels() > 1 )
- result.add( new DefaultLinearAxis( Axes.CHANNEL ) );
- if ( image.getNSlices() > 1 )
- result.add( new DefaultLinearAxis( Axes.Z, calibration.getZUnit(), calibration.pixelDepth, calibration.zOrigin ) );
- if ( image.getNFrames() > 1 )
- result.add( new DefaultLinearAxis( Axes.TIME, calibration.getTimeUnit(), calibration.frameInterval ) );
- return result.toArray( new CalibratedAxis[ 0 ] );
- }
-}
diff --git a/src/main/java/net/imglib2/imagej/img/CellImgToImagePlus.java b/src/main/java/net/imglib2/imagej/img/CellImgToImagePlus.java
index de7e473..292ba0c 100644
--- a/src/main/java/net/imglib2/imagej/img/CellImgToImagePlus.java
+++ b/src/main/java/net/imglib2/imagej/img/CellImgToImagePlus.java
@@ -35,17 +35,17 @@
package net.imglib2.imagej.img;
import ij.ImagePlus;
-import net.imagej.ImgPlus;
import net.imglib2.Dimensions;
import net.imglib2.FinalDimensions;
import net.imglib2.RandomAccess;
import net.imglib2.RandomAccessible;
-import net.imglib2.imagej.ImgPlusToImagePlus;
import net.imglib2.img.Img;
+import net.imglib2.img.array.ArrayImg;
import net.imglib2.img.basictypeaccess.array.ArrayDataAccess;
import net.imglib2.img.cell.AbstractCellImg;
import net.imglib2.img.cell.Cell;
import net.imglib2.img.cell.CellGrid;
+import net.imglib2.img.cell.CellImg;
import net.imglib2.img.planar.PlanarImg;
import net.imglib2.type.NativeType;
import net.imglib2.type.NativeTypeFactory;
@@ -62,7 +62,6 @@
* cells contains exactly one image plane), and certain pixel types:
* UnsignedByteType, UnsignedShortType, ARGBType and FloatType.
*
- * @see ImgPlusToImagePlus
* @see PlanarImgToImagePlus
* @see ArrayImgToImagePlus
*/
@@ -70,18 +69,25 @@ public class CellImgToImagePlus
{
/**
- * Returns true if {@link #wrap(ImgPlus)} supports the given image.
+ * Returns true, if {@link #wrap(CellImg, String)} supports the given image.
+ * @param obj an {@link Object} that may be supported by {@code wrap}
+ * @return {@code true} iff {@code obj} can be converted into an {@link ImagePlus}.
*/
- public static boolean isSupported( ImgPlus< ? > imgPlus )
+ public static boolean isSupported( Object obj )
{
- return isCellImgWithPlanarCells( imgPlus.getImg() ) &&
- PlanarImgToImagePlus.isSupported( toPlanarImgPlus( imgPlus ) );
+ if (!(obj instanceof CellImg))
+ return false;
+ CellImg, ?> img = (CellImg, ?>) obj;
+ if (!(img.update(img.cursor()) instanceof ArrayDataAccess))
+ return false;
+ return isCellImgWithPlanarCells( img ) &&
+ PlanarImgToImagePlus.isSupported( toPlanarImgPlus( (CellImg extends NativeType, ? extends ArrayDataAccess>) img ) );
}
- private static boolean isCellImgWithPlanarCells( Img< ? > imgPlus )
+ private static boolean isCellImgWithPlanarCells( Img< ? > img )
{
- return ( imgPlus instanceof AbstractCellImg ) &&
- areCellsPlanar( ( ( AbstractCellImg ) imgPlus ).getCellGrid() );
+ return ( img instanceof AbstractCellImg ) &&
+ areCellsPlanar( ( ( AbstractCellImg, ?, ?, ?> ) img ).getCellGrid() );
}
private static boolean areCellsPlanar( CellGrid cellGrid )
@@ -100,21 +106,16 @@ private static boolean areCellsPlanar( CellGrid cellGrid )
* by an {@link AbstractCellImg} with planar cells. The pixel type must be
* UnsignedByte-, UnsignedShort-, ARGB- or FloatType. First two axes must be
* X and Y (or unknown).
+ * @param img the {@link CellImg} to convert
+ * @param name the {@link String} title to assign to the result
+ * @return an {@link ImagePlus} wrapping the data in {@code img}
*/
- public static ImagePlus wrap( ImgPlus< ? > imgPlus )
+ public static
* The image must be {@link UnsignedByteType}, {@link UnsignedShortType},
* {@link ARGBType} or {@link FloatType}. Only up to five dimensions are
- * support. Axes oder must start with X, Y axes. Channel, Time and Z axes
- * might follow in arbitrary order. The image title and calibration are
- * derived from the given image.
+ * supported. Axes are presumed to start with X, Y. Channel, Z, and Time
+ * axes are assumed to map to any following dimensions, in that order.
*
- * Use {@link #isSupported(ImgPlus)} to check if an {@link ImagePlus} is
+ * Use {@link #isSupported(Object)} to check if the {@link PlanarImg} is
* supported.
*
- * @see #isSupported(ImgPlus)
+ * @param img the {@link PlanarImg} to convert
+ * @param name the {@link String} title to assign to the result
+ * @return an {@link ImagePlus} wrapping the data in {@code img}
+ * @see #isSupported(Object)
*/
- public static ImagePlus wrap( ImgPlus< ? > imgPlus )
+ public static ImagePlus wrap(PlanarImg< ?, ? > img, String name )
{
- imgPlus = ImgPlusViews.fixAxes( imgPlus );
- final Img< ? > img = imgPlus.getImg();
- if ( !( img instanceof PlanarImg ) )
- throw new IllegalArgumentException( "Image must be a PlanarImg." );
- final IntUnaryOperator indexer = getIndexer( imgPlus );
- final VirtualStack stack = new PlanarImgToImagePlus( ( PlanarImg< ?, ? > ) img, indexer );
- final ImagePlus imagePlus = new ImagePlus( imgPlus.getName(), stack );
- imagePlus.setDimensions( dimension( imgPlus, Axes.CHANNEL ), dimension( imgPlus, Axes.Z ), dimension( imgPlus, Axes.TIME ) );
- CalibrationUtils.copyCalibrationToImagePlus( imgPlus, imagePlus );
- return imagePlus;
- }
-
- private static int dimension( final ImgPlus< ? > imgPlus, final AxisType axisType )
- {
- final int index = imgPlus.dimensionIndex( axisType );
- return index < 0 ? 1 : ( int ) imgPlus.dimension( index );
- }
-
- public static VirtualStack wrap( final PlanarImg< ?, ? > img )
- {
- return new PlanarImgToImagePlus( img, x -> x );
+ final VirtualStack stack = new PlanarImgToImagePlus( img, x -> x );
+ final ImagePlus imp = new ImagePlus(name, stack);
+ final int c = img.numDimensions() > 2 ? (int) img.dimension(2) : 1;
+ final int z = img.numDimensions() > 3 ? (int) img.dimension(3) : 1;
+ final int t = img.numDimensions() > 4 ? (int) img.dimension(4) : 1;
+ imp.setDimensions(c, z, t);
+ return imp;
}
// fields
@@ -214,71 +185,4 @@ private static int getBitDepth( final Type< ? > type )
throw new IllegalArgumentException( "unsupported type" );
}
- private static IntUnaryOperator getIndexer( final ImgPlus< ? > imgPlus )
- {
- final List< AxisType > axes = getAxes( imgPlus );
- if ( !checkAxisOrder( axes ) )
- throw new IllegalArgumentException( "Unsupported axis order, first axis must be X, second axis must be Y, and then optionally, arbitrary ordered: channel, Z and time." );
- if ( inPreferredOrder( axes ) )
- return x -> x;
- final int[] stackSizes = { dimension( imgPlus, Axes.CHANNEL ), dimension( imgPlus, Axes.Z ), dimension( imgPlus, Axes.TIME ) };
- final int channelSkip = getSkip( imgPlus, Axes.CHANNEL );
- final int zSkip = getSkip( imgPlus, Axes.Z );
- final int timeSkip = getSkip( imgPlus, Axes.TIME );
- return stackIndex -> {
- final int[] stackPosition = new int[ 3 ];
- IntervalIndexer.indexToPosition( stackIndex, stackSizes, stackPosition );
- return channelSkip * stackPosition[ 0 ] + zSkip * stackPosition[ 1 ] + timeSkip * stackPosition[ 2 ];
- };
- }
-
- private static List< AxisType > getAxes( final ImgPlus< ? > img )
- {
- return IntStream.range( 0, img.numDimensions() ).mapToObj( img::axis ).map( CalibratedAxis::type ).collect( Collectors.toList() );
- }
-
- private static boolean checkAxisOrder( final List< AxisType > axes )
- {
- return axes.size() >= 2 && axes.size() <= 5 && testUnique( axes ) &&
- axes.get( 0 ) == Axes.X && axes.get( 1 ) == Axes.Y &&
- axes.stream().allMatch( ALLOWED_AXES::contains );
- }
-
- private static final List< AxisType > ALLOWED_AXES = Arrays.asList( Axes.X, Axes.Y, Axes.CHANNEL, Axes.Z, Axes.TIME );
-
- private static boolean inPreferredOrder( final List< AxisType > axes )
- {
- for ( int i = 0; i < axes.size() - 1; i++ )
- if ( preferredPosition( axes.get( i ) ) >= preferredPosition( axes.get( i + 1 ) ) )
- return false;
- return true;
- }
-
- private static int preferredPosition( final AxisType axisType )
- {
- if ( axisType == Axes.X )
- return 0;
- if ( axisType == Axes.Y )
- return 1;
- if ( axisType == Axes.CHANNEL )
- return 2;
- if ( axisType == Axes.Z )
- return 3;
- if ( axisType == Axes.TIME )
- return 4;
- throw new IllegalArgumentException( "unknown axis" );
- }
-
- private static int getSkip( final ImgPlus< ? > imgPlus, final AxisType axis )
- {
- final int channelIndex = imgPlus.dimensionIndex( axis );
- return IntStream.range( 2, channelIndex ).map( i -> ( int ) imgPlus.dimension( i ) ).reduce( 1, ( a, b ) -> a * b );
- }
-
- private static < T > boolean testUnique( final List< T > list )
- {
- final Set< T > set = new HashSet<>( list );
- return set.size() == list.size();
- }
-
}
diff --git a/src/test/java/net/imglib2/imagej/ImagePlusToImgLib2Benchmark.java b/src/test/java/net/imglib2/imagej/ImagePlusToImgLib2Benchmark.java
index b80eac6..ad6e4ec 100644
--- a/src/test/java/net/imglib2/imagej/ImagePlusToImgLib2Benchmark.java
+++ b/src/test/java/net/imglib2/imagej/ImagePlusToImgLib2Benchmark.java
@@ -33,7 +33,6 @@
*/
package net.imglib2.imagej;
-import net.imagej.ImgPlus;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.Img;
import net.imglib2.type.numeric.integer.UnsignedByteType;
@@ -62,41 +61,41 @@ public class ImagePlusToImgLib2Benchmark
@Benchmark
public void wrapSmall()
{
- net.imglib2.imagej.ImagePlusToImgPlus.wrap( small );
+ net.imglib2.imagej.ImagePlusToImg.wrapCached( small );
}
@Benchmark
public void wrapDeep()
{
- net.imglib2.imagej.ImagePlusToImgPlus.wrap( deep );
+ net.imglib2.imagej.ImagePlusToImg.wrapCached( deep );
}
@Benchmark
public void wrapWide()
{
- ImagePlusToImgPlus.wrap( wide );
+ ImagePlusToImg.wrapCached( wide );
}
@Benchmark
public void wrapSmallOld()
{
- net.imglib2.imagej.ImagePlusToImg.wrap( small );
+ net.imglib2.imagej.ImagePlusToImg.wrapDirect( small );
}
@Benchmark
public void wrapDeepOld()
{
- net.imglib2.imagej.ImagePlusToImg.wrap( deep );
+ net.imglib2.imagej.ImagePlusToImg.wrapDirect( deep );
}
@Benchmark
public void wrapWideOld()
{
- net.imglib2.imagej.ImagePlusToImg.wrap( wide );
+ net.imglib2.imagej.ImagePlusToImg.wrapDirect( wide );
}
- private final ImgPlus< UnsignedByteType > wrapped = net.imglib2.imagej.ImagePlusToImgPlus.wrapByte( imageForIteration );
- private final Img< UnsignedByteType > wrappedOld = net.imglib2.imagej.ImagePlusToImg.wrapByte( imageForIteration );
+ private final Img< UnsignedByteType > wrapped = net.imglib2.imagej.ImagePlusToImg.wrapByteCached( imageForIteration );
+ private final Img< UnsignedByteType > wrappedOld = net.imglib2.imagej.ImagePlusToImg.wrapByteDirect( imageForIteration );
@Benchmark
public void iterateWrapped()
diff --git a/src/test/java/net/imglib2/imagej/ImagePlusToImgLib2PerformanceTest.java b/src/test/java/net/imglib2/imagej/ImagePlusToImgLib2PerformanceTest.java
index 28956a4..56d074d 100644
--- a/src/test/java/net/imglib2/imagej/ImagePlusToImgLib2PerformanceTest.java
+++ b/src/test/java/net/imglib2/imagej/ImagePlusToImgLib2PerformanceTest.java
@@ -57,7 +57,7 @@ public void testIterateVirtualStack()
{
final AtomicInteger counter = new AtomicInteger();
final ImagePlus image = countingImagePlus( counter );
- final Img< ? extends RealType< ? > > img = net.imglib2.imagej.ImagePlusToImgPlus.wrapByte( image );
+ final Img< ? extends RealType< ? > > img = net.imglib2.imagej.ImagePlusToImg.wrapByteCached( image );
runFlatIteration( img );
assertTrue( counter.get() < 120 ); // don't call getProcessor too often
}
@@ -67,7 +67,7 @@ public void testIteratePermutedVirtualStack()
{
final AtomicInteger counter = new AtomicInteger();
final ImagePlus image = countingImagePlus( counter );
- final Img< ? extends RealType< ? > > img = ImagePlusToImgPlus.wrapByte( image );
+ final Img< ? extends RealType< ? > > img = ImagePlusToImg.wrapByteCached( image );
runFlatIteration( Views.permute( img, 0, 2 ) );
assertTrue( counter.get() < 120 ); // don't call getProcessor too often
}
@@ -77,7 +77,7 @@ public void testIterateImagePlusAdapter()
{
final AtomicInteger counter = new AtomicInteger();
final ImagePlus image = countingImagePlus( counter );
- final Img< ? extends RealType< ? > > img = net.imglib2.imagej.ImagePlusToImg.wrapByte( image );
+ final Img< ? extends RealType< ? > > img = net.imglib2.imagej.ImagePlusToImg.wrapByteDirect( image );
runFlatIteration( Views.permute( img, 0, 2 ) );
assertTrue( counter.get() < 120 ); // don't call getProcessor too often
}
diff --git a/src/test/java/net/imglib2/imagej/ImagePlusToImgPlusTest.java b/src/test/java/net/imglib2/imagej/ImagePlusToImgPlusTest.java
deleted file mode 100644
index c58f6f8..0000000
--- a/src/test/java/net/imglib2/imagej/ImagePlusToImgPlusTest.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * #%L
- * ImgLib2: a general-purpose, multidimensional image processing library.
- * %%
- * Copyright (C) 2009 - 2025 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
- * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
- * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
- * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
- * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
- * Jean-Yves Tinevez and Michael Zinsmaier.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-
-package net.imglib2.imagej;
-
-import ij.ImagePlus;
-import ij.gui.NewImage;
-import ij.measure.Calibration;
-import net.imagej.ImgPlus;
-import net.imagej.axis.Axes;
-import net.imglib2.type.NativeType;
-import net.imglib2.type.numeric.NumericType;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class ImagePlusToImgPlusTest< T extends NumericType< T > & NativeType< T > >
-{
-
- /** Which dimensions to test. */
- final int[][] dim = new int[][] {
- // nX nY nC nZ nT
- { 128, 128, 1, 1, 1 }, // 2D
- { 128, 128, 1, 10, 1 }, // 3D
- { 128, 128, 5, 10, 1 }, // 3D over 5 channels
- { 128, 128, 1, 10, 30 }, // 4D
- { 128, 128, 5, 10, 30 }, // 4D over 5 channels
- { 128, 128, 1, 1, 30 }, // 2D + T
- { 128, 128, 5, 1, 30 } // 2D + T over 5 channels
-
- };
-
- /** Corresponding calibrations. */
- final float[][] calibration = new float[][] {
- // X Y C (ignored) Z T
- { 0.2f, 0.2f, Float.NaN, 1.5f, 2 },
- { 0.2f, 0.2f, Float.NaN, 1.5f, 2 },
- { 0.2f, 0.2f, Float.NaN, 1.5f, 2 },
- { 0.2f, 0.2f, Float.NaN, 1.5f, 2 },
- { 0.2f, 0.2f, Float.NaN, 1.5f, 2 },
- { 0.2f, 0.2f, Float.NaN, 1.5f, 2 },
- { 0.2f, 0.2f, Float.NaN, 1.5f, 2 }
-
- };
-
- final String[] units = new String[] { "um", "mm", "cm", "minutes" };
-
- @Test
- public void testDimensionality()
- {
- for ( int i = 0; i < dim.length; i++ )
- testDimensionality( dim[ i ], calibration[ i ] );
- }
-
- private void testDimensionality( final int[] dim, final float[] calibration )
- {
- final ImagePlus imp = createCalibratedImagePlus( dim, calibration );
- final ImgPlus< ? > img = ImagePlusToImgPlus.wrap( imp );
- // Print stuff
-// System.out.println( "got: " + img.getName() );
-// for ( int d = 0; d < img.numDimensions(); d++ )
-// {
-// System.out.println( " Axis " + d + "\t - " + img.axis( d ) + ", spacing = " + img.calibration( d ) + ", dimension = " + img.dimension( d ) );
-// }
- assertEquals( getExpectedNumDimensions( dim ), img.numDimensions() );
- checkDimensionality( dim, img );
- checkCalibration( dim, calibration, img );
- }
-
- private ImagePlus createCalibratedImagePlus( final int[] dim, final float[] calibration )
- {
- // Create ImagePlus
- final int slices = dim[ 2 ] * dim[ 3 ] * dim[ 4 ];
- final ImagePlus imp = NewImage.createByteImage( "Test", dim[ 0 ], dim[ 1 ], slices, NewImage.FILL_BLACK );
- imp.setDimensions( dim[ 2 ], dim[ 3 ], dim[ 4 ] );
-
- // Set calibration
- final Calibration impCal = imp.getCalibration();
- impCal.pixelWidth = calibration[ 0 ];
- impCal.pixelHeight = calibration[ 1 ];
- // 2 is for channels
- impCal.pixelDepth = calibration[ 3 ];
- impCal.frameInterval = calibration[ 4 ];
- impCal.setXUnit( units[ 0 ] );
- impCal.setYUnit( units[ 1 ] );
- impCal.setZUnit( units[ 2 ] );
- impCal.setTimeUnit( units[ 3 ] );
-
- // Print stuff
-// System.out.println( "\nFor ImagePlus " + imp + " with " + imp.getCalibration() );
- return imp;
- }
-
- private int getExpectedNumDimensions( final int[] dim )
- {
- // Are num dimension correct?
- int expectedNumDimensions = 0;
- for ( int d = 0; d < dim.length; d++ )
- {
- if ( dim[ d ] > 1 )
- expectedNumDimensions++;
- }
- return expectedNumDimensions;
- }
-
- private void checkDimensionality( final int[] dim, final ImgPlus< ? > img )
- {
- int skipDim = 0;
- for ( int d = 0; d < dim.length; d++ )
- {
- if ( dim[ d ] > 1 )
- {
- // imglib skips singleton dimensions, so we must test only
- // against non-singleton dimension
- assertEquals(
- String.format( "For dimension %d, expected %d, but got %d.", d, dim[ d ], img.dimension( skipDim ) ),
- dim[ d ], img.dimension( skipDim ) );
- skipDim++;
- }
- }
- }
-
- private void checkCalibration( final int[] dim, final float[] calibration, final ImgPlus< ? > img )
- {
- int skipDim = 0;
- for ( int d = 0; d < calibration.length; d++ )
- {
- if ( dim[ d ] > 1 )
- {
- // Is it the channel axis?
- if ( d < getExpectedNumDimensions( dim ) && img.axis( d ).type() == Axes.CHANNEL )
- {
-
- // Then the calibration should be 1,
- assertEquals( 1f, img.averageScale( skipDim ),
- Float.MIN_VALUE );
-
- }
- else
- {
-
- // otherwise it should be what we set.
- assertEquals( calibration[ d ], img.averageScale( skipDim ),
- Float.MIN_VALUE );
- }
- skipDim++;
-
- }
- }
- }
-}
diff --git a/src/test/java/net/imglib2/imagej/ImagePlusToImgPlusLazyTest.java b/src/test/java/net/imglib2/imagej/ImagePlusToImgTest.java
similarity index 71%
rename from src/test/java/net/imglib2/imagej/ImagePlusToImgPlusLazyTest.java
rename to src/test/java/net/imglib2/imagej/ImagePlusToImgTest.java
index c10f391..f7d580d 100644
--- a/src/test/java/net/imglib2/imagej/ImagePlusToImgPlusLazyTest.java
+++ b/src/test/java/net/imglib2/imagej/ImagePlusToImgTest.java
@@ -42,54 +42,71 @@
import net.imglib2.type.numeric.ARGBType;
import net.imglib2.type.numeric.NumericType;
import net.imglib2.type.numeric.integer.UnsignedByteType;
+import net.imglib2.type.numeric.integer.UnsignedIntType;
import net.imglib2.type.numeric.integer.UnsignedShortType;
import net.imglib2.type.numeric.real.FloatType;
import org.junit.Test;
/**
- * Tests the lazy wrapping functions of {@link ImagePlusToImgPlus}.
+ * Tests the lazy wrapping functions of {@link ImagePlusToImg}.
*
* @author Matthias Arzt
+ * @author Gabriel Selzer
*/
-public class ImagePlusToImgPlusLazyTest
+public class ImagePlusToImgTest
{
private static final long[] DIMENSIONS = { 2, 3, 4, 5, 6 };
- // TODO fix test
+ /**
+ * Tests that {@link ImagePlusToImg#wrapByteCached(ImagePlus)} returns the
+ * same image as {@link ImagePlusToImg#wrapByteDirect(ImagePlus)}.
+ */
@Test
- public void testUnsignedByte()
+ public void testWrapByteCached()
{
final ImagePlus image = randomImagePlus( 123, new UnsignedByteType(), DIMENSIONS );
- final Img< UnsignedByteType > actual = ImagePlusToImgPlus.wrapByte( image );
- final Img< UnsignedByteType > expected = ImagePlusToImg.wrapByte( image );
+ final Img< UnsignedByteType > actual = ImagePlusToImg.wrapByteCached( image );
+ final Img< UnsignedByteType > expected = ImagePlusToImg.wrapByteDirect( image );
ImgLib2Assert.assertImageEquals( expected, actual );
}
+ /**
+ * Tests that {@link ImagePlusToImg#wrapShortCached(ImagePlus)} returns the
+ * same image as {@link ImagePlusToImg#wrapShortDirect(ImagePlus)}.
+ */
@Test
- public void testUnsignedShort()
+ public void testWrapShortCached()
{
final ImagePlus image = randomImagePlus( 234, new UnsignedShortType(), DIMENSIONS );
- final Img< UnsignedShortType > actual = ImagePlusToImgPlus.wrapShort( image );
- final Img< UnsignedShortType > expected = ImagePlusToImg.wrapShort( image );
+ final Img< UnsignedShortType > actual = ImagePlusToImg.wrapShortCached( image );
+ final Img< UnsignedShortType > expected = ImagePlusToImg.wrapShortDirect( image );
ImgLib2Assert.assertImageEquals( expected, actual );
}
+ /**
+ * Tests that {@link ImagePlusToImg#wrapRGBACached(ImagePlus)} returns the
+ * same image as {@link ImagePlusToImg#wrapRGBADirect(ImagePlus)}.
+ */
@Test
public void testRGB()
{
final ImagePlus image = randomImagePlus( 345, new ARGBType(), DIMENSIONS );
- final Img< ARGBType > actual = ImagePlusToImgPlus.wrapRGBA( image );
- final Img< ARGBType > expected = ImagePlusToImg.wrapRGBA( image );
+ final Img< ARGBType > actual = ImagePlusToImg.wrapRGBACached( image );
+ final Img< ARGBType > expected = ImagePlusToImg.wrapRGBADirect( image );
ImgLib2Assert.assertImageEquals( expected, actual );
}
+ /**
+ * Tests that {@link ImagePlusToImg#wrapFloatCached(ImagePlus)} returns the
+ * same image as {@link ImagePlusToImg#wrapFloatDirect(ImagePlus)}.
+ */
@Test
public void testFloat()
{
final ImagePlus image = randomImagePlus( 456, new FloatType(), DIMENSIONS );
- final Img< FloatType > actual = ImagePlusToImgPlus.wrapFloat( image );
- final Img< FloatType > expected = ImagePlusToImg.wrapFloat( image );
+ final Img< FloatType > actual = ImagePlusToImg.wrapFloatCached( image );
+ final Img< FloatType > expected = ImagePlusToImg.wrapFloatDirect( image );
ImgLib2Assert.assertImageEquals( expected, actual );
}
@@ -97,8 +114,8 @@ public void testFloat()
public void testLowerNumDimensions()
{
final ImagePlus image = randomImagePlus( 567, new UnsignedByteType(), 2, 3, 6 );
- final Img< UnsignedByteType > actual = ImagePlusToImgPlus.wrapByte( image );
- final Img< UnsignedByteType > expected = ImagePlusToImg.wrapByte( image );
+ final Img< UnsignedByteType > actual = ImagePlusToImg.wrapByteCached( image );
+ final Img< UnsignedByteType > expected = ImagePlusToImg.wrapByteDirect( image );
ImgLib2Assert.assertImageEquals( expected, actual );
}
@@ -106,8 +123,8 @@ public void testLowerNumDimensions()
public void testSingletonDimensions()
{
final ImagePlus image = randomImagePlus( 678, new UnsignedByteType(), 2, 1, 1, 6 );
- final Img< UnsignedByteType > actual = ImagePlusToImgPlus.wrapByte( image );
- final Img< UnsignedByteType > expected = ImagePlusToImg.wrapByte( image );
+ final Img< UnsignedByteType > actual = ImagePlusToImg.wrapByteCached( image );
+ final Img< UnsignedByteType > expected = ImagePlusToImg.wrapByteDirect( image );
ImgLib2Assert.assertImageEquals( expected, actual );
}
diff --git a/src/test/java/net/imglib2/imagej/ImgPlusViewsTest.java b/src/test/java/net/imglib2/imagej/ImgPlusViewsTest.java
deleted file mode 100644
index 6e3f0e6..0000000
--- a/src/test/java/net/imglib2/imagej/ImgPlusViewsTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*-
- * #%L
- * ImgLib2: a general-purpose, multidimensional image processing library.
- * %%
- * Copyright (C) 2009 - 2025 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
- * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
- * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
- * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
- * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
- * Jean-Yves Tinevez and Michael Zinsmaier.
- * %%
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * #L%
- */
-package net.imglib2.imagej;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-
-import net.imagej.ImgPlus;
-import net.imagej.axis.Axes;
-import net.imagej.axis.AxisType;
-import net.imglib2.img.Img;
-import net.imglib2.img.array.ArrayImg;
-import net.imglib2.img.array.ArrayImgs;
-import net.imglib2.img.basictypeaccess.array.ByteArray;
-import net.imglib2.type.numeric.integer.UnsignedByteType;
-
-import org.junit.Test;
-
-public class ImgPlusViewsTest
-{
-
- @Test
- public void testHyperSlice()
- {
- final ArrayImg< UnsignedByteType, ByteArray > img = ArrayImgs.unsignedBytes( 1, 1, 1, 1 );
- final ImgPlus< UnsignedByteType > imgPlus = new ImgPlus<>( img, "image", new AxisType[] { Axes.X, Axes.Y, Axes.Z, Axes.TIME } );
- final ImgPlus< UnsignedByteType > result = ImgPlusViews.hyperSlice( imgPlus, 2, 0 );
- assertEquals( 3, result.numDimensions() );
- assertEquals( Axes.X, result.axis( 0 ).type() );
- assertEquals( Axes.Y, result.axis( 1 ).type() );
- assertEquals( Axes.TIME, result.axis( 2 ).type() );
- }
-
- @Test
- public void testFixAxes()
- {
- final AxisType[] in = { Axes.X, Axes.unknown(), Axes.Y, Axes.Z, Axes.Y };
- final List< AxisType > expected = Arrays.asList( Axes.X, Axes.CHANNEL, Axes.Y, Axes.Z, Axes.TIME );
- final Img< UnsignedByteType > img = ArrayImgs.unsignedBytes( 1, 1, 1, 1, 1 );
- final ImgPlus< UnsignedByteType > imgPlus = new ImgPlus<>( img, "test", in );
- final ImgPlus< UnsignedByteType > result = ImgPlusViews.fixAxes( imgPlus );
- assertEquals( expected, ImgPlusViews.getAxes( result ) );
- }
-
- @Test
- public void testReplaceDuplicates()
- {
- final Predicate< Integer > isDuplicate = ImgPlusViews.createIsDuplicatePredicate();
- assertFalse( isDuplicate.test( 1 ) );
- assertTrue( isDuplicate.test( 1 ) );
- assertFalse( isDuplicate.test( 2 ) );
- }
-
- @Test
- public void testReplaceNulls()
- {
- final List< AxisType > in = Arrays.asList( Axes.X, null, Axes.Y, Axes.Z, null );
- final List< AxisType > expected = Arrays.asList( Axes.X, Axes.CHANNEL, Axes.Y, Axes.Z, Axes.TIME );
- final Supplier< AxisType > replacements = Arrays.asList( Axes.CHANNEL, Axes.TIME ).iterator()::next;
- final List< AxisType > result = ImgPlusViews.replaceMatches( in, Objects::isNull, replacements );
- assertEquals( expected, result );
- }
-}
diff --git a/src/test/java/net/imglib2/imagej/ImgPlusToImagePlusTest.java b/src/test/java/net/imglib2/imagej/RAIToImagePlusTest.java
similarity index 63%
rename from src/test/java/net/imglib2/imagej/ImgPlusToImagePlusTest.java
rename to src/test/java/net/imglib2/imagej/RAIToImagePlusTest.java
index f286b01..b04049c 100644
--- a/src/test/java/net/imglib2/imagej/ImgPlusToImagePlusTest.java
+++ b/src/test/java/net/imglib2/imagej/RAIToImagePlusTest.java
@@ -34,106 +34,56 @@
package net.imglib2.imagej;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import net.imagej.ImgPlus;
-import net.imagej.axis.Axes;
-import net.imagej.axis.AxisType;
+import ij.ImagePlus;
+import ij.process.ByteProcessor;
+import ij.process.FloatProcessor;
+import ij.process.ImageProcessor;
+import ij.process.ShortProcessor;
import net.imglib2.FinalInterval;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.Img;
-import net.imglib2.img.ImgView;
import net.imglib2.img.array.ArrayImgs;
import net.imglib2.type.logic.BitType;
import net.imglib2.type.logic.BoolType;
import net.imglib2.type.numeric.IntegerType;
import net.imglib2.type.numeric.RealType;
-import net.imglib2.type.numeric.integer.ByteType;
-import net.imglib2.type.numeric.integer.IntType;
-import net.imglib2.type.numeric.integer.LongType;
-import net.imglib2.type.numeric.integer.ShortType;
-import net.imglib2.type.numeric.integer.Unsigned128BitType;
-import net.imglib2.type.numeric.integer.Unsigned12BitType;
-import net.imglib2.type.numeric.integer.Unsigned2BitType;
-import net.imglib2.type.numeric.integer.Unsigned4BitType;
-import net.imglib2.type.numeric.integer.UnsignedByteType;
-import net.imglib2.type.numeric.integer.UnsignedIntType;
-import net.imglib2.type.numeric.integer.UnsignedLongType;
-import net.imglib2.type.numeric.integer.UnsignedShortType;
+import net.imglib2.type.numeric.integer.*;
import net.imglib2.type.numeric.real.DoubleType;
import net.imglib2.type.numeric.real.FloatType;
import net.imglib2.util.ConstantUtils;
import net.imglib2.view.Views;
-
import org.junit.Assert;
-import org.junit.Ignore;
import org.junit.Test;
-import ij.ImagePlus;
-import ij.process.ByteProcessor;
-import ij.process.FloatProcessor;
-import ij.process.ImageProcessor;
-import ij.process.ShortProcessor;
+import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.*;
-public class ImgPlusToImagePlusTest
+public class RAIToImagePlusTest
{
@Test
public void testAxisOrder()
{
final Img< UnsignedByteType > img = ArrayImgs.unsignedBytes( 1, 1, 2, 3, 4 );
fill( img );
- final ImgPlus< UnsignedByteType > imgPlus = new ImgPlus<>( img, "title", new AxisType[] { Axes.X, Axes.Y, Axes.TIME, Axes.CHANNEL, Axes.Z } );
- final ImagePlus imagePlus = ImgPlusToImagePlus.wrap( imgPlus, false );
- assertEquals( 2, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 1, 2 ) ).get( 0, 0 ) );
- assertEquals( 7, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 2, 1 ) ).get( 0, 0 ) );
- assertEquals( 3, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 2, 1, 1 ) ).get( 0, 0 ) );
- }
-
- @Test
- public void test1DStack()
- {
- final Img< UnsignedByteType > img = ArrayImgs.unsignedBytes( 2, 2 );
- fill( img );
- final ImgPlus< UnsignedByteType > imgPlus = new ImgPlus<>( img, "title", new AxisType[] { Axes.TIME, Axes.X } );
- final ImagePlus imagePlus = ImgPlusToImagePlus.wrap( imgPlus, false );
- assertArrayEquals( new byte[] { 1, 3 }, ( byte[] ) imagePlus.getStack().getPixels( imagePlus.getStackIndex( 1, 1, 1 ) ) );
- assertArrayEquals( new byte[] { 2, 4 }, ( byte[] ) imagePlus.getStack().getPixels( imagePlus.getStackIndex( 1, 1, 2 ) ) );
- }
-
- @Test
- public void testNoXY()
- {
- final Img< UnsignedByteType > img = ArrayImgs.unsignedBytes( 2, 2 );
- fill( img );
- final ImgPlus< UnsignedByteType > imgPlus = new ImgPlus<>( img, "title", new AxisType[] { Axes.TIME, Axes.CHANNEL } );
- final ImagePlus imagePlus = ImgPlusToImagePlus.wrap( imgPlus, false );
- assertArrayEquals( new byte[] { 2 }, ( byte[] ) imagePlus.getStack().getPixels( imagePlus.getStackIndex( 1, 1, 2 ) ) );
- assertArrayEquals( new byte[] { 3 }, ( byte[] ) imagePlus.getStack().getPixels( imagePlus.getStackIndex( 2, 1, 1 ) ) );
- }
-
- @Ignore( "not supporting more than five dimensions yet" )
- @Test
- public void test6d()
- {
- final Img< UnsignedByteType > img = ArrayImgs.unsignedBytes( 2, 2, 2, 2, 2, 2 );
- fill( img );
- final ImgPlus< UnsignedByteType > imgPlus = new ImgPlus<>( img, "title", new AxisType[] { Axes.X, Axes.Y, Axes.Z, Axes.CHANNEL, Axes.TIME, Axes.CHANNEL } );
- final ImagePlus imagePlus = ImgPlusToImagePlus.wrap( imgPlus, true );
- assertArrayEquals( new byte[] { 2 }, ( byte[] ) imagePlus.getStack().getPixels( imagePlus.getStackIndex( 1, 1, 2 ) ) );
- assertArrayEquals( new byte[] { 3 }, ( byte[] ) imagePlus.getStack().getPixels( imagePlus.getStackIndex( 2, 1, 1 ) ) );
+ final ImagePlus imagePlus = RAIToImagePlus.wrap( img, "title" );
+ assertEquals( 7, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 1, 2 ) ).get( 0, 0 ) );
+ assertEquals( 3, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 2, 1 ) ).get( 0, 0 ) );
+ assertEquals( 2, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 2, 1, 1 ) ).get( 0, 0 ) );
}
@Test
public void testColoredAxisOrder()
{
- final Img< UnsignedByteType > img = ArrayImgs.unsignedBytes( 1, 1, 2, 3, 4 );
+ final Img< UnsignedByteType > img = ArrayImgs.unsignedBytes( 1, 1, 3, 2, 4 );
fill( img );
- final ImgPlus< UnsignedByteType > imgPlus = new ImgPlus<>( img, "title", new AxisType[] { Axes.X, Axes.Y, Axes.TIME, Axes.CHANNEL, Axes.Z } );
- final ImagePlus imagePlus = ImgPlusToImagePlus.wrap( imgPlus, true );
- assertEquals( 0xff020406, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 1, 2 ) ).get( 0, 0 ) );
- assertEquals( 0xff07090b, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 2, 1 ) ).get( 0, 0 ) );
+ final ImagePlus imagePlus = RAIToImagePlus.convertRGB( img, "title" );
+ // img[0, 0, :, 0, 0] is [1, 2, 3]
+ assertEquals( 0xff010203, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 1, 1 ) ).get( 0, 0 ) );
+ // img[0, 0, :, 1, 0] is [4, 5, 6]
+ assertEquals( 0xff040506, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 2, 1 ) ).get( 0, 0 ) );
+ // img[0, 0, :, 0, 1] is [7, 8, 9]
+ assertEquals( 0xff070809, imagePlus.getStack().getProcessor( imagePlus.getStackIndex( 1, 1, 2 ) ).get( 0, 0 ) );
}
@Test
@@ -235,10 +185,8 @@ public void testDoubleType()
private < T extends RealType< T > > void testTypeConversion( final Class< ? extends ImageProcessor > processorClass, final float expected, final T input )
{
final RandomAccessibleInterval< T > rai = ConstantUtils.constantRandomAccessibleInterval( input, new FinalInterval( 1, 1 ) );
- final Img< T > image = ImgView.wrap( rai, null );
- final ImgPlus< T > imgPlus = new ImgPlus< T >( image, "title", new AxisType[] { Axes.X, Axes.Y } );
// process
- final ImagePlus imagePlus = ImgPlusToImagePlus.wrap( imgPlus, false );
+ final ImagePlus imagePlus = RAIToImagePlus.wrap( rai, "title" );
// test
final ImageProcessor processor = imagePlus.getProcessor();
Assert.assertTrue( processorClass.isInstance( processor ) );
@@ -256,10 +204,9 @@ public void testUnknownAxes()
{
final byte[] array = { 1, 2, 3, 4, 5, 6 };
final Img< UnsignedByteType > img = ArrayImgs.unsignedBytes( array, 1, 1, 2, 3 );
- final AxisType[] axes = { Axes.unknown(), Axes.unknown(), Axes.TIME, Axes.unknown() };
- final ImagePlus result = ImgPlusToImagePlus.wrap( new ImgPlus<>( img, "title", axes ), false );
- assertEquals( 3, result.getNChannels() );
- assertEquals( 2, result.getNFrames() );
+ final ImagePlus result = RAIToImagePlus.wrap( img, "title" );
+ assertEquals( 2, result.getNChannels() );
+ assertEquals( 3, result.getNSlices() );
}
@Test
@@ -267,8 +214,7 @@ public void testPersistence()
{
// setup
final Img< FloatType > img = ArrayImgs.floats( 1, 1 );
- final ImgPlus< FloatType > imgPlus = new ImgPlus<>( img, "title", new AxisType[] { Axes.X, Axes.Y } );
- final ImagePlus imagePlus = ImgPlusToImagePlus.wrap( imgPlus, false );
+ final ImagePlus imagePlus = RAIToImagePlus.wrap( img, "title" );
final float expected = 42;
// process
final ImageProcessor processor = imagePlus.getStack().getProcessor( 1 );
@@ -287,8 +233,7 @@ public void testPersistenceBits()
{
// setup
final Img< BitType > img = ArrayImgs.bits( 1, 1 );
- final ImgPlus< BitType > imgPlus = new ImgPlus<>( img, "title", new AxisType[] { Axes.X, Axes.Y } );
- final ImagePlus imagePlus = ImgPlusToImagePlus.wrapAndScaleBitType( imgPlus );
+ final ImagePlus imagePlus = RAIToImagePlus.wrapAndScaleBoolean( img, "test" );
// process
final ImageProcessor processor = imagePlus.getStack().getProcessor( 1 );
processor.setf( 0, 0, 255 );
diff --git a/src/test/java/net/imglib2/imagej/img/ArrayImgToImagePlusTest.java b/src/test/java/net/imglib2/imagej/img/ArrayImgToImagePlusTest.java
index 5c0f1fe..7720d1d 100644
--- a/src/test/java/net/imglib2/imagej/img/ArrayImgToImagePlusTest.java
+++ b/src/test/java/net/imglib2/imagej/img/ArrayImgToImagePlusTest.java
@@ -34,24 +34,18 @@
package net.imglib2.imagej.img;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import net.imagej.ImgPlus;
-import net.imagej.axis.Axes;
-import net.imagej.axis.AxisType;
+import ij.ImagePlus;
import net.imglib2.img.Img;
+import net.imglib2.img.array.ArrayImg;
import net.imglib2.img.array.ArrayImgs;
-import net.imglib2.img.cell.CellImg;
+import net.imglib2.img.basictypeaccess.array.ByteArray;
+import net.imglib2.img.basictypeaccess.array.FloatArray;
import net.imglib2.img.cell.CellImgFactory;
import net.imglib2.type.numeric.integer.UnsignedByteType;
import net.imglib2.type.numeric.real.FloatType;
-
import org.junit.Test;
-import ij.ImagePlus;
+import static org.junit.Assert.*;
public class ArrayImgToImagePlusTest
{
@@ -61,8 +55,8 @@ public void testSharedBuffer()
final int width = 2;
final int height = 3;
final byte[] buffer = new byte[ width * height ];
- final ImgPlus< UnsignedByteType > img = new ImgPlus<>( ArrayImgs.unsignedBytes( buffer, width, height ) );
- final ImagePlus imagePlus = ArrayImgToImagePlus.wrap( img );
+ final ArrayImg< UnsignedByteType, ByteArray > img = ArrayImgs.unsignedBytes( buffer, width, height );
+ final ImagePlus imagePlus = ArrayImgToImagePlus.wrap( img, "test" );
assertEquals( width, imagePlus.getWidth() );
assertEquals( height, imagePlus.getHeight() );
assertSame( buffer, imagePlus.getProcessor().getPixels() );
@@ -71,13 +65,12 @@ public void testSharedBuffer()
@Test
public void testIsSupported()
{
- final ImgPlus< UnsignedByteType > supported = new ImgPlus<>( ArrayImgs.unsignedBytes( 2, 2 ), "image", new AxisType[] { Axes.X, Axes.Y } );
- final ImgPlus< UnsignedByteType > unsupported1 = new ImgPlus<>( ArrayImgs.unsignedBytes( 2, 2, 3 ), "image", new AxisType[] { Axes.X, Axes.Y, Axes.Z } );
- final CellImg< UnsignedByteType, ? > cellImg = new CellImgFactory<>( new UnsignedByteType() ).create( 2, 2 );
- final ImgPlus< UnsignedByteType > unsupported2 = new ImgPlus<>( cellImg, "image", new AxisType[] { Axes.X, Axes.Y } );
+ final Img< UnsignedByteType > supported = ArrayImgs.unsignedBytes( 2, 2 );
+ final Img< UnsignedByteType > unsupported1 = ArrayImgs.unsignedBytes( 2, 2, 3 );
+ final Img< UnsignedByteType > cellImg = new CellImgFactory<>( new UnsignedByteType() ).create( 2, 2 );
assertTrue( ArrayImgToImagePlus.isSupported( supported ) );
assertFalse( ArrayImgToImagePlus.isSupported( unsupported1 ) );
- assertFalse( ArrayImgToImagePlus.isSupported( unsupported2 ) );
+ assertFalse( ArrayImgToImagePlus.isSupported( cellImg ) );
}
@Test
@@ -85,9 +78,8 @@ public void testPersistence()
{
// setup
final float expected = 42.0f;
- final Img< FloatType > img = ArrayImgs.floats( 1, 1 );
- final ImgPlus< FloatType > imgPlus = new ImgPlus<>( img, "title", new AxisType[] { Axes.X, Axes.Y } );
- final ImagePlus imagePlus = ArrayImgToImagePlus.wrap( imgPlus );
+ final ArrayImg
- * img = new ImagePlusImgFactory< MyType >.create( new long[] { 100, 200 }, new MyType() );
- *
- *
- * @author Stephan Saalfeld
- */
-final public class ImagePlusImgs
-{
- private ImagePlusImgs()
- {}
-
- /**
- * Create a {@link ByteImagePlus}{@code <}{@link UnsignedByteType}{@code >}.
- *
- *