diff --git a/pom.xml b/pom.xml index 04f284fbe..43d91eae2 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.embl.mobie mobie-viewer-fiji - 5.0.9 + 5.0.11 diff --git a/src/main/java/org/embl/mobie/command/context/AbstractTransformationCommand.java b/src/main/java/org/embl/mobie/command/context/AbstractTransformationCommand.java index 6e37089d4..d3903fa69 100644 --- a/src/main/java/org/embl/mobie/command/context/AbstractTransformationCommand.java +++ b/src/main/java/org/embl/mobie/command/context/AbstractTransformationCommand.java @@ -66,8 +66,9 @@ public abstract class AbstractTransformationCommand extends DynamicCommand imple public String selectedSourceName; @Parameter ( label = "Transformed image(s) suffix", - description = "Upon transformation this suffix will be appended to the moving image(s).\n" + - "Carefully choose a meaningful suffix here that will create a unique new image name.") + description = "Upon transformation this suffix will be appended to the moving image name.\n" + + "Carefully choose a meaningful suffix here that will create a unique new image name.\n" + + "If you leave this empty the input image view will be overwritten.") public String suffix = "transformed"; // Too complex to maintain right now @@ -134,7 +135,9 @@ protected void createAndSaveAffineTransformedImages( { for ( Image< ? > movingImage : movingImages ) { - String transformedImageName = movingImage.getName() + "-" + suffix; + String transformedImageName = movingImage.getName(); + if ( ! suffix.isEmpty() ) + transformedImageName += "-" + suffix; AffineTransformation affineTransformation = new AffineTransformation( suffix, diff --git a/src/main/java/org/embl/mobie/command/context/ManualTransformationCommand.java b/src/main/java/org/embl/mobie/command/context/ManualTransformationCommand.java index 37e7528c3..11274d1cc 100644 --- a/src/main/java/org/embl/mobie/command/context/ManualTransformationCommand.java +++ b/src/main/java/org/embl/mobie/command/context/ManualTransformationCommand.java @@ -80,7 +80,7 @@ public void startManualTransform() transformationEditor.setActive( true ); getInfo().getMutableInput( "status", String.class ) - .setValue( this, "Status: You are transforming " + selectedSourceName + "..."); + .setValue( this, "Status: You are transforming \"" + selectedSourceName + "\"..."); } private void acceptManualTransform() diff --git a/src/main/java/org/embl/mobie/command/open/OpenBlobsCommand.java b/src/main/java/org/embl/mobie/command/open/OpenBlobsCommand.java deleted file mode 100644 index 448338d9a..000000000 --- a/src/main/java/org/embl/mobie/command/open/OpenBlobsCommand.java +++ /dev/null @@ -1,47 +0,0 @@ -/*- - * #%L - * Fiji viewer for MoBIE projects - * %% - * Copyright (C) 2018 - 2024 EMBL - * %% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * #L% - */ -package org.embl.mobie.command.open; - -import ij.IJ; -import org.embl.mobie.command.CommandConstants; -import org.scijava.command.Command; -import org.scijava.plugin.Plugin; - -@Plugin(type = Command.class, menuPath = CommandConstants.MOBIE_PLUGIN_OPEN + "Open Blobs..." ) -public class OpenBlobsCommand implements Command { - - static { net.imagej.patcher.LegacyInjector.preinit(); } - - @Override - public void run() - { - IJ.run("Blobs (25K)"); - } - -} diff --git a/src/main/java/org/embl/mobie/command/open/project/OpenMoBIEProjectCommand.java b/src/main/java/org/embl/mobie/command/open/project/OpenMoBIEProjectCommand.java index 870b37b34..ba1a2cad5 100644 --- a/src/main/java/org/embl/mobie/command/open/project/OpenMoBIEProjectCommand.java +++ b/src/main/java/org/embl/mobie/command/open/project/OpenMoBIEProjectCommand.java @@ -32,11 +32,13 @@ import org.embl.mobie.MoBIE; import org.embl.mobie.MoBIESettings; import org.embl.mobie.command.CommandConstants; +import org.embl.mobie.lib.MoBIEHelper; import org.embl.mobie.lib.io.DataFormats; import org.scijava.command.Command; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; +import java.io.File; import java.io.IOException; @@ -46,7 +48,7 @@ public class OpenMoBIEProjectCommand implements Command static { net.imagej.patcher.LegacyInjector.preinit(); } @Parameter ( label = "Project Location" ) - public String projectLocation = "https://github.com/mobie/platybrowser-datasets"; + public File projectLocation = new File( "https://github.com/mobie/platybrowser-datasets" ); @Parameter ( label = "Preferentially Fetch Data From", choices = {"Remote", "Local"} ) public String location = "Remote"; @@ -60,7 +62,7 @@ public void run() try { - new MoBIE( projectLocation, settings ); + new MoBIE( MoBIEHelper.toURI( projectLocation ), settings ); } catch ( IOException e ) { diff --git a/src/main/java/org/embl/mobie/command/open/project/OpenMoBIEProjectExpertCommand.java b/src/main/java/org/embl/mobie/command/open/project/OpenMoBIEProjectExpertCommand.java index 327d216a7..93c645084 100644 --- a/src/main/java/org/embl/mobie/command/open/project/OpenMoBIEProjectExpertCommand.java +++ b/src/main/java/org/embl/mobie/command/open/project/OpenMoBIEProjectExpertCommand.java @@ -29,20 +29,23 @@ package org.embl.mobie.command.open.project; import org.embl.mobie.command.CommandConstants; +import org.embl.mobie.lib.MoBIEHelper; import org.embl.mobie.lib.ThreadHelper; import org.embl.mobie.lib.bdv.view.SliceViewer; import org.scijava.command.Command; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; +import java.io.File; + @Plugin(type = Command.class, menuPath = CommandConstants.MOBIE_PLUGIN_OPEN_PROJECT + "Open MoBIE Project Expert Mode..." ) public class OpenMoBIEProjectExpertCommand extends OpenMoBIEProjectBranchCommand { @Parameter ( label = "Image Data Location" ) - public String imageDataLocation = "https://github.com/platybrowser/platybrowser"; + public File imageDataLocation = new File( "https://github.com/platybrowser/platybrowser" ); @Parameter ( label = "Table Data Location" ) - public String tableDataLocation = "https://github.com/platybrowser/platybrowser"; + public File tableDataLocation = new File( "https://github.com/platybrowser/platybrowser" ); @Parameter ( label = "Table Data Branch" ) public String tableDataBranch = "master"; @@ -60,8 +63,8 @@ public void run() ThreadHelper.setNumIoThreads( numThreads ); settings.gitProjectBranch( projectBranch ) - .imageDataLocation( imageDataLocation ) - .tableDataLocation( tableDataLocation ) + .imageDataLocation( MoBIEHelper.toURI( imageDataLocation ) ) + .tableDataLocation( MoBIEHelper.toURI( tableDataLocation ) ) .gitTablesBranch( tableDataBranch ); super.run(); diff --git a/src/main/java/org/embl/mobie/lib/MoBIEHelper.java b/src/main/java/org/embl/mobie/lib/MoBIEHelper.java index 28a4adcdf..e044dac2c 100644 --- a/src/main/java/org/embl/mobie/lib/MoBIEHelper.java +++ b/src/main/java/org/embl/mobie/lib/MoBIEHelper.java @@ -35,6 +35,8 @@ import net.imglib2.Cursor; import net.imglib2.RandomAccessibleInterval; import net.imglib2.type.numeric.RealType; +import net.imglib2.util.Intervals; +import net.imglib2.util.ValuePair; import net.imglib2.view.Views; import org.embl.mobie.io.ImageDataOpener; import org.embl.mobie.io.github.GitHubUtils; @@ -47,10 +49,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Matcher; @@ -312,6 +311,25 @@ public static List< String > getFullPaths( String regex, String root ) } } + public static double[] estimateMinMax( + RandomAccessibleInterval > rai) + { + Cursor> cursor = Views.iterable(rai).cursor(); + if (!cursor.hasNext()) return new double[]{0, 255}; + long stepSize = Intervals.numElements(rai) / 10000 + 1; + int randomLimit = (int) Math.min(Integer.MAX_VALUE, stepSize); + Random random = new Random(42); + double min = cursor.next().getRealDouble(); + double max = min; + while (cursor.hasNext()) { + double value = cursor.get().getRealDouble(); + cursor.jumpFwd(stepSize + random.nextInt(randomLimit)); + min = Math.min(min, value); + max = Math.max(max, value); + } + return new double[]{min, max}; + } + public static > double[] computeMinMax( RandomAccessibleInterval rai) { Cursor cursor = Views.iterable(rai).cursor(); diff --git a/src/main/java/org/embl/mobie/lib/create/ui/ProjectsCreatorUI.java b/src/main/java/org/embl/mobie/lib/create/ui/ProjectsCreatorUI.java index d2c347ade..1c0f87f75 100644 --- a/src/main/java/org/embl/mobie/lib/create/ui/ProjectsCreatorUI.java +++ b/src/main/java/org/embl/mobie/lib/create/ui/ProjectsCreatorUI.java @@ -336,14 +336,14 @@ private void addButtonsPanel() { remoteButton.addActionListener( e -> { - new Thread( () -> { remoteMetadataSettingsDialog(); } ).start(); + new Thread( this::remoteMetadataSettingsDialog ).start(); } ); openMoBIEButton.addActionListener( e -> { new Thread( () -> { OpenMoBIEProjectCommand openMoBIE = new OpenMoBIEProjectCommand(); - openMoBIE.projectLocation = this.projectCreator.getProjectLocation().getAbsolutePath(); + openMoBIE.projectLocation = new File( this.projectCreator.getProjectLocation().getAbsolutePath() ); openMoBIE.run(); } ).start(); } ); diff --git a/src/main/java/org/embl/mobie/lib/files/ImageFileSources.java b/src/main/java/org/embl/mobie/lib/files/ImageFileSources.java index 4285cb855..9860d7f7f 100644 --- a/src/main/java/org/embl/mobie/lib/files/ImageFileSources.java +++ b/src/main/java/org/embl/mobie/lib/files/ImageFileSources.java @@ -35,6 +35,7 @@ import net.imglib2.Volatile; import net.imglib2.realtransform.AffineTransform3D; import org.apache.commons.io.FilenameUtils; +import org.embl.mobie.DataStore; import org.embl.mobie.MoBIE; import org.embl.mobie.io.ImageDataOpener; import org.embl.mobie.io.imagedata.ImageData; @@ -51,6 +52,7 @@ import tech.tablesaw.api.StringColumn; import tech.tablesaw.api.Table; +import javax.xml.crypto.Data; import java.io.File; import java.util.*; @@ -180,17 +182,19 @@ protected static boolean isCellProfilerColumn( String column, Table table ) private void setMetadata( Integer channelIndex ) { metadataSource = nameToFullPath.keySet().iterator().next(); - IJ.log( "Fetching metadata from " + nameToFullPath.get( metadataSource ) ); + IJ.log( "Fetching metadata for channel " + channelIndex + "..." ); + IJ.log( "...from image file " + nameToFullPath.get( metadataSource ) ); + // FIXME: Cache the image data, because for multiple images it is now reloaded! ImageData< ? > imageData = ImageDataOpener.open( nameToFullPath.get( metadataSource ) ); CanonicalDatasetMetadata canonicalDatasetMetadata = imageData.getMetadata( channelIndex ); metadata = new Metadata( canonicalDatasetMetadata ); Source< ? > source = imageData.getSourcePair( channelIndex ).getA(); metadata.numZSlices = (int) source.getSource( 0, 0 ).dimension( 2 ); metadata.numTimePoints = SourceHelper.getNumTimePoints( source ); - metadata.contrastLimits = MoBIEHelper.computeMinMax( ( RandomAccessibleInterval ) source.getSource( 0, source.getNumMipmapLevels() -1 ) ); + metadata.contrastLimits = MoBIEHelper.estimateMinMax( ( RandomAccessibleInterval ) source.getSource( 0, source.getNumMipmapLevels() -1 ) ); IJ.log( "Slices: " + metadata.numZSlices ); IJ.log( "Frames: " + metadata.numTimePoints ); - IJ.log( "Min, max: " + Arrays.toString( metadata.contrastLimits ) ); + IJ.log( "Contrast limits: " + Arrays.toString( metadata.contrastLimits ) ); } private static String applyPathMapping( String pathMapping, String path ) diff --git a/src/main/java/org/embl/mobie/lib/source/SourceHelper.java b/src/main/java/org/embl/mobie/lib/source/SourceHelper.java index f8719bcd9..ae9b97b74 100644 --- a/src/main/java/org/embl/mobie/lib/source/SourceHelper.java +++ b/src/main/java/org/embl/mobie/lib/source/SourceHelper.java @@ -38,19 +38,18 @@ import bdv.viewer.Source; import mpicbg.spim.data.sequence.FinalVoxelDimensions; import mpicbg.spim.data.sequence.VoxelDimensions; -import net.imglib2.FinalRealInterval; -import net.imglib2.Interval; -import net.imglib2.Point; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.RealInterval; -import net.imglib2.RealPoint; +import net.imglib2.*; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.roi.RealMaskRealInterval; import net.imglib2.roi.geom.GeomMasks; import net.imglib2.roi.geom.real.WritableBox; +import net.imglib2.type.numeric.RealType; import net.imglib2.util.Intervals; +import net.imglib2.util.ValuePair; +import net.imglib2.view.Views; import org.embl.mobie.lib.bdv.CalibratedMousePositionProvider; import org.jetbrains.annotations.NotNull; +import sc.fiji.bdvpg.sourceandconverter.SourceAndConverterHelper; import java.lang.reflect.Field; import java.util.*; @@ -60,7 +59,6 @@ public abstract class SourceHelper { - public static < T > T unwrapSource( Source source, Class< T > clazz ) { if ( source == null ) @@ -375,4 +373,5 @@ public static boolean isPositionWithinSourceInterval( Source< ? > source, RealPo // } // else { } + } diff --git a/src/main/java/org/embl/mobie/ui/UserInterfaceHelper.java b/src/main/java/org/embl/mobie/ui/UserInterfaceHelper.java index 4a36da0c2..dc4f815b8 100644 --- a/src/main/java/org/embl/mobie/ui/UserInterfaceHelper.java +++ b/src/main/java/org/embl/mobie/ui/UserInterfaceHelper.java @@ -37,6 +37,7 @@ import de.embl.cba.tables.SwingUtils; import ij.IJ; import ij.gui.GenericDialog; +import net.imglib2.RandomAccessibleInterval; import net.imglib2.converter.Converter; import net.imglib2.display.ColorConverter; import net.imglib2.realtransform.AffineTransform3D; @@ -44,6 +45,7 @@ import org.embl.mobie.command.context.ConfigureSegmentRenderingCommand; import org.embl.mobie.io.util.IOHelper; import org.embl.mobie.MoBIE; +import org.embl.mobie.lib.MoBIEHelper; import org.embl.mobie.lib.io.FileLocation; import org.embl.mobie.lib.MoBIEInfo; import org.embl.mobie.lib.Services; @@ -488,7 +490,6 @@ public static JFrame showOpacityAndContrastLimitsDialog( selection.setUpdateListener( opacityUpdateListener ); panel.add( opacitySlider ); - if ( addContrastLimitUI ) { // Contrast Limits @@ -503,7 +504,6 @@ public static JFrame showOpacityAndContrastLimitsDialog( .map( sac -> sac.getConverter() ) .collect( Collectors.toList() ); - final double currentContrastLimitsMin = converterSetups.get( 0 ).getDisplayRangeMin(); final double currentContrastLimitsMax = converterSetups.get( 0 ).getDisplayRangeMax(); final double absCurrentRange = Math.abs( currentContrastLimitsMax - currentContrastLimitsMin ); @@ -548,6 +548,18 @@ public static JFrame showOpacityAndContrastLimitsDialog( panel.add( minSlider ); panel.add( maxSlider ); + JButton autoButton = new JButton("Auto Min Max"); + autoButton.addActionListener( e -> + { + Source< ? > source = sacs.get( 0 ).getSpimSource(); + RandomAccessibleInterval< ? > rai = source.getSource( bdvHandle.getViewerPanel().state().getCurrentTimepoint(), + source.getNumMipmapLevels() - 1 ); + double[] minMax = MoBIEHelper.estimateMinMax( ( RandomAccessibleInterval ) rai ); + min.setCurrentValue( minMax[ 0 ] ); + max.setCurrentValue( minMax[ 1 ] ); + }); + panel.add( autoButton ); + boolean isInvert = false; for ( Converter< ?, ARGBType > converter : converters ) { diff --git a/src/test/java/projects/muscle_patterning_drosophila/OpenTeresaData.java b/src/test/java/projects/muscle_patterning_drosophila/OpenTeresaData.java index 7213ae5d6..c0b926cbe 100644 --- a/src/test/java/projects/muscle_patterning_drosophila/OpenTeresaData.java +++ b/src/test/java/projects/muscle_patterning_drosophila/OpenTeresaData.java @@ -41,15 +41,37 @@ public static void main( String[] args ) final ImageJ imageJ = new ImageJ(); imageJ.ui().showUI(); +// OpenTableCommand command = new OpenTableCommand(); +// command.table = new File( "/Users/tischer/Desktop/teresa/summary_calculated1_subset.txt" ); +// command.root = command.table.getParentFile(); +// command.images = "FileName_Result.Image_IMG"; // Result.Image.Zarr +// command.gridType = GridType.Transformed; // TODO: not working with Stitched! +// command.run(); + OpenTableCommand command = new OpenTableCommand(); - //command.table = new File( "/Volumes/almf/group/Aliaksandr/User_data/Furlong_CrispR/test_data_20231018/20231004/20231004-172458/summary_calculated1.txt" ); - //command.table = new File( "/Volumes/almf/group/Aliaksandr/User_data/Furlong_CrispR/test_data_20231018/20231004/20231004-172458/summary_calculated1_subset.txt" ); - command.table = new File( "/Users/tischer/Desktop/teresa/summary_calculated1_subset.txt" ); - //command.table = new File( "/Volumes/cba/exchange/furlong_test/summary_calculated1_subset_zarr.txt" ); - //command.images = "Result.Image.Zarr"; // Result.Image.Zarr + command.table = new File( "/Volumes/CRISPR_project_data/test_data_new/20231122-170451/summary_new.txt" ); command.root = command.table.getParentFile(); - command.images = "FileName_Result.Image_IMG"; // Result.Image.Zarr + command.images = "FileName_Result.Image_IMG"; command.gridType = GridType.Transformed; // TODO: not working with Stitched! command.run(); + + /* + TODO: + + Why is it fetching so much metadata?? It is opening the same data again for all channels. + + Also initialisation is slow... + + Min, max: [6.0, 2608.0] + Fetching metadata from /Volumes/CRISPR_project_data/test_data_new/20231122-170451/Result-Image/Result-Image--WA01--P0001--T0001.oir + Slices: 11 + Frames: 1 + Min, max: [13.0, 981.0] + Fetching metadata from /Volumes/CRISPR_project_data/test_data_new/20231122-170451/Result-Image/Result-Image--WA01--P0001--T0001.oir + Slices: 11 + Frames: 1 + Min, max: [7.0, 2060.0] + */ + } } diff --git a/src/test/resources/minimal-mobie-project/data/blobs/dataset.json b/src/test/resources/minimal-mobie-project/data/blobs/dataset.json index 9b32751a2..2dd3ba7f6 100644 --- a/src/test/resources/minimal-mobie-project/data/blobs/dataset.json +++ b/src/test/resources/minimal-mobie-project/data/blobs/dataset.json @@ -42,26 +42,35 @@ } } ], - "sourceTransforms": [], - "viewerTransform": { - "normalizedAffine": [ - 0.0016175016000465467, - 0.0, - 0.0, - -0.20623145400593473, - 0.0, - 0.0016175016000465467, - 0.0, - -0.20461395240588817, - 0.0, - 0.0, - 0.0016175016000465467, - 0.0 - ], - "timepoint": 0 - }, - "isExclusive": true, - "description": "" + "sourceTransforms": [ + { + "affine": { + "parameters": [ + 1.0000000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0000000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0000000000000002, + 0.0 + ], + "name": "", + "sources": [ + "blobs" + ], + "sourceNamesAfterTransform": [ + "blobs" + ] + } + } + ], + "isExclusive": false, + "description": "blobs, overwrite" }, "default": { "uiSelectionGroup": "bookmark",