Skip to content

Instantly share code, notes, and snippets.

@NicoKiaru
Last active January 20, 2023 17:06
Show Gist options
  • Save NicoKiaru/a07c88db1be4ec6524170627819d6f60 to your computer and use it in GitHub Desktop.
Save NicoKiaru/a07c88db1be4ec6524170627819d6f60 to your computer and use it in GitHub Desktop.
A Fiji script that can generate a procedural big image (>4GPix) and resaves it as a multi resolution OME TIFF image #BIOP #Fiji
/**
* Makes a big 2d procedural plane and saves it as a multiresolution ome.tiff image
*
* Tested on a 128 000 x 128 000 images with 8000 objects (11G pix), 10 resolutions levels, downscale 2 ~ 30 minutes to generate
*
* PTBIOP update site needed
* @author Nicolas Chiaruttini, 2023
*/
#@Integer nPixelsX
#@Integer nPixelsY
#@Integer nObjects
#@TaskService taskService
#@File(label = "save path, '.ome.tiff' extension", style="save") filepath
// Get a test image
RandomAccessibleInterval< UnsignedByteType > labelImage = getTestLabelImage([ nPixelsX, nPixelsY, 1 ] as long[], nObjects);
BdvOptions opt = new BdvOptions();
// Show it in BigDataViewer, that's in fact the most easy way I found to turn a RandomAccessibleInterval
// into a SourceAndConverter. A SourceAndConverter has many useful extra 'metadata':
// Color per channel, a display range (min max)
// And 'location' metadata: through its AffineTransform3d, a position in space (x0, y0, z0)
// as well as voxel sizes can be written in the bioformats metadata (it's not as general as a fully free affine transform 3d however)
final BdvSource source = BdvFunctions.show(
labelImage,
"Label Image 80000 byte" );
def sourceAndConverter = source.getBdvHandle().getViewerPanel().state().getCurrentSource()
// Set color and display range
source.setColor(new ARGBType((int)0xFF00FF00));
source.setDisplayRange(0,255);
// Builder pattern for OME TIFF export, parallel reading and block computation, serial writing
OMETiffPyramidizerExporter.builder()
.tileSize(1024, 1024) // One block = size 1024x1024x1
.lzw() // lossless LZW compression
.downsample(2) // downscale by a factor 2 between resolution levels (integer compulsory)
.nResolutionLevels(10) // ten resolution levels
.monitor(taskService) // Optional, but providing it gives a time estimation for the export
.nThreads(16) // Each thread computes a block, taken from a queue of blocks to be processed
.maxTilesInQueue(60) // Naximum number of blocks computed in advanced. The queue of blocks to be processed won't be longer than this value
.savePath(filepath.getAbsolutePath()) // output path : you need to add .ome.tiff to this path
.micrometer() // units
.create(sourceAndConverter) // an array of sourceandconverter can be passed, each source and converter is a channel
.export() // actually performs the export (blocking)
// For other arguments that can be provided in the builder patterm look at https://github.com/BIOP/ijp-kheops/blob/2ed70fe5009682903243abf7b1a8aadf83467476/src/main/java/ch/epfl/biop/kheops/ometiff/OMETiffPyramidizerExporter.java#L679
// (channel names, selecting a subset of CZT range, compression type, compression of the temporary files)
//------------------------------------- METHODS TO CREATE TEST IMAGE
public static RandomAccessibleInterval< UnsignedByteType > getTestLabelImage(final long[] imgTestSize, int nPts) {
// the interval in which to create random points
FinalInterval interval = new FinalInterval( imgTestSize );
// create an IterableRealInterval
IterableRealInterval< UnsignedByteType > realInterval = createRandomPoints( interval, nPts );
// using nearest neighbor search we will be able to return a value an any position in space
NearestNeighborSearch< UnsignedByteType > search =
new NearestNeighborSearchOnKDTree<>(
new KDTree<>( realInterval ) );
// make it into RealRandomAccessible using nearest neighbor search
RealRandomAccessible< UnsignedByteType > realRandomAccessible =
Views.interpolate( search, new NearestNeighborSearchInterpolatorFactory< UnsignedByteType >() );
// convert it into a RandomAccessible which can be displayed
RandomAccessible< UnsignedByteType > randomAccessible = Views.raster( realRandomAccessible );
// set the initial interval as area to view
RandomAccessibleInterval< UnsignedByteType > labelImage = Views.interval( randomAccessible, interval );
// Returning it
return labelImage; // labelImageCopy;
}
/**
* Create a number of n-dimensional random points in a certain interval
* having a random intensity 0...1
*
* @param interval - the interval in which points are created
* @param numPoints - the amount of points
*
* @return a RealPointSampleList (which is an IterableRealInterval)
*/
public static RealPointSampleList< UnsignedByteType > createRandomPoints(
RealInterval interval, int numPoints )
{
// the number of dimensions
int numDimensions = interval.numDimensions();
// a random number generator
Random rnd = new Random( 2001);//System.currentTimeMillis() );
// a list of Samples with coordinates
RealPointSampleList< FloatType > elements =
new RealPointSampleList<>( numDimensions );
for ( int i = 0; i < numPoints; ++i )
{
RealPoint point = new RealPoint( numDimensions );
for ( int d = 0; d < numDimensions; ++d )
point.setPosition( rnd.nextDouble() *
( interval.realMax( d ) - interval.realMin( d ) ) + interval.realMin( d ), d );
// add a new element with a random intensity in the range 0...1
elements.add( point, new UnsignedByteType( (int) (rnd.nextFloat()*255) ) );
}
return elements;
}
import bdv.util.BdvFunctions
import bdv.util.BdvOptions
import bdv.util.BdvSource
import bdv.util.volatiles.SharedQueue
import bdv.util.volatiles.VolatileViews
import net.imglib2.*
import net.imglib2.algorithm.util.Grids
import net.imglib2.cache.img.*
import net.imglib2.img.Img
import net.imglib2.img.array.ArrayImgFactory
import net.imglib2.img.basictypeaccess.AccessFlags
import net.imglib2.img.basictypeaccess.array.ArrayDataAccess
import net.imglib2.img.cell.CellGrid
import net.imglib2.interpolation.neighborsearch.NearestNeighborSearchInterpolatorFactory
import net.imglib2.neighborsearch.NearestNeighborSearch
import net.imglib2.neighborsearch.NearestNeighborSearchOnKDTree
import net.imglib2.type.NativeType
import net.imglib2.type.Type
import net.imglib2.type.numeric.ARGBType
import net.imglib2.type.numeric.integer.ByteType
import net.imglib2.type.numeric.integer.UnsignedByteType
import net.imglib2.type.numeric.real.FloatType
import net.imglib2.util.Intervals
import net.imglib2.util.Util
import net.imglib2.view.Views
import java.io.IOException
import java.util.Random
import static java.lang.Math.abs
import static net.imglib2.cache.img.DiskCachedCellImgOptions.options
import ch.epfl.biop.kheops.ometiff.OMETiffPyramidizerExporter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment