Lazily loading large images with SciFio in ImageJ2 - Issue with ImgLib2 CACHE?

Hi people.

I would like to develop an ImageJ2 plugin that can harness large images, larger than what can fit in RAM. To do so, I rely on SCIFIO to open the large file.

I have tried to configure SCIFIO so that the image is opened à la VirtalStack: only loading 1 plane at a time, and loading other planes on demand. So as to minimize memory usage.

I have tried several things but always failed. It seems that several errors interplay, and that maybe the core one is on imglib2-cache.

How would you open such an image?
Here is what I tried. I used pom-scijava v28.0.0 in everything below, with version of scifio 0.37.3.

1. Loading a large IJ1 TIFF file via ImageJ2 services.

in a main():

public static < T extends RealType< T > & NativeType< T > > void main( final String[] args ) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, IOException, FormatException
	{
		final ImageJ ij = new ImageJ();
		ij.launch( args );
		
		final String imageFile = "/Users/tinevez/Desktop/A.tif";

		final SCIFIOConfig config = new SCIFIOConfig();
		config.imgOpenerSetImgModes( ImgMode.PLANAR );

		final Dataset dataset = ij.scifio().datasetIO().open( imageFile, config );
		ij.ui().show( dataset );
	}

With this snippet the image opens in Fiji and the first slice is shown correctly. However, as soon as I try to change the slider to display another plane, I get this:

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:32)
	at net.imglib2.img.cell.LazyCellImg$LazyCells.get(LazyCellImg.java:104)
	at net.imglib2.img.list.AbstractLongListImg$LongListRandomAccess.get(AbstractLongListImg.java:274)
	at net.imglib2.img.cell.CellRandomAccess.getCell(CellRandomAccess.java:136)
	at net.imglib2.img.cell.CellRandomAccess.updatePosition(CellRandomAccess.java:474)
	at net.imglib2.img.cell.CellRandomAccess.setPosition(CellRandomAccess.java:437)
	at net.imglib2.view.MixedRandomAccess.setPosition(MixedRandomAccess.java:332)
	at net.imglib2.AbstractInterval.min(AbstractInterval.java:199)
	at net.imglib2.util.Util.getTypeFromInterval(Util.java:800)
	at net.imglib2.view.Views.iterable(Views.java:759)
	at net.imglib2.display.projector.IterableIntervalProjector2D.map(IterableIntervalProjector2D.java:119)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getSlice(ImageJVirtualStack.java:148)
	at net.imglib2.img.display.imagej.ImageJVirtualStack.getPixelsZeroBasedIndex(ImageJVirtualStack.java:155)
	at net.imglib2.img.display.imagej.AbstractVirtualStack.getPixels(AbstractVirtualStack.java:89)
	at net.imglib2.img.display.imagej.AbstractVirtualStack.getProcessor(AbstractVirtualStack.java:111)
	at ij.ImagePlus.setSlice(ImagePlus.java:1745)
	at ij.gui.StackWindow.setSlice(StackWindow.java:318)
	at ij.gui.StackWindow.mouseWheelMoved(StackWindow.java:196)
...
Caused by: java.util.concurrent.ExecutionException: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
	at net.imglib2.cache.ref.SoftRefLoaderRemoverCache.get(SoftRefLoaderRemoverCache.java:168)
	at net.imglib2.cache.util.LoaderRemoverCacheAsLoaderCacheAdapter.get(LoaderRemoverCacheAsLoaderCacheAdapter.java:37)
	at net.imglib2.cache.util.LoaderCacheAsCacheAdapter.get(LoaderCacheAsCacheAdapter.java:30)
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:28)
	... 44 more
