diff --git a/src/main/java/bdv/ij/export/imgloader/ImagePlusImgLoader.java b/src/main/java/bdv/ij/export/imgloader/ImagePlusImgLoader.java index fbefc4ad89bcf786835780ca1350b1ac408e9a93..77ecf62a16609e4f816f6a772671ee7c663de842 100644 --- a/src/main/java/bdv/ij/export/imgloader/ImagePlusImgLoader.java +++ b/src/main/java/bdv/ij/export/imgloader/ImagePlusImgLoader.java @@ -1,7 +1,11 @@ package bdv.ij.export.imgloader; +import java.util.ArrayList; + import ij.ImagePlus; import mpicbg.spim.data.generic.sequence.BasicImgLoader; +import mpicbg.spim.data.generic.sequence.BasicSetupImgLoader; +import mpicbg.spim.data.generic.sequence.TypedBasicImgLoader; import mpicbg.spim.data.sequence.ViewId; import net.imglib2.RandomAccessibleInterval; import net.imglib2.algorithm.stats.ComputeMinMax; @@ -9,9 +13,7 @@ import net.imglib2.converter.Converters; import net.imglib2.converter.RealUnsignedShortConverter; import net.imglib2.type.NativeType; import net.imglib2.type.numeric.RealType; -import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.type.numeric.integer.UnsignedShortType; -import net.imglib2.type.numeric.real.FloatType; import bdv.img.cache.VolatileGlobalCellCache; import bdv.img.imagestack.ImageStackImageLoader; import bdv.img.virtualstack.VirtualStackImageLoader; @@ -29,7 +31,7 @@ import bdv.img.virtualstack.VirtualStackImageLoader; * * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ -public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > implements BasicImgLoader< UnsignedShortType > +public class ImagePlusImgLoader implements TypedBasicImgLoader< UnsignedShortType > { public static enum MinMaxOption { @@ -38,49 +40,51 @@ public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > imp TAKE_FROM_IMAGEPROCESSOR } - public static ImagePlusImgLoader< UnsignedByteType > createGray8( final ImagePlus imp, final MinMaxOption minMaxOption, final double min, final double max ) + public static ImagePlusImgLoader createGray8( final ImagePlus imp, final MinMaxOption minMaxOption, final double min, final double max ) { if( imp.getType() != ImagePlus.GRAY8 ) throw new RuntimeException( "expected ImagePlus type GRAY8" ); if ( imp.getStack() != null && imp.getStack().isVirtual() ) - return new ImagePlusImgLoader< UnsignedByteType >( imp, VirtualStackImageLoader.createUnsignedByteInstance( imp ), minMaxOption, min, max ); + return new ImagePlusImgLoader( imp, VirtualStackImageLoader.createUnsignedByteInstance( imp ), minMaxOption, min, max ); else - return new ImagePlusImgLoader< UnsignedByteType >( imp, ImageStackImageLoader.createUnsignedByteInstance( imp ), minMaxOption, min, max ); + return new ImagePlusImgLoader( imp, ImageStackImageLoader.createUnsignedByteInstance( imp ), minMaxOption, min, max ); } - public static ImagePlusImgLoader< UnsignedShortType > createGray16( final ImagePlus imp, final MinMaxOption minMaxOption, final double min, final double max ) + public static ImagePlusImgLoader createGray16( final ImagePlus imp, final MinMaxOption minMaxOption, final double min, final double max ) { if( imp.getType() != ImagePlus.GRAY16 ) throw new RuntimeException( "expected ImagePlus type GRAY16" ); if ( imp.getStack() != null && imp.getStack().isVirtual() ) - return new ImagePlusImgLoader< UnsignedShortType >( imp, VirtualStackImageLoader.createUnsignedShortInstance( imp ), minMaxOption, min, max ); + return new ImagePlusImgLoader( imp, VirtualStackImageLoader.createUnsignedShortInstance( imp ), minMaxOption, min, max ); else - return new ImagePlusImgLoader< UnsignedShortType >( imp, ImageStackImageLoader.createUnsignedShortInstance( imp ), minMaxOption, min, max ); + return new ImagePlusImgLoader( imp, ImageStackImageLoader.createUnsignedShortInstance( imp ), minMaxOption, min, max ); } - public static ImagePlusImgLoader< FloatType > createGray32( final ImagePlus imp, final MinMaxOption minMaxOption, final double min, final double max ) + public static ImagePlusImgLoader createGray32( final ImagePlus imp, final MinMaxOption minMaxOption, final double min, final double max ) { if( imp.getType() != ImagePlus.GRAY32 ) throw new RuntimeException( "expected ImagePlus type GRAY32" ); if ( imp.getStack() != null && imp.getStack().isVirtual() ) - return new ImagePlusImgLoader< FloatType >( imp, VirtualStackImageLoader.createFloatInstance( imp ), minMaxOption, min, max ); + return new ImagePlusImgLoader( imp, VirtualStackImageLoader.createFloatInstance( imp ), minMaxOption, min, max ); else - return new ImagePlusImgLoader< FloatType >( imp, ImageStackImageLoader.createFloatInstance( imp ), minMaxOption, min, max ); + return new ImagePlusImgLoader( imp, ImageStackImageLoader.createFloatInstance( imp ), minMaxOption, min, max ); } protected final ImagePlus imp; - protected final BasicImgLoader< T > loader; + protected final BasicImgLoader loader; + + protected VolatileGlobalCellCache loadercache; - protected VolatileGlobalCellCache< ? > loadercache; + protected final ArrayList< SetupImgLoader< ? > > setupImgLoaders; protected double impMin; protected double impMax; @SuppressWarnings( "unchecked" ) - protected ImagePlusImgLoader( final ImagePlus imp, - final BasicImgLoader< T > loader, + protected< T extends RealType< T > & NativeType< T > > ImagePlusImgLoader( final ImagePlus imp, + final TypedBasicImgLoader< T > loader, final MinMaxOption minMaxOption, final double min, final double max ) @@ -88,8 +92,13 @@ public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > imp this.imp = imp; this.loader = loader; + final int numSetups = imp.getNChannels(); + setupImgLoaders = new ArrayList< SetupImgLoader< ? > >(); + for ( int setupId = 0; setupId < numSetups; ++setupId ) + setupImgLoaders.add( new SetupImgLoader< T >( loader.getSetupImgLoader( setupId ) ) ); + if ( loader instanceof VirtualStackImageLoader ) - this.loadercache = ( ( VirtualStackImageLoader< T, ?, ? > ) loader ).getCache(); + this.loadercache = ( ( VirtualStackImageLoader< ?, ?, ? > ) loader ).getCache(); else this.loadercache = null; @@ -97,14 +106,13 @@ public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > imp { impMin = Double.POSITIVE_INFINITY; impMax = Double.NEGATIVE_INFINITY; - final T minT = loader.getImageType().createVariable(); - final T maxT = loader.getImageType().createVariable(); - final int numSetups = imp.getNChannels(); + final T minT = loader.getSetupImgLoader( 0 ).getImageType().createVariable(); + final T maxT = minT.createVariable(); final int numTimepoints = imp.getNFrames(); for ( int t = 0; t < numTimepoints; t++ ) for ( int s = 0; s < numSetups; ++s ) { - ComputeMinMax.computeMinMax( loader.getImage( new ViewId( t, s ) ), minT, maxT ); + ComputeMinMax.computeMinMax( loader.getSetupImgLoader( s ).getImage( t ), minT, maxT ); impMin = Math.min( minT.getRealDouble(), impMin ); impMax = Math.max( maxT.getRealDouble(), impMax ); if ( loadercache != null ) @@ -139,18 +147,34 @@ public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > imp } } - @Override - public RandomAccessibleInterval< UnsignedShortType > getImage( final ViewId view ) + public class SetupImgLoader< T extends RealType< T > & NativeType< T > > implements BasicSetupImgLoader< UnsignedShortType > { - if ( loadercache != null ) - loadercache.clearCache(); - final RandomAccessibleInterval< T > img = loader.getImage( view ); - return Converters.convert( img, new RealUnsignedShortConverter< T >( impMin, impMax ), new UnsignedShortType() ); + final BasicSetupImgLoader< T > loader; + + protected SetupImgLoader( final BasicSetupImgLoader< T > loader ) + { + this.loader = loader; + } + + @Override + public RandomAccessibleInterval< UnsignedShortType > getImage( final int timepointId ) + { + if ( loadercache != null ) + loadercache.clearCache(); + final RandomAccessibleInterval< T > img = loader.getImage( timepointId ); + return Converters.convert( img, new RealUnsignedShortConverter< T >( impMin, impMax ), new UnsignedShortType() ); + } + + @Override + public UnsignedShortType getImageType() + { + return new UnsignedShortType(); + } } @Override - public UnsignedShortType getImageType() + public SetupImgLoader< ? > getSetupImgLoader( final int setupId ) { - return new UnsignedShortType(); + return setupImgLoaders.get( setupId ); } } diff --git a/src/main/java/bdv/img/imagestack/ImageStackImageLoader.java b/src/main/java/bdv/img/imagestack/ImageStackImageLoader.java index c3014bb52f50eef2cf73fd2f70e94a59598d4026..6c5c813d6500e4e03c949610844a1378047db564 100644 --- a/src/main/java/bdv/img/imagestack/ImageStackImageLoader.java +++ b/src/main/java/bdv/img/imagestack/ImageStackImageLoader.java @@ -1,8 +1,11 @@ package bdv.img.imagestack; +import java.util.ArrayList; + import ij.ImagePlus; import mpicbg.spim.data.generic.sequence.BasicImgLoader; -import mpicbg.spim.data.sequence.ViewId; +import mpicbg.spim.data.generic.sequence.BasicSetupImgLoader; +import mpicbg.spim.data.generic.sequence.TypedBasicImgLoader; import net.imglib2.RandomAccessibleInterval; import net.imglib2.img.basictypeaccess.array.ArrayDataAccess; import net.imglib2.img.basictypeaccess.array.ByteArray; @@ -17,7 +20,7 @@ import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.type.numeric.integer.UnsignedShortType; import net.imglib2.type.numeric.real.FloatType; -public abstract class ImageStackImageLoader< T extends NumericType< T > & NativeType< T >, A extends ArrayDataAccess< A > > implements BasicImgLoader< T > +public abstract class ImageStackImageLoader< T extends NumericType< T > & NativeType< T >, A extends ArrayDataAccess< A > > implements TypedBasicImgLoader< T >, BasicImgLoader { public static ImageStackImageLoader< UnsignedByteType, ByteArray > createUnsignedByteInstance( final ImagePlus imp ) { @@ -97,37 +100,59 @@ public abstract class ImageStackImageLoader< T extends NumericType< T > & Native private final long[] dim; + private final ArrayList< SetupImgLoader > setupImgLoaders; + public ImageStackImageLoader( final T type, final ImagePlus imp ) { this.type = type; this.imp = imp; this.dim = new long[] { imp.getWidth(), imp.getHeight(), imp.getNSlices() }; + final int numSetups = imp.getNChannels(); + setupImgLoaders = new ArrayList< SetupImgLoader >(); + for ( int setupId = 0; setupId < numSetups; ++setupId ) + setupImgLoaders.add( new SetupImgLoader( setupId ) ); } protected abstract A wrapPixels( Object array ); protected abstract void linkType( PlanarImg< T, A > img ); - @Override - public RandomAccessibleInterval< T > getImage( final ViewId view ) + public class SetupImgLoader implements BasicSetupImgLoader< T > { - return new PlanarImg< T, A >( dim, type.getEntitiesPerPixel() ) + private final int setupId; + + public SetupImgLoader( final int setupId ) { - private PlanarImg< T, A > init() + this.setupId = setupId; + } + + @Override + public RandomAccessibleInterval< T > getImage( final int timepointId ) + { + return new PlanarImg< T, A >( dim, type.getEntitiesPerPixel() ) { - final int channel = view.getViewSetupId() + 1; - final int frame = view.getTimePointId() + 1; - for ( int slice = 1; slice <= dim[ 2 ]; ++slice ) - mirror.set( slice - 1, wrapPixels( imp.getStack().getPixels( imp.getStackIndex( channel, slice, frame ) ) ) ); - linkType( this ); - return this; - } - }.init(); + private PlanarImg< T, A > init() + { + final int channel = setupId + 1; + final int frame = timepointId + 1; + for ( int slice = 1; slice <= dim[ 2 ]; ++slice ) + mirror.set( slice - 1, wrapPixels( imp.getStack().getPixels( imp.getStackIndex( channel, slice, frame ) ) ) ); + linkType( this ); + return this; + } + }.init(); + } + + @Override + public T getImageType() + { + return type; + } } @Override - public T getImageType() + public SetupImgLoader getSetupImgLoader( final int setupId ) { - return type; + return setupImgLoaders.get( setupId ); } } \ No newline at end of file diff --git a/src/main/java/bdv/img/virtualstack/VirtualStackImageLoader.java b/src/main/java/bdv/img/virtualstack/VirtualStackImageLoader.java index 4d2f27000a020b97176f735b4f1d13119fccd483..f159c4845925f354d89f3f273a9809e21b570a62 100644 --- a/src/main/java/bdv/img/virtualstack/VirtualStackImageLoader.java +++ b/src/main/java/bdv/img/virtualstack/VirtualStackImageLoader.java @@ -1,6 +1,9 @@ package bdv.img.virtualstack; +import java.util.ArrayList; + import ij.ImagePlus; +import mpicbg.spim.data.generic.sequence.TypedBasicImgLoader; import mpicbg.spim.data.sequence.ViewId; import net.imglib2.RandomAccessibleInterval; import net.imglib2.Volatile; @@ -22,6 +25,7 @@ import net.imglib2.type.volatiles.VolatileUnsignedByteType; import net.imglib2.type.volatiles.VolatileUnsignedShortType; import net.imglib2.util.Fraction; import bdv.AbstractViewerImgLoader; +import bdv.AbstractViewerSetupImgLoader; import bdv.img.cache.CacheArrayLoader; import bdv.img.cache.CacheHints; import bdv.img.cache.CachedCellImg; @@ -54,7 +58,7 @@ import bdv.img.cache.VolatileImgCells.CellCache; * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ public abstract class VirtualStackImageLoader< T extends NativeType< T >, V extends Volatile< T > & NativeType< V >, A extends VolatileAccess > - extends AbstractViewerImgLoader< T, V > + extends AbstractViewerImgLoader< T, V > implements TypedBasicImgLoader< T > { public static VirtualStackImageLoader< FloatType, VolatileFloatType, VolatileFloatArray > createFloatInstance( final ImagePlus imp ) { @@ -136,77 +140,102 @@ public abstract class VirtualStackImageLoader< T extends NativeType< T >, V exte private static AffineTransform3D[] mipmapTransforms = new AffineTransform3D[] { new AffineTransform3D() }; - private final VolatileGlobalCellCache< A > cache; + private final VolatileGlobalCellCache cache; private final long[] dimensions; private final int[] cellDimensions; + private final CacheArrayLoader< A > loader; + + private final ArrayList< SetupImgLoader > setupImgLoaders; + protected VirtualStackImageLoader( final ImagePlus imp, final CacheArrayLoader< A > loader, final T type, final V volatileType ) { super( type, volatileType ); + this.loader = loader; dimensions = new long[] { imp.getWidth(), imp.getHeight(), imp.getNSlices() }; cellDimensions = new int[] { imp.getWidth(), imp.getHeight(), 1 }; final int numTimepoints = imp.getNFrames(); final int numSetups = imp.getNChannels(); - cache = new VolatileGlobalCellCache< A >( loader, numTimepoints, numSetups, 1, 1 ); + cache = new VolatileGlobalCellCache( numTimepoints, numSetups, 1, 1 ); + setupImgLoaders = new ArrayList< SetupImgLoader >(); + for ( int setupId = 0; setupId < numSetups; ++setupId ) + setupImgLoaders.add( new SetupImgLoader( setupId ) ); } - protected abstract void linkType( CachedCellImg< T, A > img ); + public class SetupImgLoader extends AbstractViewerSetupImgLoader< T, V > + { + private final int setupId; - protected abstract void linkVolatileType( CachedCellImg< V, A > img ); + public SetupImgLoader( final int setupId ) + { + super( VirtualStackImageLoader.this.type, VirtualStackImageLoader.this.volatileType ); + this.setupId = setupId; + } - @Override - public RandomAccessibleInterval< T > getImage( final ViewId view, final int level ) - { - final CachedCellImg< T, A > img = prepareCachedImage( view, level, LoadingStrategy.BLOCKING ); - linkType( img ); - return img; - } + @Override + public RandomAccessibleInterval< T > getImage( final int timepointId, final int level ) + { + final CachedCellImg< T, A > img = prepareCachedImage( timepointId, setupId, level, LoadingStrategy.BLOCKING ); + linkType( img ); + return img; + } - @Override - public RandomAccessibleInterval< V > getVolatileImage( final ViewId view, final int level ) - { - final CachedCellImg< V, A > img = prepareCachedImage( view, level, LoadingStrategy.BUDGETED ); - linkVolatileType( img ); - return img; - } + @Override + public RandomAccessibleInterval< V > getVolatileImage( final int timepointId, final int level ) + { + final CachedCellImg< V, A > img = prepareCachedImage( timepointId, setupId, level, LoadingStrategy.BUDGETED ); + linkVolatileType( img ); + return img; + } - @Override - public double[][] getMipmapResolutions( final int setup ) - { - return mipmapResolutions; - } + @Override + public double[][] getMipmapResolutions() + { + return mipmapResolutions; + } - @Override - public AffineTransform3D[] getMipmapTransforms( final int setup ) - { - return mipmapTransforms; + @Override + public AffineTransform3D[] getMipmapTransforms() + { + return mipmapTransforms; + } + + @Override + public int numMipmapLevels() + { + return 1; + } } @Override - public int numMipmapLevels( final int setup ) + public SetupImgLoader getSetupImgLoader( final int setupId ) { - return 1; + return setupImgLoaders.get( setupId ); } @Override - public VolatileGlobalCellCache< A > getCache() + public VolatileGlobalCellCache getCache() { return cache; } + protected abstract void linkType( CachedCellImg< T, A > img ); + + protected abstract void linkVolatileType( CachedCellImg< V, A > img ); + /** * (Almost) create a {@link CachedCellImg} backed by the cache. The created * image needs a {@link NativeImg#setLinkedType(net.imglib2.type.Type) * linked type} before it can be used. The type should be either * {@link ARGBType} and {@link VolatileARGBType}. */ - protected < T extends NativeType< T > > CachedCellImg< T, A > prepareCachedImage( final ViewId view, final int level, final LoadingStrategy loadingStrategy ) + protected < T extends NativeType< T > > CachedCellImg< T, A > prepareCachedImage( final int timepointId, final int setupId, final int level, final LoadingStrategy loadingStrategy ) { final int priority = 0; final CacheHints cacheHints = new CacheHints( loadingStrategy, priority, false ); - final CellCache< A > c = cache.new VolatileCellCache( view.getTimePointId(), view.getViewSetupId(), level, cacheHints ); + final CellCache< A > c = cache.new VolatileCellCache< A >( timepointId, setupId, level, cacheHints, loader ); final VolatileImgCells< A > cells = new VolatileImgCells< A >( c, new Fraction(), dimensions, cellDimensions ); final CachedCellImg< T, A > img = new CachedCellImg< T, A >( cells ); return img;