diff --git a/.gitignore b/.gitignore index cbacafce2e63531cc4d06db5118df7c7c53cfeba..d358561c28d0de740515edbafc6966af56b99dc4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ **/.settings/ **/target/ *.orig +*.iml .classpath .project .settings diff --git a/pom.xml b/pom.xml index 384754f74c3c3047f24276975b7796d153f11806..9f783f4507ed2da6398e304761dc6d6a4a857078 100644 --- a/pom.xml +++ b/pom.xml @@ -5,13 +5,13 @@ <parent> <groupId>org.scijava</groupId> <artifactId>pom-scijava</artifactId> - <version>26.0.0</version> + <version>28.0.0</version> <relativePath /> </parent> <groupId>sc.fiji</groupId> <artifactId>bigdataviewer_fiji</artifactId> - <version>6.0.1-SNAPSHOT</version> + <version>6.2.1-SNAPSHOT</version> <name>BigDataViewer Fiji</name> <description>Fiji plugins for starting BigDataViewer and exporting data.</description> @@ -98,6 +98,12 @@ <license.licenseName>gpl_v3</license.licenseName> <license.copyrightOwners>BigDataViewer developers.</license.copyrightOwners> + <imglib2.version>5.9.0</imglib2.version> + <imglib2-ij.version>2.0.0-beta-46</imglib2-ij.version> + <bigdataviewer-core.version>9.0.3</bigdataviewer-core.version> + <spim_data.version>2.2.4</spim_data.version> + <ui-behaviour.version>2.0.1</ui-behaviour.version> + <!-- NB: Deploy releases to the SciJava Maven repository. --> <releaseProfiles>deploy-to-scijava</releaseProfiles> </properties> diff --git a/src/main/java/bdv/ij/ExportImagePlusAsN5PlugIn.java b/src/main/java/bdv/ij/ExportImagePlusAsN5PlugIn.java new file mode 100644 index 0000000000000000000000000000000000000000..5fc5e97253ad9b2b4d71f677fb5968fb3cd22b0c --- /dev/null +++ b/src/main/java/bdv/ij/ExportImagePlusAsN5PlugIn.java @@ -0,0 +1,565 @@ +package bdv.ij; + +import bdv.export.ExportMipmapInfo; +import bdv.export.ExportScalePyramid.AfterEachPlane; +import bdv.export.ExportScalePyramid.LoopbackHeuristic; +import bdv.export.ProgressWriter; +import bdv.export.ProposeMipmaps; +import bdv.export.SubTaskProgressWriter; +import bdv.export.n5.WriteSequenceToN5; +import bdv.ij.util.PluginHelper; +import bdv.ij.util.ProgressWriterIJ; +import bdv.img.imagestack.ImageStackImageLoader; +import bdv.img.n5.N5ImageLoader; +import bdv.img.virtualstack.VirtualStackImageLoader; +import bdv.spimdata.SequenceDescriptionMinimal; +import bdv.spimdata.SpimDataMinimal; +import bdv.spimdata.XmlIoSpimDataMinimal; +import fiji.util.gui.GenericDialogPlus; +import ij.IJ; +import ij.ImageJ; +import ij.ImagePlus; +import ij.WindowManager; +import java.awt.Checkbox; +import java.awt.TextField; +import java.awt.event.ItemEvent; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import mpicbg.spim.data.SpimDataException; +import mpicbg.spim.data.generic.sequence.BasicViewSetup; +import mpicbg.spim.data.generic.sequence.TypedBasicImgLoader; +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.RandomAccessibleInterval; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.util.Intervals; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; +import org.janelia.saalfeldlab.n5.Bzip2Compression; +import org.janelia.saalfeldlab.n5.Compression; +import org.janelia.saalfeldlab.n5.GzipCompression; +import org.janelia.saalfeldlab.n5.Lz4Compression; +import org.janelia.saalfeldlab.n5.RawCompression; +import org.janelia.saalfeldlab.n5.XzCompression; +import org.scijava.command.Command; +import org.scijava.plugin.Plugin; + +/** + * ImageJ plugin to export the current image to xml/n5. + * + * @author Tobias Pietzsch + */ +@Plugin(type = Command.class, + menuPath = "Plugins>BigDataViewer>Export Current Image as XML/N5") +public class ExportImagePlusAsN5PlugIn implements Command +{ + public static void main( final String[] args ) + { + new ImageJ(); + final ImagePlus imp = IJ.openImage( "/Users/pietzsch/workspace/data/confocal-series.tif" ); + imp.show(); + new ExportImagePlusAsN5PlugIn().run(); + } + + @Override + public void run() + { + if ( ij.Prefs.setIJMenuBar ) + System.setProperty( "apple.laf.useScreenMenuBar", "true" ); + + // 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: + break; + default: + IJ.showMessage( "Only 8, 16, 32-bit images are supported currently!" ); + return; + } + + // check the image dimensionality + if ( imp.getNDimensions() < 2 ) + { + IJ.showMessage( "Image must be at least 2-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( w, h, d ); + + // propose reasonable mipmap settings + final int maxNumElements = 64 * 64 * 64; + final ExportMipmapInfo autoMipmapSettings = ProposeMipmaps.proposeMipmaps( + new BasicViewSetup( 0, "", size, voxelSize ), + maxNumElements ); + + // show dialog to get output paths, resolutions, subdivisions, min-max option + final Parameters params = getParameters( autoMipmapSettings ); + if ( params == null ) + return; + + final ProgressWriter progressWriter = new ProgressWriterIJ(); + progressWriter.out().println( "starting export..." ); + + // create ImgLoader wrapping the image + final TypedBasicImgLoader< ? > imgLoader; + final Runnable clearCache; + final boolean isVirtual = imp.getStack() != null && imp.getStack().isVirtual(); + if ( isVirtual ) + { + final VirtualStackImageLoader< ?, ?, ? > il; + switch ( imp.getType() ) + { + case ImagePlus.GRAY8: + il = VirtualStackImageLoader.createUnsignedByteInstance( imp ); + break; + case ImagePlus.GRAY16: + il = VirtualStackImageLoader.createUnsignedShortInstance( imp ); + break; + case ImagePlus.GRAY32: + default: + il = VirtualStackImageLoader.createFloatInstance( imp ); + break; + } + imgLoader = il; + clearCache = il.getCacheControl()::clearCache; + } + else + { + switch ( imp.getType() ) + { + case ImagePlus.GRAY8: + imgLoader = ImageStackImageLoader.createUnsignedByteInstance( imp ); + break; + case ImagePlus.GRAY16: + imgLoader = ImageStackImageLoader.createUnsignedShortInstance( imp ); + break; + case ImagePlus.GRAY32: + default: + imgLoader = ImageStackImageLoader.createFloatInstance( imp ); + break; + } + clearCache = () -> {}; + } + + final int numTimepoints = imp.getNFrames(); + final int numSetups = imp.getNChannels(); + + // create SourceTransform from the images calibration + final AffineTransform3D sourceTransform = new AffineTransform3D(); + sourceTransform.set( pw, 0, 0, 0, 0, ph, 0, 0, 0, 0, pd, 0 ); + + // write n5 + final HashMap< Integer, BasicViewSetup > setups = new HashMap<>( 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 ); + } + final ArrayList< TimePoint > timepoints = new ArrayList<>( numTimepoints ); + for ( int t = 0; t < numTimepoints; ++t ) + timepoints.add( new TimePoint( t ) ); + final SequenceDescriptionMinimal seq = new SequenceDescriptionMinimal( new TimePoints( timepoints ), setups, imgLoader, null ); + + Map< Integer, ExportMipmapInfo > perSetupExportMipmapInfo; + perSetupExportMipmapInfo = new HashMap<>(); + final ExportMipmapInfo mipmapInfo = new ExportMipmapInfo( params.resolutions, params.subdivisions ); + 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 long planeSizeInBytes = imp.getWidth() * imp.getHeight() * imp.getBytesPerPixel(); + final long ijMaxMemory = IJ.maxMemory(); + final int numCellCreatorThreads = Math.max( 1, PluginHelper.numThreads() - 1 ); + 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 ( Intervals.numElements( factorsToOriginalImg ) / Intervals.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 ) + clearCache.run(); + } + } + + }; + + try + { + WriteSequenceToN5.writeN5File( seq, perSetupExportMipmapInfo, + params.compression, params.n5File, + loopbackHeuristic, afterEachPlane, numCellCreatorThreads, + new SubTaskProgressWriter( progressWriter, 0, 0.95 ) ); + + // write xml sequence description + final N5ImageLoader n5Loader = new N5ImageLoader( params.n5File, null ); + final SequenceDescriptionMinimal seqh5 = new SequenceDescriptionMinimal( seq, n5Loader ); + + final ArrayList< ViewRegistration > registrations = new ArrayList<>(); + for ( int t = 0; t < numTimepoints; ++t ) + for ( int s = 0; s < numSetups; ++s ) + registrations.add( new ViewRegistration( t, s, sourceTransform ) ); + + final File basePath = params.seqFile.getParentFile(); + final SpimDataMinimal spimData = new SpimDataMinimal( basePath, seqh5, new ViewRegistrations( registrations ) ); + + new XmlIoSpimDataMinimal().save( spimData, params.seqFile.getAbsolutePath() ); + progressWriter.setProgress( 1.0 ); + } + catch ( final SpimDataException | IOException e ) + { + throw new RuntimeException( e ); + } + progressWriter.out().println( "done" ); + } + + protected static class Parameters + { + final boolean setMipmapManual; + + final int[][] resolutions; + + final int[][] subdivisions; + + final File seqFile; + + final File n5File; + + final Compression compression; + + public Parameters( + final boolean setMipmapManual, final int[][] resolutions, final int[][] subdivisions, + final File seqFile, final File n5File, + final Compression compression ) + { + this.setMipmapManual = setMipmapManual; + this.resolutions = resolutions; + this.subdivisions = subdivisions; + this.seqFile = seqFile; + this.n5File = n5File; + this.compression = compression; + } + } + + static boolean lastSetMipmapManual = false; + + static String lastSubsampling = ""; + + static String lastChunkSizes = ""; + + static int lastCompressionChoice = 0; + + static boolean lastCompressionDefaultSettings = true; + + static String lastExportPath = "./export.xml"; + + protected Parameters getParameters( final ExportMipmapInfo autoMipmapSettings ) + { + while ( true ) + { + final GenericDialogPlus gd = new GenericDialogPlus( "Export for BigDataViewer as XML/N5" ); + + gd.addCheckbox( "manual_mipmap_setup", lastSetMipmapManual ); + final Checkbox cManualMipmap = ( Checkbox ) gd.getCheckboxes().lastElement(); + gd.addStringField( "Subsampling_factors", lastSubsampling, 25 ); + final TextField tfSubsampling = ( TextField ) gd.getStringFields().lastElement(); + gd.addStringField( "N5_chunk_sizes", lastChunkSizes, 25 ); + final TextField tfChunkSizes = ( TextField ) gd.getStringFields().lastElement(); + + gd.addMessage( "" ); + final String[] compressionChoices = new String[] { "raw (no compression)", "bzip", "gzip", "lz4", "xz" }; + gd.addChoice( "compression", compressionChoices, compressionChoices[ lastCompressionChoice ] ); + gd.addCheckbox( "default settings", lastCompressionDefaultSettings ); + + gd.addMessage( "" ); + PluginHelper.addSaveAsFileField( gd, "Export_path", lastExportPath, 25 ); + + final String autoSubsampling = ProposeMipmaps.getArrayString( autoMipmapSettings.getExportResolutions() ); + final String autoChunkSizes = ProposeMipmaps.getArrayString( autoMipmapSettings.getSubdivisions() ); + gd.addDialogListener( ( dialog, e ) -> { + gd.getNextBoolean(); + gd.getNextString(); + gd.getNextString(); + gd.getNextChoiceIndex(); + gd.getNextBoolean(); + gd.getNextString(); + if ( e instanceof ItemEvent && e.getID() == ItemEvent.ITEM_STATE_CHANGED && e.getSource() == cManualMipmap ) + { + final boolean useManual = cManualMipmap.getState(); + tfSubsampling.setEnabled( useManual ); + tfChunkSizes.setEnabled( useManual ); + if ( !useManual ) + { + tfSubsampling.setText( autoSubsampling ); + tfChunkSizes.setText( autoChunkSizes ); + } + } + return true; + } ); + + tfSubsampling.setEnabled( lastSetMipmapManual ); + tfChunkSizes.setEnabled( lastSetMipmapManual ); + if ( !lastSetMipmapManual ) + { + tfSubsampling.setText( autoSubsampling ); + tfChunkSizes.setText( autoChunkSizes ); + } + + gd.showDialog(); + if ( gd.wasCanceled() ) + return null; + + lastSetMipmapManual = gd.getNextBoolean(); + lastSubsampling = gd.getNextString(); + lastChunkSizes = gd.getNextString(); + lastCompressionChoice = gd.getNextChoiceIndex(); + lastCompressionDefaultSettings = gd.getNextBoolean(); + lastExportPath = gd.getNextString(); + + // parse mipmap resolutions and cell sizes + final int[][] resolutions = PluginHelper.parseResolutionsString( lastSubsampling ); + final int[][] subdivisions = PluginHelper.parseResolutionsString( lastChunkSizes ); + if ( resolutions.length == 0 ) + { + IJ.showMessage( "Cannot parse subsampling factors " + lastSubsampling ); + continue; + } + if ( subdivisions.length == 0 ) + { + IJ.showMessage( "Cannot parse n5 chunk sizes " + lastChunkSizes ); + continue; + } + else if ( resolutions.length != subdivisions.length ) + { + IJ.showMessage( "subsampling factors and n5 chunk sizes must have the same number of elements" ); + continue; + } + + String seqFilename = lastExportPath; + if ( !seqFilename.endsWith( ".xml" ) ) + seqFilename += ".xml"; + final File seqFile = new File( seqFilename ); + final File parent = seqFile.getParentFile(); + if ( parent == null || !parent.exists() || !parent.isDirectory() ) + { + IJ.showMessage( "Invalid export filename " + seqFilename ); + continue; + } + final String n5Filename = seqFilename.substring( 0, seqFilename.length() - 4 ) + ".n5"; + final File n5File = new File( n5Filename ); + + final Compression compression; + switch ( lastCompressionChoice ) + { + default: + case 0: // raw (no compression) + compression = new RawCompression(); + break; + case 1: // bzip + compression = lastCompressionDefaultSettings + ? new Bzip2Compression() + : getBzip2Settings(); + break; + case 2: // gzip + compression = lastCompressionDefaultSettings + ? new GzipCompression() + : getGzipSettings(); + break; + case 3:// lz4 + compression = lastCompressionDefaultSettings + ? new Lz4Compression() + : getLz4Settings(); + break; + case 4:// xz" }; + compression = lastCompressionDefaultSettings + ? new XzCompression() + : getXzSettings(); + break; + } + if ( compression == null ) + return null; + + return new Parameters( lastSetMipmapManual, resolutions, subdivisions, seqFile, n5File, compression ); + } + } + + static int lastBzip2BlockSize = BZip2CompressorOutputStream.MAX_BLOCKSIZE; + + protected Bzip2Compression getBzip2Settings() + { + while ( true ) + { + final GenericDialogPlus gd = new GenericDialogPlus( "Bzip2 compression settings" ); + gd.addNumericField( + String.format( "block size (%d-%d)", + BZip2CompressorOutputStream.MIN_BLOCKSIZE, + BZip2CompressorOutputStream.MAX_BLOCKSIZE ), + lastBzip2BlockSize, 0 ); + gd.addMessage( "as 100k units" ); + + gd.showDialog(); + if ( gd.wasCanceled() ) + return null; + + lastBzip2BlockSize = ( int ) gd.getNextNumber(); + if ( lastBzip2BlockSize < BZip2CompressorOutputStream.MIN_BLOCKSIZE || lastBzip2BlockSize > BZip2CompressorOutputStream.MAX_BLOCKSIZE ) + { + IJ.showMessage( + String.format( "Block size must be in range [%d, %d]", + BZip2CompressorOutputStream.MIN_BLOCKSIZE, + BZip2CompressorOutputStream.MAX_BLOCKSIZE ) ); + continue; + } + return new Bzip2Compression( lastBzip2BlockSize ); + } + } + + static int lastGzipLevel = 6; + + static boolean lastGzipUseZlib = false; + + protected GzipCompression getGzipSettings() + { + while ( true ) + { + final GenericDialogPlus gd = new GenericDialogPlus( "Gzip compression settings" ); + gd.addNumericField( "level (0-9)", lastGzipLevel, 0 ); + gd.addCheckbox( "use Zlib", lastGzipUseZlib ); + + gd.showDialog(); + if ( gd.wasCanceled() ) + return null; + + lastGzipLevel = ( int ) gd.getNextNumber(); + lastGzipUseZlib = gd.getNextBoolean(); + if ( lastGzipLevel < 0 || lastGzipLevel > 9 ) + { + IJ.showMessage( "Level must be in range [0, 9]" ); + continue; + } + return new GzipCompression( lastGzipLevel, lastGzipUseZlib ); + } + } + + static int lastLz4BlockSize = 1 << 16; + + protected Lz4Compression getLz4Settings() + { + final int COMPRESSION_LEVEL_BASE = 10; + final int MIN_BLOCK_SIZE = 64; + final int MAX_BLOCK_SIZE = 1 << (COMPRESSION_LEVEL_BASE + 0x0F); + + while ( true ) + { + final GenericDialogPlus gd = new GenericDialogPlus( "LZ4 compression settings" ); + gd.addNumericField( + String.format( "block size (%d-%d)", + MIN_BLOCK_SIZE, + MAX_BLOCK_SIZE ), + lastLz4BlockSize, 0, 8, null ); + + gd.showDialog(); + if ( gd.wasCanceled() ) + return null; + + lastLz4BlockSize = ( int ) gd.getNextNumber(); + if ( lastLz4BlockSize < MIN_BLOCK_SIZE || lastLz4BlockSize > MAX_BLOCK_SIZE ) + { + IJ.showMessage( String.format( "Block size must be in range [%d, %d]", + MIN_BLOCK_SIZE, + MAX_BLOCK_SIZE ) ); + continue; + } + return new Lz4Compression( lastLz4BlockSize ); + } + } + + static int lastXzLevel = 6; + + protected XzCompression getXzSettings() + { + while ( true ) + { + final GenericDialogPlus gd = new GenericDialogPlus( "XZ compression settings" ); + gd.addNumericField( "level (0-9)", lastXzLevel, 0 ); + gd.addMessage( "LZMA2 preset level" ); + + gd.showDialog(); + if ( gd.wasCanceled() ) + return null; + + lastXzLevel = ( int ) gd.getNextNumber(); + if ( lastXzLevel < 0 || lastXzLevel > 9 ) + { + IJ.showMessage( "Level must be in range [0, 9]" ); + continue; + } + return new XzCompression( lastXzLevel ); + } + } + +} diff --git a/src/main/java/bdv/ij/ExportImagePlusPlugIn.java b/src/main/java/bdv/ij/ExportImagePlusPlugIn.java index 1a3c90b3accd850c4726df23aa990ea73cfab0e1..0312a164f4ff7107343bf8ebc2f6312bbda7dc5f 100644 --- a/src/main/java/bdv/ij/ExportImagePlusPlugIn.java +++ b/src/main/java/bdv/ij/ExportImagePlusPlugIn.java @@ -14,16 +14,17 @@ import net.imglib2.FinalDimensions; import net.imglib2.RandomAccessibleInterval; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.util.Intervals; import org.scijava.command.Command; import org.scijava.plugin.Plugin; import bdv.export.ExportMipmapInfo; +import bdv.export.ExportScalePyramid.AfterEachPlane; +import bdv.export.ExportScalePyramid.LoopbackHeuristic; 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; @@ -103,7 +104,7 @@ public class ExportImagePlusPlugIn implements Command 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 } ); + final FinalDimensions size = new FinalDimensions( w, h, d ); // propose reasonable mipmap settings final ExportMipmapInfo autoMipmapSettings = ProposeMipmaps.proposeMipmaps( new BasicViewSetup( 0, "", size, voxelSize ) ); @@ -177,7 +178,7 @@ public class ExportImagePlusPlugIn implements Command if ( previousLevel < 0 ) return false; - if ( WriteSequenceToHdf5.numElements( factorsToOriginalImg ) / WriteSequenceToHdf5.numElements( factorsToPreviousLevel ) >= 8 ) + if ( Intervals.numElements( factorsToOriginalImg ) / Intervals.numElements( factorsToPreviousLevel ) >= 8 ) return true; if ( isVirtual ) diff --git a/src/main/java/bdv/ij/ExportSpimFusionPlugIn.java b/src/main/java/bdv/ij/ExportSpimFusionPlugIn.java index 73c9e3a64e212e67ef87ca6df2db021a859a90cb..84066e29e0d087be8403df6602695360fe473c05 100644 --- a/src/main/java/bdv/ij/ExportSpimFusionPlugIn.java +++ b/src/main/java/bdv/ij/ExportSpimFusionPlugIn.java @@ -68,6 +68,7 @@ import mpicbg.spim.io.SPIMConfiguration; import mpicbg.spim.io.TextFileAccess; import spimopener.SPIMExperiment; +@Deprecated @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Deprecated>Export Fused Sequence as XML/HDF5") public class ExportSpimFusionPlugIn implements Command diff --git a/src/main/java/bdv/ij/ExportSpimSequencePlugIn.java b/src/main/java/bdv/ij/ExportSpimSequencePlugIn.java index 44bbdf36a75ef6d92fe446551506b6a898f4854c..d7378cb3a133aef2667e174b4cf6d9da61591232 100644 --- a/src/main/java/bdv/ij/ExportSpimSequencePlugIn.java +++ b/src/main/java/bdv/ij/ExportSpimSequencePlugIn.java @@ -45,6 +45,7 @@ import mpicbg.spim.io.SPIMConfiguration; import mpicbg.spim.io.TextFileAccess; import spimopener.SPIMExperiment; +@Deprecated @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Deprecated>Export Spim Sequence as XML/HDF5") public class ExportSpimSequencePlugIn implements Command diff --git a/src/main/java/bdv/ij/OpenImagePlusPlugIn.java b/src/main/java/bdv/ij/OpenImagePlusPlugIn.java index 132a981cb9851e965df599b1e254910e5ee05a30..d84afa91d8556557a907028b5509a80107a98589 100644 --- a/src/main/java/bdv/ij/OpenImagePlusPlugIn.java +++ b/src/main/java/bdv/ij/OpenImagePlusPlugIn.java @@ -1,9 +1,13 @@ package bdv.ij; +import bdv.viewer.ConverterSetups; +import bdv.viewer.SynchronizedViewerState; +import bdv.viewer.ViewerState; import java.io.File; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import net.imglib2.FinalDimensions; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.type.numeric.ARGBType; @@ -21,11 +25,9 @@ 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.SourceAndConverter; import bdv.viewer.ViewerOptions; -import bdv.viewer.VisibilityAndGrouping; import ij.CompositeImage; import ij.IJ; import ij.ImageJ; @@ -132,18 +134,19 @@ public class OpenImagePlusPlugIn implements Command nTimepoints, cache, "BigDataViewer", new ProgressWriterIJ(), ViewerOptions.options() ); - final SetupAssignments sa = bdv.getSetupAssignments(); - final VisibilityAndGrouping vg = bdv.getViewer().getVisibilityAndGrouping(); - - int channelOffset = 0; - int numActiveChannels = 0; - for ( ImagePlus imp : imgList ) + final SynchronizedViewerState state = bdv.getViewer().state(); + synchronized ( state ) { - numActiveChannels += transferChannelVisibility( channelOffset, imp,vg ); - transferChannelSettings( channelOffset, imp, sa ); - channelOffset += imp.getNChannels(); + int channelOffset = 0; + int numActiveChannels = 0; + for ( ImagePlus imp : imgList ) + { + numActiveChannels += transferChannelVisibility( channelOffset, imp, state ); + transferChannelSettings( channelOffset, imp, state, bdv.getConverterSetups() ); + channelOffset += imp.getNChannels(); + } + state.setDisplayMode( numActiveChannels > 1 ? DisplayMode.FUSED : DisplayMode.SINGLE ); } - vg.setDisplayMode( numActiveChannels > 1 ? DisplayMode.FUSED : DisplayMode.SINGLE ); } } @@ -257,19 +260,20 @@ public class OpenImagePlusPlugIn implements Command /** * @return number of setups that were set active. */ - protected int transferChannelVisibility( int channelOffset, final ImagePlus imp, final VisibilityAndGrouping visibility ) + protected int transferChannelVisibility( int channelOffset, final ImagePlus imp, final ViewerState state ) { final int nChannels = imp.getNChannels(); final CompositeImage ci = imp.isComposite() ? ( CompositeImage ) imp : null; + final List< SourceAndConverter< ? > > sources = state.getSources(); if ( ci != null && ci.getCompositeMode() == IJ.COMPOSITE ) { final boolean[] activeChannels = ci.getActiveChannels(); int numActiveChannels = 0; - for ( int i = 0; i < activeChannels.length; ++i ) + for ( int i = 0; i < Math.min( activeChannels.length, nChannels ); ++i ) { - final int setup = channelOffset + i; - visibility.setSourceActive( setup, activeChannels[ i ] ); - visibility.setCurrentSource( setup ); + final SourceAndConverter< ? > source = sources.get( channelOffset + i ); + state.setSourceActive( source, activeChannels[ i ] ); + state.setCurrentSource( source ); numActiveChannels += activeChannels[ i ] ? 1 : 0; } return numActiveChannels; @@ -278,16 +282,17 @@ public class OpenImagePlusPlugIn implements Command { final int activeChannel = imp.getChannel() - 1; for ( int i = 0; i < nChannels; ++i ) - visibility.setSourceActive( channelOffset + i, i == activeChannel ); - visibility.setCurrentSource( channelOffset + activeChannel ); + state.setSourceActive( sources.get( channelOffset + i ), i == activeChannel ); + state.setCurrentSource( sources.get( channelOffset + activeChannel ) ); return 1; } } - protected void transferChannelSettings( int channelOffset, final ImagePlus imp, final SetupAssignments setupAssignments ) + protected void transferChannelSettings( int channelOffset, final ImagePlus imp, final ViewerState state, final ConverterSetups converterSetups ) { final int nChannels = imp.getNChannels(); final CompositeImage ci = imp.isComposite() ? ( CompositeImage ) imp : null; + final List< SourceAndConverter< ? > > sources = state.getSources(); if ( ci != null ) { final int mode = ci.getCompositeMode(); @@ -295,7 +300,7 @@ public class OpenImagePlusPlugIn implements Command for ( int c = 0; c < nChannels; ++c ) { final LUT lut = ci.getChannelLut( c + 1 ); - final ConverterSetup setup = setupAssignments.getConverterSetups().get( channelOffset + c ); + final ConverterSetup setup = converterSetups.getConverterSetup( sources.get( channelOffset + c ) ); if ( transferColor ) setup.setColor( new ARGBType( lut.getRGB( 255 ) ) ); setup.setDisplayRange( lut.min, lut.max ); @@ -307,7 +312,7 @@ public class OpenImagePlusPlugIn implements Command final double displayRangeMax = imp.getDisplayRangeMax(); for ( int i = 0; i < nChannels; ++i ) { - final ConverterSetup setup = setupAssignments.getConverterSetups().get( channelOffset + i ); + final ConverterSetup setup = converterSetups.getConverterSetup( sources.get( channelOffset + i ) ); final LUT[] luts = imp.getLuts(); if ( luts.length != 0 ) setup.setColor( new ARGBType( luts[ 0 ].getRGB( 255 ) ) ); diff --git a/src/main/java/bdv/ij/export/FixAbsolutePathsInHdf5Partitions.java b/src/main/java/bdv/ij/export/FixAbsolutePathsInHdf5Partitions.java index ac4e3d4a77771c4fc5b61fe96e626a984061ae29..b660a7103ada2d6bb29308f7264e70aab5aa8d66 100644 --- a/src/main/java/bdv/ij/export/FixAbsolutePathsInHdf5Partitions.java +++ b/src/main/java/bdv/ij/export/FixAbsolutePathsInHdf5Partitions.java @@ -29,6 +29,7 @@ import mpicbg.spim.data.generic.sequence.BasicViewSetup; * * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ +@Deprecated public class FixAbsolutePathsInHdf5Partitions { public static void fix( final String xmlFilename ) throws SpimDataException, IOException diff --git a/src/main/java/bdv/ij/export/FusionResult.java b/src/main/java/bdv/ij/export/FusionResult.java index 1a57fa72e76961a78342b424ed1ffd7cac0895a1..3b0259441127a9bb81bf742a83e8673a4dc4ad52 100644 --- a/src/main/java/bdv/ij/export/FusionResult.java +++ b/src/main/java/bdv/ij/export/FusionResult.java @@ -20,6 +20,7 @@ import mpicbg.spim.data.sequence.VoxelDimensions; import net.imglib2.Dimensions; import net.imglib2.realtransform.AffineTransform3D; +@Deprecated public class FusionResult { private final SequenceDescriptionMinimal desc; diff --git a/src/main/java/bdv/ij/export/Scripting.java b/src/main/java/bdv/ij/export/Scripting.java index e7f30ae7c10b33d04139e2f04fce84487b3211af..1491f4fe70b8f256ca62f0e018043f78a0bc8746 100644 --- a/src/main/java/bdv/ij/export/Scripting.java +++ b/src/main/java/bdv/ij/export/Scripting.java @@ -17,6 +17,7 @@ import mpicbg.spim.data.SpimDataException; import mpicbg.spim.io.ConfigurationParserException; import net.imglib2.realtransform.AffineTransform3D; +@Deprecated public class Scripting { /** @@ -42,6 +43,7 @@ public class Scripting * @return an initialized {@link SpimRegistrationSequence} sequence. * @throws ConfigurationParserException */ + @Deprecated public static SpimRegistrationSequence createSpimRegistrationSequence( final String huiskenExperimentXmlFile, final String channels, @@ -85,6 +87,7 @@ public class Scripting * @return an initialized {@link SpimRegistrationSequence} sequence. * @throws ConfigurationParserException */ + @Deprecated public static SpimRegistrationSequence createSpimRegistrationSequence( final String inputDirectory, final String inputFilePattern, @@ -108,6 +111,7 @@ public class Scripting * @param cropOffsetZ * @return */ + @Deprecated public static Map< Integer, AffineTransform3D > getFusionTransforms( final SpimRegistrationSequence spimseq, final int scale, @@ -130,6 +134,7 @@ public class Scripting * @param fusionTransforms * @return */ + @Deprecated public static FusionResult createFusionResult( final SpimRegistrationSequence spimseq, final String filepath, @@ -159,6 +164,7 @@ public class Scripting * is used to generate paths for the partitions. * @return list of partitions. */ + @Deprecated public static ArrayList< Partition > split( final SetupAggregator aggregator, final int timepointsPerPartition, diff --git a/src/main/java/bdv/ij/export/SetupAggregator.java b/src/main/java/bdv/ij/export/SetupAggregator.java index b21d975da3db27e19f48c296a2657a215408b110..4650098e7fe548f8ee2eaeb604fa949d8bddcaca 100644 --- a/src/main/java/bdv/ij/export/SetupAggregator.java +++ b/src/main/java/bdv/ij/export/SetupAggregator.java @@ -34,6 +34,7 @@ import net.imglib2.img.cell.CellImg; * * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ +@Deprecated public class SetupAggregator { /** @@ -80,7 +81,7 @@ public class SetupAggregator /** * Add a new {@link BasicViewSetup} to the aggregator. * - * Adds a setup of the given source {@link SpimRegistrationSequence} to the + * Adds a setup of the given source {@link AbstractSequenceDescription} to the * aggregator. A reference to the source sequence is kept and the source * {@link ViewRegistrations} are copied. In the viewer format, every image * is stored in multiple resolutions. The resolutions are described as int[] @@ -181,6 +182,7 @@ public class SetupAggregator * "{32,32,32}, {16,16,8}, {8,8,8}" where each "{...}" * defines one subdivision. */ + @Deprecated public void addSetup( final SpimRegistrationSequence sequence, final int setupIndex, final String resolutionsString, final String subdivisionsString ) { final AbstractSequenceDescription< ?, ?, ? > desc = sequence.getSequenceDescription(); @@ -222,6 +224,7 @@ public class SetupAggregator * the set of subdivisions to store. each nested int[] array * defines one subdivision. */ + @Deprecated public void addSetup( final SpimRegistrationSequence sequence, final int setupIndex, final int[][] resolutions, final int[][] subdivisions ) { final AbstractSequenceDescription< ?, ?, ? > desc = sequence.getSequenceDescription(); @@ -257,6 +260,7 @@ public class SetupAggregator * "{32,32,32}, {16,16,8}, {8,8,8}" where each "{...}" * defines one subdivision. */ + @Deprecated public void addSetups( final SpimRegistrationSequence sequence, final String resolutionsString, final String subdivisionsString ) { for ( int s = 0; s < sequence.getSequenceDescription().getViewSetups().size(); ++s ) @@ -286,6 +290,7 @@ public class SetupAggregator * the set of subdivisions to store. each nested int[] array * defines one subdivision. */ + @Deprecated public void addSetups( final SpimRegistrationSequence sequence, final int[][] resolutions, final int[][] subdivisions ) { for ( int s = 0; s < sequence.getSequenceDescription().getViewSetups().size(); ++s ) @@ -317,6 +322,7 @@ public class SetupAggregator * "{32,32,32}, {16,16,8}, {8,8,8}" where each "{...}" * defines one subdivision. */ + @Deprecated public void addSetups( final FusionResult fusionResult, final String resolutionsString, final String subdivisionsString ) { final int[][] resolutions = PluginHelper.parseResolutionsString( resolutionsString ); @@ -354,6 +360,7 @@ public class SetupAggregator * the set of subdivisions to store. each nested int[] array * defines one subdivision. */ + @Deprecated public void addSetups( final FusionResult fusionResult, final int[][] resolutions, final int[][] subdivisions ) { if ( resolutions.length != subdivisions.length ) diff --git a/src/main/java/bdv/ij/export/SpimRegistrationSequence.java b/src/main/java/bdv/ij/export/SpimRegistrationSequence.java index bb0cd223e66181c88f007131678ac62a465a0331..2f2cdfeda09a39c60d832df804877df716aca05c 100644 --- a/src/main/java/bdv/ij/export/SpimRegistrationSequence.java +++ b/src/main/java/bdv/ij/export/SpimRegistrationSequence.java @@ -35,6 +35,7 @@ import net.imglib2.realtransform.AffineTransform3D; import spim.vecmath.Point3f; import spimopener.SPIMExperiment; +@Deprecated public class SpimRegistrationSequence { private final SequenceDescriptionMinimal sequenceDescription; diff --git a/src/main/java/bdv/ij/export/ViewSetupWrapper.java b/src/main/java/bdv/ij/export/ViewSetupWrapper.java index ebbb167838e33d821266fcb7b13d0a25295e8f2d..cf1afb839b9f757eeef187846d4bdde747c8169b 100644 --- a/src/main/java/bdv/ij/export/ViewSetupWrapper.java +++ b/src/main/java/bdv/ij/export/ViewSetupWrapper.java @@ -13,6 +13,7 @@ import mpicbg.spim.data.sequence.ViewSetup; * * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ +@Deprecated public class ViewSetupWrapper extends BasicViewSetup { private final AbstractSequenceDescription< ?, ?, ? > sourceSequence; diff --git a/src/main/java/bdv/ij/export/imgloader/FusionImageLoader.java b/src/main/java/bdv/ij/export/imgloader/FusionImageLoader.java index 5b01a1dd587d8e59d9b3f947577100656ed6144b..9a0a4c8f35cc26a835bcc28245aae4d5a4da09e7 100644 --- a/src/main/java/bdv/ij/export/imgloader/FusionImageLoader.java +++ b/src/main/java/bdv/ij/export/imgloader/FusionImageLoader.java @@ -45,6 +45,7 @@ import net.imglib2.view.Views; * * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ +@Deprecated public class FusionImageLoader< T extends RealType< T > > implements ImgLoader { private final String pattern; diff --git a/src/main/java/bdv/ij/export/imgloader/HuiskenImageLoader.java b/src/main/java/bdv/ij/export/imgloader/HuiskenImageLoader.java index 8dc85ba386139df45dd5af513d4bde0a2cdaafc0..9e88239e468597cf661afe839966a6f7423f3789 100644 --- a/src/main/java/bdv/ij/export/imgloader/HuiskenImageLoader.java +++ b/src/main/java/bdv/ij/export/imgloader/HuiskenImageLoader.java @@ -25,6 +25,7 @@ import spimopener.SPIMExperiment; * * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ +@Deprecated public class HuiskenImageLoader implements BasicImgLoader { private final File expFile; diff --git a/src/main/java/bdv/ij/export/imgloader/LegacyStackImageLoader.java b/src/main/java/bdv/ij/export/imgloader/LegacyStackImageLoader.java index c832d531e349749484db9e5c0fc4fa7de2cc35dc..474351768bff71221fd455ce177ae9bf49b3d51f 100644 --- a/src/main/java/bdv/ij/export/imgloader/LegacyStackImageLoader.java +++ b/src/main/java/bdv/ij/export/imgloader/LegacyStackImageLoader.java @@ -34,6 +34,7 @@ import net.imglib2.type.numeric.integer.UnsignedShortType; * * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ +@Deprecated public class LegacyStackImageLoader implements LegacyBasicImgLoader< UnsignedShortType > { private final ImgOpener opener; diff --git a/src/main/java/bdv/ij/export/imgloader/StackImageLoader.java b/src/main/java/bdv/ij/export/imgloader/StackImageLoader.java index e73e7dc90c012b6e6cdef6d7aea11ace53a3a766..adb96918cd89520c6a3ac1ecb9935826f8b468e2 100644 --- a/src/main/java/bdv/ij/export/imgloader/StackImageLoader.java +++ b/src/main/java/bdv/ij/export/imgloader/StackImageLoader.java @@ -18,6 +18,7 @@ import net.imglib2.type.numeric.integer.UnsignedShortType; * * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ +@Deprecated public class StackImageLoader extends LegacyBasicImgLoaderWrapper< UnsignedShortType, LegacyStackImageLoader > { public StackImageLoader( final HashMap< ViewId, String > filenames, final boolean useImageJOpener )