Commit 82838b65 authored by Tobias Pietzsch's avatar Tobias Pietzsch
Browse files

Merge branch 'paperhacks'

parents b7412778 6d35b570
......@@ -18,6 +18,7 @@
<dependency>
<groupId>sc.fiji</groupId>
<artifactId>bigdataviewer-core</artifactId>
<version>1.0.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.imagej</groupId>
......
......@@ -19,7 +19,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import mpicbg.spim.data.generic.sequence.BasicImgLoader;
import mpicbg.spim.data.generic.sequence.BasicViewSetup;
import mpicbg.spim.data.registration.ViewRegistration;
import mpicbg.spim.data.registration.ViewRegistrations;
......@@ -28,13 +27,15 @@ import mpicbg.spim.data.sequence.FinalVoxelDimensions;
import mpicbg.spim.data.sequence.TimePoint;
import mpicbg.spim.data.sequence.TimePoints;
import net.imglib2.FinalDimensions;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.type.numeric.integer.UnsignedShortType;
import bdv.export.ExportMipmapInfo;
import bdv.export.ProgressWriter;
import bdv.export.ProposeMipmaps;
import bdv.export.SubTaskProgressWriter;
import bdv.export.WriteSequenceToHdf5;
import bdv.export.WriteSequenceToHdf5.AfterEachPlane;
import bdv.export.WriteSequenceToHdf5.LoopbackHeuristic;
import bdv.ij.export.imgloader.ImagePlusImgLoader;
import bdv.ij.export.imgloader.ImagePlusImgLoader.MinMaxOption;
import bdv.ij.util.PluginHelper;
......@@ -116,7 +117,7 @@ public class ExportImagePlusPlugIn implements PlugIn
progressWriter.out().println( "starting export..." );
// create ImgLoader wrapping the image
final BasicImgLoader< UnsignedShortType > imgLoader;
final ImagePlusImgLoader< ? > imgLoader;
switch ( imp.getType() )
{
case ImagePlus.GRAY8:
......@@ -157,6 +158,57 @@ public class ExportImagePlusPlugIn implements PlugIn
for ( final BasicViewSetup setup : seq.getViewSetupsOrdered() )
perSetupExportMipmapInfo.put( setup.getId(), mipmapInfo );
// LoopBackHeuristic:
// - If saving more than 8x on pixel reads use the loopback image over
// original image
// - For virtual stacks also consider the cache size that would be
// required for all original planes contributing to a "plane of
// blocks" at the current level. If this is more than 1/4 of
// available memory, use the loopback image.
final boolean isVirtual = imp.getStack().isVirtual();
final long planeSizeInBytes = imp.getWidth() * imp.getHeight() * imp.getBytesPerPixel();
final long ijMaxMemory = IJ.maxMemory();
final LoopbackHeuristic loopbackHeuristic = new LoopbackHeuristic()
{
@Override
public boolean decide( final RandomAccessibleInterval< ? > originalImg, final int[] factorsToOriginalImg, final int previousLevel, final int[] factorsToPreviousLevel, final int[] chunkSize )
{
if ( previousLevel < 0 )
return false;
if ( WriteSequenceToHdf5.numElements( factorsToOriginalImg ) / WriteSequenceToHdf5.numElements( factorsToPreviousLevel ) >= 8 )
return true;
if ( isVirtual )
{
final long requiredCacheSize = planeSizeInBytes * factorsToOriginalImg[ 2 ] * chunkSize[ 2 ];
if ( requiredCacheSize > ijMaxMemory / 4 )
return true;
}
return false;
}
};
final AfterEachPlane afterEachPlane = new AfterEachPlane()
{
@Override
public void afterEachPlane( final boolean usedLoopBack )
{
if ( !usedLoopBack && isVirtual )
{
final long free = Runtime.getRuntime().freeMemory();
final long total = Runtime.getRuntime().totalMemory();
final long max = Runtime.getRuntime().maxMemory();
final long actuallyFree = max - total + free;
if ( actuallyFree < max / 2 )
imgLoader.clearCache();
}
}
};
final ArrayList< Partition > partitions;
if ( params.split )
{
......@@ -168,14 +220,14 @@ public class ExportImagePlusPlugIn implements PlugIn
{
final Partition partition = partitions.get( i );
final ProgressWriter p = new SubTaskProgressWriter( progressWriter, 0, 0.95 * i / partitions.size() );
WriteSequenceToHdf5.writeHdf5PartitionFile( seq, perSetupExportMipmapInfo, params.deflate, partition, p );
WriteSequenceToHdf5.writeHdf5PartitionFile( seq, perSetupExportMipmapInfo, params.deflate, partition, loopbackHeuristic, afterEachPlane, p );
}
WriteSequenceToHdf5.writeHdf5PartitionLinkFile( seq, perSetupExportMipmapInfo, partitions, params.hdf5File );
}
else
{
partitions = null;
WriteSequenceToHdf5.writeHdf5File( seq, perSetupExportMipmapInfo, params.deflate, params.hdf5File, new SubTaskProgressWriter( progressWriter, 0, 0.95 ) );
WriteSequenceToHdf5.writeHdf5File( seq, perSetupExportMipmapInfo, params.deflate, params.hdf5File, loopbackHeuristic, afterEachPlane, new SubTaskProgressWriter( progressWriter, 0, 0.95 ) );
}
// write xml sequence description
......
......@@ -294,7 +294,7 @@ public class ExportSpimFusionPlugIn implements PlugIn
for ( final Partition partition : newPartitions )
{
final SubTaskProgressWriter subtaskProgress = new SubTaskProgressWriter( progress, complete, complete + completionStep );
WriteSequenceToHdf5.writeHdf5PartitionFile( fusionSeq, perSetupExportMipmapInfo, params.deflate, partition, subtaskProgress );
WriteSequenceToHdf5.writeHdf5PartitionFile( fusionSeq, perSetupExportMipmapInfo, params.deflate, partition, null, null, subtaskProgress );
complete += completionStep;
}
......@@ -346,13 +346,13 @@ public class ExportSpimFusionPlugIn implements PlugIn
{
final Partition partition = partitions.get( i );
final ProgressWriter p = new SubTaskProgressWriter( progress, 0, 0.95 * i / partitions.size() );
WriteSequenceToHdf5.writeHdf5PartitionFile( desc, perSetupExportMipmapInfo, params.deflate, partition, p );
WriteSequenceToHdf5.writeHdf5PartitionFile( desc, perSetupExportMipmapInfo, params.deflate, partition, null, null, p );
}
WriteSequenceToHdf5.writeHdf5PartitionLinkFile( desc, perSetupExportMipmapInfo, partitions, params.hdf5File );
}
else
{
WriteSequenceToHdf5.writeHdf5File( desc, perSetupExportMipmapInfo, params.deflate, params.hdf5File, new SubTaskProgressWriter( progress, 0, 0.95 ) );
WriteSequenceToHdf5.writeHdf5File( desc, perSetupExportMipmapInfo, params.deflate, params.hdf5File, null, null, new SubTaskProgressWriter( progress, 0, 0.95 ) );
}
// write xml file
......
......@@ -86,14 +86,14 @@ public class ExportSpimSequencePlugIn implements PlugIn
{
final Partition partition = partitions.get( i );
final ProgressWriter p = new SubTaskProgressWriter( progress, 0, 0.95 * i / partitions.size() );
WriteSequenceToHdf5.writeHdf5PartitionFile( desc, perSetupExportMipmapInfo, params.deflate, partition, p );
WriteSequenceToHdf5.writeHdf5PartitionFile( desc, perSetupExportMipmapInfo, params.deflate, partition, null, null, p );
}
WriteSequenceToHdf5.writeHdf5PartitionLinkFile( desc, perSetupExportMipmapInfo, partitions, params.hdf5File );
}
else
{
partitions = null;
WriteSequenceToHdf5.writeHdf5File( desc, perSetupExportMipmapInfo, params.deflate, params.hdf5File, new SubTaskProgressWriter( progress, 0, 0.95 ) );
WriteSequenceToHdf5.writeHdf5File( desc, perSetupExportMipmapInfo, params.deflate, params.hdf5File, null, null, new SubTaskProgressWriter( progress, 0, 0.95 ) );
}
final Hdf5ImageLoader loader = new Hdf5ImageLoader( params.hdf5File, partitions, null, false );
......
package bdv.ij;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import bdv.BigDataViewer;
import bdv.ij.util.ProgressWriterIJ;
import bdv.img.imagestack.ImageStackImageLoader;
import bdv.img.virtualstack.VirtualStackImageLoader;
import bdv.spimdata.SequenceDescriptionMinimal;
import bdv.spimdata.SpimDataMinimal;
import bdv.spimdata.WrapBasicImgLoader;
import bdv.tools.brightness.ConverterSetup;
import bdv.tools.brightness.SetupAssignments;
import bdv.viewer.DisplayMode;
import bdv.viewer.VisibilityAndGrouping;
import ij.CompositeImage;
import ij.IJ;
import ij.ImageJ;
import ij.ImagePlus;
import ij.WindowManager;
import ij.plugin.PlugIn;
import ij.process.LUT;
import mpicbg.spim.data.SpimDataException;
import mpicbg.spim.data.generic.sequence.BasicImgLoader;
import mpicbg.spim.data.generic.sequence.BasicViewSetup;
import mpicbg.spim.data.registration.ViewRegistration;
import mpicbg.spim.data.registration.ViewRegistrations;
import mpicbg.spim.data.sequence.Channel;
import mpicbg.spim.data.sequence.FinalVoxelDimensions;
import mpicbg.spim.data.sequence.TimePoint;
import mpicbg.spim.data.sequence.TimePoints;
import net.imglib2.FinalDimensions;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.type.numeric.ARGBType;
/**
* ImageJ plugin to show the current image in BigDataViewer.
*
* @author Tobias Pietzsch <tobias.pietzsch@gmail.com>
*/
public class OpenImagePlusPlugIn implements PlugIn
{
public static void main( final String[] args )
{
System.setProperty( "apple.laf.useScreenMenuBar", "true" );
new ImageJ();
IJ.run("Confocal Series (2.2MB)");
// IJ.run("Fly Brain (1MB)");
new OpenImagePlusPlugIn().run( null );
}
@Override
public void run( final String arg )
{
// get the current image
final ImagePlus imp = WindowManager.getCurrentImage();
// make sure there is one
if ( imp == null )
{
IJ.showMessage( "Please open an image first." );
return;
}
// check the image type
switch ( imp.getType() )
{
case ImagePlus.GRAY8:
case ImagePlus.GRAY16:
case ImagePlus.GRAY32:
case ImagePlus.COLOR_RGB:
break;
default:
IJ.showMessage( "Only 8, 16, 32-bit images and RGB images are supported currently!" );
return;
}
// check the image dimensionality
if ( imp.getNDimensions() < 3 )
{
IJ.showMessage( "Image must be at least 3-dimensional!" );
return;
}
// get calibration and image size
final double pw = imp.getCalibration().pixelWidth;
final double ph = imp.getCalibration().pixelHeight;
final double pd = imp.getCalibration().pixelDepth;
String punit = imp.getCalibration().getUnit();
if ( punit == null || punit.isEmpty() )
punit = "px";
final FinalVoxelDimensions voxelSize = new FinalVoxelDimensions( punit, pw, ph, pd );
final int w = imp.getWidth();
final int h = imp.getHeight();
final int d = imp.getNSlices();
final FinalDimensions size = new FinalDimensions( new int[] { w, h, d } );
// propose reasonable mipmap settings
// final ExportMipmapInfo autoMipmapSettings = ProposeMipmaps.proposeMipmaps( new BasicViewSetup( 0, "", size, voxelSize ) );
// imp.getDisplayRangeMin();
// imp.getDisplayRangeMax();
// create ImgLoader wrapping the image
final BasicImgLoader< ? > imgLoader;
if ( imp.getStack().isVirtual() )
{
switch ( imp.getType() )
{
case ImagePlus.GRAY8:
imgLoader = VirtualStackImageLoader.createUnsignedByteInstance( imp );
break;
case ImagePlus.GRAY16:
imgLoader = VirtualStackImageLoader.createUnsignedShortInstance( imp );
break;
case ImagePlus.GRAY32:
imgLoader = VirtualStackImageLoader.createFloatInstance( imp );
break;
case ImagePlus.COLOR_RGB:
default:
imgLoader = VirtualStackImageLoader.createARGBInstance( imp );
break;
}
}
else
{
switch ( imp.getType() )
{
case ImagePlus.GRAY8:
imgLoader = ImageStackImageLoader.createUnsignedByteInstance( imp );
break;
case ImagePlus.GRAY16:
imgLoader = ImageStackImageLoader.createUnsignedShortInstance( imp );
break;
case ImagePlus.GRAY32:
imgLoader = ImageStackImageLoader.createFloatInstance( imp );
break;
case ImagePlus.COLOR_RGB:
default:
imgLoader = ImageStackImageLoader.createARGBInstance( imp );
break;
}
}
final int numTimepoints = imp.getNFrames();
final int numSetups = imp.getNChannels();
// create setups from channels
final HashMap< Integer, BasicViewSetup > setups = new HashMap< Integer, BasicViewSetup >( numSetups );
for ( int s = 0; s < numSetups; ++s )
{
final BasicViewSetup setup = new BasicViewSetup( s, String.format( "channel %d", s + 1 ), size, voxelSize );
setup.setAttribute( new Channel( s + 1 ) );
setups.put( s, setup );
}
// create timepoints
final ArrayList< TimePoint > timepoints = new ArrayList< TimePoint >( numTimepoints );
for ( int t = 0; t < numTimepoints; ++t )
timepoints.add( new TimePoint( t ) );
final SequenceDescriptionMinimal seq = new SequenceDescriptionMinimal( new TimePoints( timepoints ), setups, imgLoader, null );
// create ViewRegistrations from the images calibration
final AffineTransform3D sourceTransform = new AffineTransform3D();
sourceTransform.set( pw, 0, 0, 0, 0, ph, 0, 0, 0, 0, pd, 0 );
final ArrayList< ViewRegistration > registrations = new ArrayList< ViewRegistration >();
for ( int t = 0; t < numTimepoints; ++t )
for ( int s = 0; s < numSetups; ++s )
registrations.add( new ViewRegistration( t, s, sourceTransform ) );
final File basePath = new File(".");
final SpimDataMinimal spimData = new SpimDataMinimal( basePath, seq, new ViewRegistrations( registrations ) );
WrapBasicImgLoader.wrapImgLoaderIfNecessary( spimData );
try
{
final BigDataViewer bdv = new BigDataViewer( spimData, "BigDataViewer", new ProgressWriterIJ() );
final SetupAssignments sa = bdv.getSetupAssignments();
final VisibilityAndGrouping vg = bdv.getViewer().getVisibilityAndGrouping();
if ( imp.isComposite() )
transferChannelSettings( ( CompositeImage ) imp, sa, vg );
else if ( imp.getType() == ImagePlus.COLOR_RGB )
transferSettingsRGB( imp, sa );
}
catch ( final SpimDataException e )
{
throw new RuntimeException( e );
}
}
protected void transferChannelSettings( final CompositeImage ci, final SetupAssignments setupAssignments, final VisibilityAndGrouping visibility )
{
final int nChannels = ci.getNChannels();
final int mode = ci.getCompositeMode();
final boolean transferColor = mode == IJ.COMPOSITE || mode == IJ.COLOR;
for ( int c = 0; c < nChannels; ++c )
{
final LUT lut = ci.getChannelLut( c + 1 );
final ConverterSetup setup = setupAssignments.getConverterSetups().get( c );
if ( transferColor )
setup.setColor( new ARGBType( lut.getRGB( 255 ) ) );
setup.setDisplayRange( lut.min, lut.max );
}
if ( mode == IJ.COMPOSITE )
{
final boolean[] activeChannels = ci.getActiveChannels();
visibility.setDisplayMode( DisplayMode.FUSED );
for ( int i = 0; i < activeChannels.length; ++i )
visibility.setSourceActive( i, activeChannels[ i ] );
}
else
visibility.setDisplayMode( DisplayMode.SINGLE );
visibility.setCurrentSource( ci.getChannel() - 1 );
}
protected void transferSettingsRGB( final ImagePlus imp, final SetupAssignments setupAssignments )
{
final ConverterSetup setup = setupAssignments.getConverterSetups().get( 0 );
setup.setDisplayRange( imp.getDisplayRangeMin(), imp.getDisplayRangeMax() );
}
}
......@@ -203,7 +203,7 @@ public class Scripting
public void writePartition( final int index )
{
if ( index >= 0 && index < partitions.size() )
WriteSequenceToHdf5.writeHdf5PartitionFile( spimData.getSequenceDescription(), perSetupMipmapInfo, deflate, partitions.get( index ), null );
WriteSequenceToHdf5.writeHdf5PartitionFile( spimData.getSequenceDescription(), perSetupMipmapInfo, deflate, partitions.get( index ), null, null, null );
}
public void writeXmlAndLinks() throws SpimDataException
......
......@@ -12,6 +12,8 @@ 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;
/**
......@@ -40,33 +42,45 @@ public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > imp
{
if( imp.getType() != ImagePlus.GRAY8 )
throw new RuntimeException( "expected ImagePlus type GRAY8" );
return new ImagePlusImgLoader< UnsignedByteType >( imp, VirtualStackImageLoader.createUnsignedByteInstance( imp ), minMaxOption, min, max );
if ( imp.getStack() != null && imp.getStack().isVirtual() )
return new ImagePlusImgLoader< UnsignedByteType >( imp, VirtualStackImageLoader.createUnsignedByteInstance( imp ), minMaxOption, min, max );
else
return new ImagePlusImgLoader< UnsignedByteType >( imp, ImageStackImageLoader.createUnsignedByteInstance( imp ), minMaxOption, min, max );
}
public static ImagePlusImgLoader< UnsignedShortType > 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" );
return new ImagePlusImgLoader< UnsignedShortType >( imp, VirtualStackImageLoader.createUnsignedShortInstance( imp ), minMaxOption, min, max );
if ( imp.getStack() != null && imp.getStack().isVirtual() )
return new ImagePlusImgLoader< UnsignedShortType >( imp, VirtualStackImageLoader.createUnsignedShortInstance( imp ), minMaxOption, min, max );
else
return new ImagePlusImgLoader< UnsignedShortType >( imp, ImageStackImageLoader.createUnsignedShortInstance( imp ), minMaxOption, min, max );
}
public static ImagePlusImgLoader< FloatType > 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" );
return new ImagePlusImgLoader< FloatType >( imp, VirtualStackImageLoader.createFloatInstance( imp ), minMaxOption, min, max );
if ( imp.getStack() != null && imp.getStack().isVirtual() )
return new ImagePlusImgLoader< FloatType >( imp, VirtualStackImageLoader.createFloatInstance( imp ), minMaxOption, min, max );
else
return new ImagePlusImgLoader< FloatType >( imp, ImageStackImageLoader.createFloatInstance( imp ), minMaxOption, min, max );
}
protected final ImagePlus imp;
protected final VirtualStackImageLoader< T, ?, ? > loader;
protected final BasicImgLoader< T > loader;
protected VolatileGlobalCellCache< ? > loadercache;
protected double impMin;
protected double impMax;
@SuppressWarnings( "unchecked" )
protected ImagePlusImgLoader( final ImagePlus imp,
final VirtualStackImageLoader< T, ?, ? > loader,
final BasicImgLoader< T > loader,
final MinMaxOption minMaxOption,
final double min,
final double max )
......@@ -74,6 +88,11 @@ public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > imp
this.imp = imp;
this.loader = loader;
if ( loader instanceof VirtualStackImageLoader )
this.loadercache = ( ( VirtualStackImageLoader< T, ?, ? > ) loader ).getCache();
else
this.loadercache = null;
if ( minMaxOption == MinMaxOption.COMPUTE )
{
impMin = Double.POSITIVE_INFINITY;
......@@ -88,7 +107,8 @@ public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > imp
ComputeMinMax.computeMinMax( loader.getImage( new ViewId( t, s ) ), minT, maxT );
impMin = Math.min( minT.getRealDouble(), impMin );
impMax = Math.max( maxT.getRealDouble(), impMax );
loader.getCache().clearCache();
if ( loadercache != null )
loadercache.clearCache();
}
System.out.println( "COMPUTE" );
System.out.println( impMin + " " + impMax );
......@@ -109,10 +129,21 @@ public class ImagePlusImgLoader< T extends RealType< T > & NativeType< T > > imp
}
}
public void clearCache()
{
if ( loadercache != null )
{
loadercache.clearCache();
System.runFinalization();
System.gc();
}
}
@Override
public RandomAccessibleInterval< UnsignedShortType > getImage( final ViewId view )
{
loader.getCache().clearCache();
if ( loadercache != null )
loadercache.clearCache();
final RandomAccessibleInterval< T > img = loader.getImage( view );
return Converters.convert( img, new RealUnsignedShortConverter< T >( impMin, impMax ), new UnsignedShortType() );
}
......
......@@ -315,7 +315,7 @@ public class CellVoyagerDataExporter
* Write to HDF5
*/
WriteSequenceToHdf5.writeHdf5File( sequenceDescriptionHDF5, resolutions, chunks, true, hdf5File, progressWriter );
WriteSequenceToHdf5.writeHdf5File( sequenceDescriptionHDF5, resolutions, chunks, true, hdf5File, null, null, progressWriter );
/*
* write XML sequence description
......
package bdv.img.imagestack;
import ij.ImagePlus;
import mpicbg.spim.data.generic.sequence.BasicImgLoader;
import mpicbg.spim.data.sequence.ViewId;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.basictypeaccess.array.ArrayDataAccess;
import net.imglib2.img.basictypeaccess.array.ByteArray;
import net.imglib2.img.basictypeaccess.array.FloatArray;
import net.imglib2.img.basictypeaccess.array.IntArray;
import net.imglib2.img.basictypeaccess.array.ShortArray;
import net.imglib2.img.planar.PlanarImg;
import net.imglib2.type.NativeType;
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.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 static ImageStackImageLoader< UnsignedByteType, ByteArray > createUnsignedByteInstance( final ImagePlus imp )
{
return new ImageStackImageLoader< UnsignedByteType, ByteArray >( new UnsignedByteType(), imp )
{
@Override
protected ByteArray wrapPixels( final Object array )
{
return new ByteArray( ( byte[] ) array );
}
@Override
protected void linkType( final PlanarImg< UnsignedByteType, ByteArray > img )
{
img.setLinkedType( new UnsignedByteType( img ) );
}
};
}
public static ImageStackImageLoader< UnsignedShortType, ShortArray > createUnsignedShortInstance( final ImagePlus imp )
{
return new ImageStackImageLoader< UnsignedShortType, ShortArray >( new UnsignedShortType(), imp )
{
@Override
protected ShortArray wrapPixels( final Object array )
{
return new ShortArray( ( short[] ) array );
}
@Override
protected void linkType( final PlanarImg< UnsignedShortType, ShortArray > img )
{
img.setLinkedType( new UnsignedShortType( img ) );
}
};
}
public static ImageStackImageLoader< FloatType, FloatArray > createFloatInstance( final ImagePlus imp )
{
return new ImageStackImageLoader< FloatType, FloatArray >( new FloatType(), imp )
{
@Override
protected FloatArray wrapPixels( final Object array )
{
return new FloatArray( ( float[] ) array );
}
@Override
protected void linkType( final PlanarImg< FloatType, FloatArray > img )
{
img.setLinkedType( new FloatType( img ) );
}
};
}