Caused by: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
	at java.util.ArrayList.rangeCheck(ArrayList.java:653)
	at java.util.ArrayList.get(ArrayList.java:429)
	at io.scif.formats.MinimalTIFFFormat$Reader.openPlane(MinimalTIFFFormat.java:563)
	at io.scif.formats.MinimalTIFFFormat$Reader.openPlane(MinimalTIFFFormat.java:533)
	at io.scif.AbstractReader.openPlane(AbstractReader.java:166)
	at io.scif.filters.ChannelFiller.openPlane(ChannelFiller.java:163)
	at io.scif.filters.ChannelFiller.openPlane(ChannelFiller.java:146)
	at io.scif.filters.PlaneSeparator.openPlane(PlaneSeparator.java:303)
	at io.scif.filters.PlaneSeparator.openPlane(PlaneSeparator.java:209)
	at io.scif.filters.AbstractReaderFilter.openPlane(AbstractReaderFilter.java:225)
	at io.scif.filters.AbstractReaderFilter.openPlane(AbstractReaderFilter.java:193)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:281)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:269)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:251)
	at io.scif.img.cell.loaders.AbstractArrayLoader.loadArray(AbstractArrayLoader.java:231)
	at io.scif.img.cell.SCIFIOCellImgFactory$SCIFIOCellLoader.load(SCIFIOCellImgFactory.java:200)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:91)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:51)
	at net.imglib2.cache.img.DiskCellCache.get(DiskCellCache.java:104)
	at net.imglib2.cache.img.DiskCellCache.get(DiskCellCache.java:43)
	at net.imglib2.cache.IoSync.get(IoSync.java:174)
	at net.imglib2.cache.ref.SoftRefLoaderRemoverCache.get(SoftRefLoaderRemoverCache.java:158)
	... 47 more

2. Using another file format.

Using a ICS/IDS created with the BioFormats exporter, but same strategy.

public static < T extends RealType< T > & NativeType< T > > void main( final String[] args ) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, IOException, FormatException
	{
		final ImageJ ij = new ImageJ();
		ij.launch( args );
		
		final String imageFile = "/Users/tinevez/Desktop/A.ics";

		final SCIFIOConfig config = new SCIFIOConfig();
		config.imgOpenerSetImgModes( ImgMode.PLANAR );

		final Dataset dataset = ij.scifio().datasetIO().open( imageFile, config );
		ij.ui().show( dataset );
	}

Apparently related to freeing the cache? The error is triggered by the 'show( dataset )` call.

Now I get an error before the image is displayed:

Exception in thread "SciJava-66a8c9e2-Thread-6" Exception in thread "SciJava-66a8c9e2-Thread-13" java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:32)
	at net.imglib2.img.cell.LazyCellImg$LazyCells.get(LazyCellImg.java:104)
	at net.imglib2.img.list.AbstractLongListImg$LongListRandomAccess.get(AbstractLongListImg.java:274)
	at net.imglib2.img.cell.CellRandomAccess.getCell(CellRandomAccess.java:136)
	at net.imglib2.img.cell.CellRandomAccess.updatePosition(CellRandomAccess.java:474)
	at net.imglib2.img.cell.CellRandomAccess.setPosition(CellRandomAccess.java:437)
	at net.imglib2.view.RandomAccessibleIntervalCursor.jumpFwd(RandomAccessibleIntervalCursor.java:106)
	at net.imagej.minmax.DefaultMinMaxMethod.compute(DefaultMinMaxMethod.java:222)
	at net.imagej.minmax.DefaultMinMaxMethod$1.run(DefaultMinMaxMethod.java:180)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException
	at net.imglib2.cache.ref.SoftRefLoaderRemoverCache.get(SoftRefLoaderRemoverCache.java:168)
	at net.imglib2.cache.util.LoaderRemoverCacheAsLoaderCacheAdapter.get(LoaderRemoverCacheAsLoaderCacheAdapter.java:37)
	at net.imglib2.cache.util.LoaderCacheAsCacheAdapter.get(LoaderCacheAsCacheAdapter.java:30)
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:28)
	... 9 more
Caused by: java.lang.IllegalArgumentException
	at java.nio.Buffer.limit(Buffer.java:275)
	at io.scif.io.NIOFileHandle.read(NIOFileHandle.java:230)
	at io.scif.io.NIOFileHandle.read(NIOFileHandle.java:217)
	at io.scif.io.RandomAccessInputStream.read(RandomAccessInputStream.java:448)
	at io.scif.AbstractReader.readPlane(AbstractReader.java:435)
	at io.scif.AbstractReader.readPlane(AbstractReader.java:386)
	at io.scif.formats.ICSFormat$Reader.openPlane(ICSFormat.java:1499)
	at io.scif.formats.ICSFormat$Reader.openPlane(ICSFormat.java:1357)
	at io.scif.AbstractReader.openPlane(AbstractReader.java:166)
	at io.scif.filters.ChannelFiller.openPlane(ChannelFiller.java:163)
	at io.scif.filters.ChannelFiller.openPlane(ChannelFiller.java:146)
	at io.scif.filters.PlaneSeparator.openPlane(PlaneSeparator.java:303)
	at io.scif.filters.PlaneSeparator.openPlane(PlaneSeparator.java:209)
	at io.scif.filters.AbstractReaderFilter.openPlane(AbstractReaderFilter.java:225)
	at io.scif.filters.AbstractReaderFilter.openPlane(AbstractReaderFilter.java:193)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:281)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:269)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:251)
	at io.scif.img.cell.loaders.AbstractArrayLoader.loadArray(AbstractArrayLoader.java:231)
	at io.scif.img.cell.SCIFIOCellImgFactory$SCIFIOCellLoader.load(SCIFIOCellImgFactory.java:200)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:91)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:51)
	at net.imglib2.cache.img.DiskCellCache.get(DiskCellCache.java:104)
	at net.imglib2.cache.img.DiskCellCache.get(DiskCellCache.java:43)
	at net.imglib2.cache.IoSync.get(IoSync.java:174)
	at net.imglib2.cache.ref.SoftRefLoaderRemoverCache.get(SoftRefLoaderRemoverCache.java:158)
	... 12 more

3. Trying the low level SCIFIO API with an IJ1 TIFF.

If I now try to directly access SCIFIO openPlane method with the IJ1 TIFF, it only works with the first plane. I guess it relates to the same bug for the case #1 above.

	public static < T extends RealType< T > & NativeType< T > > void main( final String[] args ) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, IOException, FormatException
	{
		final ImageJ ij = new ImageJ();
		ij.launch( args );
		
		final String imageFile = "/Users/tinevez/Desktop/A.tif";

		final SCIFIOConfig config = new SCIFIOConfig();
		config.imgOpenerSetImgModes( ImgMode.PLANAR );

		final SCIFIO scifio = new SCIFIO();
		final Reader reader = scifio.initializer().initializeReader( imageFile );

		for ( int i = 0; i < 30; i++ )
		{
			final Plane plane = reader.openPlane( 0, i );
			System.out.println( "plane " + i + ": " + plane + ", length: " +
					plane.getBytes().length );
			// I CAN ONLY READ PLANE 0 THEN IT BREAKS
		}
	}

I get this for the 1st plane:

plane 0: io.scif.ByteArrayPlane@5d2828c9, length: 39617330

Then for the next one I get this error:


Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
	at java.util.ArrayList.rangeCheck(ArrayList.java:653)
	at java.util.ArrayList.get(ArrayList.java:429)
	at io.scif.formats.MinimalTIFFFormat$Reader.openPlane(MinimalTIFFFormat.java:563)
	at io.scif.formats.MinimalTIFFFormat$Reader.openPlane(MinimalTIFFFormat.java:533)
	at io.scif.AbstractReader.openPlane(AbstractReader.java:149)
	at io.scif.AbstractReader.openPlane(AbstractReader.java:125)
	at io.scif.AbstractReader.openPlane(AbstractReader.java:53)
	at io.scif.filters.AbstractReaderFilter.openPlane(AbstractReaderFilter.java:216)
	at io.scif.filters.AbstractReaderFilter.openPlane(AbstractReaderFilter.java:185)
	at fr.pasteur.iah.localzprojector.TestDrivePlaneFeeder.main(TestDrivePlaneFeeder.java:34)

I have the same error is I use ImgMode.CELL instead of ImgMode.PLANAR

4. Trying the low level SCIFIO API with another file format.

Now if I again use the ICS/IDS file instead of the TIFF, I can read all the planes. So this does not break:

public static < T extends RealType< T > & NativeType< T > > void main( final String[] args ) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, IOException, FormatException
	{
		final ImageJ ij = new ImageJ();
		ij.launch( args );
		
		final String imageFile = "/Users/tinevez/Desktop/A.ics";

		final SCIFIOConfig config = new SCIFIOConfig();
		config.imgOpenerSetImgModes( ImgMode.PLANAR );

		final SCIFIO scifio = new SCIFIO();
		final Reader reader = scifio.initializer().initializeReader( imageFile );

		for ( int i = 0; i < 30; i++ )
		{
			final Plane plane = reader.openPlane( 0, i );
			System.out.println( "plane " + i + ": " + plane + ", length: " +
					plane.getBytes().length );
			// ALL GOOD
		}

	}

But as soon as I try to open the file as an Img and display it, it again breaks:

public static < T extends RealType< T > & NativeType< T > > void main( final String[] args ) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, IOException, FormatException
	{
		final ImageJ ij = new ImageJ();
		ij.launch( args );
		
		final String imageFile = "/Users/tinevez/Desktop/A.ics";

		final SCIFIOConfig config = new SCIFIOConfig();
		config.imgOpenerSetImgModes( ImgMode.PLANAR );

		final SCIFIO scifio = new SCIFIO();
		final Reader reader = scifio.initializer().initializeReader( imageFile );

		for ( int i = 0; i < 30; i++ )
		{
			final Plane plane = reader.openPlane( 0, i );
			System.out.println( "plane " + i + ": " + plane + ", length: " +
					plane.getBytes().length );
			// ALL GOOD
		}

		final List< SCIFIOImgPlus< ? > > imgs = new ImgOpener( ij.context() ).openImgs( reader, config );
		final SCIFIOImgPlus< ? > img = imgs.get( 0 );
		ij.ui().show( img ); // BREAKS HERE
	}
Exception in thread "SciJava-2978a8d7-Thread-5" java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:32)
	at net.imglib2.img.cell.LazyCellImg$LazyCells.get(LazyCellImg.java:104)
	at net.imglib2.img.list.AbstractLongListImg$LongListRandomAccess.get(AbstractLongListImg.java:274)
	at net.imglib2.img.cell.CellRandomAccess.getCell(CellRandomAccess.java:136)
	at net.imglib2.img.cell.CellRandomAccess.updatePosition(CellRandomAccess.java:474)
	at net.imglib2.img.cell.CellRandomAccess.setPosition(CellRandomAccess.java:437)
	at net.imglib2.view.RandomAccessibleIntervalCursor.jumpFwd(RandomAccessibleIntervalCursor.java:106)
	at net.imagej.minmax.DefaultMinMaxMethod.compute(DefaultMinMaxMethod.java:222)
	at net.imagej.minmax.DefaultMinMaxMethod$1.run(DefaultMinMaxMethod.java:180)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException
	at net.imglib2.cache.ref.SoftRefLoaderRemoverCache.get(SoftRefLoaderRemoverCache.java:168)
	at net.imglib2.cache.util.LoaderRemoverCacheAsLoaderCacheAdapter.get(LoaderRemoverCacheAsLoaderCacheAdapter.java:37)
	at net.imglib2.cache.util.LoaderCacheAsCacheAdapter.get(LoaderCacheAsCacheAdapter.java:30)
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:28)
	... 9 more
Caused by: java.lang.IllegalArgumentException
	at java.nio.Buffer.limit(Buffer.java:275)
	at io.scif.io.NIOFileHandle.read(NIOFileHandle.java:230)
	at io.scif.io.NIOFileHandle.read(NIOFileHandle.java:217)
	at io.scif.io.RandomAccessInputStream.read(RandomAccessInputStream.java:448)
	at io.scif.AbstractReader.readPlane(AbstractReader.java:435)
	at io.scif.AbstractReader.readPlane(AbstractReader.java:386)
	at io.scif.formats.ICSFormat$Reader.openPlane(ICSFormat.java:1499)
	at io.scif.formats.ICSFormat$Reader.openPlane(ICSFormat.java:1357)
	at io.scif.AbstractReader.openPlane(AbstractReader.java:149)
	at io.scif.AbstractReader.openPlane(AbstractReader.java:53)
	at io.scif.filters.AbstractReaderFilter.openPlane(AbstractReaderFilter.java:225)
	at io.scif.filters.AbstractReaderFilter.openPlane(AbstractReaderFilter.java:193)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:281)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:269)
	at io.scif.img.cell.loaders.AbstractArrayLoader.read(AbstractArrayLoader.java:251)
	at io.scif.img.cell.loaders.AbstractArrayLoader.loadArray(AbstractArrayLoader.java:231)
	at io.scif.img.cell.SCIFIOCellImgFactory$SCIFIOCellLoader.load(SCIFIOCellImgFactory.java:200)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:91)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:51)
	at net.imglib2.cache.img.DiskCellCache.get(DiskCellCache.java:104)
	at net.imglib2.cache.img.DiskCellCache.get(DiskCellCache.java:43)
	at net.imglib2.cache.IoSync.get(IoSync.java:174)
	at net.imglib2.cache.ref.SoftRefLoaderRemoverCache.get(SoftRefLoaderRemoverCache.java:158)
	... 12 more
etc

We retrieve the error on cache.
Note that SCIFIO ignores the PLANAR setting and tries to open as a cell image. But this may be secondary.

5. Please help.

What am I doing wrong?
I could really welcome help here. We do not have another solution for large images in IJ2.

5 Likes

Do you need to display it in IJ1 or in Bdv ?

That’s not solving your issue, but to display large files in Bdv, I’m bypassing SCIFIO. See this repo that directly uses the bioformats API to build Bdv Sources:

Still work in progress, but there’s already a beta update site on https://biop.epfl.ch/Fiji-Bdv-Playground/ if you want to test it. Most of this repor contains the work we’ve done with @Christian_Tischer.

Try the command BigDataViewer>SpimDataset>Open [BioFormats Bdv Bridge]. Then right click on the tree that appears and click Show Sources.

3 Likes

Thanks!

This will be a great solution.
But indeed, I wanted to rely on SCIFIO and have an IJ2 display.
If I cannot fix this I will rely on your solution if this is ok?

1 Like

It’s pretty easy to get an ImageJ1 display with a simple script added on top of the previous solution:
https://youtu.be/LiqE-ycMUmw
I could display a stack of 20Gb, using ImgLib2 and ImageJFunctions wrapping. However:

  • 1st problem : I can wrap only a single channel. And I couldn’t merge two virtual stacks into a virtual stack. That’s probably solvable by making a custom virtual stack
  • 2ns problem, more serious : if I force the JVM to use only 300Mb of RAM, I get a java heap space error pretty fast (see video), which means that the cache is not released when needed unfortunately. While a TIFF virtual stack has not issue at all with that…

For the error with SciFIO, one thing I remember which may be related to your issue, is that there are some confusion between channels, timepoints and z slice (and are 0 and 1 based indexing handled properly ?). That’s one of the reason why I gave up with it at some point (+the need for multiresolution handling). I did not file an issue but there’s trace of the discussion in gitter : https://gitter.im/scifio/scifio?at=5cedadca7c1dab468c629395

Sorry, maybe I missed it, but what’s an IJ2 display ?

Now that’s funny.
If I try to use IJ1 VirtualStack with the ImgLib2 wrapper for the very virtual stack of @maarzt, I have the same error.
The virtual stack has no problem as you noted.

1 Like

I was confusing sorry. I use IJ2 Dataset. And I display everything via
ij().ui.show( dataset ).
It translates into the Fiji frontend.

1 Like

Yes! You are right I think I have the same error.
Really thank you @NicoKiaru your feedback is invaluable.

1 Like

I managed to remove the java heap space issue by setting the cache of the cells to

final DiskCachedCellImgOptions factoryOptions = options()
            .cellDimensions( cellDimensions )
            .cacheType( DiskCachedCellImgOptions.CacheType.BOUNDED )
            .maxCacheSize(1);

It now works nicely, even with a small ram amount.
But I don’t know if you have access to this in your use case (and in SCIFIO ?)

Any chance you could type the full part for the loading and presentation?

What I can give you easily is a script which works with IJ1 display if:

  • it’s a single z-stack
  • for a single timepoint
  • you have the https://biop.epfl.ch/Fiji-Bdv-Playground/ update site installed

On the plus side, it can work for almost all file formats supported by bioformats.
Would that be useful for you ?

Otherwise, here’s a groovy script which opens a huge sample image in an IJ1 window (and Bdv):

import net.imglib2.type.numeric.ARGBType
import net.imglib2.img.Img
import bdv.util.BdvFunctions
import net.imglib2.img.array.ArrayImgs
import net.imglib2.cache.img.DiskCachedCellImgFactory
import net.imglib2.cache.img.DiskCachedCellImgOptions
import net.imglib2.Cursor
import bdv.util.volatiles.VolatileViews
import ij.ImagePlus

import static net.imglib2.cache.img.DiskCachedCellImgOptions.options
import net.imglib2.view.Views
import net.imglib2.img.display.imagej.ImageJFunctions


// Random RGB Image
Random random = new Random()

cellDimensions =  [ 512, 512, 1 ] as int[]
dimensions = [ 1024, 1024, 6024 ] as long[];

final ARGBType type = new ARGBType()

final DiskCachedCellImgOptions factoryOptions = options()
                .cellDimensions( cellDimensions )
                .cacheType( DiskCachedCellImgOptions.CacheType.BOUNDED )
                .maxCacheSize( 1 )

final DiskCachedCellImgFactory<ARGBType> factory = new DiskCachedCellImgFactory<>( type, factoryOptions )

final Img<ARGBType> randomImg = factory.create( dimensions, {cell -> 
            final Cursor< ARGBType > out = Views.flatIterable( cell ).cursor();
            while ( out.hasNext() ) {
                out.next().set( random.nextInt() )
            }}, options().initializeCellsAsDirty( true ) )

