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

transferred and adjusted OpenConnectome backend from imglib2-remote-viewer

parent 9b4da64f
No related branches found
No related tags found
No related merge requests found
package bdv.img.openconnectome;
import java.io.Serializable;
import java.util.HashMap;
public class OpenConnectomeDataset implements Serializable
{
private static final long serialVersionUID = -3203047697934754547L;
public HashMap< String, int[] > cube_dimension;
public HashMap< String, long[] > imagesize;
public HashMap< String, long[] > isotropic_slicerange;
public HashMap< String, Long > neariso_scaledown;
public long[] resolutions;
public long[] slicerange;
public HashMap< String, Double > zscale;
public HashMap< String, long[] > zscaled_slicerange;
}
\ No newline at end of file
package bdv.img.openconnectome;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import mpicbg.spim.data.View;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.NativeImg;
import net.imglib2.img.basictypeaccess.volatiles.array.VolatileByteArray;
import net.imglib2.img.cell.CellImg;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.ARGBType;
import net.imglib2.type.numeric.integer.UnsignedByteType;
import net.imglib2.type.numeric.real.FloatType;
import net.imglib2.type.volatiles.VolatileARGBType;
import net.imglib2.type.volatiles.VolatileUnsignedByteType;
import org.jdom2.Element;
import bdv.ViewerImgLoader;
import bdv.img.cache.Cache;
import bdv.img.cache.VolatileCell;
import bdv.img.cache.VolatileGlobalCellCache;
import bdv.img.cache.VolatileGlobalCellCache.LoadingStrategy;
import bdv.img.cache.VolatileImgCells;
import bdv.img.cache.VolatileImgCells.CellCache;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
public class OpenConnectomeImageLoader implements ViewerImgLoader< UnsignedByteType, VolatileUnsignedByteType >
{
/**
* URL of the
*/
private String baseUrl;
private String token;
private String mode;
private int numScales;
private double[][] mipmapResolutions;
private long[][] imageDimensions;
private int[][] blockDimensions;
private AffineTransform3D[] mipmapTransforms;
protected VolatileGlobalCellCache< VolatileByteArray > cache;
/**
* Fetch the list of public tokens from an OpenConnectome volume cutout
* service, e.g.
* {@linkplain http://openconnecto.me/emca/public_tokens/}.
*
* @param baseUrl e.g. "http://openconnecto.me/emca"
* @return a list of {@link String Strings}
* @throws JsonSyntaxException
* @throws JsonIOException
* @throws IOException
*/
final static public String[] fetchTokenList( final String baseUrl )
throws JsonSyntaxException, JsonIOException, IOException
{
final Gson gson = new Gson();
final URL url = new URL( baseUrl + "/public_tokens/" );
final String[] tokens = gson.fromJson( new InputStreamReader( url.openStream() ), String[].class );
return tokens;
}
/**
* Fetch information for a token from an OpenConnectome volume cutout
* service, e.g.
* {@linkplain http://openconnecto.me/emca/<token>/info/}.
*
* @param baseUrl e.g. "http://openconnecto.me/emca"
* @param token
* @return an {@link OpenConnectomeTokenInfo} instance that carries the token information
* @throws JsonSyntaxException
* @throws JsonIOException
* @throws IOException
*/
final static public OpenConnectomeTokenInfo fetchTokenInfo( final String baseUrl, final String token )
throws JsonSyntaxException, JsonIOException, IOException
{
final Gson gson = new Gson();
final URL url = new URL( baseUrl + "/" + token + "/info/" );
return gson.fromJson( new InputStreamReader( url.openStream() ), OpenConnectomeTokenInfo.class );
}
/**
* Try to fetch the list of public tokens from an OpenConnectome volume cutout
* service, e.g.
* {@linkplain http://openconnecto.me/emca/public_tokens/}.
*
* @param baseUrl e.g. "http://openconnecto.me/emca"
* @param maxNumTrials the maximum number of trials
*
* @return a list of {@link String Strings} or <code>null</code> if
* <code>maxNumTrials</code> were executed without success
*/
final static public String[] tryFetchTokenList( final String baseUrl, final int maxNumTrials )
{
String[] tokens = null;
for ( int i = 0; i < maxNumTrials && tokens == null; ++i )
{
try
{
tokens = fetchTokenList( baseUrl );
break;
}
catch ( final Exception e ) {}
try
{
Thread.sleep( 100 );
}
catch ( final InterruptedException e ) {}
}
return tokens;
}
/**
* Try to fetch information for a token from an OpenConnectome volume cutout
* service, e.g.
* {@linkplain http://openconnecto.me/emca/<token>/info/}.
*
* @param baseUrl e.g. "http://openconnecto.me/emca"
* @param token
* @param maxNumTrials
* @return an {@link OpenConnectomeTokenInfo} instance that carries the
* token information or <code>null</code> if <code>maxNumTrials</code>
* were executed without success
*/
final static public OpenConnectomeTokenInfo tryFetchTokenInfo( final String baseUrl, final String token, final int maxNumTrials )
{
OpenConnectomeTokenInfo info = null;
for ( int i = 0; i < maxNumTrials && info == null; ++i )
{
try
{
info = fetchTokenInfo( baseUrl, token );
break;
}
catch ( final Exception e ) {}
try
{
Thread.sleep( 100 );
}
catch ( final InterruptedException e ) {}
}
return info;
}
@Override
public void init( final Element elem, final File basePath )
{
baseUrl = elem.getChildText( "baseUrl" );
token = elem.getChildText( "token" );
mode = elem.getChildText( "mode" );
final OpenConnectomeTokenInfo info = tryFetchTokenInfo( baseUrl, token, 20 );
numScales = info.dataset.cube_dimension.size();
mipmapResolutions = info.getLevelScales( mode );
imageDimensions = info.getLevelDimensions( mode );
blockDimensions = info.getLevelCellDimensions();
mipmapTransforms = info.getLevelTransforms( mode );
final int[] maxLevels = new int[]{ numScales - 1 };
cache = new VolatileGlobalCellCache< VolatileByteArray >(
new OpenConnectomeVolatileArrayLoader( baseUrl, token, mode, info.getMinZ() ), 1, 1, numScales, maxLevels, 10 );
}
@Override
public Element toXml( final File basePath )
{
throw new UnsupportedOperationException( "not implemented" );
}
@Override
public RandomAccessibleInterval< FloatType > getFloatImage( final View view )
{
throw new UnsupportedOperationException( "not implemented" );
}
@Override
public RandomAccessibleInterval< UnsignedByteType > getImage( final View view )
{
return getImage( view, 0 );
}
@Override
public RandomAccessibleInterval< UnsignedByteType > getImage( final View view, final int level )
{
final CellImg< UnsignedByteType, VolatileByteArray, VolatileCell< VolatileByteArray > > img = prepareCachedImage( view, level, LoadingStrategy.BLOCKING );
final UnsignedByteType linkedType = new UnsignedByteType( img );
img.setLinkedType( linkedType );
return img;
}
@Override
public RandomAccessibleInterval< VolatileUnsignedByteType > getVolatileImage( final View view, final int level )
{
final CellImg< VolatileUnsignedByteType, VolatileByteArray, VolatileCell< VolatileByteArray > > img = prepareCachedImage( view, level, LoadingStrategy.VOLATILE );
final VolatileUnsignedByteType linkedType = new VolatileUnsignedByteType( img );
img.setLinkedType( linkedType );
return img;
}
@Override
public double[][] getMipmapResolutions( final int setup )
{
return mipmapResolutions;
}
@Override
public int numMipmapLevels( final int setup )
{
return numScales;
}
/**
* (Almost) create a {@link CellImg} 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 > > CellImg< T, VolatileByteArray, VolatileCell< VolatileByteArray > > prepareCachedImage( final View view, final int level, final LoadingStrategy loadingStrategy )
{
final long[] dimensions = imageDimensions[ level ];
final int[] cellDimensions = blockDimensions[ level ];
final CellCache< VolatileByteArray > c = cache.new VolatileCellCache( view.getTimepointIndex(), view.getSetupIndex(), level, loadingStrategy );
final VolatileImgCells< VolatileByteArray > cells = new VolatileImgCells< VolatileByteArray >( c, 1, dimensions, cellDimensions );
final CellImg< T, VolatileByteArray, VolatileCell< VolatileByteArray > > img = new CellImg< T, VolatileByteArray, VolatileCell< VolatileByteArray > >( null, cells );
return img;
}
@Override
public Cache getCache()
{
return cache;
}
private final UnsignedByteType type = new UnsignedByteType();
private final VolatileUnsignedByteType volatileType = new VolatileUnsignedByteType();
@Override
public UnsignedByteType getImageType()
{
return type;
}
@Override
public VolatileUnsignedByteType getVolatileImageType()
{
return volatileType;
}
@Override
public AffineTransform3D[] getMipmapTransforms( int setup )
{
return mipmapTransforms;
}
}
package bdv.img.openconnectome;
import java.io.Serializable;
public class OpenConnectomeProject implements Serializable
{
private static final long serialVersionUID = 3296461682832630651L;
public String dataset;
public String dataurl;
public String dbname;
public boolean exceptions;
public String host;
public int projecttype;
public boolean readonly;
public int resolution;
}
\ No newline at end of file
package bdv.img.openconnectome;
import java.io.Serializable;
import net.imglib2.realtransform.AffineTransform3D;
public class OpenConnectomeTokenInfo implements Serializable
{
private static final long serialVersionUID = -560051267067033900L;
public OpenConnectomeDataset dataset;
public OpenConnectomeProject project;
public long[][] getLevelDimensions( final String mode )
{
final long[][] levelDimensions = new long[ dataset.imagesize.size() ][ 3 ];
if ( mode.equals( "neariso" ) )
{
for ( int i = 0; i < dataset.imagesize.size(); ++i )
{
final long[] xy = dataset.imagesize.get( new Integer( i ).toString() );
final long[] slicerange = dataset.isotropic_slicerange.get( new Integer( i ).toString() );
levelDimensions[ i ][ 0 ] = xy[ 0 ];
levelDimensions[ i ][ 1 ] = xy[ 1 ];
levelDimensions[ i ][ 2 ] = slicerange[ 1 ] - slicerange[ 0 ];
}
}
else
{
for ( int i = 0; i < dataset.imagesize.size(); ++i )
{
final long[] xy = dataset.imagesize.get( new Integer( i ).toString() );
levelDimensions[ i ][ 0 ] = xy[ 0 ];
levelDimensions[ i ][ 1 ] = xy[ 1 ];
levelDimensions[ i ][ 2 ] = dataset.slicerange[ 1 ] - dataset.slicerange[ 0 ];
}
}
return levelDimensions;
}
public int[][] getLevelCellDimensions()
{
final int[][] levelCellDimensions = new int[ dataset.cube_dimension.size() ][];
for ( int i = 0; i < dataset.cube_dimension.size(); ++i )
levelCellDimensions[ i ] = dataset.cube_dimension.get( new Integer( i ).toString() ).clone();
return levelCellDimensions;
}
public double[][] getLevelScales( final String mode )
{
final double[][] levelScales = new double[ dataset.zscale.size() ][ 3 ];
long s = 1;
if ( mode.equals( "neariso" ) )
{
final double zScale0 = dataset.zscale.get( "0" );
for ( int i = 0; i < dataset.neariso_scaledown.size(); ++i, s <<= 1 )
{
levelScales[ i ][ 0 ] = s;
levelScales[ i ][ 1 ] = s;
levelScales[ i ][ 2 ] = zScale0 * dataset.neariso_scaledown.get( new Integer( i ).toString() );
}
}
else
{
for ( int i = 0; i < dataset.zscale.size(); ++i, s <<= 1 )
{
levelScales[ i ][ 0 ] = s;
levelScales[ i ][ 1 ] = s;
levelScales[ i ][ 2 ] = dataset.zscale.get( new Integer( i ).toString() ) * s;
}
}
return levelScales;
}
public long getMinZ()
{
return dataset.slicerange[ 0 ];
}
public AffineTransform3D[] getLevelTransforms( final String mode )
{
final int n = dataset.cube_dimension.size();
final AffineTransform3D[] levelTransforms = new AffineTransform3D[ n ];
final boolean neariso = mode.equals( "neariso" );
final double zScale0 = dataset.zscale.get( "0" );
long s = 1;
for ( int i = 0; i < n; ++i, s <<= 1 )
{
final AffineTransform3D levelTransform = new AffineTransform3D();
levelTransform.set( s, 0, 0 );
levelTransform.set( s, 1, 1 );
levelTransform.set( -0.5 * ( s - 1 ), 0, 3 );
levelTransform.set( -0.5 * ( s - 1 ), 1, 3 );
if ( neariso )
{
final double zScale = zScale0 * dataset.neariso_scaledown.get( new Integer( i ).toString() );
levelTransform.set( zScale, 2, 2 );
levelTransform.set( 0.5 * ( zScale - 1 ), 2, 3 );
}
levelTransforms[ i ] = levelTransform;
}
return levelTransforms;
}
}
\ No newline at end of file
package bdv.img.openconnectome;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import net.imglib2.img.basictypeaccess.volatiles.array.VolatileByteArray;
import bdv.img.cache.CacheArrayLoader;
public class OpenConnectomeVolatileArrayLoader implements CacheArrayLoader< VolatileByteArray >
{
private VolatileByteArray theEmptyArray;
final private String tokenUrl;
final private String mode;
final private long zMin;
/**
* <p>Create a {@link CacheArrayLoader} for a source provided by the
* <a href="http://hssl.cs.jhu.edu/wiki/doku.php?id=randal:hssl:research:brain:data_set_description">Open
* Connectome Volume Cutout Service</a>.</p>
*
* <p>It is created with a base URL, e.g.
* <a href="http://openconnecto.me/emca/kasthuri11">http://openconnecto.me/emca/kasthuri11</a>
* the cell dimensions, and an offset in <em>z</em>. This offset constitutes the
* 0-coordinate in <em>z</em> and should point to the first slice of the
* dataset.</p>
*
* @param baseUrl e.g.
* <a href="http://openconnecto.me/emca">http://openconnecto.me/emca</a>
* @param token e.g. "kasthuri11"
* @param mode z-scaling mode, either of [null, "", "neariso"]
* @param zMin first z-index
*/
public OpenConnectomeVolatileArrayLoader(
final String baseUrl,
final String token,
final String mode,
final long zMin )
{
theEmptyArray = new VolatileByteArray( 1, false );
this.tokenUrl = baseUrl + "/" + token + "/zip/";
this.mode = "/" + mode + ( mode == null || mode.equals( "" ) ? "" : "/" );
this.zMin = zMin;
}
@Override
public int getBytesPerElement()
{
return 1;
}
@Override
public VolatileByteArray loadArray(
final int timepoint,
final int setup,
final int level,
final int[] dimensions,
final long[] min ) throws InterruptedException
{
try
{
return tryLoadArray( timepoint, setup, level, dimensions, min );
}
catch ( final OutOfMemoryError e )
{
System.gc();
return tryLoadArray( timepoint, setup, level, dimensions, min );
}
}
public VolatileByteArray tryLoadArray(
final int timepoint,
final int setup,
final int level,
final int[] dimensions,
final long[] min ) throws InterruptedException
{
final byte[] data = new byte[ dimensions[ 0 ] * dimensions[ 1 ] * dimensions[ 2 ] ];
final StringBuffer url = new StringBuffer( tokenUrl );
final long z = min[ 2 ] + zMin;
url.append( level );
url.append( "/" );
url.append( min[ 0 ] );
url.append( "," );
url.append( min[ 0 ] + dimensions[ 0 ] );
url.append( "/" );
url.append( min[ 1 ] );
url.append( "," );
url.append( min[ 1 ] + + dimensions[ 1 ] );
url.append( "/" );
url.append( z );
url.append( "," );
url.append( z + dimensions[ 2 ] );
url.append( mode );
try
{
final URL file = new URL( url.toString() );
final InputStream in = file.openStream();
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
final byte[] chunk = new byte[ 4096 ];
int l;
for ( l = in.read( chunk ); l > 0; l = in.read( chunk ) )
byteStream.write( chunk, 0, l );
final byte[] zippedData = byteStream.toByteArray();
final Inflater inflater = new Inflater();
inflater.setInput( zippedData );
inflater.inflate( data );
inflater.end();
byteStream.close();
}
catch ( final IOException e )
{
System.out.println( "failed loading x=" + min[ 0 ] + " y=" + min[ 1 ] + " z=" + min[ 2 ] + " url(" + url.toString() + ")" );
}
catch( final DataFormatException e )
{
System.out.println( "failed unpacking x=" + min[ 0 ] + " y=" + min[ 1 ] + " z=" + min[ 2 ] + " url(" + url.toString() + ")" );
}
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;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment