Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support more datatypes for HDF5 export #31

Merged
merged 3 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
<license.licenseName>gpl_v3</license.licenseName>
<license.copyrightOwners>BigDataViewer developers.</license.copyrightOwners>

<bigdataviewer-core.version>10.4.14</bigdataviewer-core.version>

<!-- NB: Deploy releases to the SciJava Maven repository. -->
<releaseProfiles>sign,deploy-to-scijava</releaseProfiles>
</properties>
Expand Down
173 changes: 69 additions & 104 deletions src/main/java/bdv/ij/ExportImagePlusPlugIn.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
import bdv.spimdata.SequenceDescriptionMinimal;
import bdv.spimdata.SpimDataMinimal;
import bdv.spimdata.XmlIoSpimDataMinimal;
import bdv.img.imagestack.ImageStackImageLoader;
import bdv.img.n5.N5ImageLoader;
import bdv.img.virtualstack.VirtualStackImageLoader;
import fiji.util.gui.GenericDialogPlus;
import ij.IJ;
import ij.ImageJ;
Expand All @@ -63,6 +66,7 @@
import ij.gui.DialogListener;
import ij.gui.GenericDialog;
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;
Expand Down Expand Up @@ -139,19 +143,44 @@ public void run()
progressWriter.out().println( "starting export..." );

// create ImgLoader wrapping the image
final ImagePlusImgLoader< ? > imgLoader;
switch ( imp.getType() )
final TypedBasicImgLoader< ? > imgLoader;
final Runnable clearCache;
final boolean isVirtual = imp.getStack() != null && imp.getStack().isVirtual();
if ( isVirtual )
{
case ImagePlus.GRAY8:
imgLoader = ImagePlusImgLoader.createGray8( imp, params.minMaxOption, params.rangeMin, params.rangeMax );
break;
case ImagePlus.GRAY16:
imgLoader = ImagePlusImgLoader.createGray16( imp, params.minMaxOption, params.rangeMin, params.rangeMax );
break;
case ImagePlus.GRAY32:
default:
imgLoader = ImagePlusImgLoader.createGray32( imp, params.minMaxOption, params.rangeMin, params.rangeMax );
break;
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();
Expand All @@ -174,8 +203,7 @@ public void run()
timepoints.add( new TimePoint( t ) );
final SequenceDescriptionMinimal seq = new SequenceDescriptionMinimal( new TimePoints( timepoints ), setups, imgLoader, null );

Map< Integer, ExportMipmapInfo > perSetupExportMipmapInfo;
perSetupExportMipmapInfo = new HashMap<>();
final Map< Integer, ExportMipmapInfo > perSetupExportMipmapInfo = new HashMap<>();
final ExportMipmapInfo mipmapInfo = params.setMipmapManual
? new ExportMipmapInfo( params.resolutions, params.subdivisions )
: autoMipmapSettings;
Expand All @@ -189,7 +217,6 @@ public void run()
// 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 boolean isVirtual = imp.getStack().isVirtual();
final long planeSizeInBytes = imp.getWidth() * imp.getHeight() * imp.getBytesPerPixel();
final long ijMaxMemory = IJ.maxMemory();
final int numCellCreatorThreads = Math.max( 1, PluginHelper.numThreads() - 1 );
Expand Down Expand Up @@ -228,7 +255,7 @@ public void afterEachPlane( final boolean usedLoopBack )
final long actuallyFree = max - total + free;

if ( actuallyFree < max / 2 )
imgLoader.clearCache();
clearCache.run();
}
}

Expand Down Expand Up @@ -291,12 +318,6 @@ protected static class Parameters

final File hdf5File;

final MinMaxOption minMaxOption;

final double rangeMin;

final double rangeMax;

final boolean deflate;

final boolean split;
Expand All @@ -308,17 +329,14 @@ protected static class Parameters
public Parameters(
final boolean setMipmapManual, final int[][] resolutions, final int[][] subdivisions,
final File seqFile, final File hdf5File,
final MinMaxOption minMaxOption, final double rangeMin, final double rangeMax, final boolean deflate,
final boolean deflate,
final boolean split, final int timepointsPerPartition, final int setupsPerPartition )
{
this.setMipmapManual = setMipmapManual;
this.resolutions = resolutions;
this.subdivisions = subdivisions;
this.seqFile = seqFile;
this.hdf5File = hdf5File;
this.minMaxOption = minMaxOption;
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.deflate = deflate;
this.split = split;
this.timepointsPerPartition = timepointsPerPartition;
Expand All @@ -332,12 +350,6 @@ public Parameters(

static String lastChunkSizes = "{32,32,4}, {16,16,8}, {8,8,8}";

static int lastMinMaxChoice = 2;

static double lastMin = 0;

static double lastMax = 65535;

static boolean lastSplit = false;

static int lastTimepointsPerPartition = 0;
Expand All @@ -350,12 +362,6 @@ public Parameters(

protected Parameters getParameters( final double impMin, final double impMax, final ExportMipmapInfo autoMipmapSettings )
{
if ( lastMinMaxChoice == 0 ) // use ImageJs...
{
lastMin = impMin;
lastMax = impMax;
}

while ( true )
{
final GenericDialogPlus gd = new GenericDialogPlus( "Export for BigDataViewer" );
Expand All @@ -367,15 +373,6 @@ protected Parameters getParameters( final double impMin, final double impMax, fi
gd.addStringField( "Hdf5_chunk_sizes", lastChunkSizes, 25 );
final TextField tfChunkSizes = ( TextField ) gd.getStringFields().lastElement();

gd.addMessage( "" );
final String[] minMaxChoices = new String[] { "Use ImageJ's current min/max setting", "Compute min/max of the (hyper-)stack", "Use values specified below" };
gd.addChoice( "Value_range", minMaxChoices, minMaxChoices[ lastMinMaxChoice ] );
final Choice cMinMaxChoices = (Choice) gd.getChoices().lastElement();
gd.addNumericField( "Min", lastMin, 0 );
final TextField tfMin = (TextField) gd.getNumericFields().lastElement();
gd.addNumericField( "Max", lastMax, 0 );
final TextField tfMax = (TextField) gd.getNumericFields().lastElement();

gd.addMessage( "" );
gd.addCheckbox( "split_hdf5", lastSplit );
final Checkbox cSplit = ( Checkbox ) gd.getCheckboxes().lastElement();
Expand All @@ -390,59 +387,37 @@ protected Parameters getParameters( final double impMin, final double impMax, fi
gd.addMessage( "" );
PluginHelper.addSaveAsFileField( gd, "Export_path", lastExportPath, 25 );

// gd.addMessage( "" );
// gd.addMessage( "This Plugin is developed by Tobias Pietzsch ([email protected])\n" );
// Bead_Registration.addHyperLinkListener( ( MultiLineLabel ) gd.getMessage(), "mailto:[email protected]" );

final String autoSubsampling = ProposeMipmaps.getArrayString( autoMipmapSettings.getExportResolutions() );
final String autoChunkSizes = ProposeMipmaps.getArrayString( autoMipmapSettings.getSubdivisions() );
gd.addDialogListener( new DialogListener()
{
@Override
public boolean dialogItemChanged( final GenericDialog dialog, final AWTEvent e )
gd.addDialogListener( ( dialog, e ) -> {
gd.getNextBoolean();
gd.getNextString();
gd.getNextString();
gd.getNextBoolean();
gd.getNextNumber();
gd.getNextNumber();
gd.getNextBoolean();
gd.getNextString();
if ( e instanceof ItemEvent && e.getID() == ItemEvent.ITEM_STATE_CHANGED && e.getSource() == cManualMipmap )
{
gd.getNextBoolean();
gd.getNextString();
gd.getNextString();
gd.getNextChoiceIndex();
gd.getNextNumber();
gd.getNextNumber();
gd.getNextBoolean();
gd.getNextNumber();
gd.getNextNumber();
gd.getNextBoolean();
gd.getNextString();
if ( e instanceof ItemEvent && e.getID() == ItemEvent.ITEM_STATE_CHANGED && e.getSource() == cMinMaxChoices )
final boolean useManual = cManualMipmap.getState();
tfSubsampling.setEnabled( useManual );
tfChunkSizes.setEnabled( useManual );
if ( !useManual )
{
final boolean enable = cMinMaxChoices.getSelectedIndex() == 2;
tfMin.setEnabled( enable );
tfMax.setEnabled( enable );
tfSubsampling.setText( autoSubsampling );
tfChunkSizes.setText( autoChunkSizes );
}
else 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 );
}
}
else if ( e instanceof ItemEvent && e.getID() == ItemEvent.ITEM_STATE_CHANGED && e.getSource() == cSplit )
{
final boolean split = cSplit.getState();
tfSplitTimepoints.setEnabled( split );
tfSplitSetups.setEnabled( split );
}
return true;
}
else if ( e instanceof ItemEvent && e.getID() == ItemEvent.ITEM_STATE_CHANGED && e.getSource() == cSplit )
{
final boolean split = cSplit.getState();
tfSplitTimepoints.setEnabled( split );
tfSplitSetups.setEnabled( split );
}
return true;
} );

final boolean enable = lastMinMaxChoice == 2;
tfMin.setEnabled( enable );
tfMax.setEnabled( enable );

tfSubsampling.setEnabled( lastSetMipmapManual );
tfChunkSizes.setEnabled( lastSetMipmapManual );
if ( !lastSetMipmapManual )
Expand All @@ -461,9 +436,6 @@ else if ( e instanceof ItemEvent && e.getID() == ItemEvent.ITEM_STATE_CHANGED &&
lastSetMipmapManual = gd.getNextBoolean();
lastSubsampling = gd.getNextString();
lastChunkSizes = gd.getNextString();
lastMinMaxChoice = gd.getNextChoiceIndex();
lastMin = gd.getNextNumber();
lastMax = gd.getNextNumber();
lastSplit = gd.getNextBoolean();
lastTimepointsPerPartition = ( int ) gd.getNextNumber();
lastSetupsPerPartition = ( int ) gd.getNextNumber();
Expand All @@ -489,14 +461,6 @@ else if ( resolutions.length != subdivisions.length )
continue;
}

final MinMaxOption minMaxOption;
if ( lastMinMaxChoice == 0 )
minMaxOption = MinMaxOption.TAKE_FROM_IMAGEPROCESSOR;
else if ( lastMinMaxChoice == 1 )
minMaxOption = MinMaxOption.COMPUTE;
else
minMaxOption = MinMaxOption.SET;

String seqFilename = lastExportPath;
if ( !seqFilename.endsWith( ".xml" ) )
seqFilename += ".xml";
Expand All @@ -510,6 +474,7 @@ else if ( lastMinMaxChoice == 1 )
final String hdf5Filename = seqFilename.substring( 0, seqFilename.length() - 4 ) + ".h5";
final File hdf5File = new File( hdf5Filename );

return new Parameters( lastSetMipmapManual, resolutions, subdivisions, seqFile, hdf5File, minMaxOption, lastMin, lastMax, lastDeflate, lastSplit, lastTimepointsPerPartition, lastSetupsPerPartition ); }
return new Parameters( lastSetMipmapManual, resolutions, subdivisions, seqFile, hdf5File, lastDeflate, lastSplit, lastTimepointsPerPartition, lastSetupsPerPartition );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
*
* @author Tobias Pietzsch &lt;[email protected]&gt;
*/
@Deprecated
public class ImagePlusImgLoader< T extends Type< T > > implements TypedBasicImgLoader< T >
{
public static enum MinMaxOption
Expand Down
Loading