// Bdv Display : Volatile.wrapAsVolatile for responsiveness
BdvFunctions.show(VolatileViews.wrapAsVolatile(randomImg), "img random");

// IJ1 Display
ImagePlus randomImage = ImageJFunctions.wrap(randomImg,"img random")
// slices are z slices, not channels
randomImage.setDimensions(1,(int) dimensions[2],1);

randomImage.show()



Thanks! How would you adapt the script to use the same options, but to read from a file?

I don’t if this would suit you, but if you install the update site mentioned above ( https://biop.epfl.ch/Fiji-Bdv-Playground/), you can use this script:

#@File f
#@int viewSetup
#@int level
#@int timepoint

#@OUTPUT ImagePlus imp_out

import bdv.util.BdvFunctions
import bdv.util.BdvHandle
import bdv.util.BdvOptions
import bdv.util.BdvStackSource
import bdv.viewer.Source
import ch.epfl.biop.bdv.bioformats.BioFormatsMetaDataHelper
import ch.epfl.biop.bdv.bioformats.bioformatssource.BioFormatsBdvOpener
import ch.epfl.biop.bdv.bioformats.samples.DatasetHelper
import net.imagej.ImageJ
import ome.units.UNITS
import ome.units.quantity.Length
import net.imglib2.img.display.imagej.ImageJFunctions

import java.util.List
import java.util.stream.Collectors

List<Source> sources =
				BioFormatsBdvOpener.getOpener()
                        .location(f.getAbsolutePath())
						//.location(DatasetHelper.getDataset(DatasetHelper.TIF_TIMELAPSE_3D))
						//.location(DatasetHelper.getDataset(DatasetHelper.JPG_RGB))
						//.location(DatasetHelper.getDataset(DatasetHelper.OLYMPUS_OIR))
						//.location(DatasetHelper.getDataset(DatasetHelper.LIF))
						.auto() // patches opener based on specific file formats (-> PR to be  modified)
						//.splitRGBChannels() // split RGB channels into 3 channels
						//.switchZandC(true) // switch Z and C
						//.centerPositionConvention() // bioformats location is center of the image
						.cornerPositionConvention() // bioformats location is corner of the image
						//.useCacheBlockSizeFromBioFormats(true) // true by default
						//.cacheBlockSize(512,512,10) // size of cache block used by diskcached image
						//.micronmeter() // unit = micrometer
						.millimeter() // unit = millimeter
						//.unit(UNITS.YARD) // Ok, if you really want...
						.positionReferenceFrameLength(new Length(1, UNITS.MICROMETER))
						.voxSizeReferenceFrameLength(new Length(100, UNITS.MICROMETER))
						//.getVolatileSources()
						.getConcreteSources()
						.stream().map({src -> (Source) src}).collect(Collectors.toList());


imp_out = ImageJFunctions.wrap(sources.get(viewSetup).getSource(timepoint,level), sources.get(viewSetup).getName())

It’s not optimal (single stack), but the point of the repo was to use Bdv viewer rather than IJ1, hence the limitations.

2 Likes

The issue is probably not in imglib2-cache (but maybe in the cache loader).
The exception that you are seeing is bubbled up through the cache, but it actually occurs when trying to load a plane, which is triggered by accessing data that is not yet in the cache.
Ultimately, the issue lies here:

(and similarly for the other file format at)

I don’t know why the parameters that are passed to these methods are out-of-bounds (of the file), I’l investigate once I downloaded your images @tinevez)

Regarding this:

This is caused because the cache uses SoftReference by default.
(@NicoKiaru as you observed, switching to another type of cache solves the problem)
SoftReferences should be collected if OutOfMemoryError is imminent.
But actually, in the hotspot JVM, there is a minimal time for which SoftReferences are kept alive.
What happens is that the standard keep-alive time is too high for the rate that data is loaded (new SoftReferences are established) so the data cannot be GCed and the OutOfMemory occurs.

There is a JVM flag SoftRefLRUPolicyMSPerMB that allows to tune the keep-alive time.
Just google for “SoftRefLRUPolicyMSPerMB jvm flag” for explanation and discussions about this.
In this case, starting Fiji with -XX:SoftRefLRUPolicyMSPerMB=1 or even -XX:SoftRefLRUPolicyMSPerMB=0 would probably solve the issue.

2 Likes

is probably the same issue