Skip to content
Snippets Groups Projects
Commit f2b6f764 authored by Stephan Saalfeld's avatar Stephan Saalfeld
Browse files

added TiledImageLoader including reflection hack to generate generic

cached images
parent 9c3d967c
Branches
No related tags found
No related merge requests found
/*
* #%L
* BigDataViewer core classes with minimal dependencies
* %%
* Copyright (C) 2012 - 2016 Tobias Pietzsch, Stephan Saalfeld, Stephan Preibisch,
* Jean-Yves Tinevez, HongKee Moon, Johannes Schindelin, Curtis Rueden, John Bogovic
* %%
* 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 bdv.img.catmaid;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import bdv.AbstractViewerSetupImgLoader;
import bdv.ViewerImgLoader;
import bdv.ViewerSetupImgLoader;
import bdv.cache.CacheHints;
import bdv.cache.LoadingStrategy;
import bdv.img.cache.CacheArrayLoader;
import bdv.img.cache.CachedCellImg;
import bdv.img.cache.VolatileGlobalCellCache;
import bdv.img.cache.VolatileImgCells;
import bdv.img.cache.VolatileImgCells.CellCache;
import mpicbg.spim.data.generic.sequence.ImgLoaderHint;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.Volatile;
import net.imglib2.img.NativeImg;
import net.imglib2.img.basictypeaccess.volatiles.VolatileAccess;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.type.NativeType;
import net.imglib2.util.Fraction;
public class TiledImageLoader< A extends VolatileAccess, T extends NativeType< T >, V extends Volatile< T > & NativeType< V > > implements ViewerImgLoader
{
protected final int numScales;
protected final double[][] mipmapResolutions;
protected final AffineTransform3D[] mipmapTransforms;
protected final long[][] imageDimensions;
protected final int[][] blockDimensions;
protected VolatileGlobalCellCache cache;
final protected HashMap< Integer, TiledSetupImageLoader > setupLoaders = new HashMap<>();
final static private int[][] blockDimensions(
final int tileWidth,
final int tileHeight,
final int numScales )
{
final int[][] blockDimensions = new int[ numScales ][];
for ( int i = 0; i < numScales; ++i )
blockDimensions[ i ] = new int[]{ tileWidth, tileHeight, 1 };
return blockDimensions;
}
public TiledImageLoader(
final List< CacheArrayLoader< A > > loaders,
final T type,
final V vType,
final long width,
final long height,
final long depth,
final double zScale,
final int tileWidth,
final int tileHeight,
final int[][] blockDimensions,
final boolean topLeft )
{
this.numScales = blockDimensions.length;
mipmapResolutions = new double[ numScales ][];
imageDimensions = new long[ numScales ][];
mipmapTransforms = new AffineTransform3D[ numScales ];
final int[] zScales = new int[ numScales ];
this.blockDimensions = new int[ numScales ][];
for ( int l = 0; l < numScales; ++l )
{
final int sixy = 1 << l;
final int siz = Math.max( 1, ( int )Math.round( sixy / zScale ) );
mipmapResolutions[ l ] = new double[] { sixy, sixy, siz };
imageDimensions[ l ] = new long[] { width >> l, height >> l, depth / siz };
this.blockDimensions[ l ] = blockDimensions[ l ].clone();
zScales[ l ] = siz;
final AffineTransform3D mipmapTransform = new AffineTransform3D();
mipmapTransform.set( sixy, 0, 0 );
mipmapTransform.set( sixy, 1, 1 );
mipmapTransform.set( zScale * siz, 2, 2 );
if ( topLeft )
{
mipmapTransform.set( 0.5 * ( sixy - 1 ), 0, 3 );
mipmapTransform.set( 0.5 * ( sixy - 1 ), 1, 3 );
}
mipmapTransform.set( 0.5 * ( zScale * siz - 1 ), 2, 3 );
mipmapTransforms[ l ] = mipmapTransform;
}
for ( int i = 0; i < loaders.size(); ++i )
setupLoaders.put( i, new TiledSetupImageLoader( loaders.get( i ), type, vType, i ) );
cache = new VolatileGlobalCellCache( numScales, 10 );
}
public TiledImageLoader(
final List< CacheArrayLoader< A > > loaders,
final T type,
final V vType,
final long width,
final long height,
final long depth,
final double zScale,
final int tileWidth,
final int tileHeight,
final int[][] blockDimensions )
{
this( loaders, type, vType, width, height, depth, zScale, tileWidth, tileHeight, blockDimensions, true );
}
public TiledImageLoader(
final List< CacheArrayLoader< A > > loaders,
final T type,
final V vType,
final long width,
final long height,
final long depth,
final double zScale,
final int numScales,
final int tileWidth,
final int tileHeight,
final int blockWidth,
final int blockHeight,
final boolean topLeft )
{
this( loaders, type, vType, width, height, depth, zScale, tileWidth, tileHeight, blockDimensions( blockWidth, blockHeight, numScales ), topLeft );
}
public TiledImageLoader(
final List< CacheArrayLoader< A > > loaders,
final T type,
final V vType,
final long width,
final long height,
final long depth,
final double zScale,
final int numScales,
final int tileWidth,
final int tileHeight,
final int blockWidth,
final int blockHeight )
{
this( loaders, type, vType, width, height, depth, zScale, tileWidth, tileHeight, blockDimensions( blockWidth, blockHeight, numScales ), true );
}
public TiledImageLoader(
final List< CacheArrayLoader< A > > loaders,
final T type,
final V vType,
final long width,
final long height,
final long depth,
final double zScale,
final int numScales,
final int tileWidth,
final int tileHeight,
final boolean topLeft )
{
this( loaders, type, vType, width, height, depth, zScale, numScales, tileWidth, tileHeight, tileWidth, tileHeight, topLeft );
}
public TiledImageLoader(
final List< CacheArrayLoader< A > > loaders,
final T type,
final V vType,
final long width,
final long height,
final long depth,
final double zScale,
final int numScales,
final int tileWidth,
final int tileHeight )
{
this( loaders, type, vType, width, height, depth, zScale, numScales, tileWidth, tileHeight, true );
}
final static public int getNumScales( long width, long height, final long tileWidth, final long tileHeight )
{
int i = 1;
while ( ( width >>= 1 ) > tileWidth && ( height >>= 1 ) > tileHeight )
++i;
return i;
}
/**
* (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.
*/
protected < N extends NativeType< N > > CachedCellImg< N, A > prepareCachedImage(
final CacheArrayLoader< A > loader,
final int timepointId,
final int setupId,
final int level,
final LoadingStrategy loadingStrategy )
{
final long[] dimensions = imageDimensions[ level ];
final int priority = numScales - 1 - level;
final CacheHints cacheHints = new CacheHints( loadingStrategy, priority, false );
final CellCache< A > c = cache.new VolatileCellCache<>( timepointId, setupId, level, cacheHints, loader );
final VolatileImgCells< A > cells = new VolatileImgCells<>( c, new Fraction(), dimensions, blockDimensions[ level ] );
final CachedCellImg< N, A > img = new CachedCellImg<>( cells );
return img;
}
@Override
public VolatileGlobalCellCache getCacheControl()
{
return cache;
}
@Override
public ViewerSetupImgLoader< ?, ? > getSetupImgLoader( final int setupId )
{
return setupLoaders.get( setupId );
}
/**
* Reflection hack because there is no T NativeType<T>.create(NativeImg<?, A>) method in ImgLib2
* Note that for this method to be introduced, NativeType would need an additional generic parameter A
* that specifies the accepted family of access objects that can be used in the NativeImg... big change
*
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@SuppressWarnings( { "rawtypes", "unchecked" } )
protected void linkType( final NativeType t, final CachedCellImg img ) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
final Constructor constructor = t.getClass().getDeclaredConstructor( NativeImg.class );
if ( constructor != null )
{
final NativeType linkedType = ( NativeType )constructor.newInstance( img );
img.setLinkedType( linkedType );
}
}
public void setCache( final VolatileGlobalCellCache cache )
{
this.cache = cache;
}
public class TiledSetupImageLoader extends AbstractViewerSetupImgLoader< T, V >
{
final protected int setupId;
final protected CacheArrayLoader< A > loader;
public TiledSetupImageLoader( final CacheArrayLoader< A > loader, final T type, final V volatileType, final int setupId )
{
super( type, volatileType );
this.loader = loader;
this.setupId = setupId;
}
@Override
public RandomAccessibleInterval< T > getImage( final int timepointId, final int level, final ImgLoaderHint... hints )
{
try
{
final CachedCellImg< T, A > img = prepareCachedImage( loader, timepointId, setupId, level, LoadingStrategy.BLOCKING );
linkType( type, img );
return img;
}
catch ( final Exception e )
{
e.printStackTrace( System.err );
return null;
}
}
@Override
public RandomAccessibleInterval< V > getVolatileImage( final int timepointId, final int level, final ImgLoaderHint... hints )
{
try
{
final CachedCellImg< V, A > img = prepareCachedImage( loader, timepointId, setupId, level, LoadingStrategy.VOLATILE );
linkType( volatileType, img );
return img;
}
catch ( final Exception e )
{
e.printStackTrace( System.err );
return null;
}
}
@Override
public double[][] getMipmapResolutions()
{
return mipmapResolutions;
}
@Override
public AffineTransform3D[] getMipmapTransforms()
{
return mipmapTransforms;
}
@Override
public int numMipmapLevels()
{
return numScales;
}
}
}
/*
* #%L
* BigDataViewer core classes with minimal dependencies
* %%
* Copyright (C) 2012 - 2016 Tobias Pietzsch, Stephan Saalfeld, Stephan Preibisch,
* Jean-Yves Tinevez, HongKee Moon, Johannes Schindelin, Curtis Rueden, John Bogovic
* %%
* 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 bdv.img.catmaid;
import bdv.img.cache.CacheArrayLoader;
import ij.ImagePlus;
import ij.io.Opener;
import ij.process.Blitter;
import ij.process.FloatProcessor;
import net.imglib2.img.basictypeaccess.volatiles.array.VolatileFloatArray;
public class VolatileFloatArrayTileLoader implements CacheArrayLoader< VolatileFloatArray >
{
private VolatileFloatArray theEmptyArray;
private final String urlFormat;
private final int tileWidth;
private final int tileHeight;
final private int[] zScales;
/**
* <p>Create a {@link CacheArrayLoader} for a tiled image source. Tiles are
* addressed, in this order, by their</p>
* <ul>
* <li>scale level,</li>
* <li>scale,</li>
* <li>x,</li>
* <li>y,</li>
* <li>z,</li>
* <li>tile width,</li>
* <li>tile height,</li>
* <li>tile row, and</li>
* <li>tile column.</li>
* </ul>
* <p><code>urlFormat</code> specifies how these parameters are used
* to generate a URL referencing the tile. Examples:</p>
*
* <dl>
* <dt>"http://catmaid.org/my-data/xy/%5$d/%8$d_%9$d_%1$d.jpg"</dt>
* <dd>CATMAID DefaultTileSource (type 1)</dd>
* <dt>"http://catmaid.org/my-data/xy/?x=%3$d&amp;y=%4$d&amp;width=%6d&amp;height=%7$d&amp;row=%8$d&amp;col=%9$d&amp;scale=%2$f&amp;z=%4$d"</dt>
* <dd>CATMAID RequestTileSource (type 2)</dd>
* <dt>"http://catmaid.org/my-data/xy/%1$d/%5$d/%8$d/%9$d.jpg"</dt>
* <dd>CATMAID LargeDataTileSource (type 5)</dd>
* </dl>
*
* @param urlFormat
* @param tileWidth
* @param tileHeight
*/
public VolatileFloatArrayTileLoader( final String urlFormat, final int tileWidth, final int tileHeight, final int[] zScales )
{
theEmptyArray = new VolatileFloatArray( tileWidth * tileHeight, false );
this.urlFormat = urlFormat;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.zScales = zScales;
}
@Override
public int getBytesPerElement()
{
return 4;
}
final private void loadSliceArray(
final float[] slice,
final int level,
final double scale,
final long c0,
final long r0,
final long x0,
final long y0,
final long z,
final long xm,
final long ym,
final long[] min,
final int w,
final int h ) throws InterruptedException
{
final FloatProcessor ip = new FloatProcessor( w, h, slice );
for (
long c = c0, x = x0;
x < xm;
++c, x += tileWidth )
{
for (
long r = r0, y = y0;
y < ym;
++r, y += tileHeight )
{
final String urlString = String.format( urlFormat, level, scale, x, y, z, tileWidth, tileHeight, r, c );
// System.out.println( "r=" + r + " c=" + c + " : " + urlString );
final ImagePlus tile;
// ij.io.Opener cannot handle "file:" URLs...
if ( urlString.startsWith( "file:" ) )
tile = new Opener().openImage( urlString.substring( 5 ) );
else
tile = new Opener().openURL( urlString );
if ( tile == null )
System.out.println( "failed loading r=" + r + " c=" + c );
else
{
final FloatProcessor tp = tile.getProcessor().convertToFloatProcessor();
ip.copyBits( tp, ( int )( x - min[ 0 ] ), ( int )( y - min[ 1 ] ), Blitter.COPY );
}
}
}
}
final private void averageSlice(
final float[] slice,
final int level,
final double scale,
final long c0,
final long r0,
final long x0,
final long y0,
final long xm,
final long ym,
final long[] min,
final int w,
final int h ) throws InterruptedException
{
final double[] fs = new double[ slice.length ];
for ( int z = ( int ) min[ 2 ] * zScales[ level ], dz = 0; dz < zScales[ level ]; ++dz )
{
loadSliceArray( slice, level, scale, c0, r0, x0, y0, z + dz, xm, ym, min, w, h );
for ( int i = 0; i < slice.length; ++i )
fs[ i ] += slice[ i ];
}
for ( int i = 0; i < slice.length; ++i )
slice[ i ] = ( float )fs[ i ];
}
@Override
public VolatileFloatArray loadArray(
final int timepoint,
final int setup,
final int level,
final int[] dimensions,
final long[] min ) throws InterruptedException
{
final int w = dimensions[ 0 ];
final int h = dimensions[ 1 ];
final long xm = min[ 0 ] + w;
final long ym = min[ 1 ] + h;
final double scale = 1.0 / Math.pow(2.0, level);
final float[] slice = new float[ w * h ];
final long c0 = min[ 0 ] / tileWidth;
final long r0 = min[ 1 ] / tileHeight;
final long x0 = c0 * tileWidth;
final long y0 = r0 * tileHeight;
final float[] data;
if ( dimensions[ 2 ] > 1 )
{
data = new float[ w * h * dimensions[ 2 ] ];
final long[] zMin = min.clone();
for ( int z = 0; z < dimensions[ 2 ]; ++z )
{
zMin[ 2 ] = min[ 2 ] + z;
if ( zScales[ level ] > 1 )
averageSlice( slice, level, scale, c0, r0, x0, y0, xm, ym, zMin, w, h );
else
loadSliceArray( slice, level, scale, c0, r0, x0, y0, zMin[ 2 ], xm, ym, zMin, w, h );
System.arraycopy( slice, 0, data, z * slice.length, slice.length );
}
}
else
{
data = slice;
if ( zScales[ level ] > 1 )
averageSlice( slice, level, scale, c0, r0, x0, y0, xm, ym, min, w, h );
else
loadSliceArray( slice, level, scale, c0, r0, x0, y0, min[ 2 ], xm, ym, min, w, h );
}
return new VolatileFloatArray( data, true );
}
@Override
public VolatileFloatArray emptyArray( final int[] dimensions )
{
int numEntities = 1;
for ( int i = 0; i < dimensions.length; ++i )
numEntities *= dimensions[ i ];
if ( theEmptyArray.getCurrentStorageArray().length < numEntities )
theEmptyArray = new VolatileFloatArray( numEntities, false );
return theEmptyArray;
}
}
/*
* #%L
* BigDataViewer core classes with minimal dependencies
* %%
* Copyright (C) 2012 - 2016 Tobias Pietzsch, Stephan Saalfeld, Stephan Preibisch,
* Jean-Yves Tinevez, HongKee Moon, Johannes Schindelin, Curtis Rueden, John Bogovic
* %%
* 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 bdv.img.catmaid;
import bdv.img.cache.CacheArrayLoader;
import ij.ImagePlus;
import ij.io.Opener;
import ij.process.Blitter;
import ij.process.ByteProcessor;
import net.imglib2.img.basictypeaccess.volatiles.array.VolatileByteArray;
public class VolatileUnsignedByteArrayTileLoader implements CacheArrayLoader< VolatileByteArray >
{
private VolatileByteArray theEmptyArray;
private final String urlFormat;
private final int tileWidth;
private final int tileHeight;
final private int[] zScales;
/**
* <p>Create a {@link CacheArrayLoader} for a tiled image source. Tiles are
* addressed, in this order, by their</p>
* <ul>
* <li>scale level,</li>
* <li>scale,</li>
* <li>x,</li>
* <li>y,</li>
* <li>z,</li>
* <li>tile width,</li>
* <li>tile height,</li>
* <li>tile row, and</li>
* <li>tile column.</li>
* </ul>
* <p><code>urlFormat</code> specifies how these parameters are used
* to generate a URL referencing the tile. Examples:</p>
*
* <dl>
* <dt>"http://catmaid.org/my-data/xy/%5$d/%8$d_%9$d_%1$d.jpg"</dt>
* <dd>CATMAID DefaultTileSource (type 1)</dd>
* <dt>"http://catmaid.org/my-data/xy/?x=%3$d&amp;y=%4$d&amp;width=%6d&amp;height=%7$d&amp;row=%8$d&amp;col=%9$d&amp;scale=%2$f&amp;z=%4$d"</dt>
* <dd>CATMAID RequestTileSource (type 2)</dd>
* <dt>"http://catmaid.org/my-data/xy/%1$d/%5$d/%8$d/%9$d.jpg"</dt>
* <dd>CATMAID LargeDataTileSource (type 5)</dd>
* </dl>
*
* @param urlFormat
* @param tileWidth
* @param tileHeight
*/
public VolatileUnsignedByteArrayTileLoader( final String urlFormat, final int tileWidth, final int tileHeight, final int[] zScales )
{
theEmptyArray = new VolatileByteArray( tileWidth * tileHeight, false );
this.urlFormat = urlFormat;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.zScales = zScales;
}
@Override
public int getBytesPerElement()
{
return 1;
}
final private void loadSliceArray(
final byte[] slice,
final int level,
final double scale,
final long c0,
final long r0,
final long x0,
final long y0,
final long z,
final long xm,
final long ym,
final long[] min,
final int w,
final int h ) throws InterruptedException
{
final ByteProcessor ip = new ByteProcessor( w, h, slice );
for (
long c = c0, x = x0;
x < xm;
++c, x += tileWidth )
{
for (
long r = r0, y = y0;
y < ym;
++r, y += tileHeight )
{
final String urlString = String.format( urlFormat, level, scale, x, y, z, tileWidth, tileHeight, r, c );
// System.out.println( urlString );
final ImagePlus tile;
// ij.io.Opener cannot handle "file:" URLs...
if ( urlString.startsWith( "file:" ) )
tile = new Opener().openImage( urlString.substring( 5 ) );
else
tile = new Opener().openURL( urlString );
if ( tile == null )
System.out.println( "failed loading r=" + r + " c=" + c );
else
{
final ByteProcessor tp = tile.getProcessor().convertToByteProcessor();
ip.copyBits( tp, ( int )( x - min[ 0 ] ), ( int )( y - min[ 1 ] ), Blitter.COPY );
}
}
}
}
final private void averageSlice(
final byte[] slice,
final int level,
final double scale,
final long c0,
final long r0,
final long x0,
final long y0,
final long xm,
final long ym,
final long[] min,
final int w,
final int h ) throws InterruptedException
{
final double[] fs = new double[ slice.length ];
for ( int z = ( int ) min[ 2 ] * zScales[ level ], dz = 0; dz < zScales[ level ]; ++dz )
{
loadSliceArray( slice, level, scale, c0, r0, x0, y0, z + dz, xm, ym, min, w, h );
for ( int i = 0; i < slice.length; ++i )
fs[ i ] += slice[ i ];
}
for ( int i = 0; i < slice.length; ++i )
slice[ i ] = ( byte )Math.round( fs[ i ] );
}
@Override
public VolatileByteArray loadArray(
final int timepoint,
final int setup,
final int level,
final int[] dimensions,
final long[] min ) throws InterruptedException
{
final int w = dimensions[ 0 ];
final int h = dimensions[ 1 ];
final long xm = min[ 0 ] + w;
final long ym = min[ 1 ] + h;
final double scale = 1.0 / Math.pow(2.0, level);
final byte[] slice = new byte[ w * h ];
final long c0 = min[ 0 ] / tileWidth;
final long r0 = min[ 1 ] / tileHeight;
final long x0 = c0 * tileWidth;
final long y0 = r0 * tileHeight;
final byte[] data;
if ( dimensions[ 2 ] > 1 )
{
data = new byte[ w * h * dimensions[ 2 ] ];
final long[] zMin = min.clone();
for ( int z = 0; z < dimensions[ 2 ]; ++z )
{
zMin[ 2 ] = min[ 2 ] + z;
if ( zScales[ level ] > 1 )
averageSlice( slice, level, scale, c0, r0, x0, y0, xm, ym, zMin, w, h );
else
loadSliceArray( slice, level, scale, c0, r0, x0, y0, zMin[ 2 ], xm, ym, zMin, w, h );
System.arraycopy( slice, 0, data, z * slice.length, slice.length );
}
}
else
{
data = slice;
if ( zScales[ level ] > 1 )
averageSlice( slice, level, scale, c0, r0, x0, y0, xm, ym, min, w, h );
else
loadSliceArray( slice, level, scale, c0, r0, x0, y0, min[ 2 ], xm, ym, min, w, h );
}
// new ImagePlus( "", new ByteProcessor( w, h, data) ).show();
return new VolatileByteArray( data, true );
}
@Override
public VolatileByteArray emptyArray( final int[] dimensions )
{
int numEntities = 1;
for ( int i = 0; i < dimensions.length; ++i )
numEntities *= dimensions[ i ];
if ( theEmptyArray.getCurrentStorageArray().length < numEntities )
theEmptyArray = new VolatileByteArray( numEntities, false );
return theEmptyArray;
}
}
/*
* #%L
* BigDataViewer core classes with minimal dependencies
* %%
* Copyright (C) 2012 - 2016 Tobias Pietzsch, Stephan Saalfeld, Stephan Preibisch,
* Jean-Yves Tinevez, HongKee Moon, Johannes Schindelin, Curtis Rueden, John Bogovic
* %%
* 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 bdv.img.catmaid;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.jdom2.Element;
import bdv.img.cache.CacheArrayLoader;
import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription;
import mpicbg.spim.data.generic.sequence.ImgLoaderIo;
import mpicbg.spim.data.generic.sequence.XmlIoBasicImgLoader;
import net.imglib2.Volatile;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.integer.UnsignedByteType;
import net.imglib2.type.numeric.real.FloatType;
import net.imglib2.type.volatiles.VolatileFloatType;
import net.imglib2.type.volatiles.VolatileUnsignedByteType;
@SuppressWarnings( "rawtypes" )
@ImgLoaderIo( format = "tiled", type = TiledImageLoader.class )
public class XmlIoTiledImageLoader
implements XmlIoBasicImgLoader< TiledImageLoader >
{
@Override
public Element toXml( final TiledImageLoader imgLoader, final File basePath )
{
throw new UnsupportedOperationException( "not implemented" );
}
@SuppressWarnings( { "unchecked" } )
@Override
public TiledImageLoader fromXml( final Element elem, final File basePath, final AbstractSequenceDescription< ?, ?, ? > sequenceDescription )
{
final long width = Long.parseLong( elem.getChildText( "width" ) );
final long height = Long.parseLong( elem.getChildText( "height" ) );
final long depth = Long.parseLong( elem.getChildText( "depth" ) );
final double resXY = Double.parseDouble( elem.getChildText( "resXY" ) );
final double resZ = Double.parseDouble( elem.getChildText( "resZ" ) );
final double zScale = resZ / resXY;
final List< String > urlFormats = new ArrayList<>();
elem.getChildren( "urlFormat" ).forEach( a -> urlFormats.add( a.getText() ) );
final int tileWidth = Integer.parseInt( elem.getChildText( "tileWidth" ) );
final int tileHeight = Integer.parseInt( elem.getChildText( "tileHeight" ) );
final String blockWidthString = elem.getChildText( "blockWidth" );
final String blockHeightString = elem.getChildText( "blockHeight" );
final String blockDepthString = elem.getChildText( "blockDepth" );
final int blockWidth = blockWidthString == null ? tileWidth : Integer.parseInt( blockWidthString );
final int blockHeight = blockHeightString == null ? tileHeight : Integer.parseInt( blockHeightString );
final int blockDepth = blockDepthString == null ? 1 : Integer.parseInt( blockDepthString );
System.out.println( String.format( "Block size = (%d, %d, %d)", blockWidth, blockHeight, blockDepth ) );
final String numScalesString = elem.getChildText( "numScales" );
int numScales;
if ( numScalesString == null )
numScales = CatmaidImageLoader.getNumScales( width, height, tileWidth, tileHeight );
else
numScales = Integer.parseInt( numScalesString );
final int[][] blockSize = new int[ numScales ][];
final int[] zScales = new int[ numScales ];
for ( int i = 0; i < numScales; ++i )
{
blockSize[ i ] = new int[]{ blockWidth, blockHeight, blockDepth };
final int sixy = 1 << i;
final int siz = Math.max( 1, ( int )Math.round( sixy / zScale ) );
zScales[ i ] = siz;
}
final String type = elem.getChildText( "type" );
final ArrayList< CacheArrayLoader< ? > > arrayLoaders = new ArrayList<>();
final NativeType t;
final NativeType v;
switch ( type )
{
case "float32":
urlFormats.forEach( urlFormat -> arrayLoaders.add( new VolatileFloatArrayTileLoader( urlFormat, tileWidth, tileHeight, zScales ) ) );
t = new FloatType();
v = new VolatileFloatType();
break;
default:
urlFormats.forEach( urlFormat -> arrayLoaders.add( new VolatileUnsignedByteArrayTileLoader( urlFormat, tileWidth, tileHeight, zScales ) ) );
t = new UnsignedByteType();
v =new VolatileUnsignedByteType();
}
return new TiledImageLoader(
arrayLoaders,
t,
( Volatile & NativeType )v,
width,
height,
depth,
resZ / resXY,
tileWidth,
tileHeight,
blockSize );
}
}
......@@ -7,13 +7,13 @@
* %%
* 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
......@@ -40,6 +40,7 @@ import java.util.Map;
import org.jdom2.Element;
import bdv.img.catmaid.XmlIoCatmaidImageLoader;
import bdv.img.catmaid.XmlIoTiledImageLoader;
import bdv.img.hdf5.Hdf5ImageLoader;
import bdv.img.hdf5.Partition;
import bdv.img.openconnectome.XmlIoOpenConnectomeImageLoader;
......@@ -177,6 +178,10 @@ public class XmlIoSpimDataMinimalLegacy
{
return new XmlIoCatmaidImageLoader().fromXml( elem, basePath, sequenceDescription );
}
else if ( classn.equals( "bdv.img.catmaid.TiledImageLoader" ) )
{
return new XmlIoTiledImageLoader().fromXml( elem, basePath, sequenceDescription );
}
else if ( classn.equals( "bdv.img.openconnectome.OpenConnectomeImageLoader" ) )
{
return new XmlIoOpenConnectomeImageLoader().fromXml( elem, basePath, sequenceDescription );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment