From 189acc7e9a93bf18f6c5eea2188fe564b0363c31 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Thu, 23 Jun 2022 09:54:51 -0400 Subject: [PATCH 001/282] feat: interpolated realtransform --- .../InterpolatedRealTransform.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/main/java/net/imglib2/realtransform/InterpolatedRealTransform.java diff --git a/src/main/java/net/imglib2/realtransform/InterpolatedRealTransform.java b/src/main/java/net/imglib2/realtransform/InterpolatedRealTransform.java new file mode 100644 index 00000000..92415c62 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/InterpolatedRealTransform.java @@ -0,0 +1,100 @@ +package net.imglib2.realtransform; + +import net.imglib2.RealLocalizable; +import net.imglib2.RealPoint; +import net.imglib2.RealPositionable; +import net.imglib2.RealRandomAccess; +import net.imglib2.RealRandomAccessible; +import net.imglib2.type.numeric.RealType; + +/** + * Spatially-varying interpolation between two {@link RealTransform}s. + *

+ * Given a {@link RealRandomAccessible} "lambda", and two transformations "a", and "b", implements the transformation + * lambda * a(x) + (1-lambda) * b(x) for a point x. + * + * @author John Bogovic + * + * @param lambda's type + */ +public class InterpolatedRealTransform> implements RealTransform { + + private RealRandomAccessible lambda; + + private RealRandomAccess lambdaAccess; + + private final RealTransform a; + + private final RealTransform b; + + private final RealPoint pa; + + private final RealPoint pb; + + private final double[] arrA; + + private final double[] arrB; + + public InterpolatedRealTransform(RealTransform a, RealTransform b, RealRandomAccessible lambda) { + + assert (a.numTargetDimensions() == b.numTargetDimensions() && + a.numSourceDimensions() == b.numSourceDimensions()); + this.a = a; + this.b = b; + this.lambda = lambda; + lambdaAccess = lambda.realRandomAccess(); + + int nd = a.numTargetDimensions(); + arrA = new double[nd]; + arrB = new double[nd]; + pa = RealPoint.wrap(arrA); + pb = RealPoint.wrap(arrB); + } + + @Override + public int numSourceDimensions() { + + return a.numSourceDimensions(); + } + + @Override + public int numTargetDimensions() { + + return a.numTargetDimensions(); + } + + @Override + public void apply(double[] source, double[] target) { + + a.apply(source, arrA); + b.apply(source, arrB); + + lambdaAccess.setPosition(source); + final double am = lambdaAccess.get().getRealDouble(); + final double bm = (1 - am); + + for (int i = 0; i < target.length; i++) + target[i] = am * arrA[i] + bm * arrB[i]; + } + + @Override + public void apply(RealLocalizable source, RealPositionable target) { + + a.apply(source, pa); + b.apply(source, pb); + + lambdaAccess.setPosition(source); + double am = lambdaAccess.get().getRealDouble(); + double bm = (1 - am); + + for (int i = 0; i < target.numDimensions(); i++) + target.setPosition(am * pa.getDoublePosition(i) + bm * pb.getDoublePosition(i), i); + } + + @Override + public RealTransform copy() { + + return new InterpolatedRealTransform(a.copy(), b.copy(), lambda); + } + +} From a2ecb974dbc35f08b21519486bf4f8bb1519480c Mon Sep 17 00:00:00 2001 From: bogovicj Date: Sat, 25 Jun 2022 17:10:15 -0400 Subject: [PATCH 002/282] add InterpolatedTransformTest --- .../InterpolatedTransformTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/test/java/net/imglib2/realtransform/InterpolatedTransformTest.java diff --git a/src/test/java/net/imglib2/realtransform/InterpolatedTransformTest.java b/src/test/java/net/imglib2/realtransform/InterpolatedTransformTest.java new file mode 100644 index 00000000..20b14726 --- /dev/null +++ b/src/test/java/net/imglib2/realtransform/InterpolatedTransformTest.java @@ -0,0 +1,45 @@ +package net.imglib2.realtransform; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import net.imglib2.RealPoint; +import net.imglib2.RealRandomAccessible; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.ConstantUtils; + +public class InterpolatedTransformTest +{ + + @Test + public void simpleTest() + { + final double EPS = 1e-9; + + final Translation2D a = new Translation2D( new double[]{ 1, 0 }); + final Translation2D b = new Translation2D( new double[]{ 2, 0 }); + + final RealRandomAccessible< DoubleType > l1 = ConstantUtils.constantRealRandomAccessible( new DoubleType(0.1), 2 ); + final RealRandomAccessible< DoubleType > l5 = ConstantUtils.constantRealRandomAccessible( new DoubleType(0.5), 2 ); + final RealRandomAccessible< DoubleType > l9 = ConstantUtils.constantRealRandomAccessible( new DoubleType(0.9), 2 ); + + final InterpolatedRealTransform t1 = new InterpolatedRealTransform<>( a, b, l1 ); + final InterpolatedRealTransform t5 = new InterpolatedRealTransform<>( a, b, l5 ); + final InterpolatedRealTransform t9 = new InterpolatedRealTransform<>( a, b, l9 ); + + RealPoint src = new RealPoint( 2 ); + RealPoint dst = new RealPoint( 2 ); + + t1.apply( src, dst ); + assertEquals( "lambda 0.1", 1.9, dst.getDoublePosition( 0 ), EPS ); + + t5.apply( src, dst ); + assertEquals( "lambda 0.5", 1.5, dst.getDoublePosition( 0 ), EPS ); + + t9.apply( src, dst ); + assertEquals( "lambda 0.9", 1.1, dst.getDoublePosition( 0 ), EPS ); + + } + +} From 7a601101fb3f2285f840edb40bca12282c86089a Mon Sep 17 00:00:00 2001 From: bogovicj Date: Sat, 25 Jun 2022 17:11:38 -0400 Subject: [PATCH 003/282] add mask source and start ui modifications --- .../bdv/gui/TransformTypeSelectDialog.java | 11 +- ...teauSphericalMaskRealRandomAccessible.java | 115 ++++++++++++++++++ .../source/PlateauSphericalMaskSource.java | 30 +++++ .../bigwarp/transforms/BigWarpTransform.java | 7 ++ 4 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java create mode 100644 src/main/java/bigwarp/source/PlateauSphericalMaskSource.java diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index de90e982..31670e36 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -40,15 +40,17 @@ public class TransformTypeSelectDialog extends JDialog private static final long serialVersionUID = 1L; public static final String TPS = "Thin Plate Spline"; + public static final String REGTPS = "Regularized Thin Plate Spline"; public static final String AFFINE = "Affine"; public static final String SIMILARITY = "Similarity"; public static final String ROTATION = "Rotation"; public static final String TRANSLATION = "Translation"; - + private final BigWarp< ? > bw; private String transformType; private final JRadioButton tpsButton; + private final JRadioButton regTpsButton; private final JRadioButton affineButton; private final JRadioButton similarityButton; private final JRadioButton rotationButton; @@ -70,6 +72,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) transformType = bw.getTransformType(); tpsButton = new JRadioButton( TPS ); + regTpsButton = new JRadioButton( REGTPS ); affineButton = new JRadioButton( AFFINE ); similarityButton = new JRadioButton( SIMILARITY ); rotationButton = new JRadioButton( ROTATION ); @@ -77,6 +80,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) ButtonGroup group = new ButtonGroup(); group.add( tpsButton ); + group.add( regTpsButton ); group.add( affineButton ); group.add( similarityButton ); group.add( rotationButton ); @@ -85,6 +89,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) updateButtonGroup(); addActionListender( tpsButton ); + addActionListender( regTpsButton ); addActionListender( affineButton ); addActionListender( similarityButton ); addActionListender( rotationButton ); @@ -92,6 +97,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) JPanel radioPanel = new JPanel( new GridLayout(0, 1)); radioPanel.add( tpsButton ); + radioPanel.add( regTpsButton ); radioPanel.add( affineButton ); radioPanel.add( similarityButton ); radioPanel.add( rotationButton ); @@ -116,6 +122,9 @@ private void updateButtonGroup() case TPS: tpsButton.setSelected( true ); break; + case REGTPS: + tpsButton.setSelected( true ); + break; case AFFINE: affineButton.setSelected( true ); break; diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java new file mode 100644 index 00000000..35d8f0fe --- /dev/null +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -0,0 +1,115 @@ +package bigwarp.source; + +import java.util.function.BiConsumer; + +import bdv.util.BdvFunctions; +import bdv.util.BdvOptions; +import bdv.util.BdvStackSource; +import bdv.util.RealRandomAccessibleIntervalSource; +import net.imglib2.Interval; +import net.imglib2.RealInterval; +import net.imglib2.RealLocalizable; +import net.imglib2.RealPoint; +import net.imglib2.RealRandomAccess; +import net.imglib2.RealRandomAccessible; +import net.imglib2.position.FunctionRealRandomAccessible; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.Intervals; + +public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAccessible< DoubleType > +{ + private PlateauFunction pfun; + private FunctionRealRandomAccessible< DoubleType > rra; + + private double plateauR = 8; + + private double outerSigma = 1; + + public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint pt ) + { + pfun = new PlateauFunction( pt ); + rra = new FunctionRealRandomAccessible<>( 3, pfun, DoubleType::new ); + } + + public static void main( String[] args ) + { + long S = 50; + RealPoint pt = new RealPoint( new double[]{ S, S, S } ); + + PlateauSphericalMaskRealRandomAccessible img = new PlateauSphericalMaskRealRandomAccessible( 3, pt ); + Interval interval = Intervals.createMinSize( 0, 0, 0, 2*S, 2*S, 2*S ); + + BdvOptions options = BdvOptions.options().screenScales( new double[] { 1 } ); + BdvStackSource< DoubleType > bdv = BdvFunctions.show( img.rra, interval, "img", options ); + bdv.getBdvHandle().getSetupAssignments().getMinMaxGroups().get( 0 ).setRange( 0, 1 ); + + } + + public class PlateauFunction implements BiConsumer< RealLocalizable, DoubleType > { + + public RealPoint point; + + public double plateauR = 8; + public double plateauR2 = plateauR*plateauR; + + public double outerSigma = 1; + + public double invSqrSigma = 1 / outerSigma / outerSigma; + + public PlateauFunction( RealPoint point ) { + this.point = point; + } + + @Override + public void accept( RealLocalizable x, DoubleType v ) + { + v.setZero(); + double r2 = squaredDistance( x, point ); + if( r2 <= plateauR ) + v.setOne(); + else + { + double t = (r2 - plateauR); + // TODO sample exp function and interpolate to speed up + v.set( Math.exp( -0.5 * t * invSqrSigma ) ); +// v.set( Math.cos( t * 0.5 + 0.5 )); +// v.set( 1 / t ); + } + } + + } + + final public static double squaredDistance( final RealLocalizable position1, final RealLocalizable position2 ) + { + double dist = 0; + + final int n = position1.numDimensions(); + for ( int d = 0; d < n; ++d ) + { + final double pos = position2.getDoublePosition( d ) - position1.getDoublePosition( d ); + + dist += pos * pos; + } + + return dist; + } + + @Override + public int numDimensions() + { + return rra.numDimensions(); + } + + @Override + public RealRandomAccess< DoubleType > realRandomAccess() + { + return rra.realRandomAccess(); + } + + @Override + public RealRandomAccess< DoubleType > realRandomAccess( RealInterval interval ) + { + return rra.realRandomAccess( interval ); + } + +} diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java b/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java new file mode 100644 index 00000000..48ae81c4 --- /dev/null +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java @@ -0,0 +1,30 @@ +package bigwarp.source; + +import bdv.util.RealRandomAccessibleIntervalSource; +import net.imglib2.Interval; +import net.imglib2.RealPoint; +import net.imglib2.type.numeric.real.DoubleType; + +public class PlateauSphericalMaskSource extends RealRandomAccessibleIntervalSource< DoubleType > +{ + private PlateauSphericalMaskRealRandomAccessible plateauMask; + + private PlateauSphericalMaskSource( int n, RealPoint pt, Interval interval ) + { + super( new PlateauSphericalMaskRealRandomAccessible( n, pt ), interval, new DoubleType(), "plateau-mask" ); + } + + private PlateauSphericalMaskSource( PlateauSphericalMaskRealRandomAccessible mask, Interval interval ) + { + super( mask, interval, new DoubleType(), "plateau-mask" ); + this.plateauMask = mask; + } + + public + + public static PlateauSphericalMaskSource build( int n, RealPoint pt, Interval interval ) + { + PlateauSphericalMaskRealRandomAccessible mask = new PlateauSphericalMaskRealRandomAccessible( n, pt ); + return new PlateauSphericalMaskSource( mask, interval ); + } +} diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 25ec6127..96f3eacb 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -124,6 +124,13 @@ public InvertibleRealTransform getTransformation( final int index ) tpsXfm.getOptimzer().setTolerance(inverseTolerance); invXfm = tpsXfm; } + else if( transformType.equals( TransformTypeSelectDialog.REGTPS )) + { + WrappedIterativeInvertibleRealTransform tpsXfm = new RegTpsTransformSolver().solve( tableModel ); + tpsXfm.getOptimzer().setMaxIters(maxIterations); + tpsXfm.getOptimzer().setTolerance(inverseTolerance); + invXfm = tpsXfm; + } else { final double[][] mvgPts; From 771f1dfbd10f8a6d4e67d35430e91e0265d107fa Mon Sep 17 00:00:00 2001 From: bogovicj Date: Sat, 25 Jun 2022 17:17:44 -0400 Subject: [PATCH 004/282] add RegTpsTransformSolver --- .../transforms/RegTpsTransformSolver.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/main/java/bigwarp/transforms/RegTpsTransformSolver.java diff --git a/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java b/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java new file mode 100644 index 00000000..81abc237 --- /dev/null +++ b/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java @@ -0,0 +1,70 @@ +/*- + * #%L + * BigWarp plugin for Fiji. + * %% + * Copyright (C) 2015 - 2021 Howard Hughes Medical Institute. + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package bigwarp.transforms; + +import bigwarp.landmarks.LandmarkTableModel; +import jitk.spline.ThinPlateR2LogRSplineKernelTransform; +import net.imglib2.realtransform.ThinplateSplineTransform; +import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; + +public class RegTpsTransformSolver implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> +{ + private double[][] mvgPts; + private double[][] tgtPts; + + + public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) + { + return new WrappedIterativeInvertibleRealTransform( + new ThinplateSplineTransform( + new ThinPlateR2LogRSplineKernelTransform( tgtPts.length, tgtPts, mvgPts ))); + } + + public WrappedIterativeInvertibleRealTransform solve( + final LandmarkTableModel landmarkTable ) + { + return solve( landmarkTable, -1 ); + } + + public WrappedIterativeInvertibleRealTransform solve( + final LandmarkTableModel landmarkTable, final int indexChanged ) + { + synchronized( landmarkTable ) + { + int numActive = landmarkTable.numActive(); + int ndims = landmarkTable.getNumdims(); + + if( mvgPts == null || mvgPts[0].length != numActive ) + { + mvgPts = new double[ ndims ][ numActive ]; + tgtPts = new double[ ndims ][ numActive ]; + landmarkTable.copyLandmarks( mvgPts, tgtPts ); + } + else if( indexChanged >= 0 ) + { + landmarkTable.copyLandmarks( indexChanged, mvgPts, tgtPts ); + } + } + + return solve( mvgPts, tgtPts ); + } +} From 9e0defab0e30423be5c42100660f7e7c7d13526e Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 5 Jul 2022 12:20:23 -0400 Subject: [PATCH 005/282] feat: early working version of masked tps --- .../gui/MaskedSourceEditorMouseListener.java | 130 ++++++++++++++++++ .../bdv/gui/TransformTypeSelectDialog.java | 2 +- src/main/java/bdv/img/WarpedSource.java | 2 +- src/main/java/bigwarp/BigWarp.java | 52 ++++++- src/main/java/bigwarp/BigWarpActions.java | 26 ++++ ...teauSphericalMaskRealRandomAccessible.java | 100 +++++++++++--- .../source/PlateauSphericalMaskSource.java | 14 +- .../bigwarp/transforms/BigWarpTransform.java | 11 +- .../transforms/RegTpsTransformSolver.java | 49 ++++--- 9 files changed, 331 insertions(+), 55 deletions(-) create mode 100644 src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java new file mode 100644 index 00000000..7d3cf538 --- /dev/null +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -0,0 +1,130 @@ +package bdv.gui; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +import bdv.viewer.ViewerPanel; +import bigwarp.BigWarp; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import net.imglib2.RealPoint; + +public class MaskedSourceEditorMouseListener implements MouseListener, MouseMotionListener, MouseWheelListener +{ + private PlateauSphericalMaskRealRandomAccessible mask; + + private boolean active; + private RealPoint p; + + private BigWarp bw; + private ViewerPanel viewer; + + public MaskedSourceEditorMouseListener( int nd, BigWarp bw, ViewerPanel viewer ) + { + this.bw = bw; + this.viewer = viewer; + viewer.getDisplay().addMouseListener( this ); + viewer.getDisplay().addMouseWheelListener( this ); + viewer.getDisplay().addMouseMotionListener( this ); + + p = new RealPoint( nd ); + active = false; + } + + public void setActive( boolean active ) + { + this.active = active; + bw.getViewerFrameP().setTransformEnabled( !active ); + bw.getViewerFrameQ().setTransformEnabled( !active ); + + final String msg = active ? "Mask Edit On" : "Mask Edit Off"; + bw.getViewerFrameP().getViewerPanel().showMessage( msg ); + bw.getViewerFrameQ().getViewerPanel().showMessage( msg ); + } + + public void toggleActive( ) + { + setActive( !active ); + } + + public void setMask( PlateauSphericalMaskRealRandomAccessible mask ) + { + this.mask = mask; + } + + public PlateauSphericalMaskRealRandomAccessible getMask() + { + return mask; + } + + @Override + public void mouseClicked( MouseEvent e ) { } + + @Override + public void mouseEntered( MouseEvent e ) { } + + @Override + public void mouseExited( MouseEvent e ) { } + + @Override + public void mousePressed( MouseEvent e ) + { + if( !active ) + return; + + viewer.getGlobalMouseCoordinates( p ); + synchronized ( mask ) + { + mask.setCenter( p ); + } +// viewer.requestRepaint(); + bw.getViewerFrameP().getViewerPanel().requestRepaint(); + bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + } + + @Override + public void mouseMoved( MouseEvent e ) { } + + @Override + public void mouseDragged( MouseEvent e ) + { + if( !active ) + return; + + viewer.getGlobalMouseCoordinates( p ); + synchronized ( mask ) + { + mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible + .squaredDistance( p, mask.getCenter() ) ); + } + bw.getViewerFrameP().getViewerPanel().requestRepaint(); + bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + + } + + @Override + public void mouseReleased( MouseEvent e ) { } + + @Override + public void mouseWheelMoved( MouseWheelEvent e ) + { + if( !active ) + return; + + // TODO vary based on screen scale + final int sign = e.getWheelRotation(); + if( e.isShiftDown() ) + mask.incSquaredSigma( sign * 10 ); + else if ( e.isControlDown() ) + mask.incSquaredSigma( sign * 0.1 ); + else + mask.incSquaredSigma( sign * 1.0 ); + + bw.getViewerFrameP().getViewerPanel().requestRepaint(); + bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + } + + +} diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index 31670e36..c1b32d70 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -123,7 +123,7 @@ private void updateButtonGroup() tpsButton.setSelected( true ); break; case REGTPS: - tpsButton.setSelected( true ); + regTpsButton.setSelected( true ); break; case AFFINE: affineButton.setSelected( true ); diff --git a/src/main/java/bdv/img/WarpedSource.java b/src/main/java/bdv/img/WarpedSource.java index c93c6214..35237a55 100644 --- a/src/main/java/bdv/img/WarpedSource.java +++ b/src/main/java/bdv/img/WarpedSource.java @@ -184,7 +184,7 @@ public RealRandomAccessible< T > getInterpolatedSource( final int t, final int l if( xfm == null ) return srcRaTransformed; else - return new RealTransformRealRandomAccessible< T, RealTransform >( srcRaTransformed, xfm ); + return new RealTransformRealRandomAccessible< T, RealTransform >( srcRaTransformed, xfm.copy() ); } else { diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index e4477837..fd2170b1 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -96,6 +96,7 @@ import bdv.gui.BigWarpViewerOptions; import bdv.gui.BigwarpLandmarkSelectionPanel; import bdv.gui.LandmarkKeyboardProcessor; +import bdv.gui.MaskedSourceEditorMouseListener; import bdv.gui.TransformTypeSelectDialog; import bdv.ij.ApplyBigwarpPlugin; import bdv.ij.ApplyBigwarpPlugin.WriteDestinationOptions; @@ -132,6 +133,8 @@ import bigwarp.loader.ImagePlusLoader.ColorSettings; import bigwarp.source.GridSource; import bigwarp.source.JacobianDeterminantSource; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.source.PlateauSphericalMaskSource; import bigwarp.source.WarpMagnitudeSource; import bigwarp.transforms.BigWarpTransform; import bigwarp.transforms.WrappedCoordinateTransform; @@ -155,6 +158,7 @@ import mpicbg.models.TranslationModel2D; import mpicbg.models.TranslationModel3D; import mpicbg.spim.data.SpimDataException; +import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealPoint; @@ -162,10 +166,13 @@ import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.BoundingBoxEstimation; import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.Wrapped2DTransformAs3D; +import net.imglib2.realtransform.inverse.RealTransformFiniteDerivatives; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.ARGBType; +import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; public class BigWarp< T > @@ -181,6 +188,8 @@ public class BigWarp< T > public static final int JACDET_SOURCE_ID = 1006827158; + public static final int TPSMASK_SOURCE_ID = 33872301; + protected BigWarpViewerOptions options; protected BigWarpData< T > data; @@ -262,6 +271,8 @@ public class BigWarp< T > protected MouseLandmarkTableListener landmarkTableListener; + protected MaskedSourceEditorMouseListener maskSourceMouseListener; + protected BigWarpMessageAnimator message; protected final Set< KeyEventPostProcessor > keyEventPostProcessorSet = new HashSet< KeyEventPostProcessor >(); @@ -274,6 +285,10 @@ public class BigWarp< T > protected final SourceAndConverter< FloatType > jacDetSource; + protected final SourceAndConverter< DoubleType > tpsMaskSource; + + protected PlateauSphericalMaskSource tpsMask; + protected final AbstractModel< ? >[] baseXfmList; private final double[] ptBack; @@ -385,6 +400,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie warpMagSource = addWarpMagnitudeSource( data, "WarpMagnitudeSource" ); jacDetSource = addJacobianDeterminantSource( data, "JacobianDeterminantSource" ); gridSource = addGridSource( data, "GridSource" ); + tpsMaskSource = addTpsMaskSource( data, ndims, "TPS Mask Source" ); this.sources = this.data.sources; final List< ConverterSetup > converterSetups = data.converterSetups; @@ -489,6 +505,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie bwTransform = new BigWarpTransform( landmarkModel ); bwTransform.initializeInverseParameters(data); + bwTransform.setLambda( tpsMask.getRandomAccessible() ); solverThread = new SolveThread( this ); solverThread.start(); @@ -540,6 +557,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie landmarkClickListenerP = new MouseLandmarkListener( this.viewerP ); landmarkClickListenerQ = new MouseLandmarkListener( this.viewerQ ); + addMaskMouseListener(); // have to be safe here and use 3dim point for both 3d and 2d currentLandmark = new RealPoint( 3 ); @@ -1739,6 +1757,13 @@ protected void addDefaultTableMouseListener() landmarkPanel.getJTable().addMouseListener( landmarkTableListener ); } + protected void addMaskMouseListener() + { + maskSourceMouseListener = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerQ ); + maskSourceMouseListener.setActive( false ); + maskSourceMouseListener.setMask( tpsMask.getRandomAccessible() ); + } + public void setGridType( final GridSource.GRID_TYPE method ) { ( ( GridSource< ? > ) gridSource.getSpimSource() ).setMethod( method ); @@ -1818,6 +1843,27 @@ private static < T > SourceAndConverter< FloatType > addGridSource( final BigWar return soc; } + @SuppressWarnings( { "unchecked", "rawtypes" } ) + private SourceAndConverter< DoubleType > addTpsMaskSource( final BigWarpData< T > data, final int ndims, final String name ) + { + // TODO think about whether its worth it to pass a type parameter. + // or should we just stick with Floats? + FinalInterval itvl = new FinalInterval( data.sources.get( data.targetSourceIndices[0] ).getSpimSource().getSource( 0, 0 )); + tpsMask = PlateauSphericalMaskSource.build( ndims, new RealPoint( ndims ), itvl ); + + final RealARGBColorConverter< DoubleType > converter = RealARGBColorConverter.create( new DoubleType(), 0, 1 ); + converter.setColor( new ARGBType( 0xffffffff ) ); + final SourceAndConverter< DoubleType > soc = new SourceAndConverter( tpsMask, converter, null ); + data.converterSetups.add( BigDataViewer.createConverterSetup( soc, TPSMASK_SOURCE_ID ) ); + data.sources.add( ( SourceAndConverter ) soc ); + return soc; + } + + public PlateauSphericalMaskSource getTpsMaskSource() + { + return tpsMask; + } + private static < T > SourceAndConverter< T > wrapSourceAsTransformed( final SourceAndConverter< T > src, final String name, final int ndims ) { if ( src.asVolatile() == null ) @@ -2159,7 +2205,11 @@ private void setTransformationAll( final InvertibleRealTransform transform ) } else if ( transform instanceof WrappedIterativeInvertibleRealTransform ) { - jdSrc.setTransform( (ThinplateSplineTransform)((WrappedIterativeInvertibleRealTransform)transform).getTransform() ); + RealTransform xfm = ((WrappedIterativeInvertibleRealTransform)transform).getTransform(); + if( xfm instanceof ThinplateSplineTransform ) + jdSrc.setTransform( (ThinplateSplineTransform) xfm ); + else + jdSrc.setTransform( new RealTransformFiniteDerivatives( xfm )); } else jdSrc.setTransform( null ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 96cfa15d..24f4b13a 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -84,6 +84,8 @@ public class BigWarpActions public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; + public static final String MASK_SIZE_EDIT = "mask edit"; + public static final String SAVE_WARPED = "save warped"; public static final String SAVE_WARPED_XML = "save warped xml"; @@ -253,6 +255,8 @@ public static InputMap createInputMap( final KeyStrokeAdder.Factory keyPropertie map.put( TOGGLE_POINT_NAMES_VISIBLE, "N" ); map.put( ESTIMATE_WARP, "C" ); + map.put( MASK_SIZE_EDIT, "M" ); + map.put( UNDO, "control Z" ); map.put( REDO, "control Y" ); map.put( REDO, "control shift Z" ); @@ -326,6 +330,9 @@ public static ActionMap createActionMap( final BigWarp< ? > bw ) new ToggleMovingImageDisplayAction( TOGGLE_MOVING_IMAGE_DISPLAY, bw ).put( actionMap ); new EstimateWarpAction( ESTIMATE_WARP, bw ).put( actionMap ); + // MASK + new MaskSizeEdit( bw ).put(actionMap); + for( int i = 0; i < bw.baseXfmList.length; i++ ){ final AbstractModel xfm = bw.baseXfmList[ i ]; new SetWarpMagBaseAction( String.format( WARPMAG_BASE, xfm.getClass().getName()), bw, i ).put( actionMap ); @@ -1156,4 +1163,23 @@ public void actionPerformed(ActionEvent e) LandmarkGridGenerator.fillFromDialog( bw ); } } + + public static class MaskSizeEdit extends AbstractNamedAction + { + private static final long serialVersionUID = -7918625162439713732L; + private final BigWarp< ? > bw; + + public MaskSizeEdit( final BigWarp< ? > bw ) + { + super( MASK_SIZE_EDIT ); + this.bw = bw; + } + + @Override + public void actionPerformed(ActionEvent e) + { + bw.maskSourceMouseListener.toggleActive(); + } + } + } diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 35d8f0fe..d4b7a661 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -2,10 +2,10 @@ import java.util.function.BiConsumer; +import bdv.gui.MaskedSourceEditorMouseListener; import bdv.util.BdvFunctions; import bdv.util.BdvOptions; import bdv.util.BdvStackSource; -import bdv.util.RealRandomAccessibleIntervalSource; import net.imglib2.Interval; import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; @@ -21,14 +21,24 @@ public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAcces private PlateauFunction pfun; private FunctionRealRandomAccessible< DoubleType > rra; - private double plateauR = 8; + private double plateauR; + private double plateauR2; - private double outerSigma = 1; + private double sqrSigma; + private double invSqrSigma; - public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint pt ) + private RealPoint center; + + private static final double EPS = 1e-6; + + public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) { - pfun = new PlateauFunction( pt ); + this.center = center; + pfun = new PlateauFunction(); rra = new FunctionRealRandomAccessible<>( 3, pfun, DoubleType::new ); + + setRadius( 8.0 ); + setSigma ( 10.0 ); } public static void main( String[] args ) @@ -39,44 +49,92 @@ public static void main( String[] args ) PlateauSphericalMaskRealRandomAccessible img = new PlateauSphericalMaskRealRandomAccessible( 3, pt ); Interval interval = Intervals.createMinSize( 0, 0, 0, 2*S, 2*S, 2*S ); - BdvOptions options = BdvOptions.options().screenScales( new double[] { 1 } ); +// BdvOptions options = BdvOptions.options().screenScales( new double[] { 1 } ); + BdvOptions options = BdvOptions.options(); BdvStackSource< DoubleType > bdv = BdvFunctions.show( img.rra, interval, "img", options ); bdv.getBdvHandle().getSetupAssignments().getMinMaxGroups().get( 0 ).setRange( 0, 1 ); +// InputActionBindings kb = bdv.getBdvHandle().getKeybindings(); +// System.out.println( kb ); +// kb.removeActionMap( "navigation" ); +// kb.removeInputMap( "navigation" ); + +// bdv.getBdvHandle().getTriggerbindings().removeInputTriggerMap( "block_transform" ); + + final MaskedSourceEditorMouseListener ml = new MaskedSourceEditorMouseListener( 3, null, bdv.getBdvHandle().getViewerPanel() ); + ml.setMask( img ); +// bdv.getBdvHandle().getViewerPanel().getDisplay().addMouseListener( ml ); + } - public class PlateauFunction implements BiConsumer< RealLocalizable, DoubleType > { + public void setRadius( double r ) + { + plateauR = r; + plateauR2 = plateauR * plateauR ; + } - public RealPoint point; + public void setSquaredRadius( double r2 ) + { + plateauR2 = r2; + } - public double plateauR = 8; - public double plateauR2 = plateauR*plateauR; + public void setSigma( double sigma ) + { + sqrSigma = sigma * sigma; - public double outerSigma = 1; - - public double invSqrSigma = 1 / outerSigma / outerSigma; - - public PlateauFunction( RealPoint point ) { - this.point = point; - } + if( sqrSigma <= 0 ) + sqrSigma = EPS; + + invSqrSigma = 1.0 / sqrSigma; + } + + public void setSquaredSigma( double squaredSigma ) + { + sqrSigma = squaredSigma; + if( sqrSigma <= 0 ) + sqrSigma = EPS; + + invSqrSigma = 1.0 / squaredSigma; + } + + public void incSquaredSigma( double increment ) + { + sqrSigma += increment; + + if( sqrSigma <= 0 ) + sqrSigma = EPS; + + invSqrSigma = 1.0 / sqrSigma; + } + + public void setCenter( RealLocalizable p ) + { + center.setPosition( p ); + } + + public RealPoint getCenter() + { + return center; + } + + public class PlateauFunction implements BiConsumer< RealLocalizable, DoubleType > { @Override public void accept( RealLocalizable x, DoubleType v ) { v.setZero(); - double r2 = squaredDistance( x, point ); - if( r2 <= plateauR ) + double r2 = squaredDistance( x, center ); + if( r2 <= plateauR2 ) v.setOne(); else { - double t = (r2 - plateauR); + double t = (r2 - plateauR2); // TODO sample exp function and interpolate to speed up v.set( Math.exp( -0.5 * t * invSqrSigma ) ); // v.set( Math.cos( t * 0.5 + 0.5 )); // v.set( 1 / t ); } } - } final public static double squaredDistance( final RealLocalizable position1, final RealLocalizable position2 ) diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java b/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java index 48ae81c4..58301741 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java @@ -11,20 +11,24 @@ public class PlateauSphericalMaskSource extends RealRandomAccessibleIntervalSour private PlateauSphericalMaskSource( int n, RealPoint pt, Interval interval ) { - super( new PlateauSphericalMaskRealRandomAccessible( n, pt ), interval, new DoubleType(), "plateau-mask" ); + super( new PlateauSphericalMaskRealRandomAccessible( n, pt ), interval, new DoubleType(), "transform mask" ); } private PlateauSphericalMaskSource( PlateauSphericalMaskRealRandomAccessible mask, Interval interval ) { - super( mask, interval, new DoubleType(), "plateau-mask" ); + super( mask, interval, new DoubleType(), "transform mask" ); this.plateauMask = mask; } - - public - + + public PlateauSphericalMaskRealRandomAccessible getRandomAccessible() + { + return plateauMask; + } + public static PlateauSphericalMaskSource build( int n, RealPoint pt, Interval interval ) { PlateauSphericalMaskRealRandomAccessible mask = new PlateauSphericalMaskRealRandomAccessible( n, pt ); return new PlateauSphericalMaskSource( mask, interval ); } + } diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 96f3eacb..bf107179 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -46,12 +46,14 @@ import mpicbg.models.SimilarityModel2D; import mpicbg.models.TranslationModel2D; import mpicbg.models.TranslationModel3D; +import net.imglib2.RealRandomAccessible; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.InverseRealTransform; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.Wrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; +import net.imglib2.type.numeric.RealType; public class BigWarpTransform { @@ -67,6 +69,8 @@ public class BigWarpTransform private int maxIterations = 200; + private RealRandomAccessible> lambda; + public BigWarpTransform( final LandmarkTableModel tableModel ) { this( tableModel, TransformTypeSelectDialog.TPS ); @@ -109,6 +113,11 @@ public String getTransformType() return transformType; } + public void setLambda( final RealRandomAccessible< ? extends RealType< ? > > lambda ) + { + this.lambda = lambda; + } + public InvertibleRealTransform getTransformation() { return getTransformation( -1 ); @@ -126,7 +135,7 @@ public InvertibleRealTransform getTransformation( final int index ) } else if( transformType.equals( TransformTypeSelectDialog.REGTPS )) { - WrappedIterativeInvertibleRealTransform tpsXfm = new RegTpsTransformSolver().solve( tableModel ); + WrappedIterativeInvertibleRealTransform tpsXfm = new RegTpsTransformSolver( lambda ).solve( tableModel ); tpsXfm.getOptimzer().setMaxIters(maxIterations); tpsXfm.getOptimzer().setTolerance(inverseTolerance); invXfm = tpsXfm; diff --git a/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java b/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java index 81abc237..69b09d88 100644 --- a/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java +++ b/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java @@ -23,48 +23,47 @@ import bigwarp.landmarks.LandmarkTableModel; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; +import net.imglib2.RandomAccessible; +import net.imglib2.RealRandomAccessible; +import net.imglib2.realtransform.InterpolatedRealTransform; +import net.imglib2.realtransform.RealTransform; +import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; +import net.imglib2.type.numeric.RealType; -public class RegTpsTransformSolver implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> +public class RegTpsTransformSolver> implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> { - private double[][] mvgPts; - private double[][] tgtPts; - + // TODO make regularization transform of a more general type + private final TpsTransformSolver tpsSolver; + private final RealRandomAccessible lambda; + + public RegTpsTransformSolver( RealRandomAccessible lambda ) + { + this.lambda = lambda; + tpsSolver = new TpsTransformSolver(); + } public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { - return new WrappedIterativeInvertibleRealTransform( - new ThinplateSplineTransform( - new ThinPlateR2LogRSplineKernelTransform( tgtPts.length, tgtPts, mvgPts ))); + return wrap( tpsSolver.solve( mvgPts, tgtPts ), lambda ); } public WrappedIterativeInvertibleRealTransform solve( final LandmarkTableModel landmarkTable ) { - return solve( landmarkTable, -1 ); + return wrap( tpsSolver.solve( landmarkTable ), lambda ); } public WrappedIterativeInvertibleRealTransform solve( final LandmarkTableModel landmarkTable, final int indexChanged ) { - synchronized( landmarkTable ) - { - int numActive = landmarkTable.numActive(); - int ndims = landmarkTable.getNumdims(); - - if( mvgPts == null || mvgPts[0].length != numActive ) - { - mvgPts = new double[ ndims ][ numActive ]; - tgtPts = new double[ ndims ][ numActive ]; - landmarkTable.copyLandmarks( mvgPts, tgtPts ); - } - else if( indexChanged >= 0 ) - { - landmarkTable.copyLandmarks( indexChanged, mvgPts, tgtPts ); - } - } + return wrap( tpsSolver.solve( landmarkTable, indexChanged ), lambda ); + } - return solve( mvgPts, tgtPts ); + public static > WrappedIterativeInvertibleRealTransform wrap( RealTransform base, RealRandomAccessible lambda ) + { + final RealTransformSequence identity = new RealTransformSequence(); + return new WrappedIterativeInvertibleRealTransform<>( new InterpolatedRealTransform( base, identity, lambda )); } } From f3516dd46e331a0c554a193fcf5ea0a7db4521a6 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Wed, 6 Jul 2022 14:33:26 -0400 Subject: [PATCH 006/282] enabling saving of mask settings --- src/main/java/bigwarp/BigWarp.java | 7 +++- ...teauSphericalMaskRealRandomAccessible.java | 39 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index fd2170b1..18f39cef 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3378,8 +3378,9 @@ protected void saveSettings( final String xmlFilename ) throws IOException autoSaveNode.addContent( autoSaveLocation ); autoSaveNode.addContent( autoSavePeriod ); - root.addContent( autoSaveNode ); + root.addContent( autoSaveNode ); + root.addContent( tpsMask.getRandomAccessible().toXml() ); final Document doc = new Document( root ); final XMLOutputter xout = new XMLOutputter( Format.getPrettyFormat() ); @@ -3426,6 +3427,10 @@ protected void loadSettings( final String xmlFilename ) throws IOException, setAutosaveFolder( new File( autoSavePath )); BigWarpAutoSaver.setAutosaveOptions( this, autoSavePeriod, autoSavePath ); + final Element maskSettings = root.getChild( "transform-mask" ); + if( maskSettings != null ) + tpsMask.getRandomAccessible().fromXml( maskSettings ); + viewerFrameP.repaint(); viewerFrameQ.repaint(); } diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index d4b7a661..a58a8272 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -2,10 +2,15 @@ import java.util.function.BiConsumer; +import org.apache.commons.io.input.XmlStreamReader; +import org.jdom2.DataConversionException; +import org.jdom2.Element; + import bdv.gui.MaskedSourceEditorMouseListener; import bdv.util.BdvFunctions; import bdv.util.BdvOptions; import bdv.util.BdvStackSource; +import mpicbg.spim.data.XmlHelpers; import net.imglib2.Interval; import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; @@ -112,6 +117,11 @@ public void setCenter( RealLocalizable p ) center.setPosition( p ); } + public void setCenter( double[] p ) + { + center.setPosition( p ); + } + public RealPoint getCenter() { return center; @@ -170,4 +180,33 @@ public RealRandomAccess< DoubleType > realRandomAccess( RealInterval interval ) return rra.realRandomAccess( interval ); } + public Element toXml() + { + final Element maskSettings = new Element( "transform-mask" ); + + final Element type = new Element( "type" ); + type.setText( "plateau-spherical" ); + maskSettings.addContent( type ); + + final Element c = XmlHelpers.doubleArrayElement( "center", center.positionAsDoubleArray() ); + maskSettings.addContent( c ); + + final Element p = new Element( "parameters" ); + p.addContent( XmlHelpers.doubleElement( "squaredRadius", plateauR2 ) ); + p.addContent( XmlHelpers.doubleElement( "squaredSigma", sqrSigma ) ); + + maskSettings.addContent( p ); + + return maskSettings; + } + + public void fromXml( Element elem ) + { + setCenter( XmlHelpers.getDoubleArray( elem, "center" ) ); + + final Element p = elem.getChild( "parameters" ); + setSquaredRadius( XmlHelpers.getDouble( p, "squaredRadius" )); + setSquaredSigma( XmlHelpers.getDouble( p, "squaredSigma" )); + } + } From ec8c5ee88b5f33b594ac5f3e3db4aaca9525724d Mon Sep 17 00:00:00 2001 From: bogovicj Date: Wed, 13 Jul 2022 10:51:35 -0400 Subject: [PATCH 007/282] feat: start GeomUtils --- .../org/janelia/utility/geom/GeomUtils.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/main/java/org/janelia/utility/geom/GeomUtils.java diff --git a/src/main/java/org/janelia/utility/geom/GeomUtils.java b/src/main/java/org/janelia/utility/geom/GeomUtils.java new file mode 100644 index 00000000..d19fece9 --- /dev/null +++ b/src/main/java/org/janelia/utility/geom/GeomUtils.java @@ -0,0 +1,67 @@ +package org.janelia.utility.geom; + +import java.util.List; + +import net.imglib2.RealLocalizable; +import net.imglib2.RealPoint; +import net.imglib2.util.Pair; +import net.imglib2.util.ValuePair; + +public class GeomUtils { + + /** + * Finds the parameters of the smallest hypersphere containing the points. + * + * @param pts a list of points + * @return a pair containing the center and the squared distance + */ + public static Pair smallestEnclosingSphere( List pts ) + { + RealPoint p = null; + RealPoint q = null; + double maxSqrDist = Double.POSITIVE_INFINITY; + // find pair of points with the largest distance + for( int i = 0; i < pts.size(); i++) + for( int j = i+1; j < pts.size(); j++) { + double d = squaredDistance( pts.get( i ), pts.get( j )); + if( d < maxSqrDist ) + { + maxSqrDist = d; + p = pts.get( i ); + q = pts.get( j ); + } + } + + final RealPoint center = new RealPoint( p.numDimensions()); + for( int d = 0; d < p.numDimensions(); d++ ) + { + center.setPosition( + 0.5 * p.getDoublePosition(d) + 0.5 * q.getDoublePosition(d), + d ); + } + return new ValuePair(center, maxSqrDist); + } + + final public static void scale( final RealPoint p, final double scale ) + { + for( int i = 0; i < p.numDimensions(); i++ ) + p.setPosition( p.getDoublePosition( i ) * scale , i); + } + + final public static double squaredDistance( final RealLocalizable position1, final RealLocalizable position2 ) + { + double dist = 0; + + final int n = position1.numDimensions(); + for ( int d = 0; d < n; ++d ) + { + final double pos = position2.getDoublePosition( d ) - position1.getDoublePosition( d ); + + dist += pos * pos; + } + + return dist; + } + + +} From 46f20e9cb00f408100df2130d0f65df55e6d84c4 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Wed, 13 Jul 2022 16:56:12 -0400 Subject: [PATCH 008/282] feat: option to automatically update mask based on landmarks * rename "regularized" to "masked" --- .../bdv/gui/TransformTypeSelectDialog.java | 60 +++++++-- src/main/java/bigwarp/BigWarp.java | 11 ++ src/main/java/bigwarp/BigWarpActions.java | 5 +- .../bigwarp/landmarks/LandmarkTableModel.java | 38 ++++++ .../bigwarp/transforms/BigWarpTransform.java | 4 +- ...ver.java => MaskedTpsTransformSolver.java} | 4 +- .../utility/geom/BoundingSphereRitter.java | 123 +++++++++++++++++ .../org/janelia/utility/geom/GeomUtils.java | 125 ++++++++++++++++++ .../java/org/janelia/utility/geom/Sphere.java | 62 +++++++++ 9 files changed, 416 insertions(+), 16 deletions(-) rename src/main/java/bigwarp/transforms/{RegTpsTransformSolver.java => MaskedTpsTransformSolver.java} (92%) create mode 100644 src/main/java/org/janelia/utility/geom/BoundingSphereRitter.java create mode 100644 src/main/java/org/janelia/utility/geom/GeomUtils.java create mode 100644 src/main/java/org/janelia/utility/geom/Sphere.java diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index c1b32d70..632e8131 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -28,19 +28,27 @@ import java.awt.event.ActionListener; import javax.swing.BorderFactory; +import javax.swing.BoxLayout; import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JDialog; +import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import bigwarp.BigWarp; +import bigwarp.WarpVisFrame; +import bigwarp.WarpVisFrame.MyChangeListener; public class TransformTypeSelectDialog extends JDialog { private static final long serialVersionUID = 1L; public static final String TPS = "Thin Plate Spline"; - public static final String REGTPS = "Regularized Thin Plate Spline"; + public static final String MASKEDTPS = "Masked Thin Plate Spline"; public static final String AFFINE = "Affine"; public static final String SIMILARITY = "Similarity"; public static final String ROTATION = "Rotation"; @@ -49,13 +57,16 @@ public class TransformTypeSelectDialog extends JDialog private final BigWarp< ? > bw; private String transformType; + private final ButtonGroup group; private final JRadioButton tpsButton; - private final JRadioButton regTpsButton; + private final JRadioButton maskedTpsButton; private final JRadioButton affineButton; private final JRadioButton similarityButton; private final JRadioButton rotationButton; private final JRadioButton translationButton; + private final JCheckBox autoEstimateMaskButton; + /** * Instantiates and displays a JFrame that enables * the selection of the transformation type. @@ -72,15 +83,15 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) transformType = bw.getTransformType(); tpsButton = new JRadioButton( TPS ); - regTpsButton = new JRadioButton( REGTPS ); + maskedTpsButton = new JRadioButton( MASKEDTPS ); affineButton = new JRadioButton( AFFINE ); similarityButton = new JRadioButton( SIMILARITY ); rotationButton = new JRadioButton( ROTATION ); translationButton = new JRadioButton( TRANSLATION ); - ButtonGroup group = new ButtonGroup(); + group = new ButtonGroup(); group.add( tpsButton ); - group.add( regTpsButton ); + group.add( maskedTpsButton ); group.add( affineButton ); group.add( similarityButton ); group.add( rotationButton ); @@ -89,15 +100,15 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) updateButtonGroup(); addActionListender( tpsButton ); - addActionListender( regTpsButton ); + addActionListender( maskedTpsButton ); addActionListender( affineButton ); addActionListender( similarityButton ); addActionListender( rotationButton ); addActionListender( translationButton ); - + JPanel radioPanel = new JPanel( new GridLayout(0, 1)); radioPanel.add( tpsButton ); - radioPanel.add( regTpsButton ); + radioPanel.add( maskedTpsButton ); radioPanel.add( affineButton ); radioPanel.add( similarityButton ); radioPanel.add( rotationButton ); @@ -112,6 +123,30 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); add( radioPanel, BorderLayout.LINE_START ); + + autoEstimateMaskButton = new JCheckBox( "Auto-estimate transform mask"); + radioPanel.add( autoEstimateMaskButton ); + + add( radioPanel, BorderLayout.LINE_END ); + + pack(); + addListeners(); + updateOptions(); + } + + private void addListeners() + { + maskedTpsButton.addChangeListener( new ChangeListener() { + @Override + public void stateChanged( ChangeEvent e ) { updateOptions(); } + }); + + } + + private synchronized void updateOptions() + { + System.out.println( "update options"); + autoEstimateMaskButton.setVisible( maskedTpsButton.isSelected() ); pack(); } @@ -122,8 +157,8 @@ private void updateButtonGroup() case TPS: tpsButton.setSelected( true ); break; - case REGTPS: - regTpsButton.setSelected( true ); + case MASKEDTPS: + maskedTpsButton.setSelected( true ); break; case AFFINE: affineButton.setSelected( true ); @@ -157,4 +192,9 @@ public void setTransformType( String transformType ) this.validate(); this.repaint(); } + + public boolean autoEstimateMask() + { + return autoEstimateMaskButton.isSelected(); + } } diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 18f39cef..c5516325 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -51,6 +51,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; +import java.util.stream.Collectors; import javax.swing.ActionMap; import javax.swing.InputMap; @@ -75,6 +76,9 @@ import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.ij.N5Exporter; +import org.janelia.utility.geom.BoundingSphereRitter; +import org.janelia.utility.geom.GeomUtils; +import org.janelia.utility.geom.Sphere; import org.janelia.utility.ui.RepeatingReleasedEventsFixer; import org.jdom2.Document; import org.jdom2.Element; @@ -174,6 +178,7 @@ import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; +import net.imglib2.util.Pair; public class BigWarp< T > { @@ -2827,6 +2832,12 @@ public void tableChanged( final TableModelEvent e ) BigWarp.this.restimateTransformation(); BigWarp.this.landmarkPanel.repaint(); } + + if( transformSelector.autoEstimateMask() && bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS )) { + Sphere sph = BoundingSphereRitter.boundingSphere( landmarkModel.getFixedPointsCopy() ); + tpsMask.getRandomAccessible().setCenter( sph.getCenter() ); + tpsMask.getRandomAccessible().setRadius( sph.getRadius() ); + } } } diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 24f4b13a..9e0df803 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -50,6 +50,7 @@ public class BigWarpActions public static final String LANDMARK_MODE_ON = "landmark mode on"; public static final String LANDMARK_MODE_OFF = "landmark mode off"; public static final String TOGGLE_LANDMARK_MODE = "landmark mode toggle"; + public static final String TRANSFORM_TYPE = "transform type"; public static final String TOGGLE_POINTS_VISIBLE = "toggle points visible"; public static final String TOGGLE_POINT_NAMES_VISIBLE = "toggle point names visible"; @@ -162,7 +163,7 @@ public static InputMap createInputMapViewer( final KeyStrokeAdder.Factory keyPro map.put( String.format( VISIBILITY_AND_GROUPING, "moving" ), "F3" ); map.put( String.format( VISIBILITY_AND_GROUPING, "target" ), "F4" ); - map.put( "transform type", "F2" ); + map.put( TRANSFORM_TYPE, "F2" ); map.put( String.format( ALIGN_VIEW_TRANSFORMS, AlignViewerPanelAction.TYPE.OTHER_TO_ACTIVE ), "Q" ); map.put( String.format( ALIGN_VIEW_TRANSFORMS, AlignViewerPanelAction.TYPE.ACTIVE_TO_OTHER ), "W" ); @@ -190,7 +191,7 @@ public static ActionMap createActionMapViewer( final BigWarp< ? > bw ) new ToggleDialogAction( String.format( VISIBILITY_AND_GROUPING, "moving" ), bw.activeSourcesDialogP ).put( actionMap ); new ToggleDialogAction( String.format( VISIBILITY_AND_GROUPING, "target" ), bw.activeSourcesDialogQ ).put( actionMap ); - new ToggleDialogAction( "transform type", bw.transformSelector ).put( actionMap ); + new ToggleDialogAction( TRANSFORM_TYPE, bw.transformSelector ).put( actionMap ); for( final BigWarp.WarpVisType t: BigWarp.WarpVisType.values()) { diff --git a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java index b800b873..db65ee43 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java +++ b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java @@ -1023,6 +1023,44 @@ public Double[] getFixedPoint( int index ) return targetPts.get( index ); } + public ArrayList< Double[] > getMovingPoints() + { + return movingPts; + } + + public ArrayList< Double[] > getFixedPoints() + { + return targetPts; + } + + public ArrayList getMovingPointsCopy() + { + final ArrayList< double[] > out = new ArrayList(); + for( Double[] p : movingPts ) + { + double[] q = new double[ ndims ]; + for( int d = 0; d < ndims; d++ ) + q[d] = p[d]; + + out.add( q ); + } + return out; + } + + public ArrayList getFixedPointsCopy() + { + final ArrayList< double[] > out = new ArrayList(); + for( Double[] p : targetPts ) + { + double[] q = new double[ ndims ]; + for( int d = 0; d < ndims; d++ ) + q[d] = p[d]; + + out.add( q ); + } + return out; + } + public boolean isMovingPoint( int index ) { return !Double.isInfinite( movingPts.get( index )[ 0 ] ); diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index bf107179..e4efc3ff 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -133,9 +133,9 @@ public InvertibleRealTransform getTransformation( final int index ) tpsXfm.getOptimzer().setTolerance(inverseTolerance); invXfm = tpsXfm; } - else if( transformType.equals( TransformTypeSelectDialog.REGTPS )) + else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) { - WrappedIterativeInvertibleRealTransform tpsXfm = new RegTpsTransformSolver( lambda ).solve( tableModel ); + WrappedIterativeInvertibleRealTransform tpsXfm = new MaskedTpsTransformSolver( lambda ).solve( tableModel ); tpsXfm.getOptimzer().setMaxIters(maxIterations); tpsXfm.getOptimzer().setTolerance(inverseTolerance); invXfm = tpsXfm; diff --git a/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java b/src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java similarity index 92% rename from src/main/java/bigwarp/transforms/RegTpsTransformSolver.java rename to src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java index 69b09d88..9d8cf15c 100644 --- a/src/main/java/bigwarp/transforms/RegTpsTransformSolver.java +++ b/src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java @@ -32,13 +32,13 @@ import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.RealType; -public class RegTpsTransformSolver> implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> +public class MaskedTpsTransformSolver> implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> { // TODO make regularization transform of a more general type private final TpsTransformSolver tpsSolver; private final RealRandomAccessible lambda; - public RegTpsTransformSolver( RealRandomAccessible lambda ) + public MaskedTpsTransformSolver( RealRandomAccessible lambda ) { this.lambda = lambda; tpsSolver = new TpsTransformSolver(); diff --git a/src/main/java/org/janelia/utility/geom/BoundingSphereRitter.java b/src/main/java/org/janelia/utility/geom/BoundingSphereRitter.java new file mode 100644 index 00000000..17a21bfa --- /dev/null +++ b/src/main/java/org/janelia/utility/geom/BoundingSphereRitter.java @@ -0,0 +1,123 @@ +package org.janelia.utility.geom; + +import java.util.List; + +/** + * Estimates the smallest sphere that bounds given points. + *

+ * Ritter, Jack (1990), "An efficient bounding sphere", in Glassner, Andrew S. (ed.), Graphics Gems, San Diego, CA, US: Academic Press Professional, Inc., pp. 301–303, + * + * @author John Bogovic + * + */ +public class BoundingSphereRitter +{ + + /** + * Returns an estimate of the smallest {@link ImmutableSphere} that contains the input points. + * + * @param points a collection of points + * @return the bounding sphere + */ + public static Sphere boundingSphere( final List points ) + { + if( points == null || points.isEmpty() ) + return null; + + final int nd = points.get( 0 ).length; + final double[] x = new double[ nd ]; + final double[] y = new double[ nd ]; + double maxSqrDist = -1; + // find pair of points with the largest distance + for ( int i = 0; i < points.size(); i++ ) + for ( int j = i + 1; j < points.size(); j++ ) + { + final double d = GeomUtils.squaredDistance( points.get( i ), points.get( j ) ); + if ( d > maxSqrDist ) + { + maxSqrDist = d; + System.arraycopy( points.get( i ), 0, x, 0, nd ); + System.arraycopy( points.get( j ), 0, y, 0, nd ); + } + } + + final double[] center = new double[ nd ]; + for ( int d = 0; d < nd; d++ ) + center[d] = 0.5 * ( x[d] + y[d] ); + + Sphere sph = new Sphere( center, Math.sqrt( maxSqrDist ) / 2 ); + boolean allCovered = false; + int k = 0; + while( !allCovered && k < 5) + { + allCovered = false; + for( double[] p : points ) + { + allCovered |= updateSphere( sph, p ); + } + k++; + } + return sph; + } + + /** + * return the point in point farthest from p + * + * @param points a list of points + * @param p a base point + * @return the point farthest from p + */ + public static double[] furthestFrom( final List points, double[] p ) + { + double maxSqrDist = -1; + int maxIndex = -1; + for ( int i = 0; i < points.size(); i++ ) + { + final double dist = GeomUtils.squaredDistance( p, points.get( i ) ); + if ( dist > maxSqrDist ) + { + maxSqrDist = dist; + maxIndex = i; + } + } + return points.get( maxIndex ); + } + + /** + * Changes the value of the input sphere such that it contains the given point p. + * Returns true if the sphere was modified. + * + * @param sphere + * @param p + * @return true if the sphere was changed + */ + public static boolean updateSphere( final Sphere sphere, final double[] p ) + { + double sqrDist = GeomUtils.squaredDistance( sphere.getCenterArray(), p ); + double r = sphere.getRadius(); + if ( sqrDist <= r*r ) + { + return false; + } else + { +// System.out.println( "update sphere" ); + final double halfDist = 0.5 * ( Math.sqrt( sqrDist ) - sphere.getRadius() ); + final double[] c = sphere.getCenterArray(); + final double[] v = new double[ c.length ]; + double mag = 0; + for( int i = 0; i < c.length; i++ ) + { + v[i] = ( p[i] - c[i]); + mag += v[i] * v[i]; + } + for( int i = 0; i < c.length; i++ ) + { + c[i] += v[i] * halfDist / Math.sqrt( mag ); + } + + sphere.setRadius( sphere.getRadius() + halfDist ); + return true; + } + } + +} diff --git a/src/main/java/org/janelia/utility/geom/GeomUtils.java b/src/main/java/org/janelia/utility/geom/GeomUtils.java new file mode 100644 index 00000000..6577c579 --- /dev/null +++ b/src/main/java/org/janelia/utility/geom/GeomUtils.java @@ -0,0 +1,125 @@ +package org.janelia.utility.geom; + +import java.util.Arrays; +import java.util.List; + +import bigwarp.landmarks.LandmarkTableModel; +import net.imglib2.RealLocalizable; +import net.imglib2.RealPoint; +import net.imglib2.util.Pair; +import net.imglib2.util.ValuePair; + +public class GeomUtils +{ + public static double squaredDistance( final RealLocalizable position1, final RealLocalizable position2 ) + { + double dist = 0; + final int n = position1.numDimensions(); + for ( int d = 0; d < n; ++d ) + { + final double diff = position2.getDoublePosition( d ) - position1.getDoublePosition( d ); + dist += diff * diff; + } + return dist; + } + + public static double squaredDistance( final double[] position1, final double[] position2 ) + { + double dist = 0; + final int n = position1.length; + for ( int d = 0; d < n; ++d ) + { + final double diff = position2[ d ] - position1[ d ]; + dist += diff * diff; + } + return dist; + } + + public final static void scale( final RealPoint p, final double scale ) + { + for( int i = 0; i < p.numDimensions(); i++ ) + p.setPosition( p.getDoublePosition( i ) * scale, i ); + } + + /** + * Finds the parameters of the smallest hypersphere containing the points. + * + * @param pts + * a list of points + * @return a pair containing the center and the squared distance + */ + public static Pair< RealPoint, Double > smallestEnclosingSpherePts( List< RealPoint > pts ) + { + int nd = pts.get( 0 ).numDimensions(); + RealPoint p = new RealPoint( nd ); + RealPoint q = new RealPoint( nd ); + double maxSqrDist = Double.POSITIVE_INFINITY; + // find pair of points with the largest distance + for ( int i = 0; i < pts.size(); i++ ) + for ( int j = i + 1; j < pts.size(); j++ ) + { + final double d = squaredDistance( pts.get( i ), pts.get( j ) ); + if ( d > maxSqrDist ) + { + maxSqrDist = d; + p.setPosition( pts.get( i ) ); + q.setPosition( pts.get( j ) ); + } + } + + final RealPoint center = new RealPoint( p.numDimensions() ); + for ( int d = 0; d < p.numDimensions(); d++ ) + center.setPosition( 0.5 * p.getDoublePosition( d ) + 0.5 * q.getDoublePosition( d ), d ); + + return new ValuePair< RealPoint, Double >( center, maxSqrDist ); + } + + public static Pair< RealPoint, Double > smallestEnclosingSphere( LandmarkTableModel ltm ) + { + int nd = ltm.getNumdims(); + RealPoint p = new RealPoint( nd ); + RealPoint q = new RealPoint( nd ); + + final double[] tmpA = new double[ nd ]; + final double[] tmpB = new double[ nd ]; + + double maxSqrDist = -1; + int N = ltm.getRowCount(); + // find pair of points with the largest distance + for ( int i = 0; i < N; i++ ) + for ( int j = i + 1; j < N; j++ ) + { + if( !ltm.isActive( i ) || !ltm.isActive( j )) + { + continue; + } + + for( int d = 0; d < nd; d++) + { + tmpA[d] = ltm.getFixedPoint( i )[d]; + tmpB[d] = ltm.getFixedPoint( j )[d]; + } + + final double d = squaredDistance( tmpA, tmpB ); +// System.out.println( "tmpA: " + Arrays.toString( tmpA )); +// System.out.println( "tmpB: " + Arrays.toString( tmpB )); + + if ( d > maxSqrDist ) + { + maxSqrDist = d; + p.setPosition( tmpA ); + q.setPosition( tmpB ); + } + } + +// System.out.println( "p : " + p ); +// System.out.println( "q : " + q ); + + final RealPoint center = new RealPoint( p.numDimensions() ); + for ( int d = 0; d < p.numDimensions(); d++ ) + center.setPosition( 0.5 * p.getDoublePosition( d ) + 0.5 * q.getDoublePosition( d ), d ); + + return new ValuePair< RealPoint, Double >( center, maxSqrDist / 4 ); + } + +} diff --git a/src/main/java/org/janelia/utility/geom/Sphere.java b/src/main/java/org/janelia/utility/geom/Sphere.java new file mode 100644 index 00000000..793a1bb9 --- /dev/null +++ b/src/main/java/org/janelia/utility/geom/Sphere.java @@ -0,0 +1,62 @@ +package org.janelia.utility.geom; + +import net.imglib2.RealPoint; + +public class Sphere +{ + private RealPoint center; + private double[] centerArr; + private double radius; + + public Sphere( double[] center, double radius ) + { + this.centerArr = center; + this.radius = radius; + this.center = RealPoint.wrap( center ); + } + + public Sphere( final RealPoint center, double radius ) + { + this( center.positionAsDoubleArray(), radius ); + } + + public RealPoint getCenter() + { + return center; + } + + public double[] getCenterArray() + { + return centerArr; + } + + public double getRadius() + { + return radius; + } + + public void setRadius( final double radius ) + { + this.radius = radius; + } + + public void setCenter( final double[] center ) + { + System.arraycopy( center, 0, centerArr, 0, centerArr.length ); + } + + /** + * Is a point inside this sphere. + * Returns true if the distance from the given point to the center is less than or equal to + * this sphere's radius. + * + * @param p the point + * @return true if the point inside this sphere. + */ + public boolean isInside( double[] p ) + { + final double r2 = radius * radius; + return GeomUtils.squaredDistance( centerArr, p ) <= r2; + } + +} From fb7b5bd9658d40dccdc2a823b81cc51c25e7be08 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Thu, 14 Jul 2022 13:23:26 -0400 Subject: [PATCH 009/282] feat: squared distance for double arrays --- .../java/org/janelia/utility/geom/GeomUtils.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/org/janelia/utility/geom/GeomUtils.java b/src/main/java/org/janelia/utility/geom/GeomUtils.java index d19fece9..e631045a 100644 --- a/src/main/java/org/janelia/utility/geom/GeomUtils.java +++ b/src/main/java/org/janelia/utility/geom/GeomUtils.java @@ -63,5 +63,18 @@ final public static double squaredDistance( final RealLocalizable position1, fin return dist; } + final public static double squaredDistance( final double[] position1, final double[] position2 ) + { + double dist = 0; + + final int n = position1.length; + for ( int d = 0; d < n; ++d ) + { + final double pos = position2[d] - position1[d]; + dist += pos * pos; + } + + return dist; + } } From bfe0b29c35aa48f51c4c8422d25993d40b40836a Mon Sep 17 00:00:00 2001 From: bogovicj Date: Thu, 14 Jul 2022 13:56:48 -0400 Subject: [PATCH 010/282] feat: mask edit sigma uses viewer scale --- .../bdv/gui/MaskedSourceEditorMouseListener.java | 14 ++++++++++---- src/main/java/bigwarp/BigWarp.java | 4 ---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java index 7d3cf538..2723c5af 100644 --- a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -6,10 +6,12 @@ import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; +import bdv.util.Affine3DHelpers; import bdv.viewer.ViewerPanel; import bigwarp.BigWarp; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; import net.imglib2.RealPoint; +import net.imglib2.realtransform.AffineTransform3D; public class MaskedSourceEditorMouseListener implements MouseListener, MouseMotionListener, MouseWheelListener { @@ -21,6 +23,9 @@ public class MaskedSourceEditorMouseListener implements MouseListener, MouseMoti private BigWarp bw; private ViewerPanel viewer; + private static final double fastSpeed = 10.0; + private static final double slowSpeed = 0.1; + public MaskedSourceEditorMouseListener( int nd, BigWarp bw, ViewerPanel viewer ) { this.bw = bw; @@ -113,14 +118,15 @@ public void mouseWheelMoved( MouseWheelEvent e ) if( !active ) return; - // TODO vary based on screen scale + final AffineTransform3D transform = viewer.state().getViewerTransform(); + final double scale = (1 / Affine3DHelpers.extractScale(transform, 0)) + 0.05; final int sign = e.getWheelRotation(); if( e.isShiftDown() ) - mask.incSquaredSigma( sign * 10 ); + mask.incSquaredSigma( sign * scale * fastSpeed ); else if ( e.isControlDown() ) - mask.incSquaredSigma( sign * 0.1 ); + mask.incSquaredSigma( sign * scale * slowSpeed); else - mask.incSquaredSigma( sign * 1.0 ); + mask.incSquaredSigma( sign * scale ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index c5516325..1971c16d 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -51,7 +51,6 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; -import java.util.stream.Collectors; import javax.swing.ActionMap; import javax.swing.InputMap; @@ -77,7 +76,6 @@ import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.ij.N5Exporter; import org.janelia.utility.geom.BoundingSphereRitter; -import org.janelia.utility.geom.GeomUtils; import org.janelia.utility.geom.Sphere; import org.janelia.utility.ui.RepeatingReleasedEventsFixer; import org.jdom2.Document; @@ -137,7 +135,6 @@ import bigwarp.loader.ImagePlusLoader.ColorSettings; import bigwarp.source.GridSource; import bigwarp.source.JacobianDeterminantSource; -import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; import bigwarp.source.PlateauSphericalMaskSource; import bigwarp.source.WarpMagnitudeSource; import bigwarp.transforms.BigWarpTransform; @@ -178,7 +175,6 @@ import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.util.Pair; public class BigWarp< T > { From 9c3bce01865bb366891f62cfb0ce423d0a1c46f3 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Thu, 14 Jul 2022 17:26:01 -0400 Subject: [PATCH 011/282] feat: start of loading and saving transforms as json --- src/main/java/bigwarp/BigWarp.java | 6 +- .../bigwarp/landmarks/LandmarkTableModel.java | 119 +++++++++++++++++- ...teauSphericalMaskRealRandomAccessible.java | 10 ++ .../bigwarp/transforms/BigWarpTransform.java | 7 +- .../transforms/io/LandmarkWriterJson.java | 21 ++++ .../transforms/io/TransformWriterJson.java | 60 +++++++++ 6 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 src/main/java/bigwarp/transforms/io/LandmarkWriterJson.java create mode 100644 src/main/java/bigwarp/transforms/io/TransformWriterJson.java diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 1971c16d..d4140299 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -139,6 +139,7 @@ import bigwarp.source.WarpMagnitudeSource; import bigwarp.transforms.BigWarpTransform; import bigwarp.transforms.WrappedCoordinateTransform; +import bigwarp.transforms.io.TransformWriterJson; import bigwarp.util.BigWarpUtils; import fiji.util.gui.GenericDialogPlus; import ij.IJ; @@ -3287,7 +3288,10 @@ protected void saveLandmarks() protected void saveLandmarks( final String filename ) throws IOException { - landmarkModel.save(new File( filename )); + if( filename.endsWith("csv")) + landmarkModel.save(new File( filename )); + else if( filename.endsWith("json")) + new TransformWriterJson().write(landmarkModel, bwTransform, new File( filename )); } protected void loadLandmarks() diff --git a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java index db65ee43..8b78bf07 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java +++ b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java @@ -30,6 +30,15 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -55,6 +64,12 @@ import net.imglib2.realtransform.Wrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.reflect.TypeToken; import com.opencsv.CSVReader; import com.opencsv.CSVWriter; import com.opencsv.exceptions.CsvException; @@ -211,7 +226,7 @@ public double[] getPendingPoint() { return PENDING_PT; } - + public ThinPlateR2LogRSplineKernelTransform getTransform() { return estimatedXfm; @@ -1176,12 +1191,12 @@ public void transferUpdatesToModel() resetUpdated(); // not strictly necessary } - + public void load( File f ) throws IOException { load( f, false ); } - + /** * Loads this table from a file * @param f the file @@ -1189,6 +1204,20 @@ public void load( File f ) throws IOException * @throws IOException an exception */ public void load( File f, boolean invert ) throws IOException + { + if( f.getCanonicalPath().endsWith("csv")) + loadCsv(f, invert); + else if( f.getCanonicalPath().endsWith("json")) + fromJson( f ); + } + + /** + * Loads this table from a file + * @param f the file + * @param invert invert the moving and target point sets + * @throws IOException an exception + */ + public void loadCsv( File f, boolean invert ) throws IOException { synchronized(this) { clear(); @@ -1485,6 +1514,90 @@ public void save( File f ) throws IOException } } + public JsonElement toJson() + { + final Gson gson = new Gson(); + final JsonObject out = new JsonObject(); + JsonElement mvgPtsObj = gson.toJsonTree(getMovingPoints(), new TypeToken >() {}.getType()); + JsonElement fixedPtsObj = gson.toJsonTree(getFixedPoints(), new TypeToken >() {}.getType()); + JsonElement activeObj = gson.toJsonTree( activeList ); + JsonElement namesObj = gson.toJsonTree( names ); + + out.add("type", new JsonPrimitive("BigWarpLandmarks")); + out.add("numDimensions", new JsonPrimitive( ndims )); + out.add("movingPoints", mvgPtsObj ); + out.add("fixedPoints", fixedPtsObj ); + out.add("active", activeObj ); + out.add("names", namesObj ); + + return out; + } + + public void fromJson( File f ) + { + final Gson gson = new Gson(); + final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; + try { + final Reader reader = Channels.newReader(FileChannel.open(Paths.get( f.getCanonicalPath()), options), StandardCharsets.UTF_8.name()); + fromJson( gson.fromJson(reader, JsonObject.class )); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void fromJson( JsonElement json ) + { + if( !json.isJsonObject()) + return; + + final JsonObject obj = json.getAsJsonObject(); + final JsonObject landmarks = obj.get("landmarks").getAsJsonObject(); + + synchronized(this) { + clear(); + + JsonArray namesArr = landmarks.get("names").getAsJsonArray(); + JsonArray activeArr = landmarks.get("active").getAsJsonArray(); + JsonArray mvgArr = landmarks.get("movingPoints").getAsJsonArray(); + JsonArray fixedArr = landmarks.get("fixedPoints").getAsJsonArray(); + + numRows = namesArr.size(); + final int ndims = landmarks.get("numDimensions").getAsInt(); + + for( int i = 0; i < numRows; i++ ) + { + + names.add( namesArr.get(i).getAsString() ); + activeList.add( activeArr.get(i).getAsBoolean() ); + + final JsonElement mvg = mvgArr.get( i ); + JsonElement fixed = fixedArr.get( i ); + final Double[] movingPt = new Double[ ndims ]; + final Double[] targetPt = new Double[ ndims ]; + + for( int d = 0; d < ndims; d++ ) + { + movingPt[ d ] = mvg.getAsJsonArray().get(d).getAsDouble(); + targetPt[ d ] = fixed.getAsJsonArray().get(d).getAsDouble(); + } + + movingPts.add( movingPt ); + targetPts.add( targetPt ); + + warpedPoints.add( new Double[ ndims ] ); + doesPointHaveAndNeedWarp.add( false ); + movingDisplayPointUnreliable.add( false ); + } + + this.ndims = ndims; + updateNextRows( 0 ); + buildTableToActiveIndex(); + } + + for( int i = 0; i < numRows; i++ ) + fireTableRowsInserted( i, i ); + } + public static String print( Double[] d ) { String out = ""; diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index a58a8272..cbcc526c 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -72,6 +72,11 @@ public static void main( String[] args ) } + public double getSquaredRadius() + { + return plateauR2; + } + public void setRadius( double r ) { plateauR = r; @@ -83,6 +88,11 @@ public void setSquaredRadius( double r2 ) plateauR2 = r2; } + public double getSquaredSigma() + { + return sqrSigma; + } + public void setSigma( double sigma ) { sqrSigma = sigma * sigma; diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index e4efc3ff..ba70e1c7 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -23,10 +23,8 @@ import java.lang.reflect.Field; import java.util.Arrays; -import java.util.Optional; import bdv.gui.TransformTypeSelectDialog; -import bdv.util.RandomAccessibleIntervalMipmapSource; import bdv.viewer.SourceAndConverter; import bdv.viewer.animate.SimilarityModel3D; import bigwarp.BigWarp.BigWarpData; @@ -113,6 +111,11 @@ public String getTransformType() return transformType; } + public RealRandomAccessible> getLambda( ) + { + return lambda; + } + public void setLambda( final RealRandomAccessible< ? extends RealType< ? > > lambda ) { this.lambda = lambda; diff --git a/src/main/java/bigwarp/transforms/io/LandmarkWriterJson.java b/src/main/java/bigwarp/transforms/io/LandmarkWriterJson.java new file mode 100644 index 00000000..b1f7e53b --- /dev/null +++ b/src/main/java/bigwarp/transforms/io/LandmarkWriterJson.java @@ -0,0 +1,21 @@ +package bigwarp.transforms.io; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; + +import bigwarp.landmarks.LandmarkTableModel; + +public class LandmarkWriterJson { + + private final Gson gson; + + public LandmarkWriterJson() { + gson = new Gson(); + } + + public JsonElement toJson(final LandmarkTableModel ltm) { + + return ltm.toJson(); + } + +} diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java new file mode 100644 index 00000000..c2897517 --- /dev/null +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -0,0 +1,60 @@ +package bigwarp.transforms.io; + +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import bdv.gui.TransformTypeSelectDialog; +import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.transforms.BigWarpTransform; + +public class TransformWriterJson { + + private final Gson gson; + + public TransformWriterJson() + { + gson = new Gson(); + } + + public void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) { + + JsonObject transformObj = new JsonObject(); + transformObj.add("type", new JsonPrimitive( bwTransform.getTransformType() )); + transformObj.add("landmarks", ltm.toJson()); + + if( bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS) ) + { + JsonObject maskObj = new JsonObject(); + PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); + maskObj.add("type", new JsonPrimitive("gaussianSphericalPlateau")); + maskObj.add("center", gson.toJsonTree(mask.getCenter().positionAsDoubleArray())); + maskObj.add("squaredRadius", new JsonPrimitive(mask.getSquaredRadius())); + maskObj.add("squaredSigma", new JsonPrimitive(mask.getSquaredSigma())); + transformObj.add( "mask", maskObj ); + } + + try { + final Path path = Paths.get(f.getCanonicalPath()); + final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE}; + final Writer writer = Channels.newWriter(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); + gson.toJson(transformObj, writer); + writer.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} From 80c4850fe87fd9109de44500aa2f11349ef62c98 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Sun, 24 Jul 2022 12:51:03 -0400 Subject: [PATCH 012/282] feat: add different similarity transform interpolator * selected point takes a linear path from start to end --- .../SimilarityTransformInterpolator.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/main/java/net/imglib2/realtransform/SimilarityTransformInterpolator.java diff --git a/src/main/java/net/imglib2/realtransform/SimilarityTransformInterpolator.java b/src/main/java/net/imglib2/realtransform/SimilarityTransformInterpolator.java new file mode 100644 index 00000000..080e71b2 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/SimilarityTransformInterpolator.java @@ -0,0 +1,92 @@ +package net.imglib2.realtransform; + +import net.imglib2.util.LinAlgHelpers; + +import bdv.util.Affine3DHelpers; +import bdv.viewer.animate.AbstractTransformAnimator; + +public class SimilarityTransformInterpolator extends AbstractTransformAnimator +{ + private final double[] qStart; + + private final double[] qDiff; + + private final double scaleStart; + + private final double scaleEnd; + + private final double scaleRate; + + private final double[] p; + + private final double[] pDiff; + + public SimilarityTransformInterpolator(final AffineTransform3D transform, final double[] p) { + super(1); + AffineTransform3D transformEnd = new AffineTransform3D(); + transformEnd.set(transform); + + this.p = p; + qStart = new double[]{1, 0, 0, 0}; + final double[] qStartInv = new double[4]; + final double[] qEnd = new double[4]; + final double[] qEndInv = new double[4]; + qDiff = new double[4]; + LinAlgHelpers.quaternionInvert(qStart, qStartInv); + + Affine3DHelpers.extractRotation(transformEnd, qEnd); + LinAlgHelpers.quaternionInvert(qEnd, qEndInv); + + LinAlgHelpers.quaternionMultiply(qStartInv, qEnd, qDiff); + if (qDiff[0] < 0) + LinAlgHelpers.scale(qDiff, -1, qDiff); + + scaleStart = 1.0; + scaleEnd = Affine3DHelpers.extractScale(transformEnd, 0); + scaleRate = scaleEnd / scaleStart; + + // translation needed to from reconstructed to target transformation + pDiff = new double[3]; + double[] tmp = new double[3]; + get(1).apply( p, tmp); + transform.apply(p, pDiff); + LinAlgHelpers.subtract(pDiff, tmp, pDiff); + } + + @Override + public AffineTransform3D get(final double t) { + + final double[] qDiffCurrent = new double[4]; + final double[] qCurrent = new double[4]; + LinAlgHelpers.quaternionPower(qDiff, t, qDiffCurrent); + LinAlgHelpers.quaternionMultiply(qStart, qDiffCurrent, qCurrent); + + final double alpha = Math.pow(scaleRate, t); + final double scaleCurrent = scaleStart * alpha; + + final double[][] Rcurrent = new double[3][3]; + LinAlgHelpers.quaternionToR(qCurrent, Rcurrent); + + final double[][] m = new double[3][4]; + for (int r = 0; r < 3; ++r) { + for (int c = 0; c < 3; ++c) + m[r][c] = scaleCurrent * Rcurrent[r][c]; + } + + final AffineTransform3D transform = new AffineTransform3D(); + transform.set(m); + + double[] pCurrent = new double[3]; + transform.apply(p, pCurrent); + + double[] pTgt = new double[3]; + LinAlgHelpers.scale( pDiff, t, pTgt ); + LinAlgHelpers.add( p, pTgt, pTgt ); + LinAlgHelpers.subtract( pTgt, pCurrent, pTgt ); + transform.translate( pTgt ); + + return transform; + + } + +} \ No newline at end of file From 16e72f826de3fe8e173012f54f81a8a8002521de Mon Sep 17 00:00:00 2001 From: bogovicj Date: Sun, 24 Jul 2022 13:03:50 -0400 Subject: [PATCH 013/282] add similarity transform interpolation example --- ...milarityTransformInterpolationExample.java | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java new file mode 100644 index 00000000..a592ce72 --- /dev/null +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -0,0 +1,145 @@ +package net.imglib2.realtransform; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import bdv.gui.TransformTypeSelectDialog; +import bdv.img.remote.AffineTransform3DJsonSerializer; +import bdv.util.Affine3DHelpers; +import bdv.util.BdvFunctions; +import bdv.util.BdvOptions; +import bdv.util.BdvStackSource; +import bdv.util.RandomAccessibleIntervalSource; +import bdv.viewer.animate.AbstractTransformAnimator; +import bdv.viewer.animate.SimilarityTransformAnimator; +import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.transforms.BigWarpTransform; +import ij.IJ; +import ij.ImagePlus; +import net.imglib2.FinalInterval; +import net.imglib2.FinalRealInterval; +import net.imglib2.Interval; +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.RealPoint; +import net.imglib2.RealRandomAccess; +import net.imglib2.RealRandomAccessible; +import net.imglib2.img.Img; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory; +import net.imglib2.interpolation.randomaccess.NearestNeighborInterpolatorFactory; +import net.imglib2.iterator.RealIntervalIterator; +import net.imglib2.position.FunctionRandomAccessible; +import net.imglib2.type.NativeType; +import net.imglib2.type.numeric.NumericType; +import net.imglib2.type.numeric.integer.UnsignedByteType; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.ConstantUtils; +import net.imglib2.util.Intervals; +import net.imglib2.util.LinAlgHelpers; +import net.imglib2.view.Views; + + +public class SimilarityTransformInterpolationExample { + + public static void main(String[] args) { + show( args[0] ); +// exp(); + } + + public static void exp() { + + double[] zero = new double[]{0, 0, 0}; + double[] center = new double[]{252, 76, 70}; + double[] centerOfRotation = new double[] { 252, 150, 70 }; + AffineTransform3D offset = new AffineTransform3D(); + offset.translate(center); + + AffineTransform3D dy20 = new AffineTransform3D(); + dy20.translate(new double[]{0, 300, 0}); + + AffineTransform3D transform = new AffineTransform3D(); + transform.rotate(2, Math.PI); + transform.preConcatenate(offset); + transform.concatenate(offset.inverse()); + System.out.println(transform); + System.out.println( Affine3DHelpers.toString(transform)); + + SimilarityTransformInterpolator interpolatorOtherC = new SimilarityTransformInterpolator( transform, centerOfRotation ); + AffineTransform3D z = interpolatorOtherC.get(0); + AffineTransform3D o = interpolatorOtherC.get(1); + System.out.println( "" ); + System.out.println( Affine3DHelpers.toString( z )); + System.out.println( "" ); + System.out.println( Affine3DHelpers.toString( o )); + + } + + public static void show( String imgFile ) { + + ImagePlus imp = IJ.openImage( imgFile ); + Img imgBase = ImageJFunctions.wrapByte(imp); + + Img img = imgBase; + // RandomAccessibleInterval img = Views.translateInverse( imgBase, 252, 76, 70 ); + + AffineTransform3D identity = new AffineTransform3D(); + FinalInterval bigItvl = Intervals.createMinMax(-1000, -1000, -1000, 1000, 1000, 1000); + + double[] zero = new double[]{0, 0, 0}; + double[] center = new double[]{252, 76, 70}; + double[] centerOfRotation = new double[] { 252, 150, 70 }; + AffineTransform3D offset = new AffineTransform3D(); + offset.translate(center); + + AffineTransform3D dy20 = new AffineTransform3D(); + dy20.translate(new double[]{0, 300, 0}); + + AffineTransform3D transform = new AffineTransform3D(); + transform.rotate(2, Math.PI); + transform.preConcatenate(offset); + transform.concatenate(offset.inverse()); + System.out.println(transform); + +//      AffineTransform3D transform = new AffineTransform3D(); +//      transform.rotate( 2, Math.PI ); +//      transform.preConcatenate( dy20 ); +//      System.out.println( transform ); + + SimilarityTransformAnimator interpolator = new SimilarityTransformAnimator( new AffineTransform3D(), transform, 0, 0, 1); + SimilarityTransformInterpolator interpolatorC = new SimilarityTransformInterpolator( transform, center ); + SimilarityTransformInterpolator interpolatorOtherC = new SimilarityTransformInterpolator( transform, centerOfRotation ); + + BdvOptions opts = BdvOptions.options(); + BdvStackSource bdv = makeTimeStack( img, bigItvl, interpolator, "orig", opts ); + opts = opts.addTo(bdv); + makeTimeStack( img, bigItvl, interpolatorC, "center", opts ); + makeTimeStack( img, bigItvl, interpolatorOtherC, "other C", opts ); + + } + + public static BdvStackSource makeTimeStack( RandomAccessibleInterval img, Interval interval, AbstractTransformAnimator interpolator, String name, BdvOptions opts ) + { + + double del = 0.01; + List> stack = new ArrayList<>(); + for (double t = 0.0; t < (1.0 + del); t += del) + { + AffineRandomAccessible rimg = RealViews.affine( + Views.interpolate(Views.extendZero(img), new NearestNeighborInterpolatorFactory<>()), + interpolator.get(t)); + + stack.add(Views.interval(Views.raster(rimg), interval)); + } + + RandomAccessibleInterval stackImg = Views.stack(stack); + return BdvFunctions.show(stackImg, name, opts ); + } + +} From e6c30a442b392b6fa42a505eef1bb269575cca62 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 25 Jul 2022 08:46:34 -0400 Subject: [PATCH 014/282] make plateau smoother * sadly requires a square root --- ...teauSphericalMaskRealRandomAccessible.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index cbcc526c..34dccb1b 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -2,8 +2,6 @@ import java.util.function.BiConsumer; -import org.apache.commons.io.input.XmlStreamReader; -import org.jdom2.DataConversionException; import org.jdom2.Element; import bdv.gui.MaskedSourceEditorMouseListener; @@ -40,7 +38,7 @@ public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) { this.center = center; pfun = new PlateauFunction(); - rra = new FunctionRealRandomAccessible<>( 3, pfun, DoubleType::new ); + rra = new FunctionRealRandomAccessible<>( n, pfun, DoubleType::new ); setRadius( 8.0 ); setSigma ( 10.0 ); @@ -49,7 +47,8 @@ public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) public static void main( String[] args ) { long S = 50; - RealPoint pt = new RealPoint( new double[]{ S, S, S } ); + double[] center = new double[] { S, S, S }; + RealPoint pt = RealPoint.wrap( center ); PlateauSphericalMaskRealRandomAccessible img = new PlateauSphericalMaskRealRandomAccessible( 3, pt ); Interval interval = Intervals.createMinSize( 0, 0, 0, 2*S, 2*S, 2*S ); @@ -70,6 +69,18 @@ public static void main( String[] args ) ml.setMask( img ); // bdv.getBdvHandle().getViewerPanel().getDisplay().addMouseListener( ml ); + double x = 50; + RealRandomAccess< DoubleType > access = img.realRandomAccess(); + access.setPosition( center ); + while( x < 100 ) + { + access.move( 1, 0 ); + System.out.println( x + "," + access.get().getRealDouble()); + + + x = access.getDoublePosition( 0 ); + } + } public double getSquaredRadius() @@ -86,6 +97,7 @@ public void setRadius( double r ) public void setSquaredRadius( double r2 ) { plateauR2 = r2; + plateauR = Math.sqrt( plateauR2 ); } public double getSquaredSigma() @@ -144,13 +156,15 @@ public void accept( RealLocalizable x, DoubleType v ) { v.setZero(); double r2 = squaredDistance( x, center ); + double r = Math.sqrt( r2 ); if( r2 <= plateauR2 ) v.setOne(); else { - double t = (r2 - plateauR2); +// double t = (r2 - plateauR2); + double t = (r - plateauR); // TODO sample exp function and interpolate to speed up - v.set( Math.exp( -0.5 * t * invSqrSigma ) ); + v.set( Math.exp( -0.5 * t * t * invSqrSigma ) ); // v.set( Math.cos( t * 0.5 + 0.5 )); // v.set( 1 / t ); } From 89ea19f2f302e11f135279b348153d0c9d96bfd5 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 25 Jul 2022 08:48:19 -0400 Subject: [PATCH 015/282] feat: add MaskedSimilarityTransform --- .../bigwarp/transforms/BigWarpTransform.java | 205 +++++++++++------- .../MaskedSimilarityTransform.java | 80 +++++++ 2 files changed, 202 insertions(+), 83 deletions(-) create mode 100644 src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index ba70e1c7..72580ccc 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -29,6 +29,7 @@ import bdv.viewer.animate.SimilarityModel3D; import bigwarp.BigWarp.BigWarpData; import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; import ij.IJ; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import mpicbg.models.AbstractAffineModel2D; @@ -48,6 +49,7 @@ import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.InverseRealTransform; import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.MaskedSimilarityTransform; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.Wrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; @@ -138,10 +140,31 @@ public InvertibleRealTransform getTransformation( final int index ) } else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) { - WrappedIterativeInvertibleRealTransform tpsXfm = new MaskedTpsTransformSolver( lambda ).solve( tableModel ); - tpsXfm.getOptimzer().setMaxIters(maxIterations); - tpsXfm.getOptimzer().setTolerance(inverseTolerance); - invXfm = tpsXfm; +// WrappedIterativeInvertibleRealTransform tpsXfm = new MaskedTpsTransformSolver( lambda ).solve( tableModel ); +// tpsXfm.getOptimzer().setMaxIters(maxIterations); +// tpsXfm.getOptimzer().setTolerance(inverseTolerance); +// invXfm = tpsXfm; + + final double[][] mvgPts; + final double[][] tgtPts; + + final int numActive = tableModel.numActive(); + mvgPts = new double[ ndims ][ numActive ]; + tgtPts = new double[ ndims ][ numActive ]; + tableModel.copyLandmarks( mvgPts, tgtPts ); // synchronized + + WrappedCoordinateTransform sim = new ModelTransformSolver( new SimilarityModel3D() ).solve(mvgPts, tgtPts); + final AffineTransform3D transform = new AffineTransform3D(); + affine3d( (AbstractAffineModel3D)sim.getTransform(), transform ); + + double[] center = new double[3]; + if( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) + { + ((PlateauSphericalMaskRealRandomAccessible)lambda).getCenter().localize( center ); + } + + final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); + invXfm = new WrappedIterativeInvertibleRealTransform( xfm ); } else { @@ -255,95 +278,20 @@ public AffineTransform3D affine3d() AffineTransform3D out = new AffineTransform3D(); if( transformType.equals( TransformTypeSelectDialog.TPS )) { - double[][] tpsAffine = getTpsBase().getAffine(); - double[] translation = getTpsBase().getTranslation(); - - double[] affine = new double[ 12 ]; - if( ndims == 2 ) - { - affine[ 0 ] = 1 + tpsAffine[ 0 ][ 0 ]; - affine[ 1 ] = tpsAffine[ 0 ][ 1 ]; - // dont set affine 2 - affine[ 3 ] = translation[ 0 ]; - - affine[ 4 ] = tpsAffine[ 1 ][ 0 ]; - affine[ 5 ] = 1 + tpsAffine[ 1 ][ 1 ]; - // dont set 6 - affine[ 7 ] = translation[ 1 ]; - - // dont set 8,9,11 - affine[ 10 ] = 1.0; - } - else - { - affine[ 0 ] = 1 + tpsAffine[ 0 ][ 0 ]; - affine[ 1 ] = tpsAffine[ 0 ][ 1 ]; - affine[ 2 ] = tpsAffine[ 0 ][ 2 ]; - affine[ 3 ] = translation[ 0 ]; - - affine[ 4 ] = tpsAffine[ 1 ][ 0 ]; - affine[ 5 ] = 1 + tpsAffine[ 1 ][ 1 ]; - affine[ 6 ] = tpsAffine[ 1 ][ 2 ]; - affine[ 7 ] = translation[ 1 ]; - - affine[ 8 ] = tpsAffine[ 2 ][ 0 ]; - affine[ 9 ] = tpsAffine[ 2 ][ 1 ]; - affine[ 10 ] = 1 + tpsAffine[ 2 ][ 2 ]; - affine[ 11 ] = translation[ 2 ]; - } - - out.set( affine ); + return affine3d( getTpsBase(), out ); } else { if( ndims == 2 ) { AbstractAffineModel2D model2d = (AbstractAffineModel2D)getCoordinateTransform(); - - double[][] mtx = new double[2][3]; - model2d.toMatrix( mtx ); - - double[] affine = new double[ 12 ]; - affine[ 0 ] = mtx[ 0 ][ 0 ]; - affine[ 1 ] = mtx[ 0 ][ 1 ]; - // dont set affine 2 - affine[ 3 ] = mtx[ 0 ][ 2 ]; - - affine[ 4 ] = mtx[ 1 ][ 0 ]; - affine[ 5 ] = mtx[ 1 ][ 1 ]; - // dont set affine 6 - affine[ 7 ] = mtx[ 1 ][ 2 ]; - - // dont set affines 8,9,11 - affine[ 10 ] = 1.0; - - out.set( affine ); + return affine3d( model2d, out ); } else if( ndims == 3 ) { AbstractAffineModel3D model3d = (AbstractAffineModel3D)getCoordinateTransform(); - - double[][] mtx = new double[3][4]; - model3d.toMatrix( mtx ); - - double[] affine = new double[ 12 ]; - affine[ 0 ] = mtx[ 0 ][ 0 ]; - affine[ 1 ] = mtx[ 0 ][ 1 ]; - affine[ 2 ] = mtx[ 0 ][ 2 ]; - affine[ 3 ] = mtx[ 0 ][ 3 ]; - - affine[ 4 ] = mtx[ 1 ][ 0 ]; - affine[ 5 ] = mtx[ 1 ][ 1 ]; - affine[ 6 ] = mtx[ 1 ][ 2 ]; - affine[ 7 ] = mtx[ 1 ][ 3 ]; - - affine[ 8 ] = mtx[ 2 ][ 0 ]; - affine[ 9 ] = mtx[ 2 ][ 1 ]; - affine[ 10 ] = mtx[ 2 ][ 2 ]; - affine[ 11 ] = mtx[ 2 ][ 3 ]; - - out.set( affine ); + return affine3d( model3d, out ); } else { @@ -351,7 +299,6 @@ else if( ndims == 3 ) return null; } } - return out; } public ThinPlateR2LogRSplineKernelTransform getTpsBase() @@ -535,4 +482,96 @@ public void initializeInverseParameters( BigWarpData bwData ) setInverseTolerance( 0.5 * highestResDim); } + public static AffineTransform3D affine3d( AbstractAffineModel2D model2d, AffineTransform3D out ) + { + double[][] mtx = new double[2][3]; + model2d.toMatrix( mtx ); + + double[] affine = new double[ 12 ]; + affine[ 0 ] = mtx[ 0 ][ 0 ]; + affine[ 1 ] = mtx[ 0 ][ 1 ]; + // dont set affine 2 + affine[ 3 ] = mtx[ 0 ][ 2 ]; + + affine[ 4 ] = mtx[ 1 ][ 0 ]; + affine[ 5 ] = mtx[ 1 ][ 1 ]; + // dont set affine 6 + affine[ 7 ] = mtx[ 1 ][ 2 ]; + + // dont set affines 8,9,11 + affine[ 10 ] = 1.0; + + out.set( affine ); + return out; + } + + public static AffineTransform3D affine3d( AbstractAffineModel3D model3d, AffineTransform3D out ) + { + double[][] mtx = new double[3][4]; + model3d.toMatrix( mtx ); + + double[] affine = new double[ 12 ]; + affine[ 0 ] = mtx[ 0 ][ 0 ]; + affine[ 1 ] = mtx[ 0 ][ 1 ]; + affine[ 2 ] = mtx[ 0 ][ 2 ]; + affine[ 3 ] = mtx[ 0 ][ 3 ]; + + affine[ 4 ] = mtx[ 1 ][ 0 ]; + affine[ 5 ] = mtx[ 1 ][ 1 ]; + affine[ 6 ] = mtx[ 1 ][ 2 ]; + affine[ 7 ] = mtx[ 1 ][ 3 ]; + + affine[ 8 ] = mtx[ 2 ][ 0 ]; + affine[ 9 ] = mtx[ 2 ][ 1 ]; + affine[ 10 ] = mtx[ 2 ][ 2 ]; + affine[ 11 ] = mtx[ 2 ][ 3 ]; + + out.set( affine ); + return out; + } + + public static AffineTransform3D affine3d( ThinPlateR2LogRSplineKernelTransform tps, AffineTransform3D out ) + { + double[][] tpsAffine = tps.getAffine(); + double[] translation = tps.getTranslation(); + int ndims = tps.getNumDims(); + + double[] affine = new double[ 12 ]; + if( ndims == 2 ) + { + affine[ 0 ] = 1 + tpsAffine[ 0 ][ 0 ]; + affine[ 1 ] = tpsAffine[ 0 ][ 1 ]; + // dont set affine 2 + affine[ 3 ] = translation[ 0 ]; + + affine[ 4 ] = tpsAffine[ 1 ][ 0 ]; + affine[ 5 ] = 1 + tpsAffine[ 1 ][ 1 ]; + // dont set 6 + affine[ 7 ] = translation[ 1 ]; + + // dont set 8,9,11 + affine[ 10 ] = 1.0; + } + else + { + affine[ 0 ] = 1 + tpsAffine[ 0 ][ 0 ]; + affine[ 1 ] = tpsAffine[ 0 ][ 1 ]; + affine[ 2 ] = tpsAffine[ 0 ][ 2 ]; + affine[ 3 ] = translation[ 0 ]; + + affine[ 4 ] = tpsAffine[ 1 ][ 0 ]; + affine[ 5 ] = 1 + tpsAffine[ 1 ][ 1 ]; + affine[ 6 ] = tpsAffine[ 1 ][ 2 ]; + affine[ 7 ] = translation[ 1 ]; + + affine[ 8 ] = tpsAffine[ 2 ][ 0 ]; + affine[ 9 ] = tpsAffine[ 2 ][ 1 ]; + affine[ 10 ] = 1 + tpsAffine[ 2 ][ 2 ]; + affine[ 11 ] = translation[ 2 ]; + } + + out.set( affine ); + return out; + } + } diff --git a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java new file mode 100644 index 00000000..ed3544f8 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java @@ -0,0 +1,80 @@ +package net.imglib2.realtransform; + +import bdv.viewer.animate.SimilarityTransformAnimator; +import net.imglib2.RealLocalizable; +import net.imglib2.RealPoint; +import net.imglib2.RealPositionable; +import net.imglib2.RealRandomAccess; +import net.imglib2.RealRandomAccessible; +import net.imglib2.type.numeric.RealType; + +/** + * Spatially-varying mask for a {@link RealTransform}. + *

+ * Given a {@link RealRandomAccessible} "lambda", and a transformation "a", implements the transformation + * lambda * a(x) + (1-lambda) * x for a point x. + * + * @author John Bogovic + * + * @param lambda's type + */ +public class MaskedSimilarityTransform> implements RealTransform { + + private final RealRandomAccessible lambda; + + private RealRandomAccess lambdaAccess; + + private final AffineTransform3D transform; + + private final SimilarityTransformInterpolator interpolator; + + private final double[] c; + + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda ) { + this( transform, lambda, new double[3] ); + } + + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c ) { + + assert ( transform.numSourceDimensions() == lambda.numDimensions() ); + this.transform = transform; + this.c = c; + + this.lambda = lambda; + lambdaAccess = lambda.realRandomAccess(); + interpolator = new SimilarityTransformInterpolator( transform, c ); + } + + @Override + public int numSourceDimensions() { + + return transform.numSourceDimensions(); + } + + @Override + public int numTargetDimensions() { + + return transform.numTargetDimensions(); + } + + @Override + public void apply(double[] source, double[] target) { + lambdaAccess.setPosition(source); + final double lam = lambdaAccess.get().getRealDouble(); + interpolator.get( lam ).apply( source, target ); + } + + @Override + public void apply(RealLocalizable source, RealPositionable target) { + lambdaAccess.setPosition(source); + final double lam = lambdaAccess.get().getRealDouble(); + interpolator.get( lam ).apply( source, target ); + } + + @Override + public RealTransform copy() { + + return new MaskedSimilarityTransform(transform.copy(), lambda, c ); + } + +} From 2f42e26dfc359f0bdc3ea4e8c0de13f19aa35b22 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 25 Jul 2022 09:23:55 -0400 Subject: [PATCH 016/282] refactor: SpatiallyInterpolatedRealTransform --- ...RealTransform.java => SpatiallyInterpolatedRealTransform.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/net/imglib2/realtransform/{InterpolatedRealTransform.java => SpatiallyInterpolatedRealTransform.java} (100%) diff --git a/src/main/java/net/imglib2/realtransform/InterpolatedRealTransform.java b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java similarity index 100% rename from src/main/java/net/imglib2/realtransform/InterpolatedRealTransform.java rename to src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java From 6956ec1af79d999dded38bbb0b908e1300a65c3c Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 25 Jul 2022 09:27:10 -0400 Subject: [PATCH 017/282] prelim interpolated tps-sim sequence --- .../bigwarp/transforms/BigWarpTransform.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 72580ccc..90511b41 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -50,6 +50,9 @@ import net.imglib2.realtransform.InverseRealTransform; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.MaskedSimilarityTransform; +import net.imglib2.realtransform.RealTransformSequence; +import net.imglib2.realtransform.Scale3D; +import net.imglib2.realtransform.SpatiallyInterpolatedRealTransform; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.Wrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; @@ -140,11 +143,18 @@ public InvertibleRealTransform getTransformation( final int index ) } else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) { + /* + * TPS ONLY + */ // WrappedIterativeInvertibleRealTransform tpsXfm = new MaskedTpsTransformSolver( lambda ).solve( tableModel ); // tpsXfm.getOptimzer().setMaxIters(maxIterations); // tpsXfm.getOptimzer().setTolerance(inverseTolerance); // invXfm = tpsXfm; + + /* + * SIMILARITY ONLY + */ final double[][] mvgPts; final double[][] tgtPts; @@ -164,6 +174,40 @@ else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) } final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); + + /* + * SIMILARITY AND TPS + */ +// final double[][] mvgPts; +// final double[][] tgtPts; +// +// final int numActive = tableModel.numActive(); +// mvgPts = new double[ ndims ][ numActive ]; +// tgtPts = new double[ ndims ][ numActive ]; +// tableModel.copyLandmarks( mvgPts, tgtPts ); // synchronized +// +// WrappedCoordinateTransform sim = new ModelTransformSolver( new SimilarityModel3D() ).solve(mvgPts, tgtPts); +// final AffineTransform3D transform = new AffineTransform3D(); +// affine3d( (AbstractAffineModel3D)sim.getTransform(), transform ); +// +// double[] center = new double[3]; +// if( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) +// { +// ((PlateauSphericalMaskRealRandomAccessible)lambda).getCenter().localize( center ); +// } +// +// // masked similarity +//// final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); +// final WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( tableModel ); +// +// final Scale3D id = new Scale3D(1,1,1); +// final SpatiallyInterpolatedRealTransform first = new SpatiallyInterpolatedRealTransform( tpsXfm, transform.inverse(), lambda ); +// final SpatiallyInterpolatedRealTransform second = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); +// +// final RealTransformSequence xfm = new RealTransformSequence(); +// xfm.add( first ); +// xfm.add( second ); + invXfm = new WrappedIterativeInvertibleRealTransform( xfm ); } else From 4f168b2db6e532b3de493bc10636ebadeef718dd Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 25 Jul 2022 16:54:21 -0400 Subject: [PATCH 018/282] testing and vis --- .../bigwarp/transforms/BigWarpTransform.java | 68 ++++---- .../transforms/MaskedTpsTransformSolver.java | 4 +- .../transforms/io/TransformWriterJson.java | 31 ++++ .../SpatiallyInterpolatedRealTransform.java | 6 +- .../AnimatorTimeVaryingTransformation.java | 19 +++ ...InterpolatedTimeVaryingTransformation.java | 23 +++ .../InterpolatedTransformTest.java | 6 +- ...milarityTransformInterpolationExample.java | 151 ++++++++++++++---- .../TimeVaryingTransformation.java | 8 + 9 files changed, 247 insertions(+), 69 deletions(-) create mode 100644 src/test/java/net/imglib2/realtransform/AnimatorTimeVaryingTransformation.java create mode 100644 src/test/java/net/imglib2/realtransform/InterpolatedTimeVaryingTransformation.java create mode 100644 src/test/java/net/imglib2/realtransform/TimeVaryingTransformation.java diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 90511b41..b9fc1c0a 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -152,8 +152,31 @@ else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) // invXfm = tpsXfm; +// /* +// * SIMILARITY ONLY +// */ +// final double[][] mvgPts; +// final double[][] tgtPts; +// +// final int numActive = tableModel.numActive(); +// mvgPts = new double[ ndims ][ numActive ]; +// tgtPts = new double[ ndims ][ numActive ]; +// tableModel.copyLandmarks( mvgPts, tgtPts ); // synchronized +// +// WrappedCoordinateTransform sim = new ModelTransformSolver( new SimilarityModel3D() ).solve(mvgPts, tgtPts); +// final AffineTransform3D transform = new AffineTransform3D(); +// affine3d( (AbstractAffineModel3D)sim.getTransform(), transform ); +// +// double[] center = new double[3]; +// if( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) +// { +// ((PlateauSphericalMaskRealRandomAccessible)lambda).getCenter().localize( center ); +// } +// +// final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); + /* - * SIMILARITY ONLY + * SIMILARITY AND TPS */ final double[][] mvgPts; final double[][] tgtPts; @@ -173,40 +196,17 @@ else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) ((PlateauSphericalMaskRealRandomAccessible)lambda).getCenter().localize( center ); } - final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); + // masked similarity +// final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); + final WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( tableModel ); - /* - * SIMILARITY AND TPS - */ -// final double[][] mvgPts; -// final double[][] tgtPts; -// -// final int numActive = tableModel.numActive(); -// mvgPts = new double[ ndims ][ numActive ]; -// tgtPts = new double[ ndims ][ numActive ]; -// tableModel.copyLandmarks( mvgPts, tgtPts ); // synchronized -// -// WrappedCoordinateTransform sim = new ModelTransformSolver( new SimilarityModel3D() ).solve(mvgPts, tgtPts); -// final AffineTransform3D transform = new AffineTransform3D(); -// affine3d( (AbstractAffineModel3D)sim.getTransform(), transform ); -// -// double[] center = new double[3]; -// if( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) -// { -// ((PlateauSphericalMaskRealRandomAccessible)lambda).getCenter().localize( center ); -// } -// -// // masked similarity -//// final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); -// final WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( tableModel ); -// -// final Scale3D id = new Scale3D(1,1,1); -// final SpatiallyInterpolatedRealTransform first = new SpatiallyInterpolatedRealTransform( tpsXfm, transform.inverse(), lambda ); -// final SpatiallyInterpolatedRealTransform second = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); -// -// final RealTransformSequence xfm = new RealTransformSequence(); -// xfm.add( first ); -// xfm.add( second ); + final Scale3D id = new Scale3D(1,1,1); + final SpatiallyInterpolatedRealTransform first = new SpatiallyInterpolatedRealTransform( tpsXfm, transform, lambda ); + final SpatiallyInterpolatedRealTransform second = new SpatiallyInterpolatedRealTransform( id, transform.inverse(), lambda ); + + final RealTransformSequence xfm = new RealTransformSequence(); + xfm.add( second ); + xfm.add( first ); invXfm = new WrappedIterativeInvertibleRealTransform( xfm ); } diff --git a/src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java b/src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java index 9d8cf15c..49573cf3 100644 --- a/src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java +++ b/src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java @@ -25,7 +25,7 @@ import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import net.imglib2.RandomAccessible; import net.imglib2.RealRandomAccessible; -import net.imglib2.realtransform.InterpolatedRealTransform; +import net.imglib2.realtransform.SpatiallyInterpolatedRealTransform; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.ThinplateSplineTransform; @@ -64,6 +64,6 @@ public WrappedIterativeInvertibleRealTransform solve( public static > WrappedIterativeInvertibleRealTransform wrap( RealTransform base, RealRandomAccessible lambda ) { final RealTransformSequence identity = new RealTransformSequence(); - return new WrappedIterativeInvertibleRealTransform<>( new InterpolatedRealTransform( base, identity, lambda )); + return new WrappedIterativeInvertibleRealTransform<>( new SpatiallyInterpolatedRealTransform( base, identity, lambda )); } } diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index c2897517..ade09b08 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -2,6 +2,7 @@ import java.io.File; import java.io.IOException; +import java.io.Reader; import java.io.Writer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; @@ -14,8 +15,10 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import com.google.gson.stream.JsonReader; import bdv.gui.TransformTypeSelectDialog; +import bigwarp.BigWarp; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; import bigwarp.transforms.BigWarpTransform; @@ -56,5 +59,33 @@ public void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) e.printStackTrace(); } } + + public void read( final File f, final BigWarp bw ) + { + try + { + final Path path = Paths.get(f.getCanonicalPath()); + final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; + final Reader reader = Channels.newReader(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); + JsonObject json = gson.fromJson( reader, JsonObject.class ); + + if( json.has( "landmarks" )) + bw.getLandmarkPanel().getTableModel().fromJson( json.get("landmarks")); + + if( json.has( "mask" )) + { + JsonObject maskParams = json.get("mask").getAsJsonObject(); + final PlateauSphericalMaskRealRandomAccessible mask = bw.getTpsMaskSource().getRandomAccessible(); + mask.setCenter( gson.fromJson( maskParams.get( "center" ), double[].class )); + mask.setSquaredRadius( maskParams.get("squaredRadius").getAsDouble() ); + mask.setSquaredSigma( maskParams.get("squaredSigma").getAsDouble() ); + } + + } catch ( IOException e ) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } } diff --git a/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java index 92415c62..05bb0f6b 100644 --- a/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java +++ b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java @@ -17,7 +17,7 @@ * * @param lambda's type */ -public class InterpolatedRealTransform> implements RealTransform { +public class SpatiallyInterpolatedRealTransform> implements RealTransform { private RealRandomAccessible lambda; @@ -35,7 +35,7 @@ public class InterpolatedRealTransform> implements RealTra private final double[] arrB; - public InterpolatedRealTransform(RealTransform a, RealTransform b, RealRandomAccessible lambda) { + public SpatiallyInterpolatedRealTransform(RealTransform a, RealTransform b, RealRandomAccessible lambda) { assert (a.numTargetDimensions() == b.numTargetDimensions() && a.numSourceDimensions() == b.numSourceDimensions()); @@ -94,7 +94,7 @@ public void apply(RealLocalizable source, RealPositionable target) { @Override public RealTransform copy() { - return new InterpolatedRealTransform(a.copy(), b.copy(), lambda); + return new SpatiallyInterpolatedRealTransform(a.copy(), b.copy(), lambda); } } diff --git a/src/test/java/net/imglib2/realtransform/AnimatorTimeVaryingTransformation.java b/src/test/java/net/imglib2/realtransform/AnimatorTimeVaryingTransformation.java new file mode 100644 index 00000000..47cc2ecf --- /dev/null +++ b/src/test/java/net/imglib2/realtransform/AnimatorTimeVaryingTransformation.java @@ -0,0 +1,19 @@ +package net.imglib2.realtransform; + +import bdv.viewer.animate.AbstractTransformAnimator; + +public class AnimatorTimeVaryingTransformation< T extends AbstractTransformAnimator > implements TimeVaryingTransformation +{ + private T animator; + + public AnimatorTimeVaryingTransformation( T animator ) + { + this.animator = animator; + } + + public RealTransform get( double t ) + { + return animator.get( t ); + } + +} diff --git a/src/test/java/net/imglib2/realtransform/InterpolatedTimeVaryingTransformation.java b/src/test/java/net/imglib2/realtransform/InterpolatedTimeVaryingTransformation.java new file mode 100644 index 00000000..db39bbed --- /dev/null +++ b/src/test/java/net/imglib2/realtransform/InterpolatedTimeVaryingTransformation.java @@ -0,0 +1,23 @@ +package net.imglib2.realtransform; + +import bdv.viewer.animate.AbstractTransformAnimator; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.ConstantUtils; + +public class InterpolatedTimeVaryingTransformation< T extends AbstractTransformAnimator > implements TimeVaryingTransformation +{ + private RealTransform a; + private RealTransform b; + + public InterpolatedTimeVaryingTransformation( RealTransform a, RealTransform b ) + { + this.a = a; + this.b = b; + } + + public RealTransform get( double t ) + { + return new SpatiallyInterpolatedRealTransform<>( a, b, ConstantUtils.constantRealRandomAccessible( new DoubleType( t ), a.numSourceDimensions() ) ); + } + +} diff --git a/src/test/java/net/imglib2/realtransform/InterpolatedTransformTest.java b/src/test/java/net/imglib2/realtransform/InterpolatedTransformTest.java index 20b14726..ac609c46 100644 --- a/src/test/java/net/imglib2/realtransform/InterpolatedTransformTest.java +++ b/src/test/java/net/imglib2/realtransform/InterpolatedTransformTest.java @@ -24,9 +24,9 @@ public void simpleTest() final RealRandomAccessible< DoubleType > l5 = ConstantUtils.constantRealRandomAccessible( new DoubleType(0.5), 2 ); final RealRandomAccessible< DoubleType > l9 = ConstantUtils.constantRealRandomAccessible( new DoubleType(0.9), 2 ); - final InterpolatedRealTransform t1 = new InterpolatedRealTransform<>( a, b, l1 ); - final InterpolatedRealTransform t5 = new InterpolatedRealTransform<>( a, b, l5 ); - final InterpolatedRealTransform t9 = new InterpolatedRealTransform<>( a, b, l9 ); + final SpatiallyInterpolatedRealTransform t1 = new SpatiallyInterpolatedRealTransform<>( a, b, l1 ); + final SpatiallyInterpolatedRealTransform t5 = new SpatiallyInterpolatedRealTransform<>( a, b, l5 ); + final SpatiallyInterpolatedRealTransform t9 = new SpatiallyInterpolatedRealTransform<>( a, b, l9 ); RealPoint src = new RealPoint( 2 ); RealPoint dst = new RealPoint( 2 ); diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index a592ce72..6eb4e381 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -1,55 +1,57 @@ package net.imglib2.realtransform; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.PrintWriter; +import java.io.Reader; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import bdv.gui.TransformTypeSelectDialog; -import bdv.img.remote.AffineTransform3DJsonSerializer; +import com.google.gson.Gson; +import com.google.gson.JsonObject; + import bdv.util.Affine3DHelpers; import bdv.util.BdvFunctions; import bdv.util.BdvOptions; import bdv.util.BdvStackSource; -import bdv.util.RandomAccessibleIntervalSource; import bdv.viewer.animate.AbstractTransformAnimator; +import bdv.viewer.animate.SimilarityModel3D; import bdv.viewer.animate.SimilarityTransformAnimator; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.source.PlateauSphericalMaskSource; import bigwarp.transforms.BigWarpTransform; +import bigwarp.transforms.ModelTransformSolver; +import bigwarp.transforms.TpsTransformSolver; +import bigwarp.transforms.WrappedCoordinateTransform; import ij.IJ; import ij.ImagePlus; +import mpicbg.models.AbstractAffineModel3D; import net.imglib2.FinalInterval; -import net.imglib2.FinalRealInterval; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealPoint; -import net.imglib2.RealRandomAccess; -import net.imglib2.RealRandomAccessible; +import net.imglib2.RealRandomAccessible; import net.imglib2.img.Img; import net.imglib2.img.display.imagej.ImageJFunctions; -import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory; import net.imglib2.interpolation.randomaccess.NearestNeighborInterpolatorFactory; -import net.imglib2.iterator.RealIntervalIterator; -import net.imglib2.position.FunctionRandomAccessible; -import net.imglib2.type.NativeType; -import net.imglib2.type.numeric.NumericType; +import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.type.numeric.real.DoubleType; -import net.imglib2.util.ConstantUtils; import net.imglib2.util.Intervals; -import net.imglib2.util.LinAlgHelpers; import net.imglib2.view.Views; public class SimilarityTransformInterpolationExample { public static void main(String[] args) { - show( args[0] ); +// show( args[0] ); + showSeq( args[0], args[1] ); // exp(); } @@ -81,6 +83,95 @@ public static void exp() { } + public static void showSeq( String imgFile, String jsonFile ) { + ImagePlus imp = IJ.openImage( imgFile ); + Img imgBase = ImageJFunctions.wrapByte(imp); + Scale3D toPhysical = new Scale3D( + imp.getCalibration().pixelWidth, + imp.getCalibration().pixelHeight, + imp.getCalibration().pixelDepth); + + Img img = imgBase; + // RandomAccessibleInterval img = Views.translateInverse( imgBase, 252, 76, 70 ); + + AffineTransform3D identity = new AffineTransform3D(); + FinalInterval bigItvl = Intervals.createMinMax(0, -200, 0, 1000, 1000, 150); + + Gson gson = new Gson(); + final Path path = Paths.get( jsonFile ); + final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; + Reader reader; + JsonObject json = null; + try + { + reader = Channels.newReader(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); + json = gson.fromJson( reader, JsonObject.class ); + } catch ( IOException e ) + { + e.printStackTrace(); + return; + } + + LandmarkTableModel ltm = new LandmarkTableModel( 3 ); + if( json.has( "landmarks" )) + ltm.fromJson( json ); + + + PlateauSphericalMaskSource tpsMask = PlateauSphericalMaskSource.build( 3, new RealPoint( 3 ), bigItvl ); + PlateauSphericalMaskRealRandomAccessible lambda = tpsMask.getRandomAccessible(); + tpsMask.getRandomAccessible().fromJson( json.getAsJsonObject( "mask" ) ); + + + // build transformations + final double[][] mvgPts; + final double[][] tgtPts; + + final int numActive = ltm.numActive(); + mvgPts = new double[ 3 ][ numActive ]; + tgtPts = new double[ 3 ][ numActive ]; + ltm.copyLandmarks( mvgPts, tgtPts ); // synchronized + + WrappedCoordinateTransform sim = new ModelTransformSolver( new SimilarityModel3D() ).solve(mvgPts, tgtPts); + final AffineTransform3D transform = new AffineTransform3D(); + BigWarpTransform.affine3d( (AbstractAffineModel3D)sim.getTransform(), transform ); + + final double[] center = new double[3]; + lambda.getCenter().localize( center ); + System.out.println( "center: " + Arrays.toString( center )); + + // masked similarity +// final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); + final WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( ltm ); + + final Scale3D id = new Scale3D(1,1,1); + final SpatiallyInterpolatedRealTransform first = new SpatiallyInterpolatedRealTransform( tpsXfm, transform.inverse(), lambda ); + final SpatiallyInterpolatedRealTransform second = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); + + + +// final RealTransformSequence xfm = new RealTransformSequence(); +// xfm.add( first ); +// xfm.add( second ); + + final InterpolatedTimeVaryingTransformation sim2tps = new InterpolatedTimeVaryingTransformation( tpsXfm, transform ); +// final InterpolatedTimeVaryingTransformation id2simi = new InterpolatedTimeVaryingTransformation( id, transform.inverse() ); + SimilarityTransformInterpolator id2simi = new SimilarityTransformInterpolator( transform, center ); + +// SimilarityTransformAnimator intebcwrpolator = new SimilarityTransformAnimator( new AffineTransform3D(), transform, 0, 0, 1); +// SimilarityTransformInterpolator interpolatorC = new SimilarityTransformInterpolator( transform, center ); +// SimilarityTransformInterpolator interpolatorOtherC = new SimilarityTransformInterpolator( transform, centerOfRotation ); + + + RealRandomAccessible< UnsignedByteType > rimg = RealViews.affine( + Views.interpolate(Views.extendZero(img), new NearestNeighborInterpolatorFactory<>()), + toPhysical); + + BdvOptions opts = BdvOptions.options(); + BdvStackSource bdv = makeTimeStack( rimg, bigItvl, sim2tps, "sim 2 tps", opts ); + opts = opts.addTo(bdv); + makeTimeStack( rimg, bigItvl, id2simi, "id 2 simi", opts ); + } + public static void show( String imgFile ) { ImagePlus imp = IJ.openImage( imgFile ); @@ -115,27 +206,33 @@ public static void show( String imgFile ) { SimilarityTransformAnimator interpolator = new SimilarityTransformAnimator( new AffineTransform3D(), transform, 0, 0, 1); SimilarityTransformInterpolator interpolatorC = new SimilarityTransformInterpolator( transform, center ); SimilarityTransformInterpolator interpolatorOtherC = new SimilarityTransformInterpolator( transform, centerOfRotation ); + + RealRandomAccessible< UnsignedByteType > rimg = Views.interpolate(Views.extendZero(img), new NearestNeighborInterpolatorFactory<>()); BdvOptions opts = BdvOptions.options(); - BdvStackSource bdv = makeTimeStack( img, bigItvl, interpolator, "orig", opts ); + BdvStackSource bdv = makeTimeStack( rimg, bigItvl, interpolator, "orig", opts ); opts = opts.addTo(bdv); - makeTimeStack( img, bigItvl, interpolatorC, "center", opts ); - makeTimeStack( img, bigItvl, interpolatorOtherC, "other C", opts ); + makeTimeStack( rimg, bigItvl, interpolatorC, "center", opts ); + makeTimeStack( rimg, bigItvl, interpolatorOtherC, "other C", opts ); } - public static BdvStackSource makeTimeStack( RandomAccessibleInterval img, Interval interval, AbstractTransformAnimator interpolator, String name, BdvOptions opts ) + public static BdvStackSource makeTimeStack( RealRandomAccessible img, Interval interval, AbstractTransformAnimator interpolator, String name, BdvOptions opts ) + { + return makeTimeStack( img, interval, new AnimatorTimeVaryingTransformation( interpolator ), name, opts ); + } + + public static BdvStackSource makeTimeStack( RealRandomAccessible rimg, Interval interval, TimeVaryingTransformation interpolator, String name, BdvOptions opts ) { double del = 0.01; List> stack = new ArrayList<>(); for (double t = 0.0; t < (1.0 + del); t += del) { - AffineRandomAccessible rimg = RealViews.affine( - Views.interpolate(Views.extendZero(img), new NearestNeighborInterpolatorFactory<>()), - interpolator.get(t)); + RealRandomAccessible xfmimg = new RealTransformRandomAccessible< >( + rimg, interpolator.get(t)); - stack.add(Views.interval(Views.raster(rimg), interval)); + stack.add(Views.interval(Views.raster(xfmimg), interval)); } RandomAccessibleInterval stackImg = Views.stack(stack); diff --git a/src/test/java/net/imglib2/realtransform/TimeVaryingTransformation.java b/src/test/java/net/imglib2/realtransform/TimeVaryingTransformation.java new file mode 100644 index 00000000..1bd49f1d --- /dev/null +++ b/src/test/java/net/imglib2/realtransform/TimeVaryingTransformation.java @@ -0,0 +1,8 @@ +package net.imglib2.realtransform; + +public interface TimeVaryingTransformation +{ + + public RealTransform get( double t ); + +} From a0afdacf9d69396c1c7455eba3bf2854cf5b67e0 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 26 Jul 2022 16:27:56 -0400 Subject: [PATCH 019/282] fix: enable reading of jsons through the ui --- src/main/java/bigwarp/BigWarp.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index d4140299..9647178c 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2410,7 +2410,7 @@ else if ( !fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) if ( !fnLandmarks.isEmpty() ) - bw.getLandmarkPanel().getTableModel().load( new File( fnLandmarks ) ); + bw.loadLandmarks( fnLandmarks ); if ( doInverse ) bw.invertPointCorrespondences(); @@ -3318,13 +3318,21 @@ public void loadLandmarks( final String filename ) { File file = new File( filename ); setLastDirectory( file.getParentFile() ); - try + + if( filename.endsWith( "csv" )) { - landmarkModel.load( file ); + try + { + landmarkModel.load( file ); + } + catch ( final IOException e1 ) + { + e1.printStackTrace(); + } } - catch ( final IOException e1 ) + else if( filename.endsWith( "json" )) { - e1.printStackTrace(); + new TransformWriterJson().read( file, this ); } boolean didCompute = restimateTransformation(); From 4c24646f3661af39fb9a070299678f00d35de617 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 26 Jul 2022 16:34:45 -0400 Subject: [PATCH 020/282] feat: mostly working masked tps with similarity interpolation --- ...teauSphericalMaskRealRandomAccessible.java | 15 ++ .../bigwarp/transforms/BigWarpTransform.java | 53 +------ .../MaskedTpsSimTransformSolver.java | 112 ++++++++++++++ .../transforms/io/TransformWriterJson.java | 3 +- .../MaskedSimilarityTransform.java | 25 +++- ...milarityTransformInterpolationExample.java | 137 +++++++++++++++++- 6 files changed, 289 insertions(+), 56 deletions(-) create mode 100644 src/main/java/bigwarp/transforms/MaskedTpsSimTransformSolver.java diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 34dccb1b..ca0189f6 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -4,6 +4,9 @@ import org.jdom2.Element; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + import bdv.gui.MaskedSourceEditorMouseListener; import bdv.util.BdvFunctions; import bdv.util.BdvOptions; @@ -233,4 +236,16 @@ public void fromXml( Element elem ) setSquaredSigma( XmlHelpers.getDouble( p, "squaredSigma" )); } + public void fromJson( JsonObject json ) + { + final JsonArray c = json.get("center").getAsJsonArray(); + final double[] center = new double[ c.size() ]; + for( int i = 0; i < c.size(); i++ ) + center[i] = c.get( i ).getAsDouble(); + + setCenter( center ); + setSquaredRadius( json.get("squaredRadius").getAsDouble() ); + setSquaredSigma( json.get("squaredSigma").getAsDouble() ); + } + } diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index b9fc1c0a..53827a2d 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -49,10 +49,6 @@ import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.InverseRealTransform; import net.imglib2.realtransform.InvertibleRealTransform; -import net.imglib2.realtransform.MaskedSimilarityTransform; -import net.imglib2.realtransform.RealTransformSequence; -import net.imglib2.realtransform.Scale3D; -import net.imglib2.realtransform.SpatiallyInterpolatedRealTransform; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.Wrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; @@ -150,33 +146,10 @@ else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) // tpsXfm.getOptimzer().setMaxIters(maxIterations); // tpsXfm.getOptimzer().setTolerance(inverseTolerance); // invXfm = tpsXfm; - - -// /* -// * SIMILARITY ONLY -// */ -// final double[][] mvgPts; -// final double[][] tgtPts; -// -// final int numActive = tableModel.numActive(); -// mvgPts = new double[ ndims ][ numActive ]; -// tgtPts = new double[ ndims ][ numActive ]; -// tableModel.copyLandmarks( mvgPts, tgtPts ); // synchronized -// -// WrappedCoordinateTransform sim = new ModelTransformSolver( new SimilarityModel3D() ).solve(mvgPts, tgtPts); -// final AffineTransform3D transform = new AffineTransform3D(); -// affine3d( (AbstractAffineModel3D)sim.getTransform(), transform ); -// -// double[] center = new double[3]; -// if( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) -// { -// ((PlateauSphericalMaskRealRandomAccessible)lambda).getCenter().localize( center ); -// } -// -// final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); +// invXfm = new WrappedIterativeInvertibleRealTransform( xfm ); /* - * SIMILARITY AND TPS + * SIMILARITY AND TPS - resolving tps with transformed points */ final double[][] mvgPts; final double[][] tgtPts; @@ -186,29 +159,15 @@ else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) tgtPts = new double[ ndims ][ numActive ]; tableModel.copyLandmarks( mvgPts, tgtPts ); // synchronized - WrappedCoordinateTransform sim = new ModelTransformSolver( new SimilarityModel3D() ).solve(mvgPts, tgtPts); - final AffineTransform3D transform = new AffineTransform3D(); - affine3d( (AbstractAffineModel3D)sim.getTransform(), transform ); - - double[] center = new double[3]; + final double[] center = new double[3]; if( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) { ((PlateauSphericalMaskRealRandomAccessible)lambda).getCenter().localize( center ); } - // masked similarity -// final MaskedSimilarityTransform xfm = new MaskedSimilarityTransform( transform, lambda, center ); - final WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( tableModel ); - - final Scale3D id = new Scale3D(1,1,1); - final SpatiallyInterpolatedRealTransform first = new SpatiallyInterpolatedRealTransform( tpsXfm, transform, lambda ); - final SpatiallyInterpolatedRealTransform second = new SpatiallyInterpolatedRealTransform( id, transform.inverse(), lambda ); - - final RealTransformSequence xfm = new RealTransformSequence(); - xfm.add( second ); - xfm.add( first ); - - invXfm = new WrappedIterativeInvertibleRealTransform( xfm ); + @SuppressWarnings({ "rawtypes", "unchecked" }) + MaskedTpsSimTransformSolver> solver = new MaskedTpsSimTransformSolver( lambda, center ); + invXfm = solver.solve( mvgPts, tgtPts ); } else { diff --git a/src/main/java/bigwarp/transforms/MaskedTpsSimTransformSolver.java b/src/main/java/bigwarp/transforms/MaskedTpsSimTransformSolver.java new file mode 100644 index 00000000..78ee57c9 --- /dev/null +++ b/src/main/java/bigwarp/transforms/MaskedTpsSimTransformSolver.java @@ -0,0 +1,112 @@ +/*- + * #%L + * BigWarp plugin for Fiji. + * %% + * Copyright (C) 2015 - 2021 Howard Hughes Medical Institute. + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package bigwarp.transforms; + +import bdv.viewer.animate.SimilarityModel3D; +import bigwarp.landmarks.LandmarkTableModel; +import jitk.spline.ThinPlateR2LogRSplineKernelTransform; +import mpicbg.models.AbstractAffineModel3D; +import net.imglib2.RandomAccessible; +import net.imglib2.RealRandomAccessible; +import net.imglib2.realtransform.SpatiallyInterpolatedRealTransform; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.MaskedSimilarityTransform; +import net.imglib2.realtransform.RealTransform; +import net.imglib2.realtransform.RealTransformSequence; +import net.imglib2.realtransform.ThinplateSplineTransform; +import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; +import net.imglib2.type.numeric.RealType; + +public class MaskedTpsSimTransformSolver> implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> +{ + private final TpsTransformSolver tpsSolver; + private final ModelTransformSolver simSolver; + private final RealRandomAccessible lambda; + private final double[] center; + + public MaskedTpsSimTransformSolver( RealRandomAccessible lambda, double[] center) + { + this.lambda = lambda; + this.center = center; + tpsSolver = new TpsTransformSolver(); + simSolver = new ModelTransformSolver( new SimilarityModel3D() ); + } + + public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) + { + WrappedCoordinateTransform simXfm = simSolver.solve( mvgPts, tgtPts ); + + AffineTransform3D sim = new AffineTransform3D(); + BigWarpTransform.affine3d( (AbstractAffineModel3D)simXfm.getTransform(), sim ); + + @SuppressWarnings({ "rawtypes", "rawtypes" }) + final MaskedSimilarityTransform msim = new MaskedSimilarityTransform( sim, lambda, center ); + + final double[][] xfmMvg = transformPoints( simXfm, mvgPts ); + final WrappedIterativeInvertibleRealTransform< ? > tps = tpsSolver.solve( xfmMvg, tgtPts ); + + final RealTransformSequence seq = new RealTransformSequence(); + seq.add( msim ); + seq.add( tps ); + + return wrap( seq, lambda ); + } + + public WrappedIterativeInvertibleRealTransform solve( + final LandmarkTableModel landmarkTable ) + { + final int numActive = landmarkTable.numActive(); + final int nd = landmarkTable.getNumdims(); + final double[][] mvgPts = new double[ nd ][ numActive ]; + final double[][] tgtPts = new double[ nd ][ numActive ]; + landmarkTable.copyLandmarks( mvgPts, tgtPts ); // synchronized + return solve( mvgPts, tgtPts ); + } + + public static > WrappedIterativeInvertibleRealTransform wrap( RealTransform base, RealRandomAccessible lambda ) + { + final RealTransformSequence identity = new RealTransformSequence(); + return new WrappedIterativeInvertibleRealTransform<>( new SpatiallyInterpolatedRealTransform( base, identity, lambda )); + } + + private static double[][] transformPoints( RealTransform xfm, double[][] pts ) + { + int nd = pts.length; + int np = pts[0].length; + + final double[] tmp = new double[nd]; + final double[][] out = new double[ nd ][ np ]; + + for( int i = 0; i < np; i++ ) + { + for( int d = 0; d < nd; d++ ) + tmp[d] = pts[d][i]; + + xfm.apply(tmp,tmp); + + for( int d = 0; d < nd; d++ ) + out[d][i] = tmp[d]; + } + + return out; + } +} diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index ade09b08..c777065f 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -15,7 +15,6 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import com.google.gson.stream.JsonReader; import bdv.gui.TransformTypeSelectDialog; import bigwarp.BigWarp; @@ -70,7 +69,7 @@ public void read( final File f, final BigWarp bw ) JsonObject json = gson.fromJson( reader, JsonObject.class ); if( json.has( "landmarks" )) - bw.getLandmarkPanel().getTableModel().fromJson( json.get("landmarks")); + bw.getLandmarkPanel().getTableModel().fromJson( json ); if( json.has( "mask" )) { diff --git a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java index ed3544f8..775afef2 100644 --- a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java +++ b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java @@ -1,8 +1,6 @@ package net.imglib2.realtransform; -import bdv.viewer.animate.SimilarityTransformAnimator; import net.imglib2.RealLocalizable; -import net.imglib2.RealPoint; import net.imglib2.RealPositionable; import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; @@ -30,15 +28,26 @@ public class MaskedSimilarityTransform> implements RealTra private final double[] c; + private final boolean flip; + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda ) { - this( transform, lambda, new double[3] ); + this( transform, lambda, new double[3], false ); + } + + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, boolean flip ) { + this( transform, lambda, new double[3], flip ); } public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c ) { + this( transform, lambda, c, false ); + } + + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c, boolean flip ) { assert ( transform.numSourceDimensions() == lambda.numDimensions() ); this.transform = transform; this.c = c; + this.flip = flip; this.lambda = lambda; lambdaAccess = lambda.realRandomAccess(); @@ -61,14 +70,20 @@ public int numTargetDimensions() { public void apply(double[] source, double[] target) { lambdaAccess.setPosition(source); final double lam = lambdaAccess.get().getRealDouble(); - interpolator.get( lam ).apply( source, target ); + if( flip ) + interpolator.get( 1-lam ).apply( source, target ); + else + interpolator.get( lam ).apply( source, target ); } @Override public void apply(RealLocalizable source, RealPositionable target) { lambdaAccess.setPosition(source); final double lam = lambdaAccess.get().getRealDouble(); - interpolator.get( lam ).apply( source, target ); + if( flip ) + interpolator.get( 1-lam ).apply( source, target ); + else + interpolator.get( lam ).apply( source, target ); } @Override diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index 6eb4e381..f35ac2f1 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -40,6 +40,7 @@ import net.imglib2.RealRandomAccessible; import net.imglib2.img.Img; import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory; import net.imglib2.interpolation.randomaccess.NearestNeighborInterpolatorFactory; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.integer.UnsignedByteType; @@ -51,8 +52,9 @@ public class SimilarityTransformInterpolationExample { public static void main(String[] args) { // show( args[0] ); - showSeq( args[0], args[1] ); // exp(); +// showSeq( args[0], args[1] ); + expSeq( args[0], args[1] ); } public static void exp() { @@ -82,6 +84,135 @@ public static void exp() { System.out.println( Affine3DHelpers.toString( o )); } + + public static void expSeq( String imgFile, String jsonFile ) { + ImagePlus imp = IJ.openImage( imgFile ); + Img imgBase = ImageJFunctions.wrapByte(imp); + Scale3D toPhysical = new Scale3D( + imp.getCalibration().pixelWidth, + imp.getCalibration().pixelHeight, + imp.getCalibration().pixelDepth); + + Img img = imgBase; + // RandomAccessibleInterval img = Views.translateInverse( imgBase, 252, 76, 70 ); + + AffineTransform3D identity = new AffineTransform3D(); + FinalInterval bigItvl = Intervals.createMinMax(0, -200, 0, 1000, 1000, 150); + + Gson gson = new Gson(); + final Path path = Paths.get( jsonFile ); + final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; + Reader reader; + JsonObject json = null; + try + { + reader = Channels.newReader(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); + json = gson.fromJson( reader, JsonObject.class ); + } catch ( IOException e ) + { + e.printStackTrace(); + return; + } + + LandmarkTableModel ltm = new LandmarkTableModel( 3 ); + if( json.has( "landmarks" )) + ltm.fromJson( json ); + + + PlateauSphericalMaskSource tpsMask = PlateauSphericalMaskSource.build( 3, new RealPoint( 3 ), bigItvl ); + PlateauSphericalMaskRealRandomAccessible lambda = tpsMask.getRandomAccessible(); + tpsMask.getRandomAccessible().fromJson( json.getAsJsonObject( "mask" ) ); + + + // build transformations + final double[][] mvgPts; + final double[][] tgtPts; + + final int numActive = ltm.numActive(); + mvgPts = new double[ 3 ][ numActive ]; + tgtPts = new double[ 3 ][ numActive ]; + ltm.copyLandmarks( mvgPts, tgtPts ); // synchronized + + WrappedCoordinateTransform sim = new ModelTransformSolver( new SimilarityModel3D() ).solve(mvgPts, tgtPts); + final AffineTransform3D transform = new AffineTransform3D(); + BigWarpTransform.affine3d( (AbstractAffineModel3D)sim.getTransform(), transform ); + + final double[] center = new double[3]; + lambda.getCenter().localize( center ); + System.out.println( "center: " + Arrays.toString( center )); + + // masked similarity + final MaskedSimilarityTransform msim = new MaskedSimilarityTransform( transform, lambda, center ); + final MaskedSimilarityTransform msimInv = new MaskedSimilarityTransform( transform.inverse(), lambda, center, true ); + final WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( ltm ); + + final Scale3D id = new Scale3D(1,1,1); + final SpatiallyInterpolatedRealTransform tpsLmsim = new SpatiallyInterpolatedRealTransform( tpsXfm, transform.inverse(), lambda ); +// final SpatiallyInterpolatedRealTransform idLmsimI = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); +// final SpatiallyInterpolatedRealTransform msimILid = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); + + final double[] x = new double[]{358.1, 171.0, 85.7 }; + + double lam = lambda.getAt( x ).getRealDouble(); + System.out.println( " x: " + Arrays.toString( x )); + System.out.println( " l: " + lam ); + + + final double[] tx = new double[3]; + final double[] sx = new double[3]; + final double[] msx = new double[3]; + + tpsXfm.apply( x, tx ); + transform.inverse().apply( x, sx ); + msim.apply( x, msx ); + + System.out.println( " t(x): " + Arrays.toString( tx )); + System.out.println( " s(x): " + Arrays.toString( sx )); + System.out.println( " ms(x): " + Arrays.toString( msx )); + + double ltx = lambda.getAt( tx ).getRealDouble(); + double lsx = lambda.getAt( sx ).getRealDouble(); + double lmsx = lambda.getAt( msx ).getRealDouble(); + System.out.println( " lam(t(x)) : " + ltx ); + System.out.println( " lam(s(x)) : " + lsx ); + System.out.println( " lam( ms(x)): " + lmsx ); + System.out.println( " " ); + + final double[] msxMinv = new double[3]; + msimInv.apply( msx, msxMinv ); + System.out.println( " minv(ms(x)): " + Arrays.toString( msxMinv )); + + /** + * Conclusion: + * msimInv ( msim ( x )) is almost the identity + * good + */ + + + double[] tlmsx = new double[3]; + tpsLmsim.apply( x, tlmsx ); + + System.out.println( " " ); + System.out.println( " tlms(x): " + Arrays.toString( tlmsx )); + + double[] msi_tlmsx = new double[3]; + msimInv.apply( tlmsx, msi_tlmsx ); + System.out.println( " msi(tlms(x)): " + Arrays.toString( msi_tlmsx )); + + /* + * CONCLUSION + * msi_tlmsx is approximately where we want it to be + * + */ + + final RealTransformSequence xfm = new RealTransformSequence(); + xfm.add( tpsLmsim ); + xfm.add( msimInv ); + + double[] y = new double[3]; + xfm.apply( x, y ); + System.out.println( " f(x): " + Arrays.toString( y )); + } public static void showSeq( String imgFile, String jsonFile ) { ImagePlus imp = IJ.openImage( imgFile ); @@ -162,8 +293,10 @@ public static void showSeq( String imgFile, String jsonFile ) { // SimilarityTransformInterpolator interpolatorOtherC = new SimilarityTransformInterpolator( transform, centerOfRotation ); +// NearestNeighborInterpolatorFactory pixInterp = new NearestNeighborInterpolatorFactory(); + NLinearInterpolatorFactory pixInterp = new NLinearInterpolatorFactory(); RealRandomAccessible< UnsignedByteType > rimg = RealViews.affine( - Views.interpolate(Views.extendZero(img), new NearestNeighborInterpolatorFactory<>()), + Views.interpolate(Views.extendZero(img), pixInterp), toPhysical); BdvOptions opts = BdvOptions.options(); From 1c590284735b574a9f56340d065a40bfd7890f7e Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 1 Aug 2022 16:48:18 -0400 Subject: [PATCH 021/282] feat: add spherical mask overlay, cosine mask falloff --- .../gui/MaskedSourceEditorMouseListener.java | 59 +++++-- .../bdv/gui/TransformTypeSelectDialog.java | 9 ++ src/main/java/bdv/viewer/BigWarpOverlay.java | 1 - .../java/bdv/viewer/BigWarpViewerPanel.java | 19 +++ .../overlay/BigWarpMaskSphereOverlay.java | 149 +++++++++++++++++ src/main/java/bigwarp/BigWarp.java | 22 ++- src/main/java/bigwarp/BigWarpActions.java | 3 +- ...teauSphericalMaskRealRandomAccessible.java | 152 ++++++++++++------ .../bigwarp/transforms/BigWarpTransform.java | 13 +- ...milarityTransformInterpolationExample.java | 4 +- 10 files changed, 359 insertions(+), 72 deletions(-) create mode 100644 src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java index 2723c5af..2d5f50dc 100644 --- a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -5,9 +5,14 @@ import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import bdv.util.Affine3DHelpers; +import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.ViewerPanel; +import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import bigwarp.BigWarp; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; import net.imglib2.RealPoint; @@ -15,24 +20,30 @@ public class MaskedSourceEditorMouseListener implements MouseListener, MouseMotionListener, MouseWheelListener { - private PlateauSphericalMaskRealRandomAccessible mask; + protected PlateauSphericalMaskRealRandomAccessible mask; + protected BigWarpViewerPanel viewer; + protected List overlays; private boolean active; private RealPoint p; private BigWarp bw; - private ViewerPanel viewer; private static final double fastSpeed = 10.0; private static final double slowSpeed = 0.1; - public MaskedSourceEditorMouseListener( int nd, BigWarp bw, ViewerPanel viewer ) + public MaskedSourceEditorMouseListener( int nd, BigWarp bw, BigWarpViewerPanel viewer ) { this.bw = bw; this.viewer = viewer; - viewer.getDisplay().addMouseListener( this ); - viewer.getDisplay().addMouseWheelListener( this ); - viewer.getDisplay().addMouseMotionListener( this ); + + this.viewer.getDisplay().addMouseListener( this ); + this.viewer.getDisplay().addMouseWheelListener( this ); + this.viewer.getDisplay().addMouseMotionListener( this ); + + overlays = new ArrayList(); + overlays.add( bw.getViewerFrameP().getViewerPanel().getMaskOverlay() ); + overlays.add( bw.getViewerFrameQ().getViewerPanel().getMaskOverlay() ); p = new RealPoint( nd ); active = false; @@ -57,8 +68,24 @@ public void toggleActive( ) public void setMask( PlateauSphericalMaskRealRandomAccessible mask ) { this.mask = mask; + overlays.forEach( o -> { + o.setCenter( mask.getCenter() ); + o.setInnerRadius( Math.sqrt( mask.getSquaredRadius())); + o.setOuterRadiusDelta( Math.sqrt( mask.getSquaredSigma())); + }); } +// public void setOverlay( final BigWarpMaskSphereOverlay overlay ) +// { +// this.overlay = overlay; +// if( mask != null ) +// { +// this.overlay.setCenter( mask.getCenter() ); +// this.overlay.setInnerRadius( Math.sqrt( mask.getSquaredRadius() ) ); +// this.overlay.setOuterRadiusDelta( Math.sqrt( mask.getSquaredSigma() ) ); +// } +// } + public PlateauSphericalMaskRealRandomAccessible getMask() { return mask; @@ -83,8 +110,8 @@ public void mousePressed( MouseEvent e ) synchronized ( mask ) { mask.setCenter( p ); + overlays.stream().forEach( o -> o.setCenter( p ) ); } -// viewer.requestRepaint(); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } @@ -101,12 +128,12 @@ public void mouseDragged( MouseEvent e ) viewer.getGlobalMouseCoordinates( p ); synchronized ( mask ) { - mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible - .squaredDistance( p, mask.getCenter() ) ); + mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ) ); + final double r = Math.sqrt( mask.getSquaredRadius() ); + overlays.stream().forEach( o -> o.setInnerRadius( r )); } bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); - } @Override @@ -119,14 +146,18 @@ public void mouseWheelMoved( MouseWheelEvent e ) return; final AffineTransform3D transform = viewer.state().getViewerTransform(); - final double scale = (1 / Affine3DHelpers.extractScale(transform, 0)) + 0.05; + final double scale = (1.0 / Affine3DHelpers.extractScale(transform, 0)) + 0.05; final int sign = e.getWheelRotation(); + if( e.isShiftDown() ) - mask.incSquaredSigma( sign * scale * fastSpeed ); + mask.incSquaredSigma( sign * scale * scale * fastSpeed * fastSpeed ); else if ( e.isControlDown() ) - mask.incSquaredSigma( sign * scale * slowSpeed); + mask.incSquaredSigma( sign * scale * scale * slowSpeed * slowSpeed ); else - mask.incSquaredSigma( sign * scale ); + mask.incSquaredSigma( sign * scale * scale ); + + final double r = Math.sqrt( mask.getSquaredSigma() ); + overlays.stream().forEach( o -> o.setOuterRadiusDelta( r )); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index 632e8131..debf4aae 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -49,6 +49,7 @@ public class TransformTypeSelectDialog extends JDialog public static final String TPS = "Thin Plate Spline"; public static final String MASKEDTPS = "Masked Thin Plate Spline"; + public static final String MASKEDSIMTPS = "Masked Similarity + Thin Plate Spline"; public static final String AFFINE = "Affine"; public static final String SIMILARITY = "Similarity"; public static final String ROTATION = "Rotation"; @@ -60,6 +61,7 @@ public class TransformTypeSelectDialog extends JDialog private final ButtonGroup group; private final JRadioButton tpsButton; private final JRadioButton maskedTpsButton; + private final JRadioButton maskedSimTpsButton; private final JRadioButton affineButton; private final JRadioButton similarityButton; private final JRadioButton rotationButton; @@ -84,6 +86,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) tpsButton = new JRadioButton( TPS ); maskedTpsButton = new JRadioButton( MASKEDTPS ); + maskedSimTpsButton = new JRadioButton( MASKEDSIMTPS ); affineButton = new JRadioButton( AFFINE ); similarityButton = new JRadioButton( SIMILARITY ); rotationButton = new JRadioButton( ROTATION ); @@ -92,6 +95,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) group = new ButtonGroup(); group.add( tpsButton ); group.add( maskedTpsButton ); + group.add( maskedSimTpsButton ); group.add( affineButton ); group.add( similarityButton ); group.add( rotationButton ); @@ -101,6 +105,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) addActionListender( tpsButton ); addActionListender( maskedTpsButton ); + addActionListender( maskedSimTpsButton ); addActionListender( affineButton ); addActionListender( similarityButton ); addActionListender( rotationButton ); @@ -109,6 +114,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) JPanel radioPanel = new JPanel( new GridLayout(0, 1)); radioPanel.add( tpsButton ); radioPanel.add( maskedTpsButton ); + radioPanel.add( maskedSimTpsButton ); radioPanel.add( affineButton ); radioPanel.add( similarityButton ); radioPanel.add( rotationButton ); @@ -160,6 +166,9 @@ private void updateButtonGroup() case MASKEDTPS: maskedTpsButton.setSelected( true ); break; + case MASKEDSIMTPS: + maskedSimTpsButton.setSelected( true ); + break; case AFFINE: affineButton.setSelected( true ); break; diff --git a/src/main/java/bdv/viewer/BigWarpOverlay.java b/src/main/java/bdv/viewer/BigWarpOverlay.java index 693d9352..6c0aa6ab 100644 --- a/src/main/java/bdv/viewer/BigWarpOverlay.java +++ b/src/main/java/bdv/viewer/BigWarpOverlay.java @@ -245,7 +245,6 @@ public void paint( final Graphics2D g ) } } - } } diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index 23f1d988..ce64bbe1 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -38,6 +38,7 @@ import bdv.viewer.animate.OverlayAnimator; import bdv.viewer.animate.RotationAnimator; import bdv.viewer.animate.SimilarityTransformAnimator3D; +import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import bigwarp.util.Rotation2DHelpers; import net.imglib2.RealPoint; import net.imglib2.realtransform.AffineTransform3D; @@ -58,6 +59,8 @@ public class BigWarpViewerPanel extends ViewerPanel protected BigWarpOverlay overlay; protected BigWarpDragOverlay dragOverlay; + + protected BigWarpMaskSphereOverlay maskOverlay; protected final MessageOverlayAnimator message; @@ -250,10 +253,26 @@ public void addDragOverlay( BigWarpDragOverlay dragOverlay ){ this.dragOverlay = dragOverlay; } + public void addOverlay( OverlayRenderer overlay ) + { + super.getDisplay().overlays().add( overlay ); + } + public BigWarpDragOverlay getDragOverlay(){ return dragOverlay; } + public BigWarpMaskSphereOverlay getMaskOverlay() + { + return maskOverlay; + } + + public void setMaskOverlay( final BigWarpMaskSphereOverlay maskOverlay ) + { + this.maskOverlay = maskOverlay; + addOverlay( maskOverlay ); + } + public boolean getIsMoving() { return isMoving; diff --git a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java new file mode 100644 index 00000000..92c39a49 --- /dev/null +++ b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java @@ -0,0 +1,149 @@ +package bdv.viewer.overlay; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; + +import bdv.util.Affine3DHelpers; +import bdv.viewer.BigWarpViewerPanel; +import bdv.viewer.OverlayRenderer; +import net.imglib2.RealPoint; +import net.imglib2.realtransform.AffineTransform3D; + +public class BigWarpMaskSphereOverlay implements OverlayRenderer +{ + + final static protected BasicStroke stroke = new BasicStroke( 1 ); + final protected BigWarpViewerPanel viewer; + + protected double[] radii; + protected final double[] viewerCoords; + protected double minWidth = 0.1; + + protected final Color[] colors; + final protected AffineTransform3D viewerTransform; + + protected double[] center; + protected int width, height; + protected boolean is3d; + protected boolean visible = false; + + public BigWarpMaskSphereOverlay( final BigWarpViewerPanel viewer, boolean is3d ) + { + this( viewer, new double[]{}, new Color[]{ Color.ORANGE, Color.YELLOW }, is3d ); + } + + public BigWarpMaskSphereOverlay( final BigWarpViewerPanel viewer, final Color[] colors, boolean is3d ) + { + this( viewer, new double[]{0, 0}, colors, is3d ); + } + + public BigWarpMaskSphereOverlay( final BigWarpViewerPanel viewer, final double[] radii, final Color[] colors, boolean is3d ) + { + this.viewer = viewer; + this.radii = radii; + this.colors = colors; + viewerCoords = new double[ 3 ]; + center = new double[ 3 ]; + this.is3d = is3d; + viewerTransform = new AffineTransform3D(); + } + + public void setCenter( final double[] center ) + { + this.center = center; + } + + public void setCenter( final RealPoint center ) + { + center.localize( this.center ); + } + + public void setRadii( double[] radii ) + { + this.radii = radii; + } + + public void setInnerRadius( double inner ) + { + double del = radii[1] - radii[0]; + radii[0] = inner; + radii[1] = inner + del; + } + + public void setOuterRadiusDelta( double outerDelta ) + { + radii[1] = radii[0] + outerDelta; + } + + public void setColor( final Color color, final int i ) + { + colors[ i ] = color; + } + + public void setColors( final Color[] colors ) + { + System.arraycopy( colors, 0, this.colors, 0, Math.min( colors.length, this.colors.length ) ); + } + + public void setVisible( final boolean visible ) + { + this.visible = visible; + } + + @Override + public void drawOverlays( final Graphics g ) + { + if ( visible ) + { + final Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); + g2d.setComposite( AlphaComposite.SrcOver ); + + final double scale; + viewer.state().getViewerTransform( viewerTransform ); // synchronized + scale = Affine3DHelpers.extractScale( viewerTransform, 0 ); + + viewerTransform.apply( center, viewerCoords ); + + final double zv; + if( is3d ) + zv = viewerCoords[ 2 ]; + else + zv = 0; + + final double dz2 = zv * zv; + for ( int i = 0; i < radii.length; ++i ) + { + final double rad = radii[i]; + final double scaledRadius = scale * rad; + final double arad; + if( is3d ) + arad = Math.sqrt( scaledRadius * scaledRadius - dz2 ); + else + arad = rad; + + final int rarad = (int)Math.round( arad ); + if ( viewerCoords[0] + scaledRadius > 0 && viewerCoords[0] - scaledRadius < width + && viewerCoords[1] + scaledRadius > 0 && viewerCoords[1] - scaledRadius < height ) + { + g2d.setColor( colors[ i ] ); + g2d.setStroke( stroke ); + g2d.drawOval( (int)viewerCoords[0] - rarad, (int)viewerCoords[1] - rarad, + (2 * rarad + 1), 2 * rarad + 1 ); + } + } + } + } + + @Override + public void setCanvasSize( final int width, final int height ) + { + this.width = width; + this.height = height; + } + +} diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 9647178c..accc1492 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -129,6 +129,7 @@ import bdv.viewer.WarpNavigationActions; import bdv.viewer.animate.SimilarityModel3D; import bdv.viewer.animate.TranslationAnimator; +import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import bdv.viewer.overlay.BigWarpSourceOverlayRenderer; import bdv.viewer.overlay.MultiBoxOverlayRenderer; import bigwarp.landmarks.LandmarkTableModel; @@ -273,7 +274,9 @@ public class BigWarp< T > protected MouseLandmarkTableListener landmarkTableListener; - protected MaskedSourceEditorMouseListener maskSourceMouseListener; + protected MaskedSourceEditorMouseListener maskSourceMouseListenerP; + + protected MaskedSourceEditorMouseListener maskSourceMouseListenerQ; protected BigWarpMessageAnimator message; @@ -1761,9 +1764,20 @@ protected void addDefaultTableMouseListener() protected void addMaskMouseListener() { - maskSourceMouseListener = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerQ ); - maskSourceMouseListener.setActive( false ); - maskSourceMouseListener.setMask( tpsMask.getRandomAccessible() ); + final Color[] maskColors = new Color[]{ Color.ORANGE, Color.YELLOW }; + viewerP.setMaskOverlay( new BigWarpMaskSphereOverlay( viewerP, maskColors, numDimensions() == 3 )); + viewerQ.setMaskOverlay( new BigWarpMaskSphereOverlay( viewerQ, maskColors, numDimensions() == 3 )); + + maskSourceMouseListenerP = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerP ); + maskSourceMouseListenerP.setActive( false ); + maskSourceMouseListenerP.setMask( tpsMask.getRandomAccessible() ); + + maskSourceMouseListenerQ = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerQ ); + maskSourceMouseListenerQ.setActive( false ); + maskSourceMouseListenerQ.setMask( tpsMask.getRandomAccessible() ); + + viewerP.getMaskOverlay().setVisible( true ); + viewerQ.getMaskOverlay().setVisible( true ); } public void setGridType( final GridSource.GRID_TYPE method ) diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 9e0df803..7c34f553 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -1179,7 +1179,8 @@ public MaskSizeEdit( final BigWarp< ? > bw ) @Override public void actionPerformed(ActionEvent e) { - bw.maskSourceMouseListener.toggleActive(); + bw.maskSourceMouseListenerP.toggleActive(); + bw.maskSourceMouseListenerQ.toggleActive(); } } diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index ca0189f6..929fb782 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -7,10 +7,6 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import bdv.gui.MaskedSourceEditorMouseListener; -import bdv.util.BdvFunctions; -import bdv.util.BdvOptions; -import bdv.util.BdvStackSource; import mpicbg.spim.data.XmlHelpers; import net.imglib2.Interval; import net.imglib2.RealInterval; @@ -24,23 +20,29 @@ public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAccessible< DoubleType > { - private PlateauFunction pfun; + private BiConsumer< RealLocalizable, DoubleType > pfun; private FunctionRealRandomAccessible< DoubleType > rra; private double plateauR; private double plateauR2; + private double sigma; private double sqrSigma; private double invSqrSigma; private RealPoint center; private static final double EPS = 1e-6; + private static final double PIon2 = Math.PI / 2.0; + private static final double PI = Math.PI; + + public static enum FalloffType { GAUSSIAN, COSINE }; public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) { this.center = center; - pfun = new PlateauFunction(); +// pfun = new GaussianFalloff(); + pfun = new CosineFalloff(); rra = new FunctionRealRandomAccessible<>( n, pfun, DoubleType::new ); setRadius( 8.0 ); @@ -54,24 +56,26 @@ public static void main( String[] args ) RealPoint pt = RealPoint.wrap( center ); PlateauSphericalMaskRealRandomAccessible img = new PlateauSphericalMaskRealRandomAccessible( 3, pt ); + img.setRadius( 10 ); + img.setSigma( 10 ); Interval interval = Intervals.createMinSize( 0, 0, 0, 2*S, 2*S, 2*S ); - -// BdvOptions options = BdvOptions.options().screenScales( new double[] { 1 } ); - BdvOptions options = BdvOptions.options(); - BdvStackSource< DoubleType > bdv = BdvFunctions.show( img.rra, interval, "img", options ); - bdv.getBdvHandle().getSetupAssignments().getMinMaxGroups().get( 0 ).setRange( 0, 1 ); - -// InputActionBindings kb = bdv.getBdvHandle().getKeybindings(); -// System.out.println( kb ); -// kb.removeActionMap( "navigation" ); -// kb.removeInputMap( "navigation" ); - -// bdv.getBdvHandle().getTriggerbindings().removeInputTriggerMap( "block_transform" ); - - final MaskedSourceEditorMouseListener ml = new MaskedSourceEditorMouseListener( 3, null, bdv.getBdvHandle().getViewerPanel() ); - ml.setMask( img ); -// bdv.getBdvHandle().getViewerPanel().getDisplay().addMouseListener( ml ); - +// +//// BdvOptions options = BdvOptions.options().screenScales( new double[] { 1 } ); +// BdvOptions options = BdvOptions.options(); +// BdvStackSource< DoubleType > bdv = BdvFunctions.show( img.rra, interval, "img", options ); +// bdv.getBdvHandle().getSetupAssignments().getMinMaxGroups().get( 0 ).setRange( 0, 1 ); +// +//// InputActionBindings kb = bdv.getBdvHandle().getKeybindings(); +//// System.out.println( kb ); +//// kb.removeActionMap( "navigation" ); +//// kb.removeInputMap( "navigation" ); +// +//// bdv.getBdvHandle().getTriggerbindings().removeInputTriggerMap( "block_transform" ); +// +// final MaskedSourceEditorMouseListener ml = new MaskedSourceEditorMouseListener( 3, null, bdv.getBdvHandle().getViewerPanel() ); +// ml.setMask( img ); +//// bdv.getBdvHandle().getViewerPanel().getDisplay().addMouseListener( ml ); +// double x = 50; RealRandomAccess< DoubleType > access = img.realRandomAccess(); access.setPosition( center ); @@ -80,10 +84,31 @@ public static void main( String[] args ) access.move( 1, 0 ); System.out.println( x + "," + access.get().getRealDouble()); - x = access.getDoublePosition( 0 ); } +// x = 70; +// access.setPosition( new double[] { x, 50, 50 } ); +// System.out.println( x + "," + access.get().getRealDouble()); + } + + public void setType( String type ) + { + setType( FalloffType.valueOf( type )); + } + + public void setType( FalloffType type ) + { + switch (type) { + case GAUSSIAN: + pfun = new GaussianFalloff(); + break; + case COSINE: + pfun = new CosineFalloff(); + break; + default: + break; + } } public double getSquaredRadius() @@ -110,6 +135,7 @@ public double getSquaredSigma() public void setSigma( double sigma ) { + this.sigma = sigma; sqrSigma = sigma * sigma; if( sqrSigma <= 0 ) @@ -121,6 +147,7 @@ public void setSigma( double sigma ) public void setSquaredSigma( double squaredSigma ) { sqrSigma = squaredSigma; + sigma = Math.sqrt( sqrSigma ); if( sqrSigma <= 0 ) sqrSigma = EPS; @@ -130,12 +157,24 @@ public void setSquaredSigma( double squaredSigma ) public void incSquaredSigma( double increment ) { sqrSigma += increment; + sigma = Math.sqrt( sqrSigma ); if( sqrSigma <= 0 ) sqrSigma = EPS; invSqrSigma = 1.0 / sqrSigma; } +// +// public void mulSquaredSigma( double factor ) +// { +// sqrSigma *= factor; +// sigma = Math.sqrt( sqrSigma ); +// +// if( sqrSigma <= 0 ) +// sqrSigma = EPS; +// +// invSqrSigma = 1.0 / sqrSigma; +// } public void setCenter( RealLocalizable p ) { @@ -152,27 +191,6 @@ public RealPoint getCenter() return center; } - public class PlateauFunction implements BiConsumer< RealLocalizable, DoubleType > { - - @Override - public void accept( RealLocalizable x, DoubleType v ) - { - v.setZero(); - double r2 = squaredDistance( x, center ); - double r = Math.sqrt( r2 ); - if( r2 <= plateauR2 ) - v.setOne(); - else - { -// double t = (r2 - plateauR2); - double t = (r - plateauR); - // TODO sample exp function and interpolate to speed up - v.set( Math.exp( -0.5 * t * t * invSqrSigma ) ); -// v.set( Math.cos( t * 0.5 + 0.5 )); -// v.set( 1 / t ); - } - } - } final public static double squaredDistance( final RealLocalizable position1, final RealLocalizable position2 ) { @@ -248,4 +266,48 @@ public void fromJson( JsonObject json ) setSquaredSigma( json.get("squaredSigma").getAsDouble() ); } + public class GaussianFalloff implements BiConsumer< RealLocalizable, DoubleType > { + + @Override + public void accept( RealLocalizable x, DoubleType v ) + { + v.setZero(); + double r2 = squaredDistance( x, center ); + if( r2 <= plateauR2 ) + v.setOne(); + else + { + final double r = Math.sqrt( r2 ); +// final double t = (r2 - plateauR2); + final double t = (r - plateauR); + // TODO sample exp function and interpolate to speed up + v.set( Math.exp( -0.5 * t * t * invSqrSigma ) ); +// v.set( Math.cos( t * 0.5 + 0.5 )); +// v.set( 1 / t ); + } + } + } + + public class CosineFalloff implements BiConsumer< RealLocalizable, DoubleType > { + + @Override + public void accept( RealLocalizable x, DoubleType v ) + { + final double r2 = squaredDistance( x, center ); + final double r = Math.sqrt( r2 ); + if( r2 <= plateauR2 ) + v.setOne(); + else if ( r > plateauR + 2 * sigma ) + v.setZero(); + else + { +// final double t = (r2 - plateauR2); +// final double r = Math.sqrt( r2 ); + final double t = (r - plateauR); + double val = 0.5 + 0.5 * Math.cos( t * PIon2 / sigma ); + v.set( val ); + } + } + } + } diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 53827a2d..99e02719 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -142,11 +142,14 @@ else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) /* * TPS ONLY */ -// WrappedIterativeInvertibleRealTransform tpsXfm = new MaskedTpsTransformSolver( lambda ).solve( tableModel ); -// tpsXfm.getOptimzer().setMaxIters(maxIterations); -// tpsXfm.getOptimzer().setTolerance(inverseTolerance); -// invXfm = tpsXfm; -// invXfm = new WrappedIterativeInvertibleRealTransform( xfm ); + WrappedIterativeInvertibleRealTransform tpsXfm = new MaskedTpsTransformSolver( lambda ).solve( tableModel ); + tpsXfm.getOptimzer().setMaxIters(maxIterations); + tpsXfm.getOptimzer().setTolerance(inverseTolerance); + invXfm = new WrappedIterativeInvertibleRealTransform( tpsXfm ); + + } + else if( transformType.equals( TransformTypeSelectDialog.MASKEDSIMTPS )) + { /* * SIMILARITY AND TPS - resolving tps with transformed points diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index f35ac2f1..8ef36a42 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -148,8 +148,8 @@ public static void expSeq( String imgFile, String jsonFile ) { final Scale3D id = new Scale3D(1,1,1); final SpatiallyInterpolatedRealTransform tpsLmsim = new SpatiallyInterpolatedRealTransform( tpsXfm, transform.inverse(), lambda ); -// final SpatiallyInterpolatedRealTransform idLmsimI = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); -// final SpatiallyInterpolatedRealTransform msimILid = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); + final SpatiallyInterpolatedRealTransform idLmsimI = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); + final SpatiallyInterpolatedRealTransform msimILid = new SpatiallyInterpolatedRealTransform( id, transform, lambda ); final double[] x = new double[]{358.1, 171.0, 85.7 }; From a7e5c4dc4a683a2ab7582b44366830f141d49686 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Wed, 3 Aug 2022 16:44:24 -0400 Subject: [PATCH 022/282] feat: add UI options for mask --- .../bdv/gui/TransformTypeSelectDialog.java | 62 ++++++++++++++++--- .../overlay/BigWarpMaskSphereOverlay.java | 6 ++ src/main/java/bigwarp/BigWarp.java | 3 - src/main/java/bigwarp/BigWarpActions.java | 22 +++++++ src/main/java/bigwarp/WarpVisFrame.java | 2 +- ...teauSphericalMaskRealRandomAccessible.java | 13 +++- 6 files changed, 93 insertions(+), 15 deletions(-) diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index debf4aae..c6beefa5 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -28,9 +28,7 @@ import java.awt.event.ActionListener; import javax.swing.BorderFactory; -import javax.swing.BoxLayout; import javax.swing.ButtonGroup; -import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JLabel; @@ -40,8 +38,8 @@ import javax.swing.event.ChangeListener; import bigwarp.BigWarp; -import bigwarp.WarpVisFrame; -import bigwarp.WarpVisFrame.MyChangeListener; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffType;; public class TransformTypeSelectDialog extends JDialog { @@ -69,6 +67,10 @@ public class TransformTypeSelectDialog extends JDialog private final JCheckBox autoEstimateMaskButton; + private final ButtonGroup falloffGroup; + private final JRadioButton gaussFalloffButton; + private final JRadioButton cosFalloffButton; + /** * Instantiates and displays a JFrame that enables * the selection of the transformation type. @@ -128,12 +130,39 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) "Transform type" ), BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - add( radioPanel, BorderLayout.LINE_START ); + add( radioPanel, BorderLayout.PAGE_START ); + + + // panel containing options for transforms and mask + JPanel optionsPanel = new JPanel( new GridLayout(0, 1)); + + optionsPanel.setBorder( BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), + BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "options" ), + BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); + + autoEstimateMaskButton = new JCheckBox( "Auto-estimate mask"); + optionsPanel.add( autoEstimateMaskButton ); - autoEstimateMaskButton = new JCheckBox( "Auto-estimate transform mask"); - radioPanel.add( autoEstimateMaskButton ); + cosFalloffButton = new JRadioButton( FalloffType.COSINE.toString() ); + gaussFalloffButton = new JRadioButton( FalloffType.GAUSSIAN.toString() ); + cosFalloffButton.setSelected( true ); - add( radioPanel, BorderLayout.LINE_END ); + addFalloffActionListender( cosFalloffButton ); + addFalloffActionListender( gaussFalloffButton ); + + falloffGroup = new ButtonGroup(); + falloffGroup.add( cosFalloffButton ); + falloffGroup.add( gaussFalloffButton ); + + optionsPanel.add( new JLabel( "Mask falloff shape" ) ); + optionsPanel.add( cosFalloffButton ); + optionsPanel.add( gaussFalloffButton ); + + add( optionsPanel, BorderLayout.PAGE_END ); pack(); addListeners(); @@ -151,8 +180,9 @@ private void addListeners() private synchronized void updateOptions() { - System.out.println( "update options"); autoEstimateMaskButton.setVisible( maskedTpsButton.isSelected() ); + cosFalloffButton.setVisible( maskedTpsButton.isSelected() ); + gaussFalloffButton.setVisible( maskedTpsButton.isSelected() ); pack(); } @@ -194,6 +224,20 @@ public void actionPerformed(ActionEvent e) { }); } + public void addFalloffActionListender( final JRadioButton button ) + { + button.addActionListener( new ActionListener() + { + @Override + public void actionPerformed( ActionEvent e ) + { + bw.getTpsMaskSource().getRandomAccessible().setType( button.getText() ); + bw.getViewerFrameP().getViewerPanel().requestRepaint(); + bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + } + } ); + } + public void setTransformType( String transformType ) { this.transformType = transformType; diff --git a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java index 92c39a49..38a516c2 100644 --- a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java +++ b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java @@ -92,6 +92,12 @@ public void setColors( final Color[] colors ) public void setVisible( final boolean visible ) { this.visible = visible; + viewer.requestRepaint(); + } + + public void toggleVisible() + { + setVisible( !visible ); } @Override diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index accc1492..ca8e39aa 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1775,9 +1775,6 @@ protected void addMaskMouseListener() maskSourceMouseListenerQ = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerQ ); maskSourceMouseListenerQ.setActive( false ); maskSourceMouseListenerQ.setMask( tpsMask.getRandomAccessible() ); - - viewerP.getMaskOverlay().setVisible( true ); - viewerQ.getMaskOverlay().setVisible( true ); } public void setGridType( final GridSource.GRID_TYPE method ) diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 7c34f553..cdacffc5 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -86,6 +86,7 @@ public class BigWarpActions public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; public static final String MASK_SIZE_EDIT = "mask edit"; + public static final String MASK_VIS_TOGGLE = "mask vis toggle"; public static final String SAVE_WARPED = "save warped"; public static final String SAVE_WARPED_XML = "save warped xml"; @@ -257,6 +258,7 @@ public static InputMap createInputMap( final KeyStrokeAdder.Factory keyPropertie map.put( ESTIMATE_WARP, "C" ); map.put( MASK_SIZE_EDIT, "M" ); + map.put( MASK_VIS_TOGGLE, "control M" ); map.put( UNDO, "control Z" ); map.put( REDO, "control Y" ); @@ -333,6 +335,7 @@ public static ActionMap createActionMap( final BigWarp< ? > bw ) // MASK new MaskSizeEdit( bw ).put(actionMap); + new MaskVisToggle( bw ).put(actionMap); for( int i = 0; i < bw.baseXfmList.length; i++ ){ final AbstractModel xfm = bw.baseXfmList[ i ]; @@ -1184,4 +1187,23 @@ public void actionPerformed(ActionEvent e) } } + public static class MaskVisToggle extends AbstractNamedAction + { + private static final long serialVersionUID = 493457851797644046L; + private final BigWarp< ? > bw; + + public MaskVisToggle( final BigWarp< ? > bw ) + { + super( MASK_VIS_TOGGLE ); + this.bw = bw; + } + + @Override + public void actionPerformed(ActionEvent e) + { + bw.getViewerFrameP().getViewerPanel().getMaskOverlay().toggleVisible(); + bw.getViewerFrameQ().getViewerPanel().getMaskOverlay().toggleVisible(); + } + } + } diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index e04bdf1e..15680d7e 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -128,7 +128,7 @@ public class WarpVisFrame extends JDialog public WarpVisFrame( final Frame owner, final BigWarp bw ) { - super( owner, "big warp options", false ); + super( owner, "Bigwarp options", false ); this.bw = bw; this.settings = bw.viewerSettings; diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 929fb782..8c710013 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -22,6 +22,8 @@ public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAcces { private BiConsumer< RealLocalizable, DoubleType > pfun; private FunctionRealRandomAccessible< DoubleType > rra; + + private int nd; private double plateauR; private double plateauR2; @@ -40,10 +42,10 @@ public static enum FalloffType { GAUSSIAN, COSINE }; public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) { + this.nd = n; this.center = center; -// pfun = new GaussianFalloff(); pfun = new CosineFalloff(); - rra = new FunctionRealRandomAccessible<>( n, pfun, DoubleType::new ); + update(); setRadius( 8.0 ); setSigma ( 10.0 ); @@ -92,6 +94,11 @@ public static void main( String[] args ) // System.out.println( x + "," + access.get().getRealDouble()); } + private void update() + { + rra = new FunctionRealRandomAccessible<>( nd, pfun, DoubleType::new ); + } + public void setType( String type ) { setType( FalloffType.valueOf( type )); @@ -102,9 +109,11 @@ public void setType( FalloffType type ) switch (type) { case GAUSSIAN: pfun = new GaussianFalloff(); + update(); break; case COSINE: pfun = new CosineFalloff(); + update(); break; default: break; From 3abd352945ee01d402dd0bf7f05a8b7abeb102bb Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 16 Aug 2022 11:53:23 -0400 Subject: [PATCH 023/282] fix: window positioning on startup --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 2 +- src/main/java/bigwarp/BigWarp.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 4d65f439..bae24aef 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -101,7 +101,7 @@ public BigWarpViewerFrame( { super( title, AWTUtils.getSuitableGraphicsConfiguration( AWTUtils.RGB_COLOR_MODEL ) ); this.bw = bw; - viewer = new BigWarpViewerPanel( sources, viewerSettings, cache, optional.size( width / 2, height ), isMoving, movingIndexList, targetIndexList ); + viewer = new BigWarpViewerPanel( sources, viewerSettings, cache, optional.size( width, height ), isMoving, movingIndexList, targetIndexList ); setups = new ConverterSetups( viewer.state() ); setups.listeners().add( s -> viewer.requestRepaint() ); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index ca8e39aa..c72f9016 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -554,11 +554,11 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie setUpLandmarkMenus(); /* Set the locations of frames */ - final Point viewerFramePloc = getViewerFrameP().getLocation(); - viewerFramePloc.setLocation( viewerFramePloc.x + DEFAULT_WIDTH, viewerFramePloc.y ); - getViewerFrameQ().setLocation( viewerFramePloc ); - viewerFramePloc.setLocation( viewerFramePloc.x + DEFAULT_WIDTH, viewerFramePloc.y ); - landmarkFrame.setLocation( viewerFramePloc ); + viewerFrameP.setLocation( 0, 0 ); + viewerFrameP.setSize( DEFAULT_WIDTH, DEFAULT_HEIGHT ); + viewerFrameQ.setLocation( DEFAULT_WIDTH, 0 ); + viewerFrameQ.setSize( DEFAULT_WIDTH, DEFAULT_HEIGHT ); + landmarkFrame.setLocation( 2 * DEFAULT_WIDTH, 0 ); landmarkClickListenerP = new MouseLandmarkListener( this.viewerP ); landmarkClickListenerQ = new MouseLandmarkListener( this.viewerQ ); From 8c140e9a013c02dd489ee26d40b5a3e0fc98ba7d Mon Sep 17 00:00:00 2001 From: bogovicj Date: Thu, 18 Aug 2022 09:49:32 -0400 Subject: [PATCH 024/282] feat: toward user-config actions --- pom.xml | 4 +- src/main/java/bdv/gui/BigWarpViewerFrame.java | 49 +++-- src/main/java/bigwarp/BigWarp.java | 179 ++++++++++++++---- src/main/java/bigwarp/BigWarpActions.java | 157 ++++++++++----- 4 files changed, 290 insertions(+), 99 deletions(-) diff --git a/pom.xml b/pom.xml index 61ee2a08..28826c46 100644 --- a/pom.xml +++ b/pom.xml @@ -119,8 +119,8 @@ 4.3.0 1.4.1 - 2.0.6 - 10.4.2 + 2.0.7 + 10.4.3 1.0.0-beta-30 sign,deploy-to-scijava diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 4d65f439..141ae25e 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -45,6 +45,8 @@ import bdv.tools.brightness.ConverterSetup; import bdv.ui.BdvDefaultCards; import bdv.ui.CardPanel; +import bdv.ui.appearance.AppearanceManager; +import bdv.ui.keymap.KeymapManager; import bdv.ui.splitpanel.SplitPanel; import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.BigWarpViewerSettings; @@ -67,15 +69,20 @@ public class BigWarpViewerFrame extends JFrame private CardPanel cards; + private final Behaviours transformBehaviours; + private final ConverterSetups setups; + private final KeymapManager keymapManager; + + private final AppearanceManager appearanceManager; + private static final long serialVersionUID = -7630931733043185034L; public BigWarpViewerFrame( BigWarp bw, final int width, final int height, final List< SourceAndConverter< ? > > sources, - final List< ConverterSetup > converterSetups, final BigWarpViewerSettings viewerSettings, final CacheControl cache, final String title, @@ -83,16 +90,20 @@ public BigWarpViewerFrame( final int[] movingIndexList, final int[] targetIndexList ) { - this( bw, width, height, sources, converterSetups, viewerSettings, cache, BigWarpViewerOptions.options(), title, isMoving, movingIndexList, targetIndexList ); + this( bw, width, height, sources, viewerSettings, cache, + new KeymapManager( BigWarp.configDir ), + new AppearanceManager( BigWarp.configDir ), + BigWarpViewerOptions.options(), title, isMoving, movingIndexList, targetIndexList ); } public BigWarpViewerFrame( BigWarp bw, final int width, final int height, final List< SourceAndConverter< ? > > sources, - final List< ConverterSetup > converterSetups, final BigWarpViewerSettings viewerSettings, final CacheControl cache, + final KeymapManager keymapManager, + final AppearanceManager appearanceManager, final BigWarpViewerOptions optional, final String title, final boolean isMoving, @@ -101,20 +112,24 @@ public BigWarpViewerFrame( { super( title, AWTUtils.getSuitableGraphicsConfiguration( AWTUtils.RGB_COLOR_MODEL ) ); this.bw = bw; + this.keymapManager = keymapManager; + this.appearanceManager = appearanceManager; + viewer = new BigWarpViewerPanel( sources, viewerSettings, cache, optional.size( width / 2, height ), isMoving, movingIndexList, targetIndexList ); setups = new ConverterSetups( viewer.state() ); setups.listeners().add( s -> viewer.requestRepaint() ); - if ( converterSetups.size() != sources.size() ) - System.err.println( "WARNING! Constructing BigWarp with converterSetups.size() that is not the same as sources.size()." ); - final int numSetups = Math.min( converterSetups.size(), sources.size() ); - for ( int i = 0; i < numSetups; ++i ) - { - final SourceAndConverter< ? > source = sources.get( i ); - final ConverterSetup setup = converterSetups.get( i ); - if ( setup != null ) - setups.put( source, setup ); - } +// if ( converterSetups.size() != sources.size() ) +// System.err.println( "WARNING! Constructing BigWarp with converterSetups.size() that is not the same as sources.size()." ); +// +// final int numSetups = Math.min( converterSetups.size(), sources.size() ); +// for ( int i = 0; i < numSetups; ++i ) +// { +// final SourceAndConverter< ? > source = sources.get( i ); +// final ConverterSetup setup = converterSetups.get( i ); +// if ( setup != null ) +// setups.put( source, setup ); +// } if ( !isMoving ) { @@ -154,16 +169,16 @@ public void valueChanged( ListSelectionEvent e ) } }); - SwingUtilities.replaceUIActionMap( getRootPane(), keybindings.getConcatenatedActionMap() ); - SwingUtilities.replaceUIInputMap( getRootPane(), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keybindings.getConcatenatedInputMap() ); + SwingUtilities.replaceUIActionMap( viewer, keybindings.getConcatenatedActionMap() ); + SwingUtilities.replaceUIInputMap( viewer, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keybindings.getConcatenatedInputMap() ); final MouseAndKeyHandler mouseAndKeyHandler = new MouseAndKeyHandler(); mouseAndKeyHandler.setInputMap( triggerbindings.getConcatenatedInputTriggerMap() ); mouseAndKeyHandler.setBehaviourMap( triggerbindings.getConcatenatedBehaviourMap() ); + mouseAndKeyHandler.setKeypressManager( optional.values.getKeyPressedManager(), viewer.getDisplayComponent() ); viewer.getDisplay().addHandler( mouseAndKeyHandler ); - // TODO: should be a field? - final Behaviours transformBehaviours = new Behaviours( optional.values.getInputTriggerConfig(), "bdv" ); + transformBehaviours = new Behaviours( optional.values.getInputTriggerConfig(), "bdv" ); transformBehaviours.install( triggerbindings, "transform" ); final TransformEventHandler tfHandler = viewer.getTransformEventHandler(); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index d9c450da..b54d1424 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -55,6 +55,7 @@ import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JCheckBox; +import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; @@ -83,6 +84,8 @@ import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import org.scijava.ui.behaviour.io.InputTriggerConfig; +import org.scijava.ui.behaviour.util.Actions; +import org.scijava.ui.behaviour.util.InputActionBindings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -109,6 +112,9 @@ import bdv.tools.brightness.BrightnessDialog; import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.SetupAssignments; +import bdv.ui.appearance.AppearanceManager; +import bdv.ui.keymap.Keymap; +import bdv.ui.keymap.KeymapManager; import bdv.util.Bounds; import bdv.viewer.BigWarpDragOverlay; import bdv.viewer.BigWarpLandmarkFrame; @@ -118,6 +124,7 @@ import bdv.viewer.Interpolation; import bdv.viewer.LandmarkPointMenu; import bdv.viewer.MultiBoxOverlay2d; +import bdv.viewer.NavigationActions; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bdv.viewer.SynchronizedViewerState; @@ -136,6 +143,7 @@ import bigwarp.transforms.BigWarpTransform; import bigwarp.transforms.WrappedCoordinateTransform; import bigwarp.util.BigWarpUtils; +import dev.dirs.ProjectDirectories; import fiji.util.gui.GenericDialogPlus; import ij.IJ; import ij.ImageJ; @@ -170,6 +178,7 @@ public class BigWarp< T > { + public static String configDir = ProjectDirectories.from( "sc", "fiji", "bigwarp" ).configDir; protected static final int DEFAULT_WIDTH = 600; @@ -200,6 +209,10 @@ public class BigWarp< T > protected final HelpDialog helpDialog; + private final KeymapManager keymapManager; + + private final AppearanceManager appearanceManager; + protected final SourceInfoDialog sourceInfoDialog; protected final VisibilityAndGroupingDialog activeSourcesDialogP; @@ -338,6 +351,17 @@ public BigWarp( final BigWarpData data, final String windowTitle, final Progr public BigWarp( final BigWarpData data, final String windowTitle, BigWarpViewerOptions options, final ProgressWriter progressWriter ) throws SpimDataException { + System.out.println( "BigWarp actions"); + final KeymapManager optionsKeymapManager = options.values.getKeymapManager(); + final AppearanceManager optionsAppearanceManager = options.values.getAppearanceManager(); + keymapManager = optionsKeymapManager != null ? optionsKeymapManager : new KeymapManager( configDir ); + appearanceManager = optionsAppearanceManager != null ? optionsAppearanceManager : new AppearanceManager( configDir ); + + InputTriggerConfig inputTriggerConfig = options.values.getInputTriggerConfig(); + final Keymap keymap = this.keymapManager.getForwardSelectedKeymap(); + if ( inputTriggerConfig == null ) + inputTriggerConfig = keymap.getConfig(); + repeatedKeyEventsFixer = RepeatingReleasedEventsFixer.installAnyTime(); ij = IJ.getInstance(); @@ -399,19 +423,15 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie viewerSettings = new BigWarpViewerSettings(); - // key properties - final InputTriggerConfig keyProperties = BigDataViewer.getInputTriggerConfig( options ); - options = options.inputTriggerConfig( keyProperties ); - // Viewer frame for the moving image - viewerFrameP = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, (List)sources, converterSetups, viewerSettings, - data.cache, options, "Bigwarp moving image", true, movingSourceIndexList, targetSourceIndexList ); + viewerFrameP = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, (List)sources, viewerSettings, + data.cache, keymapManager, appearanceManager, options, "Bigwarp moving image", true, movingSourceIndexList, targetSourceIndexList ); viewerP = getViewerFrameP().getViewerPanel(); // Viewer frame for the fixed image - viewerFrameQ = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, (List)sources, converterSetups, viewerSettings, - data.cache, options, "Bigwarp fixed image", false, movingSourceIndexList, targetSourceIndexList ); + viewerFrameQ = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, (List)sources, viewerSettings, + data.cache, keymapManager, appearanceManager, options, "Bigwarp fixed image", false, movingSourceIndexList, targetSourceIndexList ); viewerQ = getViewerFrameQ().getViewerPanel(); @@ -515,13 +535,32 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // dialogs have to be constructed before action maps are made warpVisDialog = new WarpVisFrame( viewerFrameQ, this ); - WarpNavigationActions.installActionBindings( getViewerFrameP().getKeybindings(), viewerFrameP, keyProperties, ( ndims == 2 ) ); - BigWarpActions.installActionBindings( getViewerFrameP().getKeybindings(), this, keyProperties ); +// WarpNavigationActions.installActionBindings( getViewerFrameP().getKeybindings(), viewerFrameP, inputTriggerConfig, ( ndims == 2 ) ); +// BigWarpActions.installActionBindings( getViewerFrameP().getKeybindings(), this, inputTriggerConfig ); +// +// WarpNavigationActions.installActionBindings( getViewerFrameQ().getKeybindings(), viewerFrameQ, inputTriggerConfig, ( ndims == 2 ) ); +// BigWarpActions.installActionBindings( getViewerFrameQ().getKeybindings(), this, inputTriggerConfig ); +// +// BigWarpActions.installLandmarkPanelActionBindings( landmarkFrame.getKeybindings(), this, landmarkTable, inputTriggerConfig ); + - WarpNavigationActions.installActionBindings( getViewerFrameQ().getKeybindings(), viewerFrameQ, keyProperties, ( ndims == 2 ) ); - BigWarpActions.installActionBindings( getViewerFrameQ().getKeybindings(), this, keyProperties ); +// System.out.println( "install actions" ); + BigWarpActions bwActions = new BigWarpActions( inputTriggerConfig, "bw", "bw-general" ); + BigWarpActions.installViewerActions( bwActions, getViewerFrameP().getKeybindings(), this ); + BigWarpActions.installViewerActions( bwActions, getViewerFrameQ().getKeybindings(), this ); - BigWarpActions.installLandmarkPanelActionBindings( landmarkFrame.getKeybindings(), this, landmarkTable, keyProperties ); + +// bwActions.installViewerActions( getViewerFrameQ().getKeybindings(), this ); +// BigWarpActions.install( bwActions, ) + + +// BigWarpActions.installViewerActions( getViewerFrameP().getKeybindings(), this, inputTriggerConfig ); +// BigWarpActions.installViewerActions( getViewerFrameQ().getKeybindings(), this, inputTriggerConfig ); + + +// final Actions navigationActions = new Actions( inputTriggerConfig, "bw-bdv", "navigation" ); +// navigationActions.install( viewerFrameP.getKeybindings(), "navigation" ); +// NavigationActions.install( navigationActions, viewerP, options.values.is2D() ); // this call has to come after the actions are set warpVisDialog.setActions(); @@ -1581,6 +1620,59 @@ else if ( viewerFrameQ.isActive() ) matchWindowTransforms( panelToChange, panelToMatch ); } + + /** + * Centers the active viewer at a landmark whose index is an increment from the currently + * selected landmark. + * + * @param inc the increment + */ + public void warpToLandmarkRelative( int inc ) + { + int[] selectedRows = getLandmarkPanel().getJTable().getSelectedRows(); + + int row = 0; + if( selectedRows.length > 0 ) + row = selectedRows[ selectedRows.length - 1 ]; + + row = row + inc; // increment to get the *next* row + + // wrap to start if necessary + if( row >= getLandmarkPanel().getTableModel().getRowCount() ) + row = 0; + else if( row < 0 ) + row = getLandmarkPanel().getTableModel().getRowCount() - 1; + + // select new row + getLandmarkPanel().getJTable().setRowSelectionInterval( row, row ); + + if( getViewerFrameP().isActive() ) + { + warpToLandmark( row, getViewerFrameP().getViewerPanel() ); + } + else + { + warpToLandmark( row, getViewerFrameQ().getViewerPanel() ); + } + } + + public void warpToNextLandmark() + { + warpToLandmarkRelative( 1 ); + } + + public void warpToPrevLandmark() + { + warpToLandmarkRelative( -1 ); + } + + public void warpToNearestLandmark() + { + if( getViewerFrameP().isActive() ) + warpToNearest( getViewerFrameP().getViewerPanel() ); + else + warpToNearest( getViewerFrameQ().getViewerPanel() ); + } public void warpToNearest( BigWarpViewerPanel viewer ) { @@ -1595,8 +1687,23 @@ public void warpToNearest( BigWarpViewerPanel viewer ) warpToLandmark( landmarkModel.getIndexNearestTo( mousePt, viewer.getIsMoving() ), viewer ); } + public void warpToSelectedLandmark() + { + final int[] selectedRows = getLandmarkPanel().getJTable().getSelectedRows(); + + int row = 0; + if( selectedRows.length > 0 ) + row = selectedRows[ 0 ]; + + if( getViewerFrameP().isActive() ) + warpToLandmark( row, getViewerFrameP().getViewerPanel() ); + else + warpToLandmark( row, getViewerFrameQ().getViewerPanel() ); + } + public void warpToLandmark( int row, BigWarpViewerPanel viewer ) { + System.out.println( "warp to landmark " + row ); if( inLandmarkMode ) { message.showMessage( "Can't move viewer in landmark mode." ); @@ -2482,29 +2589,29 @@ public void transferChannelSettings( final SetupAssignments setupAssignments, fi public void transferChannelSettings( final BigWarpViewerFrame viewer ) { - SynchronizedViewerState state = viewer.getViewerPanel().state(); - ConverterSetups setups = viewer.getConverterSetups(); - synchronized ( state ) - { - for ( SourceAndConverter< ? > sac : state.getSources() ) - { - if ( sourceColorSettings.containsKey( sac ) ) - { - if ( sourceColorSettings.get( sac ) == null ) - continue; - - sourceColorSettings.get( sac ).updateSetup( setups.getConverterSetup( sac ) ); - } - else - { - final int timepoint = state.getCurrentTimepoint(); - final Bounds bounds = InitializeViewerState.estimateSourceRange( sac.getSpimSource(), timepoint, 0.001, 0.999 ); - ConverterSetup cs = setups.getConverterSetup(sac); - if( cs != null ) - cs.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); - } - } - } +// SynchronizedViewerState state = viewer.getViewerPanel().state(); +// ConverterSetups setups = viewer.getConverterSetups(); +// synchronized ( state ) +// { +// for ( SourceAndConverter< ? > sac : state.getSources() ) +// { +// if ( sourceColorSettings.containsKey( sac ) ) +// { +// if ( sourceColorSettings.get( sac ) == null ) +// continue; +// +// sourceColorSettings.get( sac ).updateSetup( setups.getConverterSetup( sac ) ); +// } +// else +// { +// final int timepoint = state.getCurrentTimepoint(); +// final Bounds bounds = InitializeViewerState.estimateSourceRange( sac.getSpimSource(), timepoint, 0.001, 0.999 ); +// ConverterSetup cs = setups.getConverterSetup(sac); +// if( cs != null ) +// cs.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); +// } +// } +// } } } diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 96cfa15d..ad74be5f 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -33,8 +33,10 @@ import org.scijava.ui.behaviour.KeyStrokeAdder; import org.scijava.ui.behaviour.util.AbstractNamedAction; +import org.scijava.ui.behaviour.util.Actions; import org.scijava.ui.behaviour.util.InputActionBindings; +import bdv.BigDataViewerActions; import bdv.gui.BigWarpViewerFrame; import bdv.tools.ToggleDialogAction; import bdv.viewer.SourceAndConverter; @@ -45,68 +47,157 @@ import mpicbg.models.AbstractModel; import net.imglib2.realtransform.AffineTransform3D; -public class BigWarpActions +public class BigWarpActions extends Actions { public static final String LANDMARK_MODE_ON = "landmark mode on"; public static final String LANDMARK_MODE_OFF = "landmark mode off"; - public static final String TOGGLE_LANDMARK_MODE = "landmark mode toggle"; - public static final String TOGGLE_POINTS_VISIBLE = "toggle points visible"; + // General options + + // Display options + public static final String TOGGLE_LANDMARK_MODE = "landmark mode toggle"; + public static final String[] TOGGLE_LANDMARK_MODE_KEYS = new String[]{ "SPACE" }; + + public static final String TOGGLE_POINTS_VISIBLE = "toggle points visible"; + public static final String[] TOGGLE_POINTS_VISIBLE_KEYS = new String[]{ "V" }; + public static final String TOGGLE_POINT_NAMES_VISIBLE = "toggle point names visible"; + public static final String[] TOGGLE_POINT_NAMES_VISIBLE_KEYS = new String[]{ "N" }; + public static final String TOGGLE_MOVING_IMAGE_DISPLAY = "toggle moving image display"; + public static final String[] TOGGLE_MOVING_IMAGE_DISPLAY_KEYS = new String[]{ "T" }; + public static final String TOGGLE_BOX_AND_TEXT_OVERLAY_VISIBLE = "toggle box and text overlay visible"; + public static final String[] TOGGLE_BOX_AND_TEXT_OVERLAY_VISIBLE_KEYS = new String[]{ "F8" }; + public static final String ESTIMATE_WARP = "estimate warp"; + public static final String[] ESTIMATE_WARP_KEYS = new String[] { "C" }; + public static final String PRINT_TRANSFORM = "print transform"; + public static final String[] PRINT_TRANSFORM_KEYS = new String[]{ "control shift T" }; + public static final String TOGGLE_ESTIMATE_WARP_ONDRAG = "toggle estimate warp on drag"; + public static final String[] TOGGLE_ESTIMATE_WARP_ONDRAG_KEYS = new String[]{}; + +// public static final String CROP = "crop"; + + public static final String SAVE_SETTINGS = "save settings"; + public static final String LOAD_SETTINGS = "load settings"; + + public static final String BRIGHTNESS_SETTINGS = "brightness settings"; + public static final String VISIBILITY_AND_GROUPING = "visibility and grouping %s"; + public static final String SHOW_HELP = "help"; + public static final String SHOW_SOURCE_INFO = "show source info"; + // Warp visualization options public static final String SHOW_WARPTYPE_DIALOG = "show warp vis dialog" ; + public static final String SET_WARPTYPE_VIS = "set warp vis type %s" ; + public static final String SET_WARPTYPE_VIS_P = "p " + SET_WARPTYPE_VIS; + public static final String SET_WARPTYPE_VIS_Q = "q " + SET_WARPTYPE_VIS; public static final String WARPMAG_BASE = "set warpmag base %s"; public static final String WARPVISGRID = "set warp vis grid %s"; public static final String WARPVISDIALOG = "warp vis dialog"; - public static final String RESET_VIEWER = "reset active viewer"; + // Navigation options + public static final String RESET_VIEWER = "reset active viewer"; + public static final String[] RESET_VIEWER_KEYS = new String[]{"R"}; + public static final String ALIGN_VIEW_TRANSFORMS = "align view transforms %s"; - public static final String BRIGHTNESS_SETTINGS = "brightness settings"; - public static final String VISIBILITY_AND_GROUPING = "visibility and grouping %s"; - public static final String SHOW_HELP = "help"; - public static final String SHOW_SOURCE_INFO = "show source info"; + public static final String ALIGN_OTHER_TO_ACTIVE = String.format( ALIGN_VIEW_TRANSFORMS, AlignViewerPanelAction.TYPE.OTHER_TO_ACTIVE ); + public static final String[] ALIGN_OTHER_TO_ACTIVE_KEYS = new String[] { "Q" }; - public static final String CROP = "crop"; - public static final String SAVE_SETTINGS = "save settings"; - public static final String LOAD_SETTINGS = "load settings"; - public static final String LOAD_LANDMARKS = "load landmarks"; - public static final String SAVE_LANDMARKS = "save landmarks"; - public static final String QUICK_SAVE_LANDMARKS = "quick save landmarks"; + public static final String ALIGN_ACTIVE_TO_OTHER = String.format( ALIGN_VIEW_TRANSFORMS, AlignViewerPanelAction.TYPE.ACTIVE_TO_OTHER ); + public static final String[] ALIGN_ACTIVE_TO_OTHER_KEYS = new String[] { "W" }; - public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; - public static final String SAVE_WARPED = "save warped"; - public static final String SAVE_WARPED_XML = "save warped xml"; + public static final String WARP_TO_SELECTED_POINT = "warp to selected landmark"; + public static final String[] WARP_TO_SELECTED_POINT_KEYS = new String[]{ "D" }; - public static final String EXPORT_IP = "export imageplus"; - public static final String EXPORT_WARP = "export warp field"; - public static final String EXPORT_AFFINE = "export affine"; + public static final String WARP_TO_NEXT_POINT = "warp to next landmark"; + public static final String[] WARP_TO_NEXT_POINT_KEYS = new String[]{ "ctrl D"}; + + public static final String WARP_TO_PREV_POINT = "warp to prev landmark"; + public static final String[] WARP_TO_PREV_POINT_KEYS = new String[]{ "ctrl shift D"}; - public static final String WARP_TO_SELECTED_POINT = "warp to selected landmark"; - public static final String WARP_TO_NEXT_POINT = "warp to next landmark %s"; public static final String WARP_TO_NEAREST_POINT = "warp to nearest landmark"; + public static final String[] WARP_TO_NEAREST_POINT_KEYS = new String[]{ "E" }; + + // landmark options + public static final String LOAD_LANDMARKS = "load landmarks"; + public static final String[] LOAD_LANDMARKS_KEYS = new String[]{ "control O" }; + + public static final String SAVE_LANDMARKS = "save landmarks"; + public static final String[] SAVE_LANDMARKS_KEYS = new String[]{ "control S" }; + + public static final String QUICK_SAVE_LANDMARKS = "quick save landmarks"; + public static final String[] QUICK_SAVE_LANDMARKS_KEYS = new String[]{ "control Q" }; public static final String SET_BOOKMARK = "set bookmark"; + public static final String[] SET_BOOKMARK_KEYS = new String[]{ "shift B" }; + public static final String GO_TO_BOOKMARK = "go to bookmark"; + public static final String[] GO_TO_BOOKMARK_KEYS = new String[]{ "B" }; + public static final String GO_TO_BOOKMARK_ROTATION = "go to bookmark rotation"; + public static final String[] GO_TO_BOOKMARK_ROTATION_KEYS = new String[]{ "O" }; public static final String UNDO = "undo"; + public static final String[] UNDO_KEYS = new String[]{ "control Z" }; + public static final String REDO = "redo"; + public static final String[] REDO_KEYS = new String[]{ "control shift Z", "control Y" }; public static final String SELECT_TABLE_ROWS = "select table row %d"; + public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; + + // export options + public static final String SAVE_WARPED = "save warped"; + public static final String SAVE_WARPED_XML = "save warped xml"; + + public static final String EXPORT_IP = "export imageplus"; + public static final String EXPORT_WARP = "export warp field"; + public static final String EXPORT_AFFINE = "export affine"; + + public static final String DEBUG = "debug"; public static final String GARBAGE_COLLECTION = "garbage collection"; + public BigWarpActions( final KeyStrokeAdder.Factory keyConfig, String name ) + { + this( keyConfig, "bw", name ); + } + + public BigWarpActions( final KeyStrokeAdder.Factory keyConfig, String context, String name ) + { + super( keyConfig, context, name ); + } + + public static void installViewerActions( + Actions actions, + final InputActionBindings inputActionBindings, + final BigWarp< ? > bw ) + { + System.out.println( "install viewer actions" ); + actions.install( inputActionBindings, "bw" ); + + actions.runnableAction( () -> { bw.getBwTransform().transformToString(); }, PRINT_TRANSFORM, PRINT_TRANSFORM_KEYS); + actions.runnableAction( bw::toggleInLandmarkMode, TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS); + + // navigation + actions.runnableAction( bw::resetView, RESET_VIEWER, RESET_VIEWER_KEYS); + actions.runnableAction( bw::matchOtherViewerPanelToActive, ALIGN_OTHER_TO_ACTIVE, ALIGN_OTHER_TO_ACTIVE_KEYS ); + actions.runnableAction( bw::matchActiveViewerPanelToOther, ALIGN_ACTIVE_TO_OTHER, ALIGN_ACTIVE_TO_OTHER_KEYS ); + actions.runnableAction( bw::warpToSelectedLandmark, WARP_TO_SELECTED_POINT, WARP_TO_SELECTED_POINT_KEYS ); + actions.runnableAction( bw::warpToNearestLandmark, WARP_TO_NEAREST_POINT, WARP_TO_NEAREST_POINT_KEYS ); + actions.runnableAction( bw::warpToNextLandmark, WARP_TO_NEXT_POINT, WARP_TO_NEXT_POINT_KEYS ); + actions.runnableAction( bw::warpToPrevLandmark, WARP_TO_PREV_POINT, WARP_TO_PREV_POINT_KEYS ); + } + /** * Create BigWarp actions and install them in the specified * {@link InputActionBindings}. @@ -226,26 +317,6 @@ public static InputMap createInputMap( final KeyStrokeAdder.Factory keyPropertie map.put( SHOW_WARPTYPE_DIALOG, "U" ); map.put( TOGGLE_LANDMARK_MODE, "SPACE" ); -// map.put( LANDMARK_MODE_ON, "pressed SPACE" ); -// // the few lines below are super ugly, but are necessary for robustness -// map.put( LANDMARK_MODE_ON, "shift pressed SPACE" ); -// map.put( LANDMARK_MODE_ON, "ctrl pressed SPACE" ); -// map.put( LANDMARK_MODE_ON, "alt pressed SPACE" ); -// map.put( LANDMARK_MODE_ON, "alt ctrl pressed SPACE" ); -// map.put( LANDMARK_MODE_ON, "alt shift pressed SPACE" ); -// map.put( LANDMARK_MODE_ON, "ctrl shift pressed SPACE" ); -// map.put( LANDMARK_MODE_ON, "alt ctrl shift pressed SPACE" ); -// -// map.put( LANDMARK_MODE_OFF, "released SPACE", "released" ); -// // the few lines below are super ugly, but are necessary for robustness -// map.put( LANDMARK_MODE_OFF, "shift released SPACE", "released" ); -// map.put( LANDMARK_MODE_OFF, "ctrl released SPACE", "released" ); -// map.put( LANDMARK_MODE_OFF, "alt released SPACE", "released" ); -// map.put( LANDMARK_MODE_OFF, "alt ctrl released SPACE", "released" ); -// map.put( LANDMARK_MODE_OFF, "alt shift released SPACE", "released" ); -// map.put( LANDMARK_MODE_OFF, "ctrl shift released SPACE", "released" ); -// map.put( LANDMARK_MODE_OFF, "alt ctrl shift released SPACE", "released" ); - map.put( BRIGHTNESS_SETTINGS, "S" ); map.put( SHOW_HELP, "F1", "H" ); @@ -343,8 +414,6 @@ public static ActionMap createActionMap( final BigWarp< ? > bw ) return actionMap; } - private BigWarpActions(){} - public static class UndoRedoAction extends AbstractNamedAction { private static final long serialVersionUID = -5413579107763110117L; From b65a29ac6bfc138dfd977b38e9b5a687f8053052 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 22 Aug 2022 16:42:26 -0400 Subject: [PATCH 025/282] feat: reworking options ui * mask options * autosave options --- .../java/bdv/gui/AutosaveOptionsPanel.java | 186 ++++++++++++++++++ src/main/java/bdv/gui/MaskOptionsPanel.java | 162 +++++++++++++++ src/main/java/bigwarp/BigWarp.java | 18 +- src/main/java/bigwarp/WarpVisFrame.java | 155 +++------------ 4 files changed, 392 insertions(+), 129 deletions(-) create mode 100644 src/main/java/bdv/gui/AutosaveOptionsPanel.java create mode 100644 src/main/java/bdv/gui/MaskOptionsPanel.java diff --git a/src/main/java/bdv/gui/AutosaveOptionsPanel.java b/src/main/java/bdv/gui/AutosaveOptionsPanel.java new file mode 100644 index 00000000..3c90fac0 --- /dev/null +++ b/src/main/java/bdv/gui/AutosaveOptionsPanel.java @@ -0,0 +1,186 @@ +package bdv.gui; + +import java.awt.Container; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.File; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.JSpinner.DefaultEditor; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import bigwarp.BigWarp; +import bigwarp.BigWarpAutoSaver; + +public class AutosaveOptionsPanel extends JPanel +{ + private static final long serialVersionUID = 2449704984531905538L; + + private final BigWarp< ? > bw; + + private final SpinnerNumberModel savePeriodModel; + private final JSpinner autoSavePeriodSpinner; + private final JCheckBox doAutoSaveBox; + private final JTextField autoSaveFolderText; + + private int lastAutoSaveFreq = 5; + private boolean updating = false; + + public AutosaveOptionsPanel( final BigWarp< ? > bw, final Container content ) + { + super( new GridBagLayout() ); + this.bw = bw; + + doAutoSaveBox = new JCheckBox( "Auto-save landmarks" ); + + final JLabel autoSavePeriodLabel = new JLabel( "Frequency (minutes)" ); + autoSavePeriodSpinner = new JSpinner(); + savePeriodModel = new SpinnerNumberModel( 0, 0, 0, 1 ); + getAutoSavePeriodSpinner().setModel( savePeriodModel ); + ((DefaultEditor)getAutoSavePeriodSpinner().getEditor()).getTextField().setEditable( false ); + ((DefaultEditor)getAutoSavePeriodSpinner().getEditor()).getTextField().setEnabled( false ); + getAutoSavePeriodSpinner().addChangeListener( new ChangeListener() + { + @Override + public void stateChanged( ChangeEvent e ) + { + if ( getDoAutoSaveBox().isSelected() && !updating ) + { + long periodMillis = ((Integer) savePeriodModel.getValue()).longValue() * 60000; + BigWarpAutoSaver autoSaver = bw.getAutoSaver(); + if ( autoSaver != null ) + autoSaver.stop(); + + new BigWarpAutoSaver( bw, periodMillis ); + } + } + } ); + + getDoAutoSaveBox().addItemListener( new ItemListener() + { + @Override + public void itemStateChanged( ItemEvent e ) + { + bw.stopAutosave(); + if ( getDoAutoSaveBox().isSelected() ) + { + updating = true; + ((DefaultEditor)getAutoSavePeriodSpinner().getEditor()).getTextField().setEditable( true ); + ((DefaultEditor)getAutoSavePeriodSpinner().getEditor()).getTextField().setEnabled( true ); + savePeriodModel.setMinimum( 1 ); + savePeriodModel.setMaximum( 5000 ); + savePeriodModel.setValue( lastAutoSaveFreq ); + + long periodMillis = ((Integer) savePeriodModel.getValue()).longValue() * 60000; + new BigWarpAutoSaver( bw, periodMillis ); + updating = false; + } + else + { + lastAutoSaveFreq = ((Integer) savePeriodModel.getValue()); + savePeriodModel.setMinimum( 0 ); + savePeriodModel.setMaximum( 0 ); + savePeriodModel.setValue( 0 ); + ((DefaultEditor)getAutoSavePeriodSpinner().getEditor()).getTextField().setEditable( false ); + ((DefaultEditor)getAutoSavePeriodSpinner().getEditor()).getTextField().setEnabled( false ); + } + } + } ); + + final JLabel destDirLabel = new JLabel( "Directory" ); + final File startingFolder = bw.getBigwarpSettingsFolder(); + autoSaveFolderText = new JTextField(); + getAutoSaveFolderText().setText( startingFolder.getAbsolutePath() ); + + final JButton browseBtn = new JButton( "Browse" ); + browseBtn.addActionListener( e -> { + + final JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); + fileChooser.setCurrentDirectory( startingFolder ); + + final int ret = fileChooser.showOpenDialog( content ); + if ( ret == JFileChooser.APPROVE_OPTION ) + { + final File folder = fileChooser.getSelectedFile(); + getAutoSaveFolderText().setText( folder.getAbsolutePath() ); + bw.setAutosaveFolder( folder ); + } + } ); + + final GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.gridwidth = 1; + gbc.gridheight = 1; + gbc.weightx = 0.0; + gbc.anchor = GridBagConstraints.LINE_END; + gbc.fill = GridBagConstraints.NONE; + gbc.insets = new Insets( 5, 5, 5, 5 ); + + add( getDoAutoSaveBox(), gbc ); + + gbc.weightx = 1.0; + gbc.gridx = 2; + gbc.gridwidth = 1; + gbc.gridy = 0; + gbc.anchor = GridBagConstraints.LINE_END; + add( autoSavePeriodLabel, gbc ); + + gbc.gridx = 3; + gbc.gridwidth = 1; + gbc.weightx = 1.0; + gbc.anchor = GridBagConstraints.LINE_START; + gbc.fill = GridBagConstraints.HORIZONTAL; + add( getAutoSavePeriodSpinner(), gbc ); + + gbc.gridy = 2; + gbc.gridx = 0; + gbc.gridwidth = 1; + gbc.weightx = 0.0; + gbc.anchor = GridBagConstraints.LINE_START; + gbc.fill = GridBagConstraints.NONE; + add( destDirLabel, gbc ); + + gbc.gridy = 2; + gbc.gridx = 1; + gbc.gridwidth = 3; + gbc.weightx = 1.0; + gbc.anchor = GridBagConstraints.LINE_START; + gbc.fill = GridBagConstraints.HORIZONTAL; + add( getAutoSaveFolderText(), gbc ); + + gbc.gridx = 4; + gbc.weightx = 0.0; + gbc.anchor = GridBagConstraints.LINE_END; + gbc.fill = GridBagConstraints.NONE; + add( browseBtn, gbc ); + } + + public JSpinner getAutoSavePeriodSpinner() + { + return autoSavePeriodSpinner; + } + + public JCheckBox getDoAutoSaveBox() + { + return doAutoSaveBox; + } + + public JTextField getAutoSaveFolderText() + { + return autoSaveFolderText; + } + +} diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java new file mode 100644 index 00000000..fda53ba7 --- /dev/null +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -0,0 +1,162 @@ +package bdv.gui; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import bigwarp.BigWarp; +import bigwarp.BigWarpAutoSaver; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffType; +import bigwarp.source.PlateauSphericalMaskSource; + +public class MaskOptionsPanel extends JPanel +{ + private static final long serialVersionUID = -8614381106547838575L; + + private static final String FALLOFF_HELP_TEXT = "Controls the shape of the mask in the transition region."; + private static final String AUTO_ESTIMATE_HELP_TEXT = "If selected, the mask location and size will be dynamically updated as you add landmarks."; + private static final String SHOW_MASK_OVERLAY_HELP_TEXT = "Toggles the visibility of the mask overlay"; + private static final String INTERPOLATION_HELP_TEXT = "Controls whether a mask is applied to the transformation and how the transformation changes " + + "in the mask transition region.\n" + + "If your transformation has lots of rotation, try selecting \"ROTATION\" or \"SIMILARITY\"."; + + public static final String[] maskTypes = new String[] { + "NONE", + "LINEAR", + "SIMILARITY", + "ROTATION" + }; + + private final BigWarp< ? > bw; + + private final JCheckBox autoEstimateMaskButton; + private final JCheckBox showMaskOverlayButton; + + private final JLabel falloffTypeLabel; + private final JComboBox< FalloffType > falloffTypeDropdown; + + private final JLabel maskTypeLabel; + private final JComboBox< String > maskTypeDropdown; + + private ActionListener falloffListener; + + public MaskOptionsPanel( BigWarp bw ) + { + super( new GridBagLayout() ); + this.bw = bw; + + setBorder( BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), + BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "Mask options" ), + BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); + + autoEstimateMaskButton = new JCheckBox( "Auto-estimate mask"); + autoEstimateMaskButton.setToolTipText( AUTO_ESTIMATE_HELP_TEXT ); + + + showMaskOverlayButton = new JCheckBox( "Show mask overlay"); + showMaskOverlayButton.setToolTipText( SHOW_MASK_OVERLAY_HELP_TEXT ); + showMaskOverlayButton.addChangeListener( new ChangeListener() + { + @Override + public void stateChanged( ChangeEvent e ) + { + bw.setMaskOverlayVisibility( showMaskOverlayButton.isSelected() ); + } + } ); + + falloffTypeLabel = new JLabel( "Mask falloff"); + falloffTypeLabel .setToolTipText( FALLOFF_HELP_TEXT ); + falloffTypeDropdown = new JComboBox<>( FalloffType.values() ); + falloffTypeDropdown .setToolTipText( FALLOFF_HELP_TEXT ); + + maskTypeLabel = new JLabel( "Mask interpolation"); + maskTypeLabel.setToolTipText( INTERPOLATION_HELP_TEXT ); + maskTypeDropdown = new JComboBox<>( maskTypes ); + maskTypeDropdown.setToolTipText( INTERPOLATION_HELP_TEXT ); + + // layout + final GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 1; + gbc.gridheight = 1; + gbc.weightx = 0.0; + gbc.weighty = 0.0; + gbc.anchor = GridBagConstraints.LINE_END; + gbc.fill = GridBagConstraints.NONE; + gbc.insets = new Insets( 5, 5, 5, 5 ); + add( maskTypeLabel, gbc ); + + gbc.gridx = 2; + gbc.weightx = 0.0; + gbc.anchor = GridBagConstraints.LINE_START; + add( maskTypeDropdown, gbc ); + + gbc.gridx = 0; + gbc.gridy = 1; + gbc.anchor = GridBagConstraints.LINE_END; + add( falloffTypeLabel, gbc ); + + gbc.gridx = 2; + gbc.anchor = GridBagConstraints.LINE_START; + add( falloffTypeDropdown, gbc ); + + gbc.gridx = 0; + gbc.gridy = 2; + gbc.anchor = GridBagConstraints.LINE_END; + add( autoEstimateMaskButton, gbc ); + + gbc.gridx = 2; + gbc.gridy = 2; + gbc.anchor = GridBagConstraints.LINE_START; + add( showMaskOverlayButton, gbc ); + } + + public void setMask( PlateauSphericalMaskSource maskSource ) + { + if( falloffListener == null ) + falloffTypeDropdown.removeActionListener( falloffListener ); + + falloffTypeDropdown.addActionListener( new ActionListener() { + @Override + public void actionPerformed( ActionEvent e ) + { + maskSource.getRandomAccessible().setType( (FalloffType)falloffTypeDropdown.getSelectedItem() ); + bw.getViewerFrameP().getViewerPanel().requestRepaint(); + bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + } + }); + + } + + public JCheckBox getAutoEstimateMaskButton() + { + return autoEstimateMaskButton; + } + + public JCheckBox getShowMaskOverlayButton() + { + return showMaskOverlayButton; + } + + public JComboBox< FalloffType > getFalloffTypeDropdown() + { + return falloffTypeDropdown; + } + +} diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index c72f9016..461ef924 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -536,6 +536,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // dialogs have to be constructed before action maps are made warpVisDialog = new WarpVisFrame( viewerFrameQ, this ); + warpVisDialog.maskOptionsPanel.setMask( tpsMask ); WarpNavigationActions.installActionBindings( getViewerFrameP().getKeybindings(), viewerFrameP, keyProperties, ( ndims == 2 ) ); BigWarpActions.installActionBindings( getViewerFrameP().getKeybindings(), this, keyProperties ); @@ -1756,6 +1757,18 @@ public boolean toggleMovingImageDisplay() return success; } + public void toggleMaskOverlayVisibility() + { + getViewerFrameP().getViewerPanel().getMaskOverlay().toggleVisible(); + getViewerFrameQ().getViewerPanel().getMaskOverlay().toggleVisible(); + } + + public void setMaskOverlayVisibility( final boolean visible ) + { + getViewerFrameP().getViewerPanel().getMaskOverlay().setVisible( visible ); + getViewerFrameQ().getViewerPanel().getMaskOverlay().setVisible( visible ); + } + protected void addDefaultTableMouseListener() { landmarkTableListener = new MouseLandmarkTableListener(); @@ -2841,7 +2854,7 @@ public void tableChanged( final TableModelEvent e ) BigWarp.this.landmarkPanel.repaint(); } - if( transformSelector.autoEstimateMask() && bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS )) { + if( warpVisDialog.autoEstimateMask() && bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS )) { Sphere sph = BoundingSphereRitter.boundingSphere( landmarkModel.getFixedPointsCopy() ); tpsMask.getRandomAccessible().setCenter( sph.getCenter() ); tpsMask.getRandomAccessible().setRadius( sph.getRadius() ); @@ -3183,7 +3196,8 @@ public void setAutosaveFolder( final File autoSaveFolder ) if( exists && autoSaveFolder.isDirectory() ) { this.autoSaveDirectory = autoSaveFolder; - warpVisDialog.autoSaveFolderText.setText( autoSaveFolder.getAbsolutePath() ); + warpVisDialog.getAutoSaveOptionsPanel().getAutoSaveFolderText() + .setText( autoSaveFolder.getAbsolutePath() ); warpVisDialog.repaint(); } } diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index 15680d7e..7df448d1 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -64,6 +64,8 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import bdv.gui.AutosaveOptionsPanel; +import bdv.gui.MaskOptionsPanel; import bdv.viewer.BigWarpViewerSettings; import bigwarp.source.GridSource; import net.imglib2.realtransform.BoundingBoxEstimation; @@ -112,11 +114,12 @@ public class WarpVisFrame extends JDialog final JComboBox bboxMethodDropdown; final JSpinner samplesPerDimSpinner; + // mask + final MaskOptionsPanel maskOptionsPanel; + // autosave - final SpinnerNumberModel savePeriodModel; - final JSpinner autoSavePeriodSpinner; - final JCheckBox doAutoSaveBox; - final JTextField autoSaveFolderText; + private final AutosaveOptionsPanel autoSaveOptionsPanel; + public static final int minGridSpacing = 5; public static final int maxGridSpacing = 400; @@ -239,128 +242,6 @@ public WarpVisFrame( final Frame owner, final BigWarp bw ) typeOptionPanel.add( gridWidthSlider ); typeOptionPanel.add( noOptionsLabel ); - // autoSave Options panel - final JPanel autoSaveOptionsPanel = new JPanel(); - autoSaveOptionsPanel.setBorder( BorderFactory.createCompoundBorder( - BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), - BorderFactory.createCompoundBorder( - BorderFactory.createTitledBorder( - BorderFactory.createEtchedBorder(), - "Auto-save options" ), - BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - autoSaveOptionsPanel.setLayout( new GridBagLayout() ); - - final JLabel autosaveLabel = new JLabel("Auto-save landmarks"); - doAutoSaveBox = new JCheckBox(); - - final JLabel autoSavePeriodLabel = new JLabel("save frequency (minutes)"); - autoSavePeriodSpinner = new JSpinner(); - savePeriodModel = new SpinnerNumberModel( 5, 1, 5000, 1 ); - autoSavePeriodSpinner.setModel( savePeriodModel ); - autoSavePeriodSpinner.addChangeListener( new ChangeListener() - { - @Override - public void stateChanged( ChangeEvent e ) - { - if( doAutoSaveBox.isSelected() ) - { - long periodMillis = ( ( Integer ) savePeriodModel.getValue() ).longValue() * 60000; - BigWarpAutoSaver autoSaver = bw.getAutoSaver(); - if ( autoSaver != null ) - autoSaver.stop(); - - new BigWarpAutoSaver( bw, periodMillis ); - } - } - } ); - - doAutoSaveBox.addItemListener( new ItemListener() - { - @Override - public void itemStateChanged( ItemEvent e ) - { - bw.stopAutosave(); - - if ( doAutoSaveBox.isSelected() ) - { - long periodMillis = ( ( Integer ) savePeriodModel.getValue() ).longValue() * 60000; - new BigWarpAutoSaver( bw, periodMillis ); - } - } - }); - - final JLabel destDirLabel = new JLabel("Directory"); - final File startingFolder = bw.getBigwarpSettingsFolder(); - autoSaveFolderText = new JTextField(); - autoSaveFolderText.setText( startingFolder.getAbsolutePath() ); - - final JButton browseBtn = new JButton( "Browse" ); - browseBtn.addActionListener( e -> { - - final JFileChooser fileChooser = new JFileChooser(); - fileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); - fileChooser.setCurrentDirectory( startingFolder ); - - final int ret = fileChooser.showOpenDialog(content); - if (ret == JFileChooser.APPROVE_OPTION) - { - final File folder = fileChooser.getSelectedFile(); - autoSaveFolderText.setText( folder.getAbsolutePath() ); - bw.setAutosaveFolder( folder ); - } - }); - - final GridBagConstraints gbcAutoSave = new GridBagConstraints(); - gbcAutoSave.gridx = 0; - gbcAutoSave.gridy = 0; - gbcAutoSave.gridwidth = 2; - gbcAutoSave.gridheight = 1; - gbcAutoSave.weightx = 1.0; - gbcAutoSave.weighty = 0.0; - gbcAutoSave.anchor = GridBagConstraints.EAST; - gbcAutoSave.fill = GridBagConstraints.HORIZONTAL; - gbcAutoSave.insets = new Insets( 5, 5, 5, 5 ); - - autoSaveOptionsPanel.add( autosaveLabel, gbcAutoSave ); - - gbcAutoSave.gridx = 2; - gbcAutoSave.gridwidth = 1; - gbcAutoSave.weightx = 0.0; - gbcAutoSave.anchor = GridBagConstraints.WEST; - autoSaveOptionsPanel.add( doAutoSaveBox, gbcAutoSave ); - - gbcAutoSave.weightx = 1.0; - gbcAutoSave.gridx = 0; - gbcAutoSave.gridwidth = 2; - gbcAutoSave.gridy = 1; - gbcAutoSave.anchor = GridBagConstraints.EAST; - autoSaveOptionsPanel.add( autoSavePeriodLabel, gbcAutoSave ); - - gbcAutoSave.weightx = 0.0; - gbcAutoSave.gridx = 2; - gbcAutoSave.anchor = GridBagConstraints.WEST; - autoSaveOptionsPanel.add( autoSavePeriodSpinner, gbcAutoSave ); - - gbcAutoSave.gridy = 2; - gbcAutoSave.gridx = 0; - gbcAutoSave.gridwidth = 1; - gbcAutoSave.weightx = 0.0; - gbcAutoSave.anchor = GridBagConstraints.EAST; - autoSaveOptionsPanel.add( destDirLabel, gbcAutoSave ); - - gbcAutoSave.gridy = 2; - gbcAutoSave.gridx = 1; - gbcAutoSave.weightx = 1.0; - gbcAutoSave.anchor = GridBagConstraints.EAST; - autoSaveOptionsPanel.add( autoSaveFolderText, gbcAutoSave ); - - gbcAutoSave.gridx = 2; - gbcAutoSave.weightx = 0.0; - gbcAutoSave.anchor = GridBagConstraints.WEST; - autoSaveOptionsPanel.add( browseBtn, gbcAutoSave ); - - - final JPanel inverseOptionsPanel = new JPanel(); inverseOptionsPanel.setLayout( new BorderLayout( 10, 10 )); @@ -459,6 +340,13 @@ public void stateChanged( ChangeEvent e ) bboxPanel.add( samplerPerDimPanel, BorderLayout.SOUTH ); + // mask options + maskOptionsPanel = new MaskOptionsPanel( bw ); + + // autosaver options + autoSaveOptionsPanel = new AutosaveOptionsPanel( bw, content ); + + // organize panels content.setLayout( new GridBagLayout() ); final GridBagConstraints gbcContent = new GridBagConstraints(); gbcContent.gridx = 0; @@ -494,7 +382,10 @@ public void stateChanged( ChangeEvent e ) content.add( bboxPanel, gbcContent ); gbcContent.gridy = 4; - content.add( autoSaveOptionsPanel , gbcContent ); + content.add( maskOptionsPanel, gbcContent ); + + gbcContent.gridy = 5; + content.add( getAutoSaveOptionsPanel(), gbcContent ); setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE ); @@ -698,4 +589,14 @@ public int getIconHeight() return size; } } + + public boolean autoEstimateMask() + { + return maskOptionsPanel.getAutoEstimateMaskButton().isSelected(); + } + + public AutosaveOptionsPanel getAutoSaveOptionsPanel() + { + return autoSaveOptionsPanel; + } } From 7b2257fc66ac82f9ec7bd671a8add6717067c477 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 22 Aug 2022 16:43:01 -0400 Subject: [PATCH 026/282] fix: autosaver after ui changes --- src/main/java/bigwarp/BigWarpAutoSaver.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpAutoSaver.java b/src/main/java/bigwarp/BigWarpAutoSaver.java index f6368981..8f1b9b23 100644 --- a/src/main/java/bigwarp/BigWarpAutoSaver.java +++ b/src/main/java/bigwarp/BigWarpAutoSaver.java @@ -91,9 +91,9 @@ public static void setAutosaveOptions( final BigWarp bw, final long period, f if( period > 0 ) { - bw.warpVisDialog.doAutoSaveBox.setSelected( true ); + bw.warpVisDialog.getAutoSaveOptionsPanel().getDoAutoSaveBox().setSelected( true ); int periodMinutes = ( int ) ( period / 60000 ); - bw.warpVisDialog.autoSavePeriodSpinner.setValue( periodMinutes ); + bw.warpVisDialog.getAutoSaveOptionsPanel().getAutoSavePeriodSpinner().setValue( periodMinutes ); if( bw.autoSaver != null ) bw.autoSaver.stop(); @@ -102,7 +102,7 @@ public static void setAutosaveOptions( final BigWarp bw, final long period, f } else { - bw.warpVisDialog.doAutoSaveBox.setSelected( false ); + bw.warpVisDialog.getAutoSaveOptionsPanel().getDoAutoSaveBox().setSelected( false ); bw.warpVisDialog.repaint(); } } From c099832e199cfd055d8cc23821502b2296807567 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 23 Aug 2022 14:07:37 -0400 Subject: [PATCH 027/282] feat: masked transforms functional * can mask any type of transform type in any of three ways * re-worked UI * some code cleanup --- .../java/bdv/gui/AutosaveOptionsPanel.java | 2 +- .../gui/BigwarpLandmarkSelectionPanel.java | 5 - src/main/java/bdv/gui/MaskOptionsPanel.java | 33 ++++- .../bdv/gui/TransformTypeSelectDialog.java | 108 +++----------- .../java/bdv/viewer/BigWarpDragOverlay.java | 4 +- .../bdv/viewer/BigWarpViewerSettings.java | 2 - src/main/java/bigwarp/BigWarp.java | 10 +- .../landmarks/LandmarkGridGenerator.java | 3 - ...teauSphericalMaskRealRandomAccessible.java | 28 +++- .../transforms/AbstractTransformSolver.java | 58 ++++++++ .../bigwarp/transforms/BigWarpTransform.java | 136 ++++++++++-------- ....java => MaskedSimRotTransformSolver.java} | 34 +++-- ...Solver.java => MaskedTransformSolver.java} | 32 +++-- .../transforms/ModelTransformSolver.java | 8 +- .../transforms/TpsTransformSolver.java | 34 +---- .../MaskedSimilarityTransform.java | 31 +++- ...milarityTransformInterpolationExample.java | 3 +- 17 files changed, 286 insertions(+), 245 deletions(-) create mode 100644 src/main/java/bigwarp/transforms/AbstractTransformSolver.java rename src/main/java/bigwarp/transforms/{MaskedTpsSimTransformSolver.java => MaskedSimRotTransformSolver.java} (74%) rename src/main/java/bigwarp/transforms/{MaskedTpsTransformSolver.java => MaskedTransformSolver.java} (61%) diff --git a/src/main/java/bdv/gui/AutosaveOptionsPanel.java b/src/main/java/bdv/gui/AutosaveOptionsPanel.java index 3c90fac0..26206242 100644 --- a/src/main/java/bdv/gui/AutosaveOptionsPanel.java +++ b/src/main/java/bdv/gui/AutosaveOptionsPanel.java @@ -124,7 +124,7 @@ public void itemStateChanged( ItemEvent e ) gbc.gridy = 0; gbc.gridwidth = 1; gbc.gridheight = 1; - gbc.weightx = 0.0; + gbc.weightx = 1.0; gbc.anchor = GridBagConstraints.LINE_END; gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets( 5, 5, 5, 5 ); diff --git a/src/main/java/bdv/gui/BigwarpLandmarkSelectionPanel.java b/src/main/java/bdv/gui/BigwarpLandmarkSelectionPanel.java index 647dc4cb..97726cfb 100644 --- a/src/main/java/bdv/gui/BigwarpLandmarkSelectionPanel.java +++ b/src/main/java/bdv/gui/BigwarpLandmarkSelectionPanel.java @@ -138,12 +138,8 @@ public BigwarpLandmarkSelectionPanel( @Override public void actionPerformed( ActionEvent e ) { - System.out.println("ok"); filterPoints( matchedPtNames, outputIntervalList, selectionTable ); - System.out.println( matchedPtNames ); - System.out.println( outputIntervalList ); - ApplyBigwarpPlugin.runExport( data, sources, fieldOfViewOption, outputIntervalList, matchedPtNames, interp, offsetIn, resolution, isVirtual, nThreads, @@ -158,7 +154,6 @@ public void actionPerformed( ActionEvent e ) @Override public void actionPerformed( ActionEvent e ) { - //System.out.println("cancel"); frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); } }); diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index fda53ba7..8b37ad6d 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -19,6 +19,7 @@ import bigwarp.BigWarpAutoSaver; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffType; import bigwarp.source.PlateauSphericalMaskSource; +import bigwarp.transforms.BigWarpTransform; public class MaskOptionsPanel extends JPanel { @@ -33,9 +34,9 @@ public class MaskOptionsPanel extends JPanel public static final String[] maskTypes = new String[] { "NONE", - "LINEAR", - "SIMILARITY", - "ROTATION" + BigWarpTransform.MASK_INTERP, + BigWarpTransform.ROT_MASK_INTERP, + BigWarpTransform.SIM_MASK_INTERP, }; private final BigWarp< ? > bw; @@ -66,7 +67,15 @@ public MaskOptionsPanel( BigWarp bw ) autoEstimateMaskButton = new JCheckBox( "Auto-estimate mask"); autoEstimateMaskButton.setToolTipText( AUTO_ESTIMATE_HELP_TEXT ); - + autoEstimateMaskButton.addChangeListener( new ChangeListener() + { + @Override + public void stateChanged( ChangeEvent e ) + { + bw.setMaskOverlayVisibility( autoEstimateMaskButton.isSelected() ); + } + } ); + showMaskOverlayButton = new JCheckBox( "Show mask overlay"); showMaskOverlayButton.setToolTipText( SHOW_MASK_OVERLAY_HELP_TEXT ); @@ -80,15 +89,25 @@ public void stateChanged( ChangeEvent e ) } ); falloffTypeLabel = new JLabel( "Mask falloff"); - falloffTypeLabel .setToolTipText( FALLOFF_HELP_TEXT ); + falloffTypeLabel.setToolTipText( FALLOFF_HELP_TEXT ); falloffTypeDropdown = new JComboBox<>( FalloffType.values() ); - falloffTypeDropdown .setToolTipText( FALLOFF_HELP_TEXT ); + falloffTypeDropdown.setToolTipText( FALLOFF_HELP_TEXT ); maskTypeLabel = new JLabel( "Mask interpolation"); maskTypeLabel.setToolTipText( INTERPOLATION_HELP_TEXT ); maskTypeDropdown = new JComboBox<>( maskTypes ); maskTypeDropdown.setToolTipText( INTERPOLATION_HELP_TEXT ); - + maskTypeDropdown.addActionListener( new ActionListener() { + @Override + public void actionPerformed( ActionEvent e ) + { + bw.getBwTransform().setMask( maskTypeDropdown.getItemAt( maskTypeDropdown.getSelectedIndex() ) ); + bw.restimateTransformation(); + bw.getViewerFrameP().getViewerPanel().requestRepaint(); + bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + } + }); + // layout final GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index c6beefa5..47b3c99d 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -38,19 +38,26 @@ import javax.swing.event.ChangeListener; import bigwarp.BigWarp; -import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; -import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffType;; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffType; +import bigwarp.transforms.BigWarpTransform;; public class TransformTypeSelectDialog extends JDialog { private static final long serialVersionUID = 1L; + @Deprecated public static final String TPS = "Thin Plate Spline"; + @Deprecated public static final String MASKEDTPS = "Masked Thin Plate Spline"; + @Deprecated public static final String MASKEDSIMTPS = "Masked Similarity + Thin Plate Spline"; + @Deprecated public static final String AFFINE = "Affine"; + @Deprecated public static final String SIMILARITY = "Similarity"; + @Deprecated public static final String ROTATION = "Rotation"; + @Deprecated public static final String TRANSLATION = "Translation"; private final BigWarp< ? > bw; @@ -58,19 +65,11 @@ public class TransformTypeSelectDialog extends JDialog private final ButtonGroup group; private final JRadioButton tpsButton; - private final JRadioButton maskedTpsButton; - private final JRadioButton maskedSimTpsButton; private final JRadioButton affineButton; private final JRadioButton similarityButton; private final JRadioButton rotationButton; private final JRadioButton translationButton; - private final JCheckBox autoEstimateMaskButton; - - private final ButtonGroup falloffGroup; - private final JRadioButton gaussFalloffButton; - private final JRadioButton cosFalloffButton; - /** * Instantiates and displays a JFrame that enables * the selection of the transformation type. @@ -86,18 +85,14 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) this.setLayout( new BorderLayout() ); transformType = bw.getTransformType(); - tpsButton = new JRadioButton( TPS ); - maskedTpsButton = new JRadioButton( MASKEDTPS ); - maskedSimTpsButton = new JRadioButton( MASKEDSIMTPS ); - affineButton = new JRadioButton( AFFINE ); - similarityButton = new JRadioButton( SIMILARITY ); - rotationButton = new JRadioButton( ROTATION ); - translationButton = new JRadioButton( TRANSLATION ); + tpsButton = new JRadioButton( BigWarpTransform.TPS ); + affineButton = new JRadioButton( BigWarpTransform.AFFINE ); + similarityButton = new JRadioButton( BigWarpTransform.SIMILARITY ); + rotationButton = new JRadioButton( BigWarpTransform.ROTATION ); + translationButton = new JRadioButton( BigWarpTransform.TRANSLATION ); group = new ButtonGroup(); group.add( tpsButton ); - group.add( maskedTpsButton ); - group.add( maskedSimTpsButton ); group.add( affineButton ); group.add( similarityButton ); group.add( rotationButton ); @@ -106,8 +101,6 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) updateButtonGroup(); addActionListender( tpsButton ); - addActionListender( maskedTpsButton ); - addActionListender( maskedSimTpsButton ); addActionListender( affineButton ); addActionListender( similarityButton ); addActionListender( rotationButton ); @@ -115,8 +108,6 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) JPanel radioPanel = new JPanel( new GridLayout(0, 1)); radioPanel.add( tpsButton ); - radioPanel.add( maskedTpsButton ); - radioPanel.add( maskedSimTpsButton ); radioPanel.add( affineButton ); radioPanel.add( similarityButton ); radioPanel.add( rotationButton ); @@ -132,57 +123,6 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) add( radioPanel, BorderLayout.PAGE_START ); - - // panel containing options for transforms and mask - JPanel optionsPanel = new JPanel( new GridLayout(0, 1)); - - optionsPanel.setBorder( BorderFactory.createCompoundBorder( - BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), - BorderFactory.createCompoundBorder( - BorderFactory.createTitledBorder( - BorderFactory.createEtchedBorder(), - "options" ), - BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - - autoEstimateMaskButton = new JCheckBox( "Auto-estimate mask"); - optionsPanel.add( autoEstimateMaskButton ); - - cosFalloffButton = new JRadioButton( FalloffType.COSINE.toString() ); - gaussFalloffButton = new JRadioButton( FalloffType.GAUSSIAN.toString() ); - cosFalloffButton.setSelected( true ); - - addFalloffActionListender( cosFalloffButton ); - addFalloffActionListender( gaussFalloffButton ); - - falloffGroup = new ButtonGroup(); - falloffGroup.add( cosFalloffButton ); - falloffGroup.add( gaussFalloffButton ); - - optionsPanel.add( new JLabel( "Mask falloff shape" ) ); - optionsPanel.add( cosFalloffButton ); - optionsPanel.add( gaussFalloffButton ); - - add( optionsPanel, BorderLayout.PAGE_END ); - - pack(); - addListeners(); - updateOptions(); - } - - private void addListeners() - { - maskedTpsButton.addChangeListener( new ChangeListener() { - @Override - public void stateChanged( ChangeEvent e ) { updateOptions(); } - }); - - } - - private synchronized void updateOptions() - { - autoEstimateMaskButton.setVisible( maskedTpsButton.isSelected() ); - cosFalloffButton.setVisible( maskedTpsButton.isSelected() ); - gaussFalloffButton.setVisible( maskedTpsButton.isSelected() ); pack(); } @@ -190,25 +130,19 @@ private void updateButtonGroup() { switch( transformType ) { - case TPS: + case BigWarpTransform.TPS: tpsButton.setSelected( true ); break; - case MASKEDTPS: - maskedTpsButton.setSelected( true ); - break; - case MASKEDSIMTPS: - maskedSimTpsButton.setSelected( true ); - break; - case AFFINE: + case BigWarpTransform.AFFINE: affineButton.setSelected( true ); break; - case SIMILARITY: + case BigWarpTransform.SIMILARITY: similarityButton.setSelected( true ); break; - case ROTATION: + case BigWarpTransform.ROTATION: rotationButton.setSelected( true ); break; - case TRANSLATION: + case BigWarpTransform.TRANSLATION: translationButton.setSelected( true ); break; } @@ -246,8 +180,4 @@ public void setTransformType( String transformType ) this.repaint(); } - public boolean autoEstimateMask() - { - return autoEstimateMaskButton.isSelected(); - } } diff --git a/src/main/java/bdv/viewer/BigWarpDragOverlay.java b/src/main/java/bdv/viewer/BigWarpDragOverlay.java index 3a4fcf7c..90897cf2 100644 --- a/src/main/java/bdv/viewer/BigWarpDragOverlay.java +++ b/src/main/java/bdv/viewer/BigWarpDragOverlay.java @@ -81,13 +81,11 @@ public void paint( final Graphics2D g ) { arad = viewer.getSettings().getSpotSize(); baseColor = viewer.getSettings().getSpotColor(); - - // System.out.println("BigWarpDragOverlay - PAINT" ); + if( inProgress ) { viewer.state().getViewerTransform( transform ); - //System.out.println("BigWarpDragOverlay - PAINT IN PROGRESS" ); transform.apply( movingPoint, movingPointScreen ); transform.apply( targetPoint, targetPointScreen ); diff --git a/src/main/java/bdv/viewer/BigWarpViewerSettings.java b/src/main/java/bdv/viewer/BigWarpViewerSettings.java index 3af4ccea..5c7ea4fd 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerSettings.java +++ b/src/main/java/bdv/viewer/BigWarpViewerSettings.java @@ -120,8 +120,6 @@ public Boolean areLandmarksVisible(){ public void togglePointsVisible(){ displaySettings.put( KEY_SPOTS_VISIBLE, !((Boolean)displaySettings.get( KEY_SPOTS_VISIBLE )).booleanValue()); - - //System.out.println(((Boolean)displaySettings.get( KEY_DISPLAY_SPOT_NAMES ))); } public void setSpotColor( Color c ) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 461ef924..2981a8de 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -794,6 +794,11 @@ protected void setUpViewerMenu( final BigWarpViewerFrame vframe ) miBrightness.setText( "Brightness & Color" ); settingsMenu.add( miBrightness ); + /* */ + final JMenuItem transformTypeMenu = new JMenuItem( actionMap.get( BigWarpActions.TRANSFORM_TYPE ) ); + transformTypeMenu.setText( "Transformation Options" ); + settingsMenu.add( transformTypeMenu ); + /* Warp Visualization */ final JMenuItem warpVisMenu = new JMenuItem( actionMap.get( BigWarpActions.SHOW_WARPTYPE_DIALOG ) ); warpVisMenu.setText( "BigWarp Options" ); @@ -2848,13 +2853,14 @@ public void tableChanged( final TableModelEvent e ) { // re-estimate if a a point was set to or from active // note - this covers "resetting" points as well - if( e.getColumn() == LandmarkTableModel.ACTIVECOLUMN ) + if ( e.getColumn() == LandmarkTableModel.ACTIVECOLUMN ) { BigWarp.this.restimateTransformation(); BigWarp.this.landmarkPanel.repaint(); } - if( warpVisDialog.autoEstimateMask() && bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS )) { + if ( warpVisDialog.autoEstimateMask() && bwTransform.isMasked() ) + { Sphere sph = BoundingSphereRitter.boundingSphere( landmarkModel.getFixedPointsCopy() ); tpsMask.getRandomAccessible().setCenter( sph.getCenter() ); tpsMask.getRandomAccessible().setRadius( sph.getRadius() ); diff --git a/src/main/java/bigwarp/landmarks/LandmarkGridGenerator.java b/src/main/java/bigwarp/landmarks/LandmarkGridGenerator.java index cbff5272..1333175d 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkGridGenerator.java +++ b/src/main/java/bigwarp/landmarks/LandmarkGridGenerator.java @@ -84,8 +84,6 @@ public int fill( LandmarkTableModel ltm ) it.fwd(); it.localize( p ); - //System.out.println( "Adding: " + Arrays.toString( p )); - // ltm makes a copy, so can re-use p ltm.add( p, true ); ltm.setPoint( ltm.getNextRow( false ), false, p, null ); @@ -164,7 +162,6 @@ public static boolean fillFromDialog( final BigWarp bw ) } double N = gen.approxNumberOfPoints(); - System.out.println("N : " + N ); if( N > 1 ) { final GenericDialog warningDialog = new GenericDialog( "Warning" ); diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 8c710013..daabc088 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -38,7 +38,7 @@ public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAcces private static final double PIon2 = Math.PI / 2.0; private static final double PI = Math.PI; - public static enum FalloffType { GAUSSIAN, COSINE }; + public static enum FalloffType { COSINE, GAUSSIAN, LINEAR }; public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) { @@ -115,6 +115,10 @@ public void setType( FalloffType type ) pfun = new CosineFalloff(); update(); break; + case LINEAR: + pfun = new LinearFalloff(); + update(); + break; default: break; } @@ -306,7 +310,7 @@ public void accept( RealLocalizable x, DoubleType v ) final double r = Math.sqrt( r2 ); if( r2 <= plateauR2 ) v.setOne(); - else if ( r > plateauR + 2 * sigma ) + else if ( r >= plateauR + 2 * sigma ) v.setZero(); else { @@ -319,4 +323,24 @@ else if ( r > plateauR + 2 * sigma ) } } + public class LinearFalloff implements BiConsumer< RealLocalizable, DoubleType > { + + @Override + public void accept( RealLocalizable x, DoubleType v ) + { + v.setZero(); + final double r2 = squaredDistance( x, center ); + final double d2 = plateauR + sigma; + if( r2 <= plateauR2 ) + v.setOne(); + else if( r2 >= d2 * d2 ) + v.setZero(); + else + { + final double r = Math.sqrt( r2 ); + v.set( 1 - (r - plateauR) / sigma ); + } + } + } + } diff --git a/src/main/java/bigwarp/transforms/AbstractTransformSolver.java b/src/main/java/bigwarp/transforms/AbstractTransformSolver.java new file mode 100644 index 00000000..8a0c81d5 --- /dev/null +++ b/src/main/java/bigwarp/transforms/AbstractTransformSolver.java @@ -0,0 +1,58 @@ +/*- + * #%L + * BigWarp plugin for Fiji. + * %% + * Copyright (C) 2015 - 2021 Howard Hughes Medical Institute. + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package bigwarp.transforms; + +import bigwarp.landmarks.LandmarkTableModel; +import net.imglib2.realtransform.InvertibleRealTransform; + +public abstract class AbstractTransformSolver implements TransformSolver +{ + protected double[][] mvgPts; + protected double[][] tgtPts; + + public T solve( final LandmarkTableModel landmarkTable ) + { + return solve( landmarkTable, -1 ); + } + + public T solve( final LandmarkTableModel landmarkTable, final int indexChanged ) + { + synchronized( landmarkTable ) + { + int numActive = landmarkTable.numActive(); + int ndims = landmarkTable.getNumdims(); + + if( mvgPts == null || mvgPts[0].length != numActive ) + { + mvgPts = new double[ ndims ][ numActive ]; + tgtPts = new double[ ndims ][ numActive ]; + landmarkTable.copyLandmarks( mvgPts, tgtPts ); + } + else if( indexChanged >= 0 ) + { + landmarkTable.copyLandmarks( indexChanged, mvgPts, tgtPts ); + } + } + + return solve( mvgPts, tgtPts ); + } +} diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 99e02719..d38542a5 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -49,6 +49,7 @@ import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.InverseRealTransform; import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.MaskedSimilarityTransform.Interpolators; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.Wrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; @@ -56,12 +57,24 @@ public class BigWarpTransform { + public static final String TPS = "Thin Plate Spline"; + public static final String AFFINE = "Affine"; + public static final String SIMILARITY = "Similarity"; + public static final String ROTATION = "Rotation"; + public static final String TRANSLATION = "Translation"; + + public static final String MASK_INTERP = "LINEAR"; + public static final String SIM_MASK_INTERP = "SIMILARITY"; + public static final String ROT_MASK_INTERP = "ROTATION"; + private final int ndims; private final LandmarkTableModel tableModel; private String transformType; - + + private String maskType; + private InvertibleRealTransform currentTransform; private double inverseTolerance = 0.5; @@ -70,9 +83,11 @@ public class BigWarpTransform private RealRandomAccessible> lambda; + private AbstractTransformSolver solver; + public BigWarpTransform( final LandmarkTableModel tableModel ) { - this( tableModel, TransformTypeSelectDialog.TPS ); + this( tableModel, TPS ); } public BigWarpTransform( final LandmarkTableModel tableModel, final String transformType ) @@ -80,11 +95,57 @@ public BigWarpTransform( final LandmarkTableModel tableModel, final String trans this.tableModel = tableModel; this.ndims = tableModel.getNumdims(); this.transformType = transformType; + this.maskType = "NONE"; + updateSolver(); } public void setTransformType( final String transformType ) { this.transformType = transformType; + updateSolver(); + } + + public void setMask( String maskType ) + { + this.maskType = maskType; + updateSolver(); + } + + public String getMask() + { + return maskType; + } + + public boolean isMasked() + { + return maskType.equals( MASK_INTERP ) || maskType.equals( ROT_MASK_INTERP ) || maskType.equals( SIM_MASK_INTERP ); + } + + public void updateSolver() + { + if ( transformType.equals( TPS ) ) + { + solver = new TpsTransformSolver(); + } + else + { + solver = new ModelTransformSolver( getModelType() ); + } + + if ( maskType.equals( MASK_INTERP ) ) + { + solver = new MaskedTransformSolver( solver, lambda ); + } + else if ( maskType.equals( ROT_MASK_INTERP ) || maskType.equals( SIM_MASK_INTERP ) ) + { + final double[] center = new double[ 3 ]; + if ( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) + { + ((PlateauSphericalMaskRealRandomAccessible) lambda).getCenter() + .localize( center ); + } + solver = new MaskedSimRotTransformSolver( solver, lambda, center, Interpolators.valueOf( maskType ) ); + } } public void setInverseTolerance( double inverseTolerance ) @@ -130,59 +191,16 @@ public InvertibleRealTransform getTransformation() public InvertibleRealTransform getTransformation( final int index ) { InvertibleRealTransform invXfm = null; - if( transformType.equals( TransformTypeSelectDialog.TPS )) + if( transformType.equals( TPS )) { - WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( tableModel ); + WrappedIterativeInvertibleRealTransform tpsXfm = (WrappedIterativeInvertibleRealTransform< ? >) solver.solve( tableModel, index ); tpsXfm.getOptimzer().setMaxIters(maxIterations); tpsXfm.getOptimzer().setTolerance(inverseTolerance); invXfm = tpsXfm; } - else if( transformType.equals( TransformTypeSelectDialog.MASKEDTPS )) - { - /* - * TPS ONLY - */ - WrappedIterativeInvertibleRealTransform tpsXfm = new MaskedTpsTransformSolver( lambda ).solve( tableModel ); - tpsXfm.getOptimzer().setMaxIters(maxIterations); - tpsXfm.getOptimzer().setTolerance(inverseTolerance); - invXfm = new WrappedIterativeInvertibleRealTransform( tpsXfm ); - - } - else if( transformType.equals( TransformTypeSelectDialog.MASKEDSIMTPS )) - { - - /* - * SIMILARITY AND TPS - resolving tps with transformed points - */ - final double[][] mvgPts; - final double[][] tgtPts; - - final int numActive = tableModel.numActive(); - mvgPts = new double[ ndims ][ numActive ]; - tgtPts = new double[ ndims ][ numActive ]; - tableModel.copyLandmarks( mvgPts, tgtPts ); // synchronized - - final double[] center = new double[3]; - if( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) - { - ((PlateauSphericalMaskRealRandomAccessible)lambda).getCenter().localize( center ); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - MaskedTpsSimTransformSolver> solver = new MaskedTpsSimTransformSolver( lambda, center ); - invXfm = solver.solve( mvgPts, tgtPts ); - } else { - final double[][] mvgPts; - final double[][] tgtPts; - - final int numActive = tableModel.numActive(); - mvgPts = new double[ ndims ][ numActive ]; - tgtPts = new double[ ndims ][ numActive ]; - tableModel.copyLandmarks( mvgPts, tgtPts ); // synchronized - - invXfm = new ModelTransformSolver( getModelType() ).solve(mvgPts, tgtPts); + invXfm = solver.solve(tableModel, index); } if( tableModel.getNumdims() == 2 ) @@ -226,13 +244,13 @@ public Model getModelType() public AbstractAffineModel3D getModel3D() { switch( transformType ){ - case TransformTypeSelectDialog.AFFINE: + case AFFINE: return new AffineModel3D(); - case TransformTypeSelectDialog.SIMILARITY: + case SIMILARITY: return new SimilarityModel3D(); - case TransformTypeSelectDialog.ROTATION: + case ROTATION: return new RigidModel3D(); - case TransformTypeSelectDialog.TRANSLATION: + case TRANSLATION: return new TranslationModel3D(); } return null; @@ -241,13 +259,13 @@ public AbstractAffineModel3D getModel3D() public AbstractAffineModel2D getModel2D() { switch( transformType ){ - case TransformTypeSelectDialog.AFFINE: + case AFFINE: return new AffineModel2D(); - case TransformTypeSelectDialog.SIMILARITY: + case SIMILARITY: return new SimilarityModel2D(); - case TransformTypeSelectDialog.ROTATION: + case ROTATION: return new RigidModel2D(); - case TransformTypeSelectDialog.TRANSLATION: + case TRANSLATION: return new TranslationModel2D(); } return null; @@ -255,7 +273,7 @@ public AbstractAffineModel2D getModel2D() public InvertibleCoordinateTransform getCoordinateTransform() { - if( !transformType.equals( TransformTypeSelectDialog.TPS )) + if( !transformType.equals( TPS )) { WrappedCoordinateTransform wct = (WrappedCoordinateTransform)( unwrap2d( getTransformation() )); return wct.getTransform(); @@ -335,7 +353,7 @@ public ThinPlateR2LogRSplineKernelTransform getTpsBase() public ThinplateSplineTransform getTps() { - if( transformType.equals( TransformTypeSelectDialog.TPS )) + if( transformType.equals( TPS )) { WrappedIterativeInvertibleRealTransform wiirt = (WrappedIterativeInvertibleRealTransform)( unwrap2d( getTransformation()) ); return ((ThinplateSplineTransform)wiirt.getTransform()); @@ -388,7 +406,7 @@ else if( currentTransform instanceof Wrapped2DTransformAs3D ) public String affineToString() { String s = ""; - if( getTransformType().equals( TransformTypeSelectDialog.TPS )) + if( getTransformType().equals( TPS )) { double[][] affine = affinePartOfTpsHC(); for( int r = 0; r < affine.length; r++ ) diff --git a/src/main/java/bigwarp/transforms/MaskedTpsSimTransformSolver.java b/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java similarity index 74% rename from src/main/java/bigwarp/transforms/MaskedTpsSimTransformSolver.java rename to src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java index 78ee57c9..b0ff1d85 100644 --- a/src/main/java/bigwarp/transforms/MaskedTpsSimTransformSolver.java +++ b/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java @@ -23,50 +23,56 @@ import bdv.viewer.animate.SimilarityModel3D; import bigwarp.landmarks.LandmarkTableModel; -import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import mpicbg.models.AbstractAffineModel3D; -import net.imglib2.RandomAccessible; +import mpicbg.models.RigidModel3D; import net.imglib2.RealRandomAccessible; import net.imglib2.realtransform.SpatiallyInterpolatedRealTransform; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.MaskedSimilarityTransform; +import net.imglib2.realtransform.MaskedSimilarityTransform.Interpolators; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.RealTransformSequence; -import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.RealType; -public class MaskedTpsSimTransformSolver> implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> +public class MaskedSimRotTransformSolver> extends AbstractTransformSolver< WrappedIterativeInvertibleRealTransform< ? >> { - private final TpsTransformSolver tpsSolver; - private final ModelTransformSolver simSolver; + private final AbstractTransformSolver baseSolver; + private final ModelTransformSolver interpSolver; private final RealRandomAccessible lambda; private final double[] center; + private final Interpolators interp; - public MaskedTpsSimTransformSolver( RealRandomAccessible lambda, double[] center) + public MaskedSimRotTransformSolver( AbstractTransformSolver solver, RealRandomAccessible lambda, double[] center, Interpolators interp ) { this.lambda = lambda; this.center = center; - tpsSolver = new TpsTransformSolver(); - simSolver = new ModelTransformSolver( new SimilarityModel3D() ); + this.interp = interp; + baseSolver = solver; + + if( interp == Interpolators.SIMILARITY ) + interpSolver = new ModelTransformSolver( new SimilarityModel3D() ); + else + interpSolver = new ModelTransformSolver( new RigidModel3D() ); } + @SuppressWarnings("rawtypes") public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { - WrappedCoordinateTransform simXfm = simSolver.solve( mvgPts, tgtPts ); + WrappedCoordinateTransform simXfm = interpSolver.solve( mvgPts, tgtPts ); AffineTransform3D sim = new AffineTransform3D(); BigWarpTransform.affine3d( (AbstractAffineModel3D)simXfm.getTransform(), sim ); - @SuppressWarnings({ "rawtypes", "rawtypes" }) - final MaskedSimilarityTransform msim = new MaskedSimilarityTransform( sim, lambda, center ); + final MaskedSimilarityTransform msim = new MaskedSimilarityTransform( sim, lambda, center, interp ); final double[][] xfmMvg = transformPoints( simXfm, mvgPts ); - final WrappedIterativeInvertibleRealTransform< ? > tps = tpsSolver.solve( xfmMvg, tgtPts ); + final InvertibleRealTransform baseTransform = baseSolver.solve( xfmMvg, tgtPts ); final RealTransformSequence seq = new RealTransformSequence(); seq.add( msim ); - seq.add( tps ); + seq.add( baseTransform ); return wrap( seq, lambda ); } diff --git a/src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java b/src/main/java/bigwarp/transforms/MaskedTransformSolver.java similarity index 61% rename from src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java rename to src/main/java/bigwarp/transforms/MaskedTransformSolver.java index 49573cf3..f43bf9e7 100644 --- a/src/main/java/bigwarp/transforms/MaskedTpsTransformSolver.java +++ b/src/main/java/bigwarp/transforms/MaskedTransformSolver.java @@ -32,38 +32,42 @@ import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.RealType; -public class MaskedTpsTransformSolver> implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> +public class MaskedTransformSolver, S extends AbstractTransformSolver > extends AbstractTransformSolver< WrappedIterativeInvertibleRealTransform< ? >> { - // TODO make regularization transform of a more general type - private final TpsTransformSolver tpsSolver; + private final S solver; + private final RealRandomAccessible lambda; - public MaskedTpsTransformSolver( RealRandomAccessible lambda ) + public MaskedTransformSolver( final S solver, final RealRandomAccessible lambda ) { this.lambda = lambda; - tpsSolver = new TpsTransformSolver(); + this.solver = solver; + } + + public S getSolver() + { + return solver; } public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { - return wrap( tpsSolver.solve( mvgPts, tgtPts ), lambda ); + return wrap( solver.solve( mvgPts, tgtPts ), lambda ); } - public WrappedIterativeInvertibleRealTransform solve( - final LandmarkTableModel landmarkTable ) + public WrappedIterativeInvertibleRealTransform< ? > solve( final LandmarkTableModel landmarkTable ) { - return wrap( tpsSolver.solve( landmarkTable ), lambda ); + return wrap( solver.solve( landmarkTable ), lambda ); } - public WrappedIterativeInvertibleRealTransform solve( - final LandmarkTableModel landmarkTable, final int indexChanged ) + public WrappedIterativeInvertibleRealTransform< ? > solve( final LandmarkTableModel landmarkTable, final int indexChanged ) { - return wrap( tpsSolver.solve( landmarkTable, indexChanged ), lambda ); + return wrap( solver.solve( landmarkTable, indexChanged ), lambda ); } - public static > WrappedIterativeInvertibleRealTransform wrap( RealTransform base, RealRandomAccessible lambda ) + public static > WrappedIterativeInvertibleRealTransform< ? > wrap( RealTransform base, RealRandomAccessible< T > lambda ) { final RealTransformSequence identity = new RealTransformSequence(); - return new WrappedIterativeInvertibleRealTransform<>( new SpatiallyInterpolatedRealTransform( base, identity, lambda )); + return new WrappedIterativeInvertibleRealTransform<>( + new SpatiallyInterpolatedRealTransform< T >( base, identity, lambda ) ); } } diff --git a/src/main/java/bigwarp/transforms/ModelTransformSolver.java b/src/main/java/bigwarp/transforms/ModelTransformSolver.java index f092360b..dca4774e 100644 --- a/src/main/java/bigwarp/transforms/ModelTransformSolver.java +++ b/src/main/java/bigwarp/transforms/ModelTransformSolver.java @@ -28,18 +28,18 @@ import mpicbg.models.Model; import mpicbg.models.NotEnoughDataPointsException; -public class ModelTransformSolver implements TransformSolver< WrappedCoordinateTransform > +public class ModelTransformSolver extends AbstractTransformSolver< WrappedCoordinateTransform > { - private Model< ? > model; + private final Model< ? > model; public ModelTransformSolver( Model< ? > model ) { this.model = model; } - + public WrappedCoordinateTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { - double[] w = new double[ mvgPts[ 0 ].length ]; + final double[] w = new double[ mvgPts[ 0 ].length ]; Arrays.fill( w, 1.0 ); try { diff --git a/src/main/java/bigwarp/transforms/TpsTransformSolver.java b/src/main/java/bigwarp/transforms/TpsTransformSolver.java index 84baddaa..2e7871c8 100644 --- a/src/main/java/bigwarp/transforms/TpsTransformSolver.java +++ b/src/main/java/bigwarp/transforms/TpsTransformSolver.java @@ -21,16 +21,12 @@ */ package bigwarp.transforms; -import bigwarp.landmarks.LandmarkTableModel; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; -public class TpsTransformSolver implements TransformSolver< WrappedIterativeInvertibleRealTransform< ? >> +public class TpsTransformSolver extends AbstractTransformSolver< WrappedIterativeInvertibleRealTransform< ? >> { - private double[][] mvgPts; - private double[][] tgtPts; - public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { return new WrappedIterativeInvertibleRealTransform( @@ -38,32 +34,4 @@ public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts new ThinPlateR2LogRSplineKernelTransform( tgtPts.length, tgtPts, mvgPts ))); } - public WrappedIterativeInvertibleRealTransform solve( - final LandmarkTableModel landmarkTable ) - { - return solve( landmarkTable, -1 ); - } - - public WrappedIterativeInvertibleRealTransform solve( - final LandmarkTableModel landmarkTable, final int indexChanged ) - { - synchronized( landmarkTable ) - { - int numActive = landmarkTable.numActive(); - int ndims = landmarkTable.getNumdims(); - - if( mvgPts == null || mvgPts[0].length != numActive ) - { - mvgPts = new double[ ndims ][ numActive ]; - tgtPts = new double[ ndims ][ numActive ]; - landmarkTable.copyLandmarks( mvgPts, tgtPts ); - } - else if( indexChanged >= 0 ) - { - landmarkTable.copyLandmarks( indexChanged, mvgPts, tgtPts ); - } - } - - return solve( mvgPts, tgtPts ); - } } diff --git a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java index 775afef2..ed3ab75e 100644 --- a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java +++ b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java @@ -1,5 +1,6 @@ package net.imglib2.realtransform; +import bdv.viewer.animate.AbstractTransformAnimator; import net.imglib2.RealLocalizable; import net.imglib2.RealPositionable; import net.imglib2.RealRandomAccess; @@ -18,31 +19,45 @@ */ public class MaskedSimilarityTransform> implements RealTransform { + public static enum Interpolators { SIMILARITY, ROTATION }; + private final RealRandomAccessible lambda; private RealRandomAccess lambdaAccess; private final AffineTransform3D transform; - private final SimilarityTransformInterpolator interpolator; + private final AbstractTransformAnimator interpolator; private final double[] c; private final boolean flip; public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda ) { - this( transform, lambda, new double[3], false ); + this( transform, lambda, new double[3], Interpolators.SIMILARITY, false ); } public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, boolean flip ) { - this( transform, lambda, new double[3], flip ); + this( transform, lambda, new double[3], Interpolators.SIMILARITY, flip ); } public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c ) { - this( transform, lambda, c, false ); + this( transform, lambda, c, Interpolators.SIMILARITY, false ); } - public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c, boolean flip ) { + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, Interpolators interp ) { + this( transform, lambda, new double[3], interp, false ); + } + + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, Interpolators interp, boolean flip ) { + this( transform, lambda, new double[3], interp, flip ); + } + + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c, Interpolators interp ) { + this( transform, lambda, c, interp, false ); + } + + public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c, Interpolators interp, boolean flip ) { assert ( transform.numSourceDimensions() == lambda.numDimensions() ); this.transform = transform; @@ -51,7 +66,11 @@ public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRa this.lambda = lambda; lambdaAccess = lambda.realRandomAccess(); - interpolator = new SimilarityTransformInterpolator( transform, c ); + + if( interp == Interpolators.SIMILARITY ) + interpolator = new SimilarityTransformInterpolator( transform, c ); + else + interpolator = new RotationTransformInterpolator( transform, c ); } @Override diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index 8ef36a42..d6303d4f 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -42,6 +42,7 @@ import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory; import net.imglib2.interpolation.randomaccess.NearestNeighborInterpolatorFactory; +import net.imglib2.realtransform.MaskedSimilarityTransform.Interpolators; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.util.Intervals; @@ -143,7 +144,7 @@ public static void expSeq( String imgFile, String jsonFile ) { // masked similarity final MaskedSimilarityTransform msim = new MaskedSimilarityTransform( transform, lambda, center ); - final MaskedSimilarityTransform msimInv = new MaskedSimilarityTransform( transform.inverse(), lambda, center, true ); + final MaskedSimilarityTransform msimInv = new MaskedSimilarityTransform( transform.inverse(), lambda, center, Interpolators.SIMILARITY, true ); final WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( ltm ); final Scale3D id = new Scale3D(1,1,1); From 010d6d3376a219b622f96520c18e3d67606158b0 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Fri, 26 Aug 2022 09:46:48 -0400 Subject: [PATCH 028/282] feat: add rotation transform interpolator --- .../RotationTransformInterpolator.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/main/java/net/imglib2/realtransform/RotationTransformInterpolator.java diff --git a/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator.java b/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator.java new file mode 100644 index 00000000..5b56282c --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator.java @@ -0,0 +1,79 @@ +package net.imglib2.realtransform; + +import net.imglib2.util.LinAlgHelpers; + +import bdv.util.Affine3DHelpers; +import bdv.viewer.animate.AbstractTransformAnimator; + +public class RotationTransformInterpolator extends AbstractTransformAnimator +{ + private final double[] qStart; + + private final double[] qDiff; + + private final double[] p; + + private final double[] pDiff; + + public RotationTransformInterpolator(final AffineTransform3D transform, final double[] p) { + super(1); + AffineTransform3D transformEnd = new AffineTransform3D(); + transformEnd.set(transform); + + this.p = p; + qStart = new double[]{1, 0, 0, 0}; + final double[] qStartInv = new double[4]; + final double[] qEnd = new double[4]; + final double[] qEndInv = new double[4]; + qDiff = new double[4]; + LinAlgHelpers.quaternionInvert(qStart, qStartInv); + + Affine3DHelpers.extractRotation(transformEnd, qEnd); + LinAlgHelpers.quaternionInvert(qEnd, qEndInv); + + LinAlgHelpers.quaternionMultiply(qStartInv, qEnd, qDiff); + if (qDiff[0] < 0) + LinAlgHelpers.scale(qDiff, -1, qDiff); + + // translation needed to from reconstructed to target transformation + pDiff = new double[3]; + double[] tmp = new double[3]; + get(1).apply( p, tmp); + transform.apply(p, pDiff); + LinAlgHelpers.subtract(pDiff, tmp, pDiff); + } + + @Override + public AffineTransform3D get(final double t) { + + final double[] qDiffCurrent = new double[4]; + final double[] qCurrent = new double[4]; + LinAlgHelpers.quaternionPower(qDiff, t, qDiffCurrent); + LinAlgHelpers.quaternionMultiply(qStart, qDiffCurrent, qCurrent); + + final double[][] Rcurrent = new double[3][3]; + LinAlgHelpers.quaternionToR(qCurrent, Rcurrent); + + final double[][] m = new double[3][4]; + for (int r = 0; r < 3; ++r) { + for (int c = 0; c < 3; ++c) + m[r][c] = Rcurrent[r][c]; + } + + final AffineTransform3D transform = new AffineTransform3D(); + transform.set(m); + + double[] pCurrent = new double[3]; + transform.apply(p, pCurrent); + + double[] pTgt = new double[3]; + LinAlgHelpers.scale( pDiff, t, pTgt ); + LinAlgHelpers.add( p, pTgt, pTgt ); + LinAlgHelpers.subtract( pTgt, pCurrent, pTgt ); + transform.translate( pTgt ); + + return transform; + + } + +} \ No newline at end of file From 0efd602a74a32d47df95fc48f78cc6164755e8aa Mon Sep 17 00:00:00 2001 From: bogovicj Date: Fri, 26 Aug 2022 13:03:13 -0400 Subject: [PATCH 029/282] feat: partially working pref dialog --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 12 +- .../java/bdv/viewer/LandmarkPointMenu.java | 1 - src/main/java/bigwarp/BigWarp.java | 58 ++++++- src/main/java/bigwarp/BigWarpActions.java | 148 +++++++++++++++++- 4 files changed, 211 insertions(+), 8 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 141ae25e..7427f8d6 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -42,7 +42,6 @@ import org.scijava.ui.behaviour.util.TriggerBehaviourBindings; import bdv.cache.CacheControl; -import bdv.tools.brightness.ConverterSetup; import bdv.ui.BdvDefaultCards; import bdv.ui.CardPanel; import bdv.ui.appearance.AppearanceManager; @@ -235,4 +234,15 @@ public void setTransformEnabled( final boolean enabled ) else triggerbindings.addInputTriggerMap( "block_transform", new InputTriggerMap(), "transform" ); } + + /** + * Get {@code Behaviours} hook where TransformEventHandler behaviours are installed. + * This is installed in {@link #getTriggerbindings} with the id "transform". + * The hook can be used to update the keymap and install additional behaviours. + */ + public Behaviours getTransformBehaviours() + { + return transformBehaviours; + } + } diff --git a/src/main/java/bdv/viewer/LandmarkPointMenu.java b/src/main/java/bdv/viewer/LandmarkPointMenu.java index 326c4039..f3420bc9 100644 --- a/src/main/java/bdv/viewer/LandmarkPointMenu.java +++ b/src/main/java/bdv/viewer/LandmarkPointMenu.java @@ -23,7 +23,6 @@ import java.awt.Point; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index b54d1424..0a4e4815 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -90,6 +90,7 @@ import org.slf4j.LoggerFactory; import bdv.BigDataViewer; +import bdv.KeyConfigContexts; import bdv.cache.CacheControl; import bdv.export.ProgressWriter; import bdv.export.ProgressWriterConsole; @@ -106,6 +107,7 @@ import bdv.ij.util.ProgressWriterIJ; import bdv.img.WarpedSource; import bdv.tools.InitializeViewerState; +import bdv.tools.PreferencesDialog; import bdv.tools.VisibilityAndGroupingDialog; import bdv.tools.bookmarks.Bookmarks; import bdv.tools.bookmarks.BookmarksEditor; @@ -113,8 +115,10 @@ import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.SetupAssignments; import bdv.ui.appearance.AppearanceManager; +import bdv.ui.appearance.AppearanceSettingsPage; import bdv.ui.keymap.Keymap; import bdv.ui.keymap.KeymapManager; +import bdv.ui.keymap.KeymapSettingsPage; import bdv.util.Bounds; import bdv.viewer.BigWarpDragOverlay; import bdv.viewer.BigWarpLandmarkFrame; @@ -219,6 +223,8 @@ public class BigWarp< T > protected final VisibilityAndGroupingDialog activeSourcesDialogQ; + protected final PreferencesDialog preferencesDialog; + final AffineTransform3D fixedViewXfm; private final Bookmarks bookmarks; @@ -545,9 +551,36 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // System.out.println( "install actions" ); + + preferencesDialog = new PreferencesDialog( viewerFrameP, keymap, new String[] { KeyConfigContexts.BIGDATAVIEWER, "bw" } ); + preferencesDialog.addPage( new AppearanceSettingsPage( "Appearance", appearanceManager ) ); + preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", this.keymapManager, this.keymapManager.getCommandDescriptions() ) ); + +// appearanceManager.appearance().updateListeners().add( viewerFrame::repaint ); +// appearanceManager.addLafComponent( fileChooser ); +// SwingUtilities.invokeLater(() -> appearanceManager.updateLookAndFeel()); + + + final Actions navigationActions = new Actions( inputTriggerConfig, "bdv", "navigation" ); + navigationActions.install( getViewerFrameP().getKeybindings(), "navigation" ); + NavigationActions.install( navigationActions, getViewerFrameP().getViewerPanel(), options.values.is2D() ); + + navigationActions.install( getViewerFrameQ().getKeybindings(), "navigation" ); + NavigationActions.install( navigationActions, getViewerFrameQ().getViewerPanel(), options.values.is2D() ); + BigWarpActions bwActions = new BigWarpActions( inputTriggerConfig, "bw", "bw-general" ); - BigWarpActions.installViewerActions( bwActions, getViewerFrameP().getKeybindings(), this ); - BigWarpActions.installViewerActions( bwActions, getViewerFrameQ().getKeybindings(), this ); + BigWarpActions.installViewerActions( bwActions, getViewerFrameP(), this ); + BigWarpActions.installViewerActions( bwActions, getViewerFrameQ(), this ); + + BigWarpActions tableActions = new BigWarpActions( inputTriggerConfig, "bw", "bw-table" ); + BigWarpActions.installTableActions( tableActions, getLandmarkFrame().getKeybindings(), this ); + + keymap.updateListeners().add( () -> { + navigationActions.updateKeyConfig( keymap.getConfig() ); + bwActions.updateKeyConfig( keymap.getConfig() ); + tableActions.updateKeyConfig( keymap.getConfig() ); + viewerFrameP.getTransformBehaviours().updateKeyConfig( keymap.getConfig() ); + } ); // bwActions.installViewerActions( getViewerFrameQ().getKeybindings(), this ); @@ -1503,6 +1536,11 @@ else if( isMoving && isMovingDisplayTransformed() ) logger.trace( "selectedLandmark: " + bestIdx ); return bestIdx; } + + public void selectAllLandmarks() + { + getLandmarkPanel().getJTable().selectAll(); + } public static double computeScaleAssumeRigid( final AffineTransform3D xfm ) { @@ -1776,6 +1814,22 @@ else if ( viewerFrameQ.isActive() ) } } + public void goToBookmarkRotation() { + + if (getViewerFrameP().isActive()) + bookmarkEditorP.initGoToBookmarkRotation(); + else if (getViewerFrameP().isActive()) + bookmarkEditorQ.initGoToBookmarkRotation(); + } + + public void setBookmark() { + + if (getViewerFrameP().isActive()) + bookmarkEditorP.initSetBookmark(); + else if (getViewerFrameQ().isActive()) + bookmarkEditorQ.initSetBookmark(); + } + public void resetView() { final RandomAccessibleInterval< ? > interval = getSources().get( 1 ).getSpimSource().getSource( 0, 0 ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index ad74be5f..91b4141d 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -31,21 +31,34 @@ import javax.swing.KeyStroke; import javax.swing.table.TableCellEditor; +import org.scijava.Context; +import org.scijava.plugin.Plugin; +import org.scijava.plugin.PluginService; import org.scijava.ui.behaviour.KeyStrokeAdder; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionsBuilder; import org.scijava.ui.behaviour.util.AbstractNamedAction; import org.scijava.ui.behaviour.util.Actions; import org.scijava.ui.behaviour.util.InputActionBindings; import bdv.BigDataViewerActions; +import bdv.KeyConfigContexts; +import bdv.KeyConfigScopes; import bdv.gui.BigWarpViewerFrame; import bdv.tools.ToggleDialogAction; +import bdv.viewer.LandmarkPointMenu; import bdv.viewer.SourceAndConverter; import bigwarp.BigWarp.BigWarpData; import bigwarp.landmarks.LandmarkGridGenerator; import bigwarp.source.GridSource; import bigwarp.util.BigWarpUtils; import mpicbg.models.AbstractModel; +import net.imglib2.img.imageplus.ByteImagePlus; +import net.imglib2.img.imageplus.ImagePlusImgs; +import net.imglib2.img.planar.PlanarCursor; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.type.numeric.integer.UnsignedByteType; public class BigWarpActions extends Actions { @@ -53,6 +66,14 @@ public class BigWarpActions extends Actions public static final String LANDMARK_MODE_OFF = "landmark mode off"; // General options + public static final String EXPAND_CARDS = "expand and focus cards panel"; + public static final String[] EXPAND_CARDS_KEYS = new String[] { "P" }; + + public static final String COLLAPSE_CARDS = "collapse cards panel"; + public static final String[] COLLAPSE_CARDS_KEYS = new String[] { "shift P", "shift ESCAPE" }; + + public static final String PREFERENCES_DIALOG = "Preferences"; + public static final String[] PREFERENCES_DIALOG_KEYS= new String[] { "meta COMMA", "ctrl COMMA" }; // Display options public static final String TOGGLE_LANDMARK_MODE = "landmark mode toggle"; @@ -82,15 +103,29 @@ public class BigWarpActions extends Actions // public static final String CROP = "crop"; public static final String SAVE_SETTINGS = "save settings"; + public static final String[] SAVE_SETTINGS_KEYS = new String[]{}; + public static final String LOAD_SETTINGS = "load settings"; + public static final String[] LOAD_SETTINGS_KEYS = new String[]{}; public static final String BRIGHTNESS_SETTINGS = "brightness settings"; + public static final String[] BRIGHTNESS_SETTINGS_KEYS = new String[]{ "S" }; + public static final String VISIBILITY_AND_GROUPING = "visibility and grouping %s"; - public static final String SHOW_HELP = "help"; + public static final String VISIBILITY_AND_GROUPING_MVG = String.format( VISIBILITY_AND_GROUPING, "moving" ); + public static final String[] VISIBILITY_AND_GROUPING_MVG_KEYS = new String[]{ "F3" }; + + public static final String VISIBILITY_AND_GROUPING_TGT = String.format( VISIBILITY_AND_GROUPING, "target" ); + public static final String[] VISIBILITY_AND_GROUPING_TGT_KEYS = new String[]{ "F4" }; + + public static final String SHOW_HELP = "help"; + public static final String[] SHOW_HELP_KEYS = new String[] { "F1" }; + public static final String SHOW_SOURCE_INFO = "show source info"; // Warp visualization options public static final String SHOW_WARPTYPE_DIALOG = "show warp vis dialog" ; + public static final String[] SHOW_WARPTYPE_DIALOG_KEYS = new String[]{ "U" }; public static final String SET_WARPTYPE_VIS = "set warp vis type %s" ; @@ -143,7 +178,7 @@ public class BigWarpActions extends Actions public static final String[] GO_TO_BOOKMARK_KEYS = new String[]{ "B" }; public static final String GO_TO_BOOKMARK_ROTATION = "go to bookmark rotation"; - public static final String[] GO_TO_BOOKMARK_ROTATION_KEYS = new String[]{ "O" }; + public static final String[] GO_TO_BOOKMARK_ROTATION_KEYS = new String[]{ "control shift B" }; public static final String UNDO = "undo"; public static final String[] UNDO_KEYS = new String[]{ "control Z" }; @@ -153,15 +188,29 @@ public class BigWarpActions extends Actions public static final String SELECT_TABLE_ROWS = "select table row %d"; + public static final String LANDMARK_SELECT_ALL = "select all landmarks"; + public static final String[] LANDMARK_SELECT_ALL_KEYS = new String[]{ "ctrl A"}; + + public static final String LANDMARK_DESELECT_ALL = "deselect all landmarks"; + public static final String[] LANDMARK_DESELECT_ALL_KEYS = new String[]{ "ESCAPE" }; + + public static final String LANDMARK_DELETE_SELECTED = "delete selected landmarks"; + public static final String[] LANDMARK_DELETE_SELECTED_KEYS = new String[]{ "DELETE"}; + public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; + // export options public static final String SAVE_WARPED = "save warped"; public static final String SAVE_WARPED_XML = "save warped xml"; public static final String EXPORT_IP = "export imageplus"; + public static final String EXPORT_WARP = "export warp field"; + public static final String[] EXPORT_WARP_KEYS = new String[] { "ctrl W" }; + public static final String EXPORT_AFFINE = "export affine"; + public static final String[] EXPORT_AFFINE_KEYS = new String[] { "ctrl A" }; public static final String DEBUG = "debug"; @@ -176,17 +225,49 @@ public BigWarpActions( final KeyStrokeAdder.Factory keyConfig, String context, S { super( keyConfig, context, name ); } + + /* + * Command descriptions for all provided commands + */ + @Plugin( type = CommandDescriptionProvider.class ) + public static class Descriptions extends CommandDescriptionProvider + { + public Descriptions() + { + super( KeyConfigScopes.BIGDATAVIEWER, KeyConfigContexts.BIGDATAVIEWER ); + } + + @Override + public void getCommandDescriptions( final CommandDescriptions descriptions ) + { + descriptions.add( BRIGHTNESS_SETTINGS,BRIGHTNESS_SETTINGS_KEYS, "Show the Brightness&Colors dialog." ); + descriptions.add( VISIBILITY_AND_GROUPING_MVG, VISIBILITY_AND_GROUPING_MVG_KEYS, "Show the Visibility&Grouping dialog for the moving frame." ); + descriptions.add( VISIBILITY_AND_GROUPING_TGT, VISIBILITY_AND_GROUPING_TGT_KEYS, "Show the Visibility&Grouping dialog for the fixed frame." ); + descriptions.add( SHOW_HELP, SHOW_HELP_KEYS, "Show the Help dialog." ); + descriptions.add( SAVE_SETTINGS, SAVE_SETTINGS_KEYS, "Save the BigDataViewer settings to a settings.xml file." ); + descriptions.add( LOAD_SETTINGS, LOAD_SETTINGS_KEYS, "Load the BigDataViewer settings from a settings.xml file." ); + + descriptions.add( SET_BOOKMARK, SET_BOOKMARK_KEYS, "Set a labeled bookmark at the current location." ); + descriptions.add( GO_TO_BOOKMARK, GO_TO_BOOKMARK_KEYS, "Retrieve a labeled bookmark location." ); + descriptions.add( GO_TO_BOOKMARK_ROTATION, GO_TO_BOOKMARK_ROTATION_KEYS, "Retrieve a labeled bookmark, set only the orientation." ); + + descriptions.add( PREFERENCES_DIALOG, PREFERENCES_DIALOG_KEYS, "Show the Preferences dialog." ); + } + } public static void installViewerActions( Actions actions, - final InputActionBindings inputActionBindings, + final BigWarpViewerFrame bwFrame, final BigWarp< ? > bw ) { + + final InputActionBindings inputActionBindings = bwFrame.getKeybindings(); System.out.println( "install viewer actions" ); actions.install( inputActionBindings, "bw" ); actions.runnableAction( () -> { bw.getBwTransform().transformToString(); }, PRINT_TRANSFORM, PRINT_TRANSFORM_KEYS); actions.runnableAction( bw::toggleInLandmarkMode, TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS); + actions.runnableAction( bw::toggleMovingImageDisplay, TOGGLE_MOVING_IMAGE_DISPLAY, TOGGLE_MOVING_IMAGE_DISPLAY_KEYS ); // navigation actions.runnableAction( bw::resetView, RESET_VIEWER, RESET_VIEWER_KEYS); @@ -196,11 +277,59 @@ public static void installViewerActions( actions.runnableAction( bw::warpToNearestLandmark, WARP_TO_NEAREST_POINT, WARP_TO_NEAREST_POINT_KEYS ); actions.runnableAction( bw::warpToNextLandmark, WARP_TO_NEXT_POINT, WARP_TO_NEXT_POINT_KEYS ); actions.runnableAction( bw::warpToPrevLandmark, WARP_TO_PREV_POINT, WARP_TO_PREV_POINT_KEYS ); + + // bookmarks + actions.runnableAction( bw::goToBookmark, GO_TO_BOOKMARK, GO_TO_BOOKMARK_KEYS ); + actions.runnableAction( bw::goToBookmarkRotation, GO_TO_BOOKMARK_ROTATION, GO_TO_BOOKMARK_ROTATION_KEYS ); + actions.runnableAction( bw::setBookmark, SET_BOOKMARK, SET_BOOKMARK_KEYS ); + + // cards + actions.runnableAction( bwFrame::expandAndFocusCardPanel, EXPAND_CARDS, EXPAND_CARDS_KEYS ); + actions.runnableAction( bwFrame::collapseCardPanel, COLLAPSE_CARDS, COLLAPSE_CARDS_KEYS ); + + // export + actions.runnableAction( bw::exportWarpField, EXPORT_WARP, EXPORT_WARP_KEYS ); + actions.runnableAction( () -> { bw.getBwTransform().printAffine(); }, EXPORT_AFFINE, EXPORT_AFFINE_KEYS ); + + // dialogs + actions.namedAction( new ToggleDialogAction( SHOW_HELP, bw.helpDialog ), SHOW_HELP_KEYS ); + actions.namedAction( new ToggleDialogAction( VISIBILITY_AND_GROUPING_MVG, bw.activeSourcesDialogP ), VISIBILITY_AND_GROUPING_MVG_KEYS ); + actions.namedAction( new ToggleDialogAction( VISIBILITY_AND_GROUPING_TGT, bw.activeSourcesDialogQ ), VISIBILITY_AND_GROUPING_TGT_KEYS ); + actions.namedAction( new ToggleDialogAction( SHOW_WARPTYPE_DIALOG, bw.warpVisDialog ), SHOW_WARPTYPE_DIALOG_KEYS ); + actions.namedAction( new ToggleDialogAction( PREFERENCES_DIALOG, bw.preferencesDialog ), PREFERENCES_DIALOG_KEYS ); + + // landmarks + actions.runnableAction( bw::loadLandmarks, LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS ); + actions.runnableAction( bw::saveLandmarks, SAVE_LANDMARKS, SAVE_LANDMARKS_KEYS ); + actions.runnableAction( bw::quickSaveLandmarks, QUICK_SAVE_LANDMARKS, QUICK_SAVE_LANDMARKS_KEYS ); + + actions.namedAction( new UndoRedoAction( UNDO, bw ), UNDO_KEYS ); + actions.namedAction( new UndoRedoAction( REDO, bw ), REDO_KEYS ); + + } + + public static void installTableActions( + Actions actions, + final InputActionBindings inputActionBindings, + final BigWarp< ? > bw ) + { + actions.install( inputActionBindings, "bw" ); + + // landmarks + actions.runnableAction( bw::loadLandmarks, LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS ); + actions.runnableAction( bw::saveLandmarks, SAVE_LANDMARKS, SAVE_LANDMARKS_KEYS ); + actions.runnableAction( bw::quickSaveLandmarks, QUICK_SAVE_LANDMARKS, QUICK_SAVE_LANDMARKS_KEYS ); + + actions.runnableAction( () -> { bw.getLandmarkPanel().getJTable().selectAll(); }, LANDMARK_SELECT_ALL, LANDMARK_SELECT_ALL_KEYS ); + actions.runnableAction( () -> { bw.getLandmarkPanel().getJTable().clearSelection(); }, LANDMARK_DESELECT_ALL, LANDMARK_DESELECT_ALL_KEYS ); + + actions.namedAction( bw.landmarkPopupMenu.deleteSelectedHandler, LANDMARK_DELETE_SELECTED_KEYS ); + } /** * Create BigWarp actions and install them in the specified - * {@link InputActionBindings}. + * {@link InputActionBindings}. * * @param inputActionBindings * {@link InputMap} and {@link ActionMap} are installed here. @@ -1225,4 +1354,15 @@ public void actionPerformed(ActionEvent e) LandmarkGridGenerator.fillFromDialog( bw ); } } + + public synchronized void discoverCommandDescriptions() + { + final CommandDescriptionsBuilder builder = new CommandDescriptionsBuilder(); + final Context context = new Context( PluginService.class ); + context.inject( builder ); + builder.discoverProviders( KeyConfigScopes.BIGDATAVIEWER ); + builder.discoverProviders( "bw" ); + context.dispose(); + setCommandDescriptions( builder.build() ); + } } From a7b370a166613f2e8380fcf0e108c204e6800d79 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 30 Aug 2022 10:54:50 -0400 Subject: [PATCH 030/282] fix: toward more intuitive mask options --- src/main/java/bdv/gui/MaskOptionsPanel.java | 17 ++++++++++++---- .../gui/MaskedSourceEditorMouseListener.java | 3 +++ src/main/java/bigwarp/BigWarp.java | 20 ++++++++++++++++--- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index 8b37ad6d..ca8339f8 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -72,19 +72,19 @@ public MaskOptionsPanel( BigWarp bw ) @Override public void stateChanged( ChangeEvent e ) { - bw.setMaskOverlayVisibility( autoEstimateMaskButton.isSelected() ); + if( autoEstimateMaskButton.isSelected() ) + bw.autoEstimateMask(); } } ); - - showMaskOverlayButton = new JCheckBox( "Show mask overlay"); + showMaskOverlayButton = new JCheckBox( "Show mask overlay", true ); showMaskOverlayButton.setToolTipText( SHOW_MASK_OVERLAY_HELP_TEXT ); showMaskOverlayButton.addChangeListener( new ChangeListener() { @Override public void stateChanged( ChangeEvent e ) { - bw.setMaskOverlayVisibility( showMaskOverlayButton.isSelected() ); + bw.setMaskOverlayVisibility( showMaskOverlayButton.isSelected() && isMask() ); } } ); @@ -101,6 +101,7 @@ public void stateChanged( ChangeEvent e ) @Override public void actionPerformed( ActionEvent e ) { + bw.setMaskOverlayVisibility( autoEstimateMaskButton.isSelected() && isMask() ); bw.getBwTransform().setMask( maskTypeDropdown.getItemAt( maskTypeDropdown.getSelectedIndex() ) ); bw.restimateTransformation(); bw.getViewerFrameP().getViewerPanel().requestRepaint(); @@ -178,4 +179,12 @@ public JComboBox< FalloffType > getFalloffTypeDropdown() return falloffTypeDropdown; } + /** + * @return true if a mask is applied to the transformation + */ + public boolean isMask() + { + return falloffTypeDropdown.getSelectedIndex() > 0; + } + } diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java index 2d5f50dc..97b1abb2 100644 --- a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -112,6 +112,7 @@ public void mousePressed( MouseEvent e ) mask.setCenter( p ); overlays.stream().forEach( o -> o.setCenter( p ) ); } + bw.setAutoEstimateMask( false ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } @@ -126,6 +127,7 @@ public void mouseDragged( MouseEvent e ) return; viewer.getGlobalMouseCoordinates( p ); + bw.setAutoEstimateMask( false ); synchronized ( mask ) { mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ) ); @@ -145,6 +147,7 @@ public void mouseWheelMoved( MouseWheelEvent e ) if( !active ) return; + bw.setAutoEstimateMask( false ); final AffineTransform3D transform = viewer.state().getViewerTransform(); final double scale = (1.0 / Affine3DHelpers.extractScale(transform, 0)) + 0.05; final int sign = e.getWheelRotation(); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 2981a8de..f46adc05 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2012,6 +2012,21 @@ public void setMovingSpimData( SpimData movingSpimData, File movingImageXml ) this.movingImageXml = movingImageXml; } + public void setAutoEstimateMask( final boolean selected ) + { + warpVisDialog.maskOptionsPanel.getAutoEstimateMaskButton().setSelected( selected ); + } + + public void autoEstimateMask() + { + if( landmarkModel.numActive() < 4 ) + return; + + Sphere sph = BoundingSphereRitter.boundingSphere(landmarkModel.getFixedPointsCopy()); + tpsMask.getRandomAccessible().setCenter(sph.getCenter()); + tpsMask.getRandomAccessible().setRadius(sph.getRadius()); + } + public enum WarpVisType { NONE, WARPMAG, JACDET, GRID @@ -2161,6 +2176,7 @@ else if ( viewerFrameQ.isActive() ) else // warp mag is invisible, turn it on { state.setSourceActive( warpMagSource, true ); + // vg.setSourceActive( offImgIndex, false ); // estimate the max warp @@ -2861,9 +2877,7 @@ public void tableChanged( final TableModelEvent e ) if ( warpVisDialog.autoEstimateMask() && bwTransform.isMasked() ) { - Sphere sph = BoundingSphereRitter.boundingSphere( landmarkModel.getFixedPointsCopy() ); - tpsMask.getRandomAccessible().setCenter( sph.getCenter() ); - tpsMask.getRandomAccessible().setRadius( sph.getRadius() ); + autoEstimateMask(); } } } From 3300697fdeb474652f801923a6b4b0638b4a7060 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 30 Aug 2022 10:57:08 -0400 Subject: [PATCH 031/282] fix: merge and clean up --- src/main/java/bdv/gui/MaskOptionsPanel.java | 1 - .../gui/MaskedSourceEditorMouseListener.java | 4 +- ...teauSphericalMaskRealRandomAccessible.java | 85 +++++++------------ 3 files changed, 31 insertions(+), 59 deletions(-) diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index ca8339f8..be3c8392 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -2,7 +2,6 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java index 97b1abb2..a78fdb5e 100644 --- a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -149,7 +149,7 @@ public void mouseWheelMoved( MouseWheelEvent e ) bw.setAutoEstimateMask( false ); final AffineTransform3D transform = viewer.state().getViewerTransform(); - final double scale = (1.0 / Affine3DHelpers.extractScale(transform, 0)) + 0.05; + final double scale = (1.0 / (Affine3DHelpers.extractScale(transform, 0) + 1e-9 ) + 1e-6 ); final int sign = e.getWheelRotation(); if( e.isShiftDown() ) @@ -159,7 +159,7 @@ else if ( e.isControlDown() ) else mask.incSquaredSigma( sign * scale * scale ); - final double r = Math.sqrt( mask.getSquaredSigma() ); + final double r = mask.getSigma(); overlays.stream().forEach( o -> o.setOuterRadiusDelta( r )); bw.getViewerFrameP().getViewerPanel().requestRepaint(); diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index daabc088..62264840 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -31,6 +31,7 @@ public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAcces private double sigma; private double sqrSigma; private double invSqrSigma; + private double gaussInvSqrSigma; private RealPoint center; @@ -50,49 +51,6 @@ public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) setRadius( 8.0 ); setSigma ( 10.0 ); } - - public static void main( String[] args ) - { - long S = 50; - double[] center = new double[] { S, S, S }; - RealPoint pt = RealPoint.wrap( center ); - - PlateauSphericalMaskRealRandomAccessible img = new PlateauSphericalMaskRealRandomAccessible( 3, pt ); - img.setRadius( 10 ); - img.setSigma( 10 ); - Interval interval = Intervals.createMinSize( 0, 0, 0, 2*S, 2*S, 2*S ); -// -//// BdvOptions options = BdvOptions.options().screenScales( new double[] { 1 } ); -// BdvOptions options = BdvOptions.options(); -// BdvStackSource< DoubleType > bdv = BdvFunctions.show( img.rra, interval, "img", options ); -// bdv.getBdvHandle().getSetupAssignments().getMinMaxGroups().get( 0 ).setRange( 0, 1 ); -// -//// InputActionBindings kb = bdv.getBdvHandle().getKeybindings(); -//// System.out.println( kb ); -//// kb.removeActionMap( "navigation" ); -//// kb.removeInputMap( "navigation" ); -// -//// bdv.getBdvHandle().getTriggerbindings().removeInputTriggerMap( "block_transform" ); -// -// final MaskedSourceEditorMouseListener ml = new MaskedSourceEditorMouseListener( 3, null, bdv.getBdvHandle().getViewerPanel() ); -// ml.setMask( img ); -//// bdv.getBdvHandle().getViewerPanel().getDisplay().addMouseListener( ml ); -// - double x = 50; - RealRandomAccess< DoubleType > access = img.realRandomAccess(); - access.setPosition( center ); - while( x < 100 ) - { - access.move( 1, 0 ); - System.out.println( x + "," + access.get().getRealDouble()); - - x = access.getDoublePosition( 0 ); - } - -// x = 70; -// access.setPosition( new double[] { x, 50, 50 } ); -// System.out.println( x + "," + access.get().getRealDouble()); - } private void update() { @@ -146,6 +104,11 @@ public double getSquaredSigma() return sqrSigma; } + public double getSigma() + { + return sigma; + } + public void setSigma( double sigma ) { this.sigma = sigma; @@ -155,6 +118,7 @@ public void setSigma( double sigma ) sqrSigma = EPS; invSqrSigma = 1.0 / sqrSigma; + updateGaussSigma(); } public void setSquaredSigma( double squaredSigma ) @@ -165,6 +129,7 @@ public void setSquaredSigma( double squaredSigma ) sqrSigma = EPS; invSqrSigma = 1.0 / squaredSigma; + updateGaussSigma(); } public void incSquaredSigma( double increment ) @@ -176,18 +141,14 @@ public void incSquaredSigma( double increment ) sqrSigma = EPS; invSqrSigma = 1.0 / sqrSigma; + updateGaussSigma(); + } + + private void updateGaussSigma() + { + final double gsig = gaussSigma( sigma ); + gaussInvSqrSigma = 1.0 / ( gsig * gsig ); } -// -// public void mulSquaredSigma( double factor ) -// { -// sqrSigma *= factor; -// sigma = Math.sqrt( sqrSigma ); -// -// if( sqrSigma <= 0 ) -// sqrSigma = EPS; -// -// invSqrSigma = 1.0 / sqrSigma; -// } public void setCenter( RealLocalizable p ) { @@ -204,7 +165,6 @@ public RealPoint getCenter() return center; } - final public static double squaredDistance( final RealLocalizable position1, final RealLocalizable position2 ) { double dist = 0; @@ -278,6 +238,19 @@ public void fromJson( JsonObject json ) setSquaredRadius( json.get("squaredRadius").getAsDouble() ); setSquaredSigma( json.get("squaredSigma").getAsDouble() ); } + + /** + * Re.turns the sigma that makes a Gaussian shape most like a cosine with period T. + *

+ * see https://gist.github.com/bogovicj/d212b236868c76798edfd11150b2c9a0 + * + * @param T the cosine period + * @return + */ + public static double gaussSigma( double T ) + { + return 1.2737486038617858 * T + 0.0019703; + } public class GaussianFalloff implements BiConsumer< RealLocalizable, DoubleType > { @@ -294,7 +267,7 @@ public void accept( RealLocalizable x, DoubleType v ) // final double t = (r2 - plateauR2); final double t = (r - plateauR); // TODO sample exp function and interpolate to speed up - v.set( Math.exp( -0.5 * t * t * invSqrSigma ) ); + v.set( Math.exp( -0.5 * t * t * gaussInvSqrSigma ) ); // v.set( Math.cos( t * 0.5 + 0.5 )); // v.set( 1 / t ); } From dce27427d3b78c25fe7ec5c25f40b4a58dfccd49 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 30 Aug 2022 16:58:41 -0400 Subject: [PATCH 032/282] feat: mask overlay correctly updated * overlay now more consistent across falloff types --- src/main/java/bdv/gui/MaskOptionsPanel.java | 2 +- .../gui/MaskedSourceEditorMouseListener.java | 20 --------- .../bdv/gui/TransformTypeSelectDialog.java | 5 --- .../overlay/BigWarpMaskSphereOverlay.java | 18 +++++++- src/main/java/bigwarp/BigWarp.java | 4 +- ...teauSphericalMaskRealRandomAccessible.java | 45 ++++++++++++++----- 6 files changed, 54 insertions(+), 40 deletions(-) diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index be3c8392..f448e6f3 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -183,7 +183,7 @@ public JComboBox< FalloffType > getFalloffTypeDropdown() */ public boolean isMask() { - return falloffTypeDropdown.getSelectedIndex() > 0; + return maskTypeDropdown.getSelectedIndex() > 0; } } diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java index a78fdb5e..0926239b 100644 --- a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -68,24 +68,8 @@ public void toggleActive( ) public void setMask( PlateauSphericalMaskRealRandomAccessible mask ) { this.mask = mask; - overlays.forEach( o -> { - o.setCenter( mask.getCenter() ); - o.setInnerRadius( Math.sqrt( mask.getSquaredRadius())); - o.setOuterRadiusDelta( Math.sqrt( mask.getSquaredSigma())); - }); } -// public void setOverlay( final BigWarpMaskSphereOverlay overlay ) -// { -// this.overlay = overlay; -// if( mask != null ) -// { -// this.overlay.setCenter( mask.getCenter() ); -// this.overlay.setInnerRadius( Math.sqrt( mask.getSquaredRadius() ) ); -// this.overlay.setOuterRadiusDelta( Math.sqrt( mask.getSquaredSigma() ) ); -// } -// } - public PlateauSphericalMaskRealRandomAccessible getMask() { return mask; @@ -110,7 +94,6 @@ public void mousePressed( MouseEvent e ) synchronized ( mask ) { mask.setCenter( p ); - overlays.stream().forEach( o -> o.setCenter( p ) ); } bw.setAutoEstimateMask( false ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); @@ -159,9 +142,6 @@ else if ( e.isControlDown() ) else mask.incSquaredSigma( sign * scale * scale ); - final double r = mask.getSigma(); - overlays.stream().forEach( o -> o.setOuterRadiusDelta( r )); - bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index 47b3c99d..d9d9955c 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -29,16 +29,11 @@ import javax.swing.BorderFactory; import javax.swing.ButtonGroup; -import javax.swing.JCheckBox; import javax.swing.JDialog; -import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import bigwarp.BigWarp; -import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffType; import bigwarp.transforms.BigWarpTransform;; public class TransformTypeSelectDialog extends JDialog diff --git a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java index 38a516c2..e455e448 100644 --- a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java +++ b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java @@ -10,6 +10,7 @@ import bdv.util.Affine3DHelpers; import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.OverlayRenderer; +import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; import net.imglib2.realtransform.AffineTransform3D; @@ -52,11 +53,26 @@ public BigWarpMaskSphereOverlay( final BigWarpViewerPanel viewer, final double[] viewerTransform = new AffineTransform3D(); } + public double[] getCenter() + { + return center; + } + + public double[] getRadii() + { + return radii; + } + public void setCenter( final double[] center ) { this.center = center; } - + + public void setCenter( final RealLocalizable c ) + { + c.localize( center ); + } + public void setCenter( final RealPoint center ) { center.localize( this.center ); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index f46adc05..b94f6577 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1793,6 +1793,8 @@ protected void addMaskMouseListener() maskSourceMouseListenerQ = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerQ ); maskSourceMouseListenerQ.setActive( false ); maskSourceMouseListenerQ.setMask( tpsMask.getRandomAccessible() ); + + tpsMask.getRandomAccessible().setOverlays( Arrays.asList( viewerP.getMaskOverlay(), viewerQ.getMaskOverlay() )); } public void setGridType( final GridSource.GRID_TYPE method ) @@ -2022,7 +2024,7 @@ public void autoEstimateMask() if( landmarkModel.numActive() < 4 ) return; - Sphere sph = BoundingSphereRitter.boundingSphere(landmarkModel.getFixedPointsCopy()); + final Sphere sph = BoundingSphereRitter.boundingSphere(landmarkModel.getFixedPointsCopy()); tpsMask.getRandomAccessible().setCenter(sph.getCenter()); tpsMask.getRandomAccessible().setRadius(sph.getRadius()); } diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 62264840..f0505aef 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -1,5 +1,6 @@ package bigwarp.source; +import java.util.List; import java.util.function.BiConsumer; import org.jdom2.Element; @@ -7,8 +8,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import mpicbg.spim.data.XmlHelpers; -import net.imglib2.Interval; import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; @@ -16,12 +17,12 @@ import net.imglib2.RealRandomAccessible; import net.imglib2.position.FunctionRealRandomAccessible; import net.imglib2.type.numeric.real.DoubleType; -import net.imglib2.util.Intervals; public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAccessible< DoubleType > { private BiConsumer< RealLocalizable, DoubleType > pfun; private FunctionRealRandomAccessible< DoubleType > rra; + private List overlays; private int nd; @@ -52,6 +53,19 @@ public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) setSigma ( 10.0 ); } + public void setOverlays( final List< BigWarpMaskSphereOverlay > overlays ) + { + this.overlays = overlays; + if ( overlays != null ) + { + overlays.stream().forEach( o -> { + o.setCenter( center ) ; + o.setInnerRadius( plateauR ); + o.setOuterRadiusDelta( sigma ); + }); + } + } + private void update() { rra = new FunctionRealRandomAccessible<>( nd, pfun, DoubleType::new ); @@ -91,12 +105,16 @@ public void setRadius( double r ) { plateauR = r; plateauR2 = plateauR * plateauR ; + if ( overlays != null ) + overlays.stream().forEach( o -> o.setInnerRadius( plateauR ) ); } public void setSquaredRadius( double r2 ) { plateauR2 = r2; plateauR = Math.sqrt( plateauR2 ); + if ( overlays != null ) + overlays.stream().forEach( o -> o.setInnerRadius( plateauR ) ); } public double getSquaredSigma() @@ -119,17 +137,14 @@ public void setSigma( double sigma ) invSqrSigma = 1.0 / sqrSigma; updateGaussSigma(); + + if ( overlays != null ) + overlays.stream().forEach( o -> o.setOuterRadiusDelta( sigma )); } public void setSquaredSigma( double squaredSigma ) { - sqrSigma = squaredSigma; - sigma = Math.sqrt( sqrSigma ); - if( sqrSigma <= 0 ) - sqrSigma = EPS; - - invSqrSigma = 1.0 / squaredSigma; - updateGaussSigma(); + setSigma( Math.sqrt( sqrSigma )); } public void incSquaredSigma( double increment ) @@ -142,6 +157,8 @@ public void incSquaredSigma( double increment ) invSqrSigma = 1.0 / sqrSigma; updateGaussSigma(); + if ( overlays != null ) + overlays.stream().forEach( o -> o.setOuterRadiusDelta( sigma )); } private void updateGaussSigma() @@ -153,11 +170,15 @@ private void updateGaussSigma() public void setCenter( RealLocalizable p ) { center.setPosition( p ); + if ( overlays != null ) + overlays.stream().forEach( o -> o.setCenter( p ) ); } public void setCenter( double[] p ) { center.setPosition( p ); + if ( overlays != null ) + overlays.stream().forEach( o -> o.setCenter( p ) ); } public RealPoint getCenter() @@ -249,7 +270,7 @@ public void fromJson( JsonObject json ) */ public static double gaussSigma( double T ) { - return 1.2737486038617858 * T + 0.0019703; + return ( 0.40535876907923957 * T + 0.03706937 ); } public class GaussianFalloff implements BiConsumer< RealLocalizable, DoubleType > { @@ -283,14 +304,14 @@ public void accept( RealLocalizable x, DoubleType v ) final double r = Math.sqrt( r2 ); if( r2 <= plateauR2 ) v.setOne(); - else if ( r >= plateauR + 2 * sigma ) + else if ( r >= plateauR + sigma ) v.setZero(); else { // final double t = (r2 - plateauR2); // final double r = Math.sqrt( r2 ); final double t = (r - plateauR); - double val = 0.5 + 0.5 * Math.cos( t * PIon2 / sigma ); + double val = 0.5 + 0.5 * Math.cos( t * PI / sigma ); v.set( val ); } } From 70e97e713b6d14dde65d82099c685fef981cb320 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 30 Aug 2022 18:01:28 -0400 Subject: [PATCH 033/282] fix: add new mouse controls for mask --- src/main/java/bdv/gui/MaskOptionsPanel.java | 2 +- .../gui/MaskedSourceEditorMouseListener.java | 36 +++++++++++++++---- src/main/java/bigwarp/BigWarp.java | 17 ++++----- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index f448e6f3..8f8fde8e 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -64,7 +64,7 @@ public MaskOptionsPanel( BigWarp bw ) "Mask options" ), BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - autoEstimateMaskButton = new JCheckBox( "Auto-estimate mask"); + autoEstimateMaskButton = new JCheckBox( "Auto-estimate mask", true ); autoEstimateMaskButton.setToolTipText( AUTO_ESTIMATE_HELP_TEXT ); autoEstimateMaskButton.addChangeListener( new ChangeListener() { diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java index 0926239b..dfaf54aa 100644 --- a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -6,12 +6,10 @@ import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import bdv.util.Affine3DHelpers; import bdv.viewer.BigWarpViewerPanel; -import bdv.viewer.ViewerPanel; import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import bigwarp.BigWarp; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; @@ -26,6 +24,7 @@ public class MaskedSourceEditorMouseListener implements MouseListener, MouseMoti private boolean active; private RealPoint p; +// private RealPoint pressPt; private BigWarp bw; @@ -46,6 +45,7 @@ public MaskedSourceEditorMouseListener( int nd, BigWarp bw, BigWarpViewerPane overlays.add( bw.getViewerFrameQ().getViewerPanel().getMaskOverlay() ); p = new RealPoint( nd ); +// pressPt = new RealPoint( nd ); active = false; } @@ -90,9 +90,14 @@ public void mousePressed( MouseEvent e ) if( !active ) return; +// viewer.getGlobalMouseCoordinates( pressPt ); viewer.getGlobalMouseCoordinates( p ); + if( e.isControlDown() || e.isShiftDown() ) + return; + synchronized ( mask ) { +// mask.setCenter( pressPt ); mask.setCenter( p ); } bw.setAutoEstimateMask( false ); @@ -111,12 +116,31 @@ public void mouseDragged( MouseEvent e ) viewer.getGlobalMouseCoordinates( p ); bw.setAutoEstimateMask( false ); - synchronized ( mask ) + + if( e.isControlDown() ) + { + synchronized ( mask ) + { +// mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, pressPt ) ); + mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ) ); + } + } + else if( e.isShiftDown() ) { - mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ) ); - final double r = Math.sqrt( mask.getSquaredRadius() ); - overlays.stream().forEach( o -> o.setInnerRadius( r )); + synchronized ( mask ) + { + double d = Math.sqrt( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() )); + mask.setSigma( d - Math.sqrt( mask.getSquaredRadius()) ); + } } + else + { + synchronized ( mask ) + { + mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ) ); + } + } + bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index b94f6577..2a248065 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2024,9 +2024,12 @@ public void autoEstimateMask() if( landmarkModel.numActive() < 4 ) return; - final Sphere sph = BoundingSphereRitter.boundingSphere(landmarkModel.getFixedPointsCopy()); - tpsMask.getRandomAccessible().setCenter(sph.getCenter()); - tpsMask.getRandomAccessible().setRadius(sph.getRadius()); + if( warpVisDialog.autoEstimateMask() && bwTransform.isMasked() ) + { + final Sphere sph = BoundingSphereRitter.boundingSphere(landmarkModel.getFixedPointsCopy()); + tpsMask.getRandomAccessible().setCenter(sph.getCenter()); + tpsMask.getRandomAccessible().setRadius(sph.getRadius()); + } } public enum WarpVisType @@ -2876,11 +2879,7 @@ public void tableChanged( final TableModelEvent e ) BigWarp.this.restimateTransformation(); BigWarp.this.landmarkPanel.repaint(); } - - if ( warpVisDialog.autoEstimateMask() && bwTransform.isMasked() ) - { - autoEstimateMask(); - } + autoEstimateMask(); } } @@ -3390,6 +3389,8 @@ else if( filename.endsWith( "json" )) if ( !didCompute ) setIsMovingDisplayTransformed( false ); + autoEstimateMask(); + viewerP.requestRepaint(); viewerQ.requestRepaint(); landmarkFrame.repaint(); From 8f0dbe3f845655a1f4825906ba737653e5d2c1ae Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 12 Sep 2022 10:16:56 -0400 Subject: [PATCH 034/282] toward adding bw keymaps to panel --- src/main/java/bigwarp/BigWarp.java | 7 +++-- src/main/java/bigwarp/BigWarpActions.java | 33 +++++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 0a4e4815..cf2b5fe5 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -139,6 +139,7 @@ import bdv.viewer.animate.TranslationAnimator; import bdv.viewer.overlay.BigWarpSourceOverlayRenderer; import bdv.viewer.overlay.MultiBoxOverlayRenderer; +import bigwarp.BigWarpActions.Descriptions; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.loader.ImagePlusLoader.ColorSettings; import bigwarp.source.GridSource; @@ -551,8 +552,10 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // System.out.println( "install actions" ); - - preferencesDialog = new PreferencesDialog( viewerFrameP, keymap, new String[] { KeyConfigContexts.BIGDATAVIEWER, "bw" } ); + + Descriptions desc = new BigWarpActions.Descriptions(); + desc.getCommandDescriptions( keymapManager.getCommandDescriptions() ); + preferencesDialog = new PreferencesDialog( viewerFrameP, keymap, new String[] { KeyConfigContexts.BIGDATAVIEWER, "bigwarp", "bw" } ); preferencesDialog.addPage( new AppearanceSettingsPage( "Appearance", appearanceManager ) ); preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", this.keymapManager, this.keymapManager.getCommandDescriptions() ) ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 91b4141d..802bd5e5 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -31,9 +31,7 @@ import javax.swing.KeyStroke; import javax.swing.table.TableCellEditor; -import org.scijava.Context; import org.scijava.plugin.Plugin; -import org.scijava.plugin.PluginService; import org.scijava.ui.behaviour.KeyStrokeAdder; import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; import org.scijava.ui.behaviour.io.gui.CommandDescriptions; @@ -47,21 +45,18 @@ import bdv.KeyConfigScopes; import bdv.gui.BigWarpViewerFrame; import bdv.tools.ToggleDialogAction; -import bdv.viewer.LandmarkPointMenu; import bdv.viewer.SourceAndConverter; import bigwarp.BigWarp.BigWarpData; import bigwarp.landmarks.LandmarkGridGenerator; import bigwarp.source.GridSource; import bigwarp.util.BigWarpUtils; import mpicbg.models.AbstractModel; -import net.imglib2.img.imageplus.ByteImagePlus; -import net.imglib2.img.imageplus.ImagePlusImgs; -import net.imglib2.img.planar.PlanarCursor; import net.imglib2.realtransform.AffineTransform3D; -import net.imglib2.type.numeric.integer.UnsignedByteType; public class BigWarpActions extends Actions { + public static final CommandDescriptionProvider.Scope BIGWARP = new CommandDescriptionProvider.Scope( "bigwarp" ); + public static final String LANDMARK_MODE_ON = "landmark mode on"; public static final String LANDMARK_MODE_OFF = "landmark mode off"; @@ -234,12 +229,14 @@ public static class Descriptions extends CommandDescriptionProvider { public Descriptions() { - super( KeyConfigScopes.BIGDATAVIEWER, KeyConfigContexts.BIGDATAVIEWER ); + super( BIGWARP, "bw" ); } @Override public void getCommandDescriptions( final CommandDescriptions descriptions ) { + descriptions.add( TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS, "Toggle landmark mode." ); + descriptions.add( BRIGHTNESS_SETTINGS,BRIGHTNESS_SETTINGS_KEYS, "Show the Brightness&Colors dialog." ); descriptions.add( VISIBILITY_AND_GROUPING_MVG, VISIBILITY_AND_GROUPING_MVG_KEYS, "Show the Visibility&Grouping dialog for the moving frame." ); descriptions.add( VISIBILITY_AND_GROUPING_TGT, VISIBILITY_AND_GROUPING_TGT_KEYS, "Show the Visibility&Grouping dialog for the fixed frame." ); @@ -1355,14 +1352,14 @@ public void actionPerformed(ActionEvent e) } } - public synchronized void discoverCommandDescriptions() - { - final CommandDescriptionsBuilder builder = new CommandDescriptionsBuilder(); - final Context context = new Context( PluginService.class ); - context.inject( builder ); - builder.discoverProviders( KeyConfigScopes.BIGDATAVIEWER ); - builder.discoverProviders( "bw" ); - context.dispose(); - setCommandDescriptions( builder.build() ); - } +// public synchronized void discoverCommandDescriptions() +// { +// final CommandDescriptionsBuilder builder = new CommandDescriptionsBuilder(); +// final Context context = new Context( PluginService.class ); +// context.inject( builder ); +// builder.discoverProviders( KeyConfigScopes.BIGDATAVIEWER ); +// builder.discoverProviders( "bw" ); +// context.dispose(); +// setCommandDescriptions( builder.build() ); +// } } From 6287e85a6c843940e85f28ea64f24e93d584f408 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 12 Sep 2022 16:51:10 -0400 Subject: [PATCH 035/282] WIP toward customizable keymappings * add bw keymap manager * default keymappings * preference panel partially works --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 2 +- .../java/bdv/gui/BigWarpViewerOptions.java | 26 ++- src/main/java/bigwarp/BigWarp.java | 20 ++- src/main/java/bigwarp/BigWarpActions.java | 64 ++++++- .../bigwarp/ui/keymap/DumpInputConfig.java | 94 +++++++++++ .../java/bigwarp/ui/keymap/KeymapManager.java | 157 ++++++++++++++++++ .../resources/bigwarp/ui/keymap/default.yaml | 45 +++++ 7 files changed, 399 insertions(+), 9 deletions(-) create mode 100644 src/main/java/bigwarp/ui/keymap/DumpInputConfig.java create mode 100644 src/main/java/bigwarp/ui/keymap/KeymapManager.java create mode 100644 src/main/resources/bigwarp/ui/keymap/default.yaml diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 7427f8d6..9a431fc5 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -45,13 +45,13 @@ import bdv.ui.BdvDefaultCards; import bdv.ui.CardPanel; import bdv.ui.appearance.AppearanceManager; -import bdv.ui.keymap.KeymapManager; import bdv.ui.splitpanel.SplitPanel; import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.BigWarpViewerSettings; import bdv.viewer.ConverterSetups; import bdv.viewer.SourceAndConverter; import bigwarp.BigWarp; +import bigwarp.ui.keymap.KeymapManager; public class BigWarpViewerFrame extends JFrame { diff --git a/src/main/java/bdv/gui/BigWarpViewerOptions.java b/src/main/java/bdv/gui/BigWarpViewerOptions.java index b3ba2217..ce4cffc0 100644 --- a/src/main/java/bdv/gui/BigWarpViewerOptions.java +++ b/src/main/java/bdv/gui/BigWarpViewerOptions.java @@ -23,7 +23,8 @@ import bdv.viewer.ViewerOptions; import bdv.viewer.ViewerPanel; -import bdv.viewer.animate.MessageOverlayAnimator; +import bigwarp.ui.keymap.KeymapManager; + import org.scijava.ui.behaviour.io.InputTriggerConfig; public class BigWarpViewerOptions extends ViewerOptions @@ -54,6 +55,12 @@ public BigWarpViewerOptions is2D( final boolean is2D ) return this; } + public BigWarpViewerOptions bwKeymapManager( final KeymapManager keymapManager ) + { + bwValues.keymapManager = keymapManager; + return this; + } + public BwValues getValues() { return bwValues; @@ -76,6 +83,8 @@ public BigWarpViewerOptions size( final int width, final int height ) public BigWarpViewerOptions copy() { BigWarpViewerOptions out = new BigWarpViewerOptions(); + out.bwKeymapManager( bwValues.keymapManager ); + out. width( values.getWidth() ). height( values.getHeight() ). @@ -88,9 +97,8 @@ public BigWarpViewerOptions copy() is2D( values.is2D() ). transformEventHandlerFactory( values.getTransformEventHandlerFactory() ). accumulateProjectorFactory( values.getAccumulateProjectorFactory() ). - inputTriggerConfig( values.getInputTriggerConfig() ). + inputTriggerConfig( bwValues.getInputTriggerConfig() ). shareKeyPressedEvents( values.getKeyPressedManager() ). - keymapManager( values.getKeymapManager() ). appearanceManager( values.getAppearanceManager() ); return out; } @@ -104,6 +112,18 @@ public ViewerOptions getViewerOptions( final boolean isMoving ) public static class BwValues { + private KeymapManager keymapManager = null; private BigWarpMessageAnimator messageAnimator = new BigWarpMessageAnimator( 1500, 0.01, 0.1 ); + private InputTriggerConfig inputTriggerConfig = null; + + public KeymapManager getKeymapManager() + { + return keymapManager; + } + + public InputTriggerConfig getInputTriggerConfig() + { + return inputTriggerConfig; + } } } diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index cf2b5fe5..b862016c 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -84,6 +84,7 @@ import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import org.scijava.ui.behaviour.io.InputTriggerConfig; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; import org.scijava.ui.behaviour.util.Actions; import org.scijava.ui.behaviour.util.InputActionBindings; import org.slf4j.Logger; @@ -117,7 +118,6 @@ import bdv.ui.appearance.AppearanceManager; import bdv.ui.appearance.AppearanceSettingsPage; import bdv.ui.keymap.Keymap; -import bdv.ui.keymap.KeymapManager; import bdv.ui.keymap.KeymapSettingsPage; import bdv.util.Bounds; import bdv.viewer.BigWarpDragOverlay; @@ -147,6 +147,7 @@ import bigwarp.source.WarpMagnitudeSource; import bigwarp.transforms.BigWarpTransform; import bigwarp.transforms.WrappedCoordinateTransform; +import bigwarp.ui.keymap.KeymapManager; import bigwarp.util.BigWarpUtils; import dev.dirs.ProjectDirectories; import fiji.util.gui.GenericDialogPlus; @@ -184,6 +185,7 @@ public class BigWarp< T > { public static String configDir = ProjectDirectories.from( "sc", "fiji", "bigwarp" ).configDir; +// public static String configDir = "/groups/saalfeld/home/bogovicj/.bigwarp"; protected static final int DEFAULT_WIDTH = 600; @@ -359,7 +361,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, final Progr public BigWarp( final BigWarpData data, final String windowTitle, BigWarpViewerOptions options, final ProgressWriter progressWriter ) throws SpimDataException { System.out.println( "BigWarp actions"); - final KeymapManager optionsKeymapManager = options.values.getKeymapManager(); + final KeymapManager optionsKeymapManager = options.getValues().getKeymapManager(); final AppearanceManager optionsAppearanceManager = options.values.getAppearanceManager(); keymapManager = optionsKeymapManager != null ? optionsKeymapManager : new KeymapManager( configDir ); appearanceManager = optionsAppearanceManager != null ? optionsAppearanceManager : new AppearanceManager( configDir ); @@ -554,10 +556,22 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // System.out.println( "install actions" ); Descriptions desc = new BigWarpActions.Descriptions(); + CommandDescriptions bwDesc = new CommandDescriptions(); + bwDesc.setKeyconfigContext( "bigwarp" ); + desc.getCommandDescriptions( bwDesc ); + desc.getCommandDescriptions( keymapManager.getCommandDescriptions() ); + + System.out.println( "####"); + printDescs( keymapManager.getCommandDescriptions() ); + System.out.println( "####"); + System.out.println( "####"); + printDescs( bwDesc ); + System.out.println( "####"); + preferencesDialog = new PreferencesDialog( viewerFrameP, keymap, new String[] { KeyConfigContexts.BIGDATAVIEWER, "bigwarp", "bw" } ); preferencesDialog.addPage( new AppearanceSettingsPage( "Appearance", appearanceManager ) ); - preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", this.keymapManager, this.keymapManager.getCommandDescriptions() ) ); + preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", this.keymapManager, new KeymapManager(), this.keymapManager.getCommandDescriptions() ) ); // appearanceManager.appearance().updateListeners().add( viewerFrame::repaint ); // appearanceManager.addLafComponent( fileChooser ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 802bd5e5..79be38ff 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -51,11 +51,13 @@ import bigwarp.source.GridSource; import bigwarp.util.BigWarpUtils; import mpicbg.models.AbstractModel; +import net.imglib2.cache.img.DiskCachedCellImg; import net.imglib2.realtransform.AffineTransform3D; public class BigWarpActions extends Actions { public static final CommandDescriptionProvider.Scope BIGWARP = new CommandDescriptionProvider.Scope( "bigwarp" ); + public static final String BIGWARP_CTXT = "bigwarp"; public static final String LANDMARK_MODE_ON = "landmark mode on"; public static final String LANDMARK_MODE_OFF = "landmark mode off"; @@ -221,6 +223,35 @@ public BigWarpActions( final KeyStrokeAdder.Factory keyConfig, String context, S super( keyConfig, context, name ); } +// /* +// * Command descriptions for all provided commands +// */ +// @Plugin( type = CommandDescriptionProvider.class ) +// public static class BdvDescriptions extends CommandDescriptionProvider +// { +// public BdvDescriptions() +// { +// super( BIGWARP, "bigwarp" ); +// bdv.BigDataViewerActions.Descriptions bdvDesc = new BigDataViewerActions.Descriptions(); +// } +// +// @Override +// public void getCommandDescriptions( final CommandDescriptions descriptions ) +// { +// descriptions.add( BRIGHTNESS_SETTINGS,BRIGHTNESS_SETTINGS_KEYS, "Show the Brightness&Colors dialog." ); +// descriptions.add( VISIBILITY_AND_GROUPING, VISIBILITY_AND_GROUPING_KEYS, "Show the Visibility&Grouping dialog." ); +// descriptions.add( SHOW_HELP, SHOW_HELP_KEYS, "Show the Help dialog." ); +// descriptions.add( SAVE_SETTINGS, SAVE_SETTINGS_KEYS, "Save the BigDataViewer settings to a settings.xml file." ); +// descriptions.add( LOAD_SETTINGS, LOAD_SETTINGS_KEYS, "Load the BigDataViewer settings from a settings.xml file." ); +// descriptions.add( EXPAND_CARDS, EXPAND_CARDS_KEYS, "Expand and focus the BigDataViewer card panel" ); +// descriptions.add( COLLAPSE_CARDS, COLLAPSE_CARDS_KEYS, "Collapse the BigDataViewer card panel" ); +// descriptions.add( SET_BOOKMARK, SET_BOOKMARK_KEYS, "Set a labeled bookmark at the current location." ); +// descriptions.add( GO_TO_BOOKMARK, GO_TO_BOOKMARK_KEYS, "Retrieve a labeled bookmark location." ); +// descriptions.add( GO_TO_BOOKMARK_ROTATION, GO_TO_BOOKMARK_ROTATION_KEYS, "Retrieve a labeled bookmark, set only the orientation." ); +// descriptions.add( PREFERENCES_DIALOG, PREFERENCES_DIALOG_KEYS, "Show the Preferences dialog." ); +// } +// } + /* * Command descriptions for all provided commands */ @@ -229,7 +260,7 @@ public static class Descriptions extends CommandDescriptionProvider { public Descriptions() { - super( BIGWARP, "bw" ); + super( BIGWARP, "bigwarp" ); } @Override @@ -251,6 +282,35 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) descriptions.add( PREFERENCES_DIALOG, PREFERENCES_DIALOG_KEYS, "Show the Preferences dialog." ); } } + +// @Plugin( type = CommandDescriptionProvider.class ) +// public static class TableDescriptions extends CommandDescriptionProvider +// { +// public TableDescriptions() +// { +// super( BIGWARP, "bw-table" ); +//// super( BDV, "bdv" ); +// } +// +// @Override +// public void getCommandDescriptions( final CommandDescriptions descriptions ) +// { +// descriptions.add( TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS, "Toggle landmark mode." ); +// +// descriptions.add( BRIGHTNESS_SETTINGS,BRIGHTNESS_SETTINGS_KEYS, "Show the Brightness&Colors dialog." ); +// descriptions.add( VISIBILITY_AND_GROUPING_MVG, VISIBILITY_AND_GROUPING_MVG_KEYS, "Show the Visibility&Grouping dialog for the moving frame." ); +// descriptions.add( VISIBILITY_AND_GROUPING_TGT, VISIBILITY_AND_GROUPING_TGT_KEYS, "Show the Visibility&Grouping dialog for the fixed frame." ); +// descriptions.add( SHOW_HELP, SHOW_HELP_KEYS, "Show the Help dialog." ); +// descriptions.add( SAVE_SETTINGS, SAVE_SETTINGS_KEYS, "Save the BigDataViewer settings to a settings.xml file." ); +// descriptions.add( LOAD_SETTINGS, LOAD_SETTINGS_KEYS, "Load the BigDataViewer settings from a settings.xml file." ); +// +// descriptions.add( SET_BOOKMARK, SET_BOOKMARK_KEYS, "Set a labeled bookmark at the current location." ); +// descriptions.add( GO_TO_BOOKMARK, GO_TO_BOOKMARK_KEYS, "Retrieve a labeled bookmark location." ); +// descriptions.add( GO_TO_BOOKMARK_ROTATION, GO_TO_BOOKMARK_ROTATION_KEYS, "Retrieve a labeled bookmark, set only the orientation." ); +// +// descriptions.add( PREFERENCES_DIALOG, PREFERENCES_DIALOG_KEYS, "Show the Preferences dialog." ); +// } +// } public static void installViewerActions( Actions actions, @@ -343,7 +403,7 @@ public static void installActionBindings( inputActionBindings.addActionMap( "bw", createActionMap( bw ) ); inputActionBindings.addInputMap( "bw", createInputMap( keyProperties ) ); - inputActionBindings.addActionMap( "bwv", createActionMapViewer( bw ) ); + inputActionBindings.addActionMap( "bwV", createActionMapViewer( bw ) ); inputActionBindings.addInputMap( "bwv", createInputMapViewer( keyProperties ) ); } diff --git a/src/main/java/bigwarp/ui/keymap/DumpInputConfig.java b/src/main/java/bigwarp/ui/keymap/DumpInputConfig.java new file mode 100644 index 00000000..b11207ba --- /dev/null +++ b/src/main/java/bigwarp/ui/keymap/DumpInputConfig.java @@ -0,0 +1,94 @@ +/*- + * #%L + * BigDataViewer core classes with minimal dependencies. + * %% + * Copyright (C) 2012 - 2022 BigDataViewer developers. + * %% + * 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 bigwarp.ui.keymap; + +import bdv.TransformEventHandler2D; +import bdv.TransformEventHandler3D; +import bdv.tools.CloseWindowActions; +import bdv.viewer.NavigationActions; +import bigwarp.BigWarpActions; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import org.scijava.Context; +import org.scijava.plugin.PluginService; +import org.scijava.ui.behaviour.io.InputTriggerConfig; +import org.scijava.ui.behaviour.io.InputTriggerDescription; +import org.scijava.ui.behaviour.io.InputTriggerDescriptionsBuilder; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionsBuilder; +import org.scijava.ui.behaviour.io.yaml.YamlConfigIO; + +class DumpInputConfig +{ + public static void writeToYaml( final String fileName, final InputTriggerConfig config ) throws IOException + { + mkdirs( fileName ); + final List< InputTriggerDescription > descriptions = new InputTriggerDescriptionsBuilder( config ).getDescriptions(); + YamlConfigIO.write( descriptions, fileName ); + } + + public static void writeDefaultConfigToYaml( final String fileName, final Context context ) throws IOException + { + mkdirs( fileName ); + final List< InputTriggerDescription > descriptions = new InputTriggerDescriptionsBuilder( buildCommandDescriptions( context ).createDefaultKeyconfig() ).getDescriptions(); + YamlConfigIO.write( descriptions, fileName ); + } + + private static boolean mkdirs( final String fileName ) + { + final File dir = new File( fileName ).getParentFile(); + return dir != null && dir.mkdirs(); + } + + static CommandDescriptions buildCommandDescriptions( final Context context ) + { + final CommandDescriptionsBuilder builder = new CommandDescriptionsBuilder(); + context.inject( builder ); + + builder.addManually( new BigWarpActions.Descriptions(), BigWarpActions.BIGWARP_CTXT ); + builder.addManually( new NavigationActions.Descriptions(), BigWarpActions.BIGWARP_CTXT ); + builder.addManually( new CloseWindowActions.Descriptions(), BigWarpActions.BIGWARP_CTXT ); + builder.addManually( new TransformEventHandler3D.Descriptions(), BigWarpActions.BIGWARP_CTXT ); + builder.addManually( new TransformEventHandler2D.Descriptions(), BigWarpActions.BIGWARP_CTXT ); + + builder.verifyManuallyAdded(); // TODO: It should be possible to filter by Scope here + + return builder.build(); + } + + public static void main( String[] args ) throws IOException + { + final String target = KeymapManager.class.getResource( "default.yaml" ).getFile(); + final File resource = new File( target.replaceAll( "target/classes", "src/main/resources" ) ); + System.out.println( "resource = " + resource ); + writeDefaultConfigToYaml( resource.getAbsolutePath(), new Context( PluginService.class ) ); + } +} diff --git a/src/main/java/bigwarp/ui/keymap/KeymapManager.java b/src/main/java/bigwarp/ui/keymap/KeymapManager.java new file mode 100644 index 00000000..7de6859c --- /dev/null +++ b/src/main/java/bigwarp/ui/keymap/KeymapManager.java @@ -0,0 +1,157 @@ +package bigwarp.ui.keymap; + +import bdv.KeyConfigScopes; +import bdv.ui.keymap.AbstractKeymapManager; +import bdv.ui.keymap.Keymap; +import bigwarp.BigWarpActions; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import org.scijava.Context; +import org.scijava.plugin.PluginService; +import org.scijava.ui.behaviour.io.InputTriggerConfig; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionsBuilder; +import org.scijava.ui.behaviour.io.yaml.YamlConfigIO; + +/** + * Manages a collection of {@link Keymap}. + *

+ * Provides de/serialization of user-defined keymaps. + * + * @author Tobias Pietzsch + * @author John Bogovic + */ +public class KeymapManager extends AbstractKeymapManager< KeymapManager > +{ + private static final String CONFIG_FILE_NAME = "keymap/"; + + private final String configFile; + + private CommandDescriptions descriptions; + + public KeymapManager( final String configDir ) + { + this( true, configDir ); + discoverCommandDescriptions(); + } + + public KeymapManager() + { + this( false, null ); + } + + private KeymapManager( final boolean loadStyles, final String configDir ) + { + System.out.println( "configDir: " + configDir ); + configFile = configDir == null ? null : configDir + "/" + CONFIG_FILE_NAME; + if ( loadStyles ) + loadStyles(); + } + + public synchronized void setCommandDescriptions( final CommandDescriptions descriptions ) + { + this.descriptions = descriptions; + final Consumer< Keymap > augmentInputTriggerConfig = k -> descriptions.augmentInputTriggerConfig( k.getConfig() ); + builtinStyles.forEach( augmentInputTriggerConfig ); + userStyles.forEach( augmentInputTriggerConfig ); + } + + public CommandDescriptions getCommandDescriptions() + { + return descriptions; + } + + /** + * Discover all {@code CommandDescriptionProvider}s with scope {@link KeyConfigScopes#BIGDATAVIEWER}, + * build {@code CommandDescriptions}, and set it. + */ + public synchronized void discoverCommandDescriptions() + { + final CommandDescriptionsBuilder builder = new CommandDescriptionsBuilder(); + final Context context = new Context( PluginService.class ); + context.inject( builder ); + builder.discoverProviders( BigWarpActions.BIGWARP ); + context.dispose(); + setCommandDescriptions( builder.build() ); + } + + @Override + protected List< Keymap > loadBuiltinStyles() + { + synchronized ( KeymapManager.class ) + { + // TODO figures this out + if ( loadedBuiltinStyles == null ) + try + { + loadedBuiltinStyles = Arrays.asList( + loadBuiltinStyle( "Default", "default.yaml" ) ); + } +// catch ( final IOException e ) + catch ( final Exception e ) + { + e.printStackTrace(); + loadedBuiltinStyles = Arrays.asList( createDefaultStyle( "Default" ) ); + } + +// if ( loadedBuiltinStyles == null ) +// loadedBuiltinStyles = Arrays.asList( createDefaultStyle( "Default" ) ); + } + + return loadedBuiltinStyles; + } + + private static List< Keymap > loadedBuiltinStyles; + + private static Keymap loadBuiltinStyle( final String name, final String filename ) throws IOException + { + System.out.println( "loadBuiltinStyle" ); + System.out.println( filename ); + System.out.println( KeymapManager.class.getResourceAsStream( filename ) ); + System.out.println( "" ); + + try ( Reader reader = new InputStreamReader( KeymapManager.class.getResourceAsStream( filename ) ) ) + { + return new Keymap( name, new InputTriggerConfig( YamlConfigIO.read( reader ) ) ); + } + } + + private static Keymap createDefaultStyle( final String name ) + { + final Context context = new Context( PluginService.class ); + final InputTriggerConfig defaultKeyconfig = DumpInputConfig.buildCommandDescriptions( context ).createDefaultKeyconfig(); + return new Keymap( name, defaultKeyconfig ); + } + + public void loadStyles() + { + try + { + loadStyles( new File( configFile ) ); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + } + + @Override + public void saveStyles() + { + System.out.println( "saveStyles" ); + try + { + saveStyles( new File( configFile ) ); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + } +} diff --git a/src/main/resources/bigwarp/ui/keymap/default.yaml b/src/main/resources/bigwarp/ui/keymap/default.yaml new file mode 100644 index 00000000..381c3012 --- /dev/null +++ b/src/main/resources/bigwarp/ui/keymap/default.yaml @@ -0,0 +1,45 @@ +--- +- !mapping + action: Preferences + contexts: [bigwarp] + triggers: [ctrl COMMA, meta COMMA] +- !mapping + action: brightness settings + contexts: [bigwarp] + triggers: [S] +- !mapping + action: go to bookmark + contexts: [bigwarp] + triggers: [B] +- !mapping + action: go to bookmark rotation + contexts: [bigwarp] + triggers: [shift ctrl B] +- !mapping + action: help + contexts: [bigwarp] + triggers: [F1] +- !mapping + action: landmark mode toggle + contexts: [bigwarp] + triggers: [SPACE] +- !mapping + action: set bookmark + contexts: [bigwarp] + triggers: [shift B] +- !mapping + action: visibility and grouping moving + contexts: [bigwarp] + triggers: [F3] +- !mapping + action: visibility and grouping target + contexts: [bigwarp] + triggers: [F4] +- !mapping + action: save settings + contexts: [bigwarp] + triggers: [not mapped] +- !mapping + action: load settings + contexts: [bigwarp] + triggers: [not mapped] From 91e8e248c33f5690865b1504aac49473a2585f09 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 13 Sep 2022 09:44:44 -0400 Subject: [PATCH 036/282] add more command descriptions --- src/main/java/bigwarp/BigWarpActions.java | 35 +++++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 79be38ff..cb62bbb7 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -267,11 +267,15 @@ public Descriptions() public void getCommandDescriptions( final CommandDescriptions descriptions ) { descriptions.add( TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS, "Toggle landmark mode." ); + descriptions.add( TOGGLE_MOVING_IMAGE_DISPLAY, TOGGLE_MOVING_IMAGE_DISPLAY_KEYS, "Toggle landmark mode." ); - descriptions.add( BRIGHTNESS_SETTINGS,BRIGHTNESS_SETTINGS_KEYS, "Show the Brightness&Colors dialog." ); + descriptions.add( SHOW_HELP, SHOW_HELP_KEYS, "Show the Help dialog." ); + descriptions.add( SHOW_WARPTYPE_DIALOG, SHOW_WARPTYPE_DIALOG_KEYS, "Show the BigWarp options dialog." ); + descriptions.add( PREFERENCES_DIALOG, PREFERENCES_DIALOG_KEYS, "Show the appearance and keymap dialog." ); + + descriptions.add( BRIGHTNESS_SETTINGS, BRIGHTNESS_SETTINGS_KEYS, "Show the Brightness & Colors dialog." ); descriptions.add( VISIBILITY_AND_GROUPING_MVG, VISIBILITY_AND_GROUPING_MVG_KEYS, "Show the Visibility&Grouping dialog for the moving frame." ); descriptions.add( VISIBILITY_AND_GROUPING_TGT, VISIBILITY_AND_GROUPING_TGT_KEYS, "Show the Visibility&Grouping dialog for the fixed frame." ); - descriptions.add( SHOW_HELP, SHOW_HELP_KEYS, "Show the Help dialog." ); descriptions.add( SAVE_SETTINGS, SAVE_SETTINGS_KEYS, "Save the BigDataViewer settings to a settings.xml file." ); descriptions.add( LOAD_SETTINGS, LOAD_SETTINGS_KEYS, "Load the BigDataViewer settings from a settings.xml file." ); @@ -279,7 +283,32 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) descriptions.add( GO_TO_BOOKMARK, GO_TO_BOOKMARK_KEYS, "Retrieve a labeled bookmark location." ); descriptions.add( GO_TO_BOOKMARK_ROTATION, GO_TO_BOOKMARK_ROTATION_KEYS, "Retrieve a labeled bookmark, set only the orientation." ); - descriptions.add( PREFERENCES_DIALOG, PREFERENCES_DIALOG_KEYS, "Show the Preferences dialog." ); + descriptions.add( RESET_VIEWER, RESET_VIEWER_KEYS, "Resets the view to the view on startup." ); + descriptions.add( ALIGN_OTHER_TO_ACTIVE, ALIGN_OTHER_TO_ACTIVE_KEYS, "Sets the view of the non-active viewer to match the active viewer." ); + descriptions.add( ALIGN_ACTIVE_TO_OTHER, ALIGN_ACTIVE_TO_OTHER_KEYS, "Sets the view of the active viewer to match the non-active viewer." ); + descriptions.add( WARP_TO_SELECTED_POINT, WARP_TO_SELECTED_POINT_KEYS, "Center the viewer on the selected landmark." ); + descriptions.add( WARP_TO_NEAREST_POINT, WARP_TO_NEAREST_POINT_KEYS, "Center the viewer on the nearest landmark." ); + descriptions.add( WARP_TO_NEXT_POINT, WARP_TO_NEXT_POINT_KEYS, "Center the viewer on the next landmark." ); + descriptions.add( WARP_TO_PREV_POINT, WARP_TO_PREV_POINT_KEYS, "Center the viewer on the previous landmark." ); + + // cards + descriptions.add( EXPAND_CARDS, EXPAND_CARDS_KEYS, "Expand and focus the BigDataViewer card panel" ); + descriptions.add( COLLAPSE_CARDS, COLLAPSE_CARDS_KEYS, "Collapse the BigDataViewer card panel" ); + + // export + descriptions.add( EXPORT_WARP, EXPORT_WARP_KEYS, "Show the dialog to export the displacement field." ); + descriptions.add( EXPORT_AFFINE, EXPORT_AFFINE_KEYS, "Print the affine transformation." ); + + // landmarks + descriptions.add( LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS, "Load landmark from a file." ); + descriptions.add( SAVE_LANDMARKS, SAVE_LANDMARKS_KEYS, "Save landmark from a file." ); + descriptions.add( QUICK_SAVE_LANDMARKS, QUICK_SAVE_LANDMARKS_KEYS, "Quick save landmarks."); + descriptions.add( UNDO, UNDO_KEYS, "Undo the last landmark change." ); + descriptions.add( REDO, REDO_KEYS, "Redo the last landmark change." ); + + descriptions.add( TOGGLE_POINTS_VISIBLE, TOGGLE_POINTS_VISIBLE_KEYS, "Toggle visibility of landmarks." ); + descriptions.add( TOGGLE_POINT_NAMES_VISIBLE, TOGGLE_POINT_NAMES_VISIBLE_KEYS , "Toggle visibility of landmark names." ); + } } From c66e67f984b8a0d186dd0092578ece75424ca296 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 13 Sep 2022 14:51:52 -0400 Subject: [PATCH 037/282] add navigation actions + landmark table actions, new table actions --- .../java/bdv/viewer/LandmarkPointMenu.java | 105 ++++++++----- src/main/java/bigwarp/BigWarp.java | 20 +-- src/main/java/bigwarp/BigWarpActions.java | 145 +++++++++--------- .../bigwarp/ui/keymap/NavigationKeys.java | 53 +++++++ 4 files changed, 200 insertions(+), 123 deletions(-) create mode 100644 src/main/java/bigwarp/ui/keymap/NavigationKeys.java diff --git a/src/main/java/bdv/viewer/LandmarkPointMenu.java b/src/main/java/bdv/viewer/LandmarkPointMenu.java index f3420bc9..89d3162e 100644 --- a/src/main/java/bdv/viewer/LandmarkPointMenu.java +++ b/src/main/java/bdv/viewer/LandmarkPointMenu.java @@ -26,6 +26,7 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.util.Arrays; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; @@ -34,6 +35,7 @@ import bdv.gui.BigWarpLandmarkPanel; import bigwarp.BigWarp; +import bigwarp.BigWarpActions; import bigwarp.landmarks.LandmarkTableModel; public class LandmarkPointMenu extends JPopupMenu @@ -50,38 +52,37 @@ public class LandmarkPointMenu extends JPopupMenu public static final String DELETE = "table delete"; public static final String DELETE_SELECTED = "table delete selected "; - public static final String ACTIVATE = "table activate"; - public static final String ACTIVATE_SELECTED = "table activate selected "; + public static final String ACTIVATE_SELECTED = "table activate selected"; + public static final String DEACTIVATE_SELECTED = "table deactivate selected "; private static final long serialVersionUID = -3676180390835767585L; protected BigWarpLandmarkPanel landmarkPanel; - protected BigWarp bw; - -// public ClearHandler clearMoving; -// public ClearHandler clearFixed; + protected BigWarp< ? > bw; + public ClearSelectedHandler clearSelectedMoving; public ClearSelectedHandler clearSelectedFixed; -// public DeleteHandler deleteHandler; public DeleteSelectedHandler deleteSelectedHandler; - public ActivateSelectedHandler activateAllHandler; - public DeactivateSelectedHandler deactivateAllHandler; - + public ActivateSelectedHandler activateSelectedHandler; + public DeactivateSelectedHandler deactivateSelectedHandler; + + public AddToSelection addAboveHandler; + public AddToSelection addAllAboveHandler; + public AddToSelection addBelowHandler; + public AddToSelection addAllBelowHandler; + protected MouseListener popupListener; -// protected JMenuItem deleteSingleItem; protected JMenuItem deleteAllItem; protected JMenuItem activateAllItem; protected JMenuItem deactivateAllItem; -// protected JMenuItem clearMovingItem; -// protected JMenuItem clearFixedItem; protected JMenuItem clearSelectedMovingItem; protected JMenuItem clearSelectedFixedItem; private Point clickPt; - public LandmarkPointMenu( BigWarp bw ) + public LandmarkPointMenu( BigWarp< ? > bw ) { this( bw.getLandmarkPanel() ); this.bw = bw; @@ -91,30 +92,23 @@ public LandmarkPointMenu( BigWarpLandmarkPanel landmarkPanel ) { this.landmarkPanel = landmarkPanel; -// deleteHandler = new DeleteHandler( DELETE ); deleteSelectedHandler = new DeleteSelectedHandler( DELETE_SELECTED ); - activateAllHandler = new ActivateSelectedHandler( ACTIVATE ); - deactivateAllHandler = new DeactivateSelectedHandler( ACTIVATE_SELECTED ); + activateSelectedHandler = new ActivateSelectedHandler( ACTIVATE_SELECTED ); + deactivateSelectedHandler = new DeactivateSelectedHandler( DEACTIVATE_SELECTED ); -// clearMoving = new ClearHandler( CLEAR_MOVING, MOVING ); -// clearFixed = new ClearHandler( CLEAR_FIXED, FIXED ); clearSelectedMoving = new ClearSelectedHandler( CLEAR_SELECTED_MOVING, MOVING ); clearSelectedFixed = new ClearSelectedHandler( CLEAR_SELECTED_FIXED, FIXED ); - popupListener = new PopupListener(); + addAboveHandler = new AddToSelection( BigWarpActions.LANDMARK_SELECT_ABOVE, true, false ); + addAllAboveHandler = new AddToSelection( BigWarpActions.LANDMARK_SELECT_ALL_ABOVE, true, true ); + addBelowHandler = new AddToSelection( BigWarpActions.LANDMARK_SELECT_BELOW, false, false ); + addAllBelowHandler = new AddToSelection( BigWarpActions.LANDMARK_SELECT_ALL_BELOW, false, true ); -// deleteSingleItem = new JMenuItem( "Delete" ); -// deleteSingleItem.addActionListener( deleteHandler ); + popupListener = new PopupListener(); deleteAllItem = new JMenuItem( "Delete" ); deleteAllItem.addActionListener( deleteSelectedHandler ); -// clearMovingItem = new JMenuItem( "Clear moving point" ); -// clearMovingItem.addActionListener( clearMoving ); -// -// clearFixedItem = new JMenuItem( "Clear fixed point" ); -// clearFixedItem.addActionListener( clearFixed ); - clearSelectedMovingItem = new JMenuItem( "Clear moving" ); clearSelectedMovingItem.addActionListener( clearSelectedMoving ); @@ -122,17 +116,14 @@ public LandmarkPointMenu( BigWarpLandmarkPanel landmarkPanel ) clearSelectedFixedItem.addActionListener( clearSelectedFixed ); activateAllItem = new JMenuItem( "Activate" ); - activateAllItem.addActionListener( activateAllHandler ); + activateAllItem.addActionListener( activateSelectedHandler ); deactivateAllItem = new JMenuItem( "Deactivate" ); - deactivateAllItem.addActionListener( deactivateAllHandler ); + deactivateAllItem.addActionListener( deactivateSelectedHandler ); -// this.add( deleteSingleItem ); this.add( deleteAllItem ); this.addSeparator(); -// this.add( clearMovingItem ); -// this.add( clearFixedItem ); this.add( clearSelectedMovingItem ); this.add( clearSelectedFixedItem ); @@ -304,7 +295,8 @@ public ActivateSelectedHandler( String name ) @Override public void actionPerformed(ActionEvent e) { - int[] selectedRows = landmarkPanel.getJTable().getSelectedRows(); + final int[] selectedRows = landmarkPanel.getJTable().getSelectedRows(); + Arrays.sort( selectedRows ); // do in reverse order so that the index for( int i = selectedRows.length - 1; i >= 0; i-- ) @@ -332,7 +324,8 @@ public DeactivateSelectedHandler( String name ) @Override public void actionPerformed(ActionEvent e) { - int[] selectedRows = landmarkPanel.getJTable().getSelectedRows(); + final int[] selectedRows = landmarkPanel.getJTable().getSelectedRows(); + Arrays.sort( selectedRows ); // do in reverse order so that the index for( int i = selectedRows.length - 1; i >= 0; i-- ) @@ -347,4 +340,46 @@ public void actionPerformed(ActionEvent e) landmarkPanel.repaint(); } } + + public class AddToSelection extends AbstractNamedAction + { + private static final long serialVersionUID = -904756750247052099L; + + private final boolean before; + private final boolean all; + + public AddToSelection( final String name, final boolean before, final boolean all ) + { + super( name ); + this.before = before; + this.all = all; + } + + @Override + public void actionPerformed( ActionEvent e ) + { + System.out.println( "add to selection " + before + " " + all ); + final int[] selectedRows = landmarkPanel.getJTable().getSelectedRows(); + Arrays.sort( selectedRows ); + + int i; + int j; + if ( before ) + { + j = selectedRows[ 0 ]; + i = all ? 0 : j - 1; + } else + { + i = selectedRows[ selectedRows.length - 1 ]; + j = all ? landmarkPanel.getJTable().getRowCount() - 1 : i + 1; + } + landmarkPanel.getJTable().getSelectionModel().addSelectionInterval( i, j ); + + if ( bw != null ) + bw.restimateTransformation(); + + landmarkPanel.repaint(); + } + } + } diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index b862016c..187860ca 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -148,6 +148,7 @@ import bigwarp.transforms.BigWarpTransform; import bigwarp.transforms.WrappedCoordinateTransform; import bigwarp.ui.keymap.KeymapManager; +import bigwarp.ui.keymap.NavigationKeys; import bigwarp.util.BigWarpUtils; import dev.dirs.ProjectDirectories; import fiji.util.gui.GenericDialogPlus; @@ -561,15 +562,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie desc.getCommandDescriptions( bwDesc ); desc.getCommandDescriptions( keymapManager.getCommandDescriptions() ); - - System.out.println( "####"); - printDescs( keymapManager.getCommandDescriptions() ); - System.out.println( "####"); - System.out.println( "####"); - printDescs( bwDesc ); - System.out.println( "####"); - - preferencesDialog = new PreferencesDialog( viewerFrameP, keymap, new String[] { KeyConfigContexts.BIGDATAVIEWER, "bigwarp", "bw" } ); + preferencesDialog = new PreferencesDialog( viewerFrameP, keymap, new String[] { KeyConfigContexts.BIGDATAVIEWER, "bigwarp", "bw", "navigation", "bw-table" } ); preferencesDialog.addPage( new AppearanceSettingsPage( "Appearance", appearanceManager ) ); preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", this.keymapManager, new KeymapManager(), this.keymapManager.getCommandDescriptions() ) ); @@ -578,12 +571,12 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // SwingUtilities.invokeLater(() -> appearanceManager.updateLookAndFeel()); - final Actions navigationActions = new Actions( inputTriggerConfig, "bdv", "navigation" ); + final Actions navigationActions = new Actions( inputTriggerConfig, "bigwarp", "navigation" ); navigationActions.install( getViewerFrameP().getKeybindings(), "navigation" ); - NavigationActions.install( navigationActions, getViewerFrameP().getViewerPanel(), options.values.is2D() ); + NavigationKeys.install( navigationActions, getViewerFrameP().getViewerPanel(), options.values.is2D() ); - navigationActions.install( getViewerFrameQ().getKeybindings(), "navigation" ); - NavigationActions.install( navigationActions, getViewerFrameQ().getViewerPanel(), options.values.is2D() ); + navigationActions.install( getViewerFrameQ().getKeybindings(), "bigwarp" ); + NavigationKeys.install( navigationActions, getViewerFrameQ().getViewerPanel(), options.values.is2D() ); BigWarpActions bwActions = new BigWarpActions( inputTriggerConfig, "bw", "bw-general" ); BigWarpActions.installViewerActions( bwActions, getViewerFrameP(), this ); @@ -603,7 +596,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // bwActions.installViewerActions( getViewerFrameQ().getKeybindings(), this ); // BigWarpActions.install( bwActions, ) - // BigWarpActions.installViewerActions( getViewerFrameP().getKeybindings(), this, inputTriggerConfig ); // BigWarpActions.installViewerActions( getViewerFrameQ().getKeybindings(), this, inputTriggerConfig ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index cb62bbb7..2f7a481e 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -35,14 +35,10 @@ import org.scijava.ui.behaviour.KeyStrokeAdder; import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; import org.scijava.ui.behaviour.io.gui.CommandDescriptions; -import org.scijava.ui.behaviour.io.gui.CommandDescriptionsBuilder; import org.scijava.ui.behaviour.util.AbstractNamedAction; import org.scijava.ui.behaviour.util.Actions; import org.scijava.ui.behaviour.util.InputActionBindings; -import bdv.BigDataViewerActions; -import bdv.KeyConfigContexts; -import bdv.KeyConfigScopes; import bdv.gui.BigWarpViewerFrame; import bdv.tools.ToggleDialogAction; import bdv.viewer.SourceAndConverter; @@ -51,7 +47,6 @@ import bigwarp.source.GridSource; import bigwarp.util.BigWarpUtils; import mpicbg.models.AbstractModel; -import net.imglib2.cache.img.DiskCachedCellImg; import net.imglib2.realtransform.AffineTransform3D; public class BigWarpActions extends Actions @@ -97,8 +92,6 @@ public class BigWarpActions extends Actions public static final String TOGGLE_ESTIMATE_WARP_ONDRAG = "toggle estimate warp on drag"; public static final String[] TOGGLE_ESTIMATE_WARP_ONDRAG_KEYS = new String[]{}; -// public static final String CROP = "crop"; - public static final String SAVE_SETTINGS = "save settings"; public static final String[] SAVE_SETTINGS_KEYS = new String[]{}; @@ -145,17 +138,16 @@ public class BigWarpActions extends Actions public static final String ALIGN_ACTIVE_TO_OTHER = String.format( ALIGN_VIEW_TRANSFORMS, AlignViewerPanelAction.TYPE.ACTIVE_TO_OTHER ); public static final String[] ALIGN_ACTIVE_TO_OTHER_KEYS = new String[] { "W" }; - - public static final String WARP_TO_SELECTED_POINT = "warp to selected landmark"; + public static final String WARP_TO_SELECTED_POINT = "center on selected landmark"; public static final String[] WARP_TO_SELECTED_POINT_KEYS = new String[]{ "D" }; - public static final String WARP_TO_NEXT_POINT = "warp to next landmark"; + public static final String WARP_TO_NEXT_POINT = "center on next landmark"; public static final String[] WARP_TO_NEXT_POINT_KEYS = new String[]{ "ctrl D"}; - public static final String WARP_TO_PREV_POINT = "warp to prev landmark"; + public static final String WARP_TO_PREV_POINT = "center on prev landmark"; public static final String[] WARP_TO_PREV_POINT_KEYS = new String[]{ "ctrl shift D"}; - public static final String WARP_TO_NEAREST_POINT = "warp to nearest landmark"; + public static final String WARP_TO_NEAREST_POINT = "center on nearest landmark"; public static final String[] WARP_TO_NEAREST_POINT_KEYS = new String[]{ "E" }; // landmark options @@ -189,19 +181,38 @@ public class BigWarpActions extends Actions public static final String[] LANDMARK_SELECT_ALL_KEYS = new String[]{ "ctrl A"}; public static final String LANDMARK_DESELECT_ALL = "deselect all landmarks"; - public static final String[] LANDMARK_DESELECT_ALL_KEYS = new String[]{ "ESCAPE" }; + public static final String[] LANDMARK_DESELECT_ALL_KEYS = new String[]{ "ESCAPE", "ctrl shift A" }; + + public static final String LANDMARK_SELECT_ABOVE = "select landmark above"; + public static final String[] LANDMARK_SELECT_ABOVE_KEYS = new String[]{ "ctrl UP"}; + + public static final String LANDMARK_SELECT_ALL_ABOVE = "select all landmarks above"; + public static final String[] LANDMARK_SELECT_ALL_ABOVE_KEYS = new String[]{ "ctrl shift UP"}; + + public static final String LANDMARK_SELECT_BELOW = "select landmark below"; + public static final String[] LANDMARK_SELECT_BELOW_KEYS = new String[]{ "ctrl DOWN"}; + + public static final String LANDMARK_SELECT_ALL_BELOW = "select all landmarks below"; + public static final String[] LANDMARK_SELECT_ALL_BELOW_KEYS = new String[]{ "ctrl shift DOWN"}; public static final String LANDMARK_DELETE_SELECTED = "delete selected landmarks"; - public static final String[] LANDMARK_DELETE_SELECTED_KEYS = new String[]{ "DELETE"}; + public static final String[] LANDMARK_DELETE_SELECTED_KEYS = new String[]{ "DELETE" }; - public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; + public static final String LANDMARK_DEACTIVATE_SELECTED = "deactivate selected landmarks"; + public static final String[] LANDMARK_DEACTIVATE_SELECTED_KEYS = new String[]{ "BACK_SPACE" }; + + public static final String LANDMARK_ACTIVATE_SELECTED = "activate selected landmarks"; + public static final String[] LANDMARK_ACTIVATE_SELECTED_KEYS = new String[]{ "ctrl BACK_SPACE" }; + public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; // export options public static final String SAVE_WARPED = "save warped"; public static final String SAVE_WARPED_XML = "save warped xml"; + public static final String[] SAVE_WARPED_XML_KEYS = new String[] { "ctrl E" }; public static final String EXPORT_IP = "export imageplus"; + public static final String[] EXPORT_IP_KEYS = new String[] { "ctrl shift W" }; public static final String EXPORT_WARP = "export warp field"; public static final String[] EXPORT_WARP_KEYS = new String[] { "ctrl W" }; @@ -222,36 +233,7 @@ public BigWarpActions( final KeyStrokeAdder.Factory keyConfig, String context, S { super( keyConfig, context, name ); } - -// /* -// * Command descriptions for all provided commands -// */ -// @Plugin( type = CommandDescriptionProvider.class ) -// public static class BdvDescriptions extends CommandDescriptionProvider -// { -// public BdvDescriptions() -// { -// super( BIGWARP, "bigwarp" ); -// bdv.BigDataViewerActions.Descriptions bdvDesc = new BigDataViewerActions.Descriptions(); -// } -// -// @Override -// public void getCommandDescriptions( final CommandDescriptions descriptions ) -// { -// descriptions.add( BRIGHTNESS_SETTINGS,BRIGHTNESS_SETTINGS_KEYS, "Show the Brightness&Colors dialog." ); -// descriptions.add( VISIBILITY_AND_GROUPING, VISIBILITY_AND_GROUPING_KEYS, "Show the Visibility&Grouping dialog." ); -// descriptions.add( SHOW_HELP, SHOW_HELP_KEYS, "Show the Help dialog." ); -// descriptions.add( SAVE_SETTINGS, SAVE_SETTINGS_KEYS, "Save the BigDataViewer settings to a settings.xml file." ); -// descriptions.add( LOAD_SETTINGS, LOAD_SETTINGS_KEYS, "Load the BigDataViewer settings from a settings.xml file." ); -// descriptions.add( EXPAND_CARDS, EXPAND_CARDS_KEYS, "Expand and focus the BigDataViewer card panel" ); -// descriptions.add( COLLAPSE_CARDS, COLLAPSE_CARDS_KEYS, "Collapse the BigDataViewer card panel" ); -// descriptions.add( SET_BOOKMARK, SET_BOOKMARK_KEYS, "Set a labeled bookmark at the current location." ); -// descriptions.add( GO_TO_BOOKMARK, GO_TO_BOOKMARK_KEYS, "Retrieve a labeled bookmark location." ); -// descriptions.add( GO_TO_BOOKMARK_ROTATION, GO_TO_BOOKMARK_ROTATION_KEYS, "Retrieve a labeled bookmark, set only the orientation." ); -// descriptions.add( PREFERENCES_DIALOG, PREFERENCES_DIALOG_KEYS, "Show the Preferences dialog." ); -// } -// } - + /* * Command descriptions for all provided commands */ @@ -296,6 +278,8 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) descriptions.add( COLLAPSE_CARDS, COLLAPSE_CARDS_KEYS, "Collapse the BigDataViewer card panel" ); // export + descriptions.add( EXPORT_IP, EXPORT_IP_KEYS, "Export moving image to ImageJ." ); + descriptions.add( SAVE_WARPED_XML, SAVE_WARPED_XML_KEYS, "Export moving image to BigDataViewer xml/h5." ); descriptions.add( EXPORT_WARP, EXPORT_WARP_KEYS, "Show the dialog to export the displacement field." ); descriptions.add( EXPORT_AFFINE, EXPORT_AFFINE_KEYS, "Print the affine transformation." ); @@ -312,34 +296,37 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) } } -// @Plugin( type = CommandDescriptionProvider.class ) -// public static class TableDescriptions extends CommandDescriptionProvider -// { -// public TableDescriptions() -// { -// super( BIGWARP, "bw-table" ); -//// super( BDV, "bdv" ); -// } -// -// @Override -// public void getCommandDescriptions( final CommandDescriptions descriptions ) -// { -// descriptions.add( TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS, "Toggle landmark mode." ); -// -// descriptions.add( BRIGHTNESS_SETTINGS,BRIGHTNESS_SETTINGS_KEYS, "Show the Brightness&Colors dialog." ); -// descriptions.add( VISIBILITY_AND_GROUPING_MVG, VISIBILITY_AND_GROUPING_MVG_KEYS, "Show the Visibility&Grouping dialog for the moving frame." ); -// descriptions.add( VISIBILITY_AND_GROUPING_TGT, VISIBILITY_AND_GROUPING_TGT_KEYS, "Show the Visibility&Grouping dialog for the fixed frame." ); -// descriptions.add( SHOW_HELP, SHOW_HELP_KEYS, "Show the Help dialog." ); -// descriptions.add( SAVE_SETTINGS, SAVE_SETTINGS_KEYS, "Save the BigDataViewer settings to a settings.xml file." ); -// descriptions.add( LOAD_SETTINGS, LOAD_SETTINGS_KEYS, "Load the BigDataViewer settings from a settings.xml file." ); -// -// descriptions.add( SET_BOOKMARK, SET_BOOKMARK_KEYS, "Set a labeled bookmark at the current location." ); -// descriptions.add( GO_TO_BOOKMARK, GO_TO_BOOKMARK_KEYS, "Retrieve a labeled bookmark location." ); -// descriptions.add( GO_TO_BOOKMARK_ROTATION, GO_TO_BOOKMARK_ROTATION_KEYS, "Retrieve a labeled bookmark, set only the orientation." ); -// -// descriptions.add( PREFERENCES_DIALOG, PREFERENCES_DIALOG_KEYS, "Show the Preferences dialog." ); -// } -// } + @Plugin( type = CommandDescriptionProvider.class ) + public static class TableDescriptions extends CommandDescriptionProvider + { + public TableDescriptions() + { + super( BIGWARP, "bw-table" ); + } + + @Override + public void getCommandDescriptions( final CommandDescriptions descriptions ) + { + descriptions.add( LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS, "Load landmark from a file." ); + descriptions.add( SAVE_LANDMARKS, SAVE_LANDMARKS_KEYS, "Save landmark from a file." ); + descriptions.add( QUICK_SAVE_LANDMARKS, QUICK_SAVE_LANDMARKS_KEYS, "Quick save landmarks."); + + descriptions.add( LANDMARK_SELECT_ALL, LANDMARK_SELECT_ALL_KEYS, "Select all landmarks." ); + descriptions.add( LANDMARK_DESELECT_ALL, LANDMARK_DESELECT_ALL_KEYS, "Deselect all landmarks." ); + + descriptions.add( LANDMARK_DELETE_SELECTED, LANDMARK_DELETE_SELECTED_KEYS, "Delete selected landmarks." ); + descriptions.add( LANDMARK_ACTIVATE_SELECTED, LANDMARK_ACTIVATE_SELECTED_KEYS, "Activate selected landmarks." ); + descriptions.add( LANDMARK_DEACTIVATE_SELECTED, LANDMARK_DEACTIVATE_SELECTED_KEYS, "Deactivate selected landmarks." ); + + descriptions.add( LANDMARK_SELECT_ABOVE, LANDMARK_SELECT_ABOVE_KEYS, "Add the row above the curent selection to the selection" ); + descriptions.add( LANDMARK_SELECT_ALL_ABOVE, LANDMARK_SELECT_ALL_ABOVE_KEYS, "Add the all rows above the curent selection to the selection" ); + descriptions.add( LANDMARK_SELECT_BELOW, LANDMARK_SELECT_BELOW_KEYS, "Add the row below the curent selection to the selection" ); + descriptions.add( LANDMARK_SELECT_ALL_BELOW, LANDMARK_SELECT_ALL_BELOW_KEYS, "Add the all rows below the curent selection to the selection" ); + + descriptions.add( UNDO, UNDO_KEYS, "Undo the last landmark change." ); + descriptions.add( REDO, REDO_KEYS, "Redo the last landmark change." ); + } + } public static void installViewerActions( Actions actions, @@ -399,7 +386,7 @@ public static void installTableActions( final InputActionBindings inputActionBindings, final BigWarp< ? > bw ) { - actions.install( inputActionBindings, "bw" ); + actions.install( inputActionBindings, "bw-table" ); // landmarks actions.runnableAction( bw::loadLandmarks, LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS ); @@ -411,6 +398,16 @@ public static void installTableActions( actions.namedAction( bw.landmarkPopupMenu.deleteSelectedHandler, LANDMARK_DELETE_SELECTED_KEYS ); + actions.namedAction( bw.landmarkPopupMenu.activateSelectedHandler, LANDMARK_ACTIVATE_SELECTED_KEYS ); + actions.namedAction( bw.landmarkPopupMenu.deactivateSelectedHandler, LANDMARK_DEACTIVATE_SELECTED_KEYS ); + + actions.namedAction( bw.landmarkPopupMenu.addAboveHandler, LANDMARK_SELECT_ABOVE_KEYS ); + actions.namedAction( bw.landmarkPopupMenu.addAllAboveHandler, LANDMARK_SELECT_ALL_ABOVE_KEYS ); + actions.namedAction( bw.landmarkPopupMenu.addBelowHandler, LANDMARK_SELECT_BELOW_KEYS ); + actions.namedAction( bw.landmarkPopupMenu.addAllBelowHandler, LANDMARK_SELECT_ALL_BELOW_KEYS ); + + actions.namedAction( new UndoRedoAction( UNDO, bw ), UNDO_KEYS ); + actions.namedAction( new UndoRedoAction( REDO, bw ), REDO_KEYS ); } /** diff --git a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java new file mode 100644 index 00000000..f574d5ee --- /dev/null +++ b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java @@ -0,0 +1,53 @@ +package bigwarp.ui.keymap; + +import java.util.stream.IntStream; + +import org.scijava.plugin.Plugin; +import org.scijava.ui.behaviour.KeyStrokeAdder.Factory; +import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; +import org.scijava.ui.behaviour.io.gui.CommandDescriptions; + +import bdv.viewer.NavigationActions; +import bigwarp.BigWarpActions; + +public class NavigationKeys extends NavigationActions +{ + + public NavigationKeys( Factory keyConfig ) + { + super( keyConfig ); + } + + /* + * Command descriptions for all provided commands + */ + @Plugin( type = CommandDescriptionProvider.class ) + public static class Descriptions extends CommandDescriptionProvider + { + public Descriptions() + { + super( BigWarpActions.BIGWARP, BigWarpActions.BIGWARP_CTXT ); + } + + @Override + public void getCommandDescriptions( final CommandDescriptions descriptions ) + { + descriptions.add( TOGGLE_INTERPOLATION, TOGGLE_INTERPOLATION_KEYS, "Switch between nearest-neighbor and n-linear interpolation mode in BigDataViewer." ); + descriptions.add( TOGGLE_FUSED_MODE, TOGGLE_FUSED_MODE_KEYS, "TODO" ); + descriptions.add( TOGGLE_GROUPING, TOGGLE_GROUPING_KEYS, "TODO" ); + + final String[] numkeys = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" }; + IntStream.range( 0, numkeys.length ).forEach( i -> { + descriptions.add( String.format( SET_CURRENT_SOURCE, i ), new String[] { String.format( SET_CURRENT_SOURCE_KEYS_FORMAT, numkeys[ i ] ) }, "TODO" ); + descriptions.add( String.format( TOGGLE_SOURCE_VISIBILITY, i ), new String[] { String.format( TOGGLE_SOURCE_VISIBILITY_KEYS_FORMAT, numkeys[ i ] ) }, "TODO" ); + } ); + + descriptions.add( NEXT_TIMEPOINT, NEXT_TIMEPOINT_KEYS, "TODO" ); + descriptions.add( PREVIOUS_TIMEPOINT, PREVIOUS_TIMEPOINT_KEYS, "TODO" ); + descriptions.add( ALIGN_XY_PLANE, ALIGN_XY_PLANE_KEYS, "TODO" ); + descriptions.add( ALIGN_ZY_PLANE, ALIGN_ZY_PLANE_KEYS, "TODO" ); + descriptions.add( ALIGN_XZ_PLANE, ALIGN_XZ_PLANE_KEYS, "TODO" ); + } + } + +} From 4d4090f81cd38265e1b895f93a1ead0fe306a163 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 14 Sep 2022 13:52:20 -0400 Subject: [PATCH 038/282] change mousde drag mask edit behavior * fix issue with negative sigmas --- .../gui/MaskedSourceEditorMouseListener.java | 68 +++++++++++++------ ...teauSphericalMaskRealRandomAccessible.java | 6 +- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java index dfaf54aa..4972d677 100644 --- a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -23,8 +23,11 @@ public class MaskedSourceEditorMouseListener implements MouseListener, MouseMoti protected List overlays; private boolean active; + private boolean dragged = false; + private RealPoint p; -// private RealPoint pressPt; + private RealPoint c; + private RealPoint pressPt; private BigWarp bw; @@ -45,7 +48,8 @@ public MaskedSourceEditorMouseListener( int nd, BigWarp bw, BigWarpViewerPane overlays.add( bw.getViewerFrameQ().getViewerPanel().getMaskOverlay() ); p = new RealPoint( nd ); -// pressPt = new RealPoint( nd ); + c = new RealPoint( nd ); + pressPt = new RealPoint( nd ); active = false; } @@ -90,19 +94,7 @@ public void mousePressed( MouseEvent e ) if( !active ) return; -// viewer.getGlobalMouseCoordinates( pressPt ); - viewer.getGlobalMouseCoordinates( p ); - if( e.isControlDown() || e.isShiftDown() ) - return; - - synchronized ( mask ) - { -// mask.setCenter( pressPt ); - mask.setCenter( p ); - } - bw.setAutoEstimateMask( false ); - bw.getViewerFrameP().getViewerPanel().requestRepaint(); - bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + dragged = false; } @Override @@ -114,30 +106,44 @@ public void mouseDragged( MouseEvent e ) if( !active ) return; + // store starting center at start of drag + if( !dragged ) + { + c.setPosition( mask.getCenter() ); + viewer.getGlobalMouseCoordinates( pressPt ); + dragged = true; + } + viewer.getGlobalMouseCoordinates( p ); bw.setAutoEstimateMask( false ); if( e.isControlDown() ) { + final double d = PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ); synchronized ( mask ) { -// mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, pressPt ) ); - mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ) ); + mask.setSquaredRadius( d ); } } else if( e.isShiftDown() ) { + final double d = Math.sqrt( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() )); synchronized ( mask ) { - double d = Math.sqrt( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() )); mask.setSigma( d - Math.sqrt( mask.getSquaredRadius()) ); } } else { + // p - pressPt inside the setPosition is the delta + // c is the original center (before dragging started) + // the code below sets the mask center to (c + delta) + for( int i = 0; i < p.numDimensions(); i++ ) + p.setPosition( c.getDoublePosition(i) + p.getDoublePosition(i) - pressPt.getDoublePosition(i), i); + synchronized ( mask ) { - mask.setSquaredRadius( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ) ); + mask.setCenter(p); } } @@ -146,7 +152,29 @@ else if( e.isShiftDown() ) } @Override - public void mouseReleased( MouseEvent e ) { } + public void mouseReleased( MouseEvent e ) { + + if( !active ) + return; + + if( e.isControlDown() || e.isShiftDown() ) + return; + + if( !dragged ) + { + viewer.getGlobalMouseCoordinates( pressPt ); + synchronized ( mask ) + { + mask.setCenter( pressPt ); + } + + bw.setAutoEstimateMask( false ); + bw.getViewerFrameP().getViewerPanel().requestRepaint(); + bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + } + else + dragged = false; + } @Override public void mouseWheelMoved( MouseWheelEvent e ) diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index f0505aef..e5753a98 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -129,8 +129,8 @@ public double getSigma() public void setSigma( double sigma ) { - this.sigma = sigma; - sqrSigma = sigma * sigma; + this.sigma = sigma < 0 ? -sigma : sigma; + sqrSigma = this.sigma * this.sigma; if( sqrSigma <= 0 ) sqrSigma = EPS; @@ -139,7 +139,7 @@ public void setSigma( double sigma ) updateGaussSigma(); if ( overlays != null ) - overlays.stream().forEach( o -> o.setOuterRadiusDelta( sigma )); + overlays.stream().forEach( o -> o.setOuterRadiusDelta( this.sigma )); } public void setSquaredSigma( double squaredSigma ) From e27676618268d73c42762b0b6c1348a8fe386dbc Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 13:35:50 -0400 Subject: [PATCH 039/282] build: add xmlunit test dep --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 9cbab85d..6801fb1b 100644 --- a/pom.xml +++ b/pom.xml @@ -302,5 +302,10 @@ junit test + + xmlunit + xmlunit + 1.5 + From 872c4551e3c2653a662a9f62aed8a21f1c957b99 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 15:15:35 -0400 Subject: [PATCH 040/282] refactor!: fall off shape --- src/main/java/bdv/gui/MaskOptionsPanel.java | 19 +- .../bdv/gui/TransformTypeSelectDialog.java | 4 +- ...teauSphericalMaskRealRandomAccessible.java | 253 ++++++++++++++---- 3 files changed, 204 insertions(+), 72 deletions(-) diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index 8f8fde8e..f0f38bd2 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -1,11 +1,14 @@ package bdv.gui; +import bigwarp.BigWarp; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffShape; +import bigwarp.source.PlateauSphericalMaskSource; +import bigwarp.transforms.BigWarpTransform; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; - import javax.swing.BorderFactory; import javax.swing.JCheckBox; import javax.swing.JComboBox; @@ -14,12 +17,6 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import bigwarp.BigWarp; -import bigwarp.BigWarpAutoSaver; -import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffType; -import bigwarp.source.PlateauSphericalMaskSource; -import bigwarp.transforms.BigWarpTransform; - public class MaskOptionsPanel extends JPanel { private static final long serialVersionUID = -8614381106547838575L; @@ -44,7 +41,7 @@ public class MaskOptionsPanel extends JPanel private final JCheckBox showMaskOverlayButton; private final JLabel falloffTypeLabel; - private final JComboBox< FalloffType > falloffTypeDropdown; + private final JComboBox< FalloffShape > falloffTypeDropdown; private final JLabel maskTypeLabel; private final JComboBox< String > maskTypeDropdown; @@ -89,7 +86,7 @@ public void stateChanged( ChangeEvent e ) falloffTypeLabel = new JLabel( "Mask falloff"); falloffTypeLabel.setToolTipText( FALLOFF_HELP_TEXT ); - falloffTypeDropdown = new JComboBox<>( FalloffType.values() ); + falloffTypeDropdown = new JComboBox<>( FalloffShape.values() ); falloffTypeDropdown.setToolTipText( FALLOFF_HELP_TEXT ); maskTypeLabel = new JLabel( "Mask interpolation"); @@ -155,7 +152,7 @@ public void setMask( PlateauSphericalMaskSource maskSource ) @Override public void actionPerformed( ActionEvent e ) { - maskSource.getRandomAccessible().setType( (FalloffType)falloffTypeDropdown.getSelectedItem() ); + maskSource.getRandomAccessible().setFalloffShape( (FalloffShape)falloffTypeDropdown.getSelectedItem() ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } @@ -173,7 +170,7 @@ public JCheckBox getShowMaskOverlayButton() return showMaskOverlayButton; } - public JComboBox< FalloffType > getFalloffTypeDropdown() + public JComboBox< FalloffShape > getFalloffShapeDropdown() { return falloffTypeDropdown; } diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index d9d9955c..8b2ce818 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -34,7 +34,7 @@ import javax.swing.JRadioButton; import bigwarp.BigWarp; -import bigwarp.transforms.BigWarpTransform;; +import bigwarp.transforms.BigWarpTransform; public class TransformTypeSelectDialog extends JDialog { @@ -160,7 +160,7 @@ public void addFalloffActionListender( final JRadioButton button ) @Override public void actionPerformed( ActionEvent e ) { - bw.getTpsMaskSource().getRandomAccessible().setType( button.getText() ); + bw.getTpsMaskSource().getRandomAccessible().setFalloffShape( button.getText() ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index e5753a98..9cf8c53b 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -1,15 +1,24 @@ package bigwarp.source; import java.util.List; +import java.util.ArrayList; import java.util.function.BiConsumer; +import java.util.function.Function; import org.jdom2.Element; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import mpicbg.spim.data.XmlHelpers; +import net.imglib2.Interval; import net.imglib2.RealInterval; import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; @@ -17,83 +26,147 @@ import net.imglib2.RealRandomAccessible; import net.imglib2.position.FunctionRealRandomAccessible; import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.Intervals; public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAccessible< DoubleType > { - private BiConsumer< RealLocalizable, DoubleType > pfun; - private FunctionRealRandomAccessible< DoubleType > rra; + transient private BiConsumer< RealLocalizable, DoubleType > pfun; + transient private FunctionRealRandomAccessible< DoubleType > rra; private List overlays; - private int nd; - - private double plateauR; - private double plateauR2; + private FalloffShape fallOffShape; - private double sigma; + transient private int nd; + + transient private double plateauR; + transient private double plateauR2; + + transient private double sigma; + + @SerializedName( SQUARED_SIGMA ) private double sqrSigma; - private double invSqrSigma; + transient private double invSqrSigma; private double gaussInvSqrSigma; + @JsonAdapter( RealPointToDoubleArray.class ) private RealPoint center; private static final double EPS = 1e-6; private static final double PIon2 = Math.PI / 2.0; private static final double PI = Math.PI; - public static enum FalloffType { COSINE, GAUSSIAN, LINEAR }; + public static enum FalloffShape + { + GAUSSIAN( it -> new GaussianFalloff( it ) ), + COSINE( it -> new CosineFalloff( it ) ), + LINEAR( it -> new LinearFalloff( it ) ); + + private final Function< PlateauSphericalMaskRealRandomAccessible, BiConsumer< RealLocalizable, DoubleType > > fallOffProvider; + + FalloffShape( Function< PlateauSphericalMaskRealRandomAccessible, BiConsumer< RealLocalizable, DoubleType > > fallOffProvider ) + { + this.fallOffProvider = fallOffProvider; + } + + public BiConsumer< RealLocalizable, DoubleType > createFalloffFunction( PlateauSphericalMaskRealRandomAccessible mask ) + { + return fallOffProvider.apply( mask ); + } - public PlateauSphericalMaskRealRandomAccessible( int n, RealPoint center ) + } + + public PlateauSphericalMaskRealRandomAccessible( RealPoint center ) { - this.nd = n; + this.nd = center.numDimensions(); this.center = center; - pfun = new CosineFalloff(); + fallOffShape = FalloffShape.COSINE; + pfun = fallOffShape.createFalloffFunction( this ); update(); setRadius( 8.0 ); setSigma ( 10.0 ); } - public void setOverlays( final List< BigWarpMaskSphereOverlay > overlays ) - { + public void setOverlays( final List< BigWarpMaskSphereOverlay > overlays ) { this.overlays = overlays; - if ( overlays != null ) - { - overlays.stream().forEach( o -> { - o.setCenter( center ) ; - o.setInnerRadius( plateauR ); - o.setOuterRadiusDelta( sigma ); + if (overlays != null) { + overlays.stream().forEach(o -> { + o.setCenter(center); + o.setInnerRadius(plateauR); + o.setOuterRadiusDelta(sigma); }); } } - private void update() + public static void main( String[] args ) { - rra = new FunctionRealRandomAccessible<>( nd, pfun, DoubleType::new ); + long S = 50; + double[] center = new double[] { S, S, S }; + RealPoint pt = RealPoint.wrap( center ); + + PlateauSphericalMaskRealRandomAccessible img = new PlateauSphericalMaskRealRandomAccessible( pt ); + img.setRadius( 10 ); + img.setSigma( 10 ); + Interval interval = Intervals.createMinSize( 0, 0, 0, 2 * S, 2 * S, 2 * S ); +// +//// BdvOptions options = BdvOptions.options().screenScales( new double[] { 1 } ); +// BdvOptions options = BdvOptions.options(); +// BdvStackSource< DoubleType > bdv = BdvFunctions.show( img.rra, interval, "img", options ); +// bdv.getBdvHandle().getSetupAssignments().getMinMaxGroups().get( 0 ).setRange( 0, 1 ); +// +//// InputActionBindings kb = bdv.getBdvHandle().getKeybindings(); +//// System.out.println( kb ); +//// kb.removeActionMap( "navigation" ); +//// kb.removeInputMap( "navigation" ); +// +//// bdv.getBdvHandle().getTriggerbindings().removeInputTriggerMap( "block_transform" ); +// +// final MaskedSourceEditorMouseListener ml = new MaskedSourceEditorMouseListener( 3, null, bdv.getBdvHandle().getViewerPanel() ); +// ml.setMask( img ); +//// bdv.getBdvHandle().getViewerPanel().getDisplay().addMouseListener( ml ); +// + double x = 50; + RealRandomAccess< DoubleType > access = img.realRandomAccess(); + access.setPosition( center ); + while ( x < 100 ) + { + access.move( 1, 0 ); + System.out.println( x + "," + access.get().getRealDouble()); + + x = access.getDoublePosition( 0 ); + } } - public void setType( String type ) + private void update() { - setType( FalloffType.valueOf( type )); + rra = new FunctionRealRandomAccessible<>( nd, getFalloffFunction(), DoubleType::new ); } - public void setType( FalloffType type ) + private BiConsumer< RealLocalizable, DoubleType > getFalloffFunction() { - switch (type) { - case GAUSSIAN: - pfun = new GaussianFalloff(); - update(); - break; - case COSINE: - pfun = new CosineFalloff(); - update(); - break; - case LINEAR: - pfun = new LinearFalloff(); - update(); - break; - default: - break; + if ( pfun == null ) + { + pfun = fallOffShape.createFalloffFunction( this ); } + return pfun; + } + + public FalloffShape getFallOffShape() + { + return fallOffShape; + } + + public void setFalloffShape( String type ) + { + setFalloffShape( FalloffShape.valueOf( type ) ); + } + + public void setFalloffShape( FalloffShape shape ) + { + + fallOffShape = shape; + pfun = shape.createFalloffFunction( this ); + update(); } public double getSquaredRadius() @@ -160,7 +233,7 @@ public void incSquaredSigma( double increment ) if ( overlays != null ) overlays.stream().forEach( o -> o.setOuterRadiusDelta( sigma )); } - + private void updateGaussSigma() { final double gsig = gaussSigma( sigma ); @@ -186,6 +259,7 @@ public RealPoint getCenter() return center; } + final public static double squaredDistance( final RealLocalizable position1, final RealLocalizable position2 ) { double dist = 0; @@ -248,6 +322,7 @@ public void fromXml( Element elem ) setSquaredSigma( XmlHelpers.getDouble( p, "squaredSigma" )); } + @Deprecated public void fromJson( JsonObject json ) { final JsonArray c = json.get("center").getAsJsonArray(); @@ -259,7 +334,7 @@ public void fromJson( JsonObject json ) setSquaredRadius( json.get("squaredRadius").getAsDouble() ); setSquaredSigma( json.get("squaredSigma").getAsDouble() ); } - + /** * Re.turns the sigma that makes a Gaussian shape most like a cosine with period T. *

@@ -273,67 +348,127 @@ public static double gaussSigma( double T ) return ( 0.40535876907923957 * T + 0.03706937 ); } - public class GaussianFalloff implements BiConsumer< RealLocalizable, DoubleType > { + public static class GaussianFalloff implements BiConsumer< RealLocalizable, DoubleType > + { + + private final PlateauSphericalMaskRealRandomAccessible mask; + + public GaussianFalloff( PlateauSphericalMaskRealRandomAccessible mask ) + { + this.mask = mask; + } @Override public void accept( RealLocalizable x, DoubleType v ) { v.setZero(); - double r2 = squaredDistance( x, center ); - if( r2 <= plateauR2 ) + double r2 = squaredDistance( x, mask.center ); + if ( r2 <= mask.plateauR2 ) v.setOne(); else { final double r = Math.sqrt( r2 ); // final double t = (r2 - plateauR2); - final double t = (r - plateauR); + final double t = ( r - mask.plateauR ); // TODO sample exp function and interpolate to speed up - v.set( Math.exp( -0.5 * t * t * gaussInvSqrSigma ) ); + v.set( Math.exp( -0.5 * t * t * mask.gaussInvSqrSigma ) ); // v.set( Math.cos( t * 0.5 + 0.5 )); // v.set( 1 / t ); } } } - public class CosineFalloff implements BiConsumer< RealLocalizable, DoubleType > { + public static class CosineFalloff implements BiConsumer< RealLocalizable, DoubleType > + { + + private final PlateauSphericalMaskRealRandomAccessible mask; + + public CosineFalloff( PlateauSphericalMaskRealRandomAccessible mask ) + { + this.mask = mask; + } @Override public void accept( RealLocalizable x, DoubleType v ) { - final double r2 = squaredDistance( x, center ); + final double r2 = squaredDistance( x, mask.center ); final double r = Math.sqrt( r2 ); - if( r2 <= plateauR2 ) + if ( r2 <= mask.plateauR2 ) v.setOne(); - else if ( r >= plateauR + sigma ) + else if ( r >= mask.plateauR + mask.sigma ) v.setZero(); else { // final double t = (r2 - plateauR2); // final double r = Math.sqrt( r2 ); - final double t = (r - plateauR); - double val = 0.5 + 0.5 * Math.cos( t * PI / sigma ); + final double t = ( r - mask.plateauR ); + double val = 0.5 + 0.5 * Math.cos( t * PI / mask.sigma ); v.set( val ); } } } - public class LinearFalloff implements BiConsumer< RealLocalizable, DoubleType > { + public static class LinearFalloff implements BiConsumer< RealLocalizable, DoubleType > + { + + private final PlateauSphericalMaskRealRandomAccessible mask; + + public LinearFalloff( PlateauSphericalMaskRealRandomAccessible mask ) + { + this.mask = mask; + } @Override public void accept( RealLocalizable x, DoubleType v ) { v.setZero(); - final double r2 = squaredDistance( x, center ); - final double d2 = plateauR + sigma; - if( r2 <= plateauR2 ) + final double r2 = squaredDistance( x, mask.center ); + final double d2 = mask.plateauR + mask.sigma; + if ( r2 <= mask.plateauR2 ) v.setOne(); - else if( r2 >= d2 * d2 ) + else if ( r2 >= d2 * d2 ) v.setZero(); else { final double r = Math.sqrt( r2 ); - v.set( 1 - (r - plateauR) / sigma ); + v.set( 1 - ( r - mask.plateauR ) / mask.sigma ); + } + } + } + + public static final String FALLOFF_SHAPE = "falloffShape"; + + public static final String CENTER = "center"; + + public static final String SQUARED_RADIUS = "squaredRadius"; + + public static final String SQUARED_SIGMA = "squaredSigma"; + + public static class RealPointToDoubleArray extends TypeAdapter< RealPoint > + { + + @Override + public void write( final JsonWriter out, final RealPoint value ) throws IOException + { + final JsonWriter jsonWriter = out.beginArray(); + for ( int i = 0; i < value.numDimensions(); i++ ) + { + jsonWriter.value( value.getDoublePosition( i ) ); + } + jsonWriter.endArray(); + } + + @Override + public RealPoint read( final JsonReader in ) throws IOException + { + in.beginArray(); + ArrayList< Double > pos = new ArrayList<>(); + while ( in.hasNext() ) + { + pos.add( in.nextDouble() ); } + in.endArray(); + return new RealPoint( pos.stream().mapToDouble( it -> it ).toArray() ); } } From 85316684cdd77c9e52f38d7286c3cfcb96a65d1f Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 15:16:59 -0400 Subject: [PATCH 041/282] refactor!: invert autosaver assignment --- src/main/java/bdv/gui/AutosaveOptionsPanel.java | 6 +++--- src/main/java/bigwarp/BigWarp.java | 5 +++++ src/main/java/bigwarp/BigWarpAutoSaver.java | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/bdv/gui/AutosaveOptionsPanel.java b/src/main/java/bdv/gui/AutosaveOptionsPanel.java index 26206242..c141ed22 100644 --- a/src/main/java/bdv/gui/AutosaveOptionsPanel.java +++ b/src/main/java/bdv/gui/AutosaveOptionsPanel.java @@ -62,7 +62,7 @@ public void stateChanged( ChangeEvent e ) if ( autoSaver != null ) autoSaver.stop(); - new BigWarpAutoSaver( bw, periodMillis ); + bw.setAutoSaver( new BigWarpAutoSaver( bw, periodMillis )); } } } ); @@ -83,7 +83,7 @@ public void itemStateChanged( ItemEvent e ) savePeriodModel.setValue( lastAutoSaveFreq ); long periodMillis = ((Integer) savePeriodModel.getValue()).longValue() * 60000; - new BigWarpAutoSaver( bw, periodMillis ); + bw.setAutoSaver( new BigWarpAutoSaver( bw, periodMillis )); updating = false; } else @@ -115,7 +115,7 @@ public void itemStateChanged( ItemEvent e ) { final File folder = fileChooser.getSelectedFile(); getAutoSaveFolderText().setText( folder.getAbsolutePath() ); - bw.setAutosaveFolder( folder ); + bw.getAutoSaver().setAutosaveFolder( folder ); } } ); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 2a248065..bd791787 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1935,6 +1935,11 @@ public void setWarpGridSpacing( final double spacing ) viewerQ.requestRepaint(); } + public void setAutoSaver( final BigWarpAutoSaver autoSaver ) + { + this.autoSaver = autoSaver; + } + protected void setupWarpMagBaselineOptions( final CoordinateTransform[] xfm, final int ndim ) { if ( ndim == 2 ) diff --git a/src/main/java/bigwarp/BigWarpAutoSaver.java b/src/main/java/bigwarp/BigWarpAutoSaver.java index 8f1b9b23..aaa72756 100644 --- a/src/main/java/bigwarp/BigWarpAutoSaver.java +++ b/src/main/java/bigwarp/BigWarpAutoSaver.java @@ -50,7 +50,6 @@ public BigWarpAutoSaver( final BigWarp bw, final long period ) { this.bw = bw; this.period = period; - bw.autoSaver = this; timer = new Timer(); saveTask = new AutoSave(); timer.schedule( saveTask, period, period ); @@ -97,8 +96,9 @@ public static void setAutosaveOptions( final BigWarp bw, final long period, f if( bw.autoSaver != null ) bw.autoSaver.stop(); - new BigWarpAutoSaver( bw, period ); - bw.warpVisDialog.repaint(); + final BigWarpAutoSaver autoSaver = new BigWarpAutoSaver( bw, period ); + bw.setAutoSaver( autoSaver ); + autoSaver.setAutosaveFolder( new File( autoSavePath ) ); } else { From d1e3f1598120722112cd0c0152369665fece3caa Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 15:17:07 -0400 Subject: [PATCH 042/282] refactor!: refactor autosaver --- src/main/java/bigwarp/BigWarp.java | 32 ++++----------------- src/main/java/bigwarp/BigWarpAutoSaver.java | 28 ++++++++++++++---- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index bd791787..e45b28f8 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -323,8 +323,6 @@ public class BigWarp< T > final FileDialog fileDialog; - protected File autoSaveDirectory; - protected File lastDirectory; protected File lastLandmarks; @@ -1882,7 +1880,7 @@ private SourceAndConverter< DoubleType > addTpsMaskSource( final BigWarpData< T // TODO think about whether its worth it to pass a type parameter. // or should we just stick with Floats? FinalInterval itvl = new FinalInterval( data.sources.get( data.targetSourceIndices[0] ).getSpimSource().getSource( 0, 0 )); - tpsMask = PlateauSphericalMaskSource.build( ndims, new RealPoint( ndims ), itvl ); + tpsMask = PlateauSphericalMaskSource.build( new RealPoint( ndims ), itvl ); final RealARGBColorConverter< DoubleType > converter = RealARGBColorConverter.create( new DoubleType(), 0, 1 ); converter.setColor( new ARGBType( 0xffffffff ) ); @@ -3208,34 +3206,14 @@ public void requestResolve( final boolean isMoving, final int index, final doubl } - /** - * Set the folder where the results of auto-saving will be stored. - * - * @param autoSaveFolder the destination folder - */ - public void setAutosaveFolder( final File autoSaveFolder ) - { - boolean exists = autoSaveFolder.exists(); - if( !exists ) - exists = autoSaveFolder.mkdir(); - - if( exists && autoSaveFolder.isDirectory() ) - { - this.autoSaveDirectory = autoSaveFolder; - warpVisDialog.getAutoSaveOptionsPanel().getAutoSaveFolderText() - .setText( autoSaveFolder.getAbsolutePath() ); - warpVisDialog.repaint(); - } - } - /** * Saves landmarks to a new File in the user's bigwarp folder. */ public void autoSaveLandmarks() { final File baseFolder; - if( autoSaveDirectory != null ) - baseFolder = autoSaveDirectory; + if ( autoSaver.autoSaveDirectory != null ) + baseFolder = autoSaver.autoSaveDirectory; else baseFolder = getBigwarpSettingsFolder(); @@ -3439,8 +3417,8 @@ protected void saveSettings( final String xmlFilename ) throws IOException final Element autoSaveNode = new Element( "autosave" ); final Element autoSaveLocation = new Element( "location" ); - if( autoSaveDirectory != null ) - autoSaveLocation.setText( autoSaveDirectory.getAbsolutePath() ); + if ( autoSaver.autoSaveDirectory != null ) + autoSaveLocation.setText( autoSaver.autoSaveDirectory.getAbsolutePath() ); else autoSaveLocation.setText( getBigwarpSettingsFolder().getAbsolutePath() ); diff --git a/src/main/java/bigwarp/BigWarpAutoSaver.java b/src/main/java/bigwarp/BigWarpAutoSaver.java index aaa72756..cff4e800 100644 --- a/src/main/java/bigwarp/BigWarpAutoSaver.java +++ b/src/main/java/bigwarp/BigWarpAutoSaver.java @@ -21,13 +21,12 @@ */ package bigwarp; +import bigwarp.landmarks.LandmarkTableModel; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; import java.io.File; -import java.io.IOException; import java.util.Timer; import java.util.TimerTask; -import java.util.function.Supplier; - -import bigwarp.landmarks.LandmarkTableModel; /** * Saves bigwarp landmarks to a file periodically, @@ -86,7 +85,6 @@ public void run() public static void setAutosaveOptions( final BigWarp bw, final long period, final String autoSavePath ) { - bw.setAutosaveFolder( new File( autoSavePath ) ); if( period > 0 ) { @@ -106,4 +104,24 @@ public static void setAutosaveOptions( final BigWarp bw, final long period, f bw.warpVisDialog.repaint(); } } + + /** + * Set the folder where the results of auto-saving will be stored. + * + * @param autoSaveFolder + * the destination folder + */ + public void setAutosaveFolder( final File autoSaveFolder ) + { + boolean exists = autoSaveFolder.exists(); + if ( !exists ) + exists = autoSaveFolder.mkdir(); + + if ( exists && autoSaveFolder.isDirectory() ) + { + autoSaveDirectory = autoSaveFolder; + bw.warpVisDialog.getAutoSaveOptionsPanel().getAutoSaveFolderText().setText( autoSaveFolder.getAbsolutePath() ); + bw.warpVisDialog.repaint(); + } + } } From b251d380ab97f2ef37b7c32eee6000d386e38d07 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 15:17:16 -0400 Subject: [PATCH 043/282] feat: make Bookmark non-final --- src/main/java/bigwarp/BigWarp.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index e45b28f8..bd87f090 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -220,7 +220,7 @@ public class BigWarp< T > final AffineTransform3D fixedViewXfm; - private final Bookmarks bookmarks; + private Bookmarks bookmarks; protected final BookmarksEditor bookmarkEditorP; @@ -2017,6 +2017,11 @@ public void setMovingSpimData( SpimData movingSpimData, File movingImageXml ) this.movingImageXml = movingImageXml; } + public void setBookmarks( final Bookmarks bookmarks ) + { + this.bookmarks = bookmarks; + } + public void setAutoEstimateMask( final boolean selected ) { warpVisDialog.maskOptionsPanel.getAutoEstimateMaskButton().setSelected( selected ); From 922343b4b5614c514deafdb8a0ba1bb754960b44 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 15:17:23 -0400 Subject: [PATCH 044/282] feat!: remove redundant dimension number paramters --- .../source/PlateauSphericalMaskSource.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java b/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java index 58301741..a595f609 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskSource.java @@ -1,6 +1,7 @@ package bigwarp.source; import bdv.util.RealRandomAccessibleIntervalSource; +import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RealPoint; import net.imglib2.type.numeric.real.DoubleType; @@ -9,9 +10,9 @@ public class PlateauSphericalMaskSource extends RealRandomAccessibleIntervalSour { private PlateauSphericalMaskRealRandomAccessible plateauMask; - private PlateauSphericalMaskSource( int n, RealPoint pt, Interval interval ) + private PlateauSphericalMaskSource( RealPoint pt, Interval interval ) { - super( new PlateauSphericalMaskRealRandomAccessible( n, pt ), interval, new DoubleType(), "transform mask" ); + super( new PlateauSphericalMaskRealRandomAccessible( pt ), interval, new DoubleType(), "transform mask" ); } private PlateauSphericalMaskSource( PlateauSphericalMaskRealRandomAccessible mask, Interval interval ) @@ -20,15 +21,19 @@ private PlateauSphericalMaskSource( PlateauSphericalMaskRealRandomAccessible mas this.plateauMask = mask; } + public static PlateauSphericalMaskSource build( final PlateauSphericalMaskRealRandomAccessible mask, final FinalInterval interval ) + { + return new PlateauSphericalMaskSource( mask, interval ); + } + public PlateauSphericalMaskRealRandomAccessible getRandomAccessible() { return plateauMask; } - public static PlateauSphericalMaskSource build( int n, RealPoint pt, Interval interval ) + public static PlateauSphericalMaskSource build( RealPoint pt, Interval interval ) { - PlateauSphericalMaskRealRandomAccessible mask = new PlateauSphericalMaskRealRandomAccessible( n, pt ); + PlateauSphericalMaskRealRandomAccessible mask = new PlateauSphericalMaskRealRandomAccessible( pt ); return new PlateauSphericalMaskSource( mask, interval ); } - } From 36de48b07b5522d88c2052faecda64c28caade66 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 15:17:54 -0400 Subject: [PATCH 045/282] feat!: json serialization --- src/main/java/bigwarp/BigWarp.java | 81 +- src/main/java/bigwarp/BigWarpAutoSaver.java | 11 +- src/main/java/bigwarp/BigwarpSettings.java | 712 ++++++++++++++++++ .../transforms/io/TransformWriterJson.java | 38 +- src/test/java/bigwarp/SerializationTest.java | 177 +++++ ...milarityTransformInterpolationExample.java | 21 +- .../compareKnownXml.bigwarp.settings.xml | 248 ++++++ 7 files changed, 1229 insertions(+), 59 deletions(-) create mode 100644 src/main/java/bigwarp/BigwarpSettings.java create mode 100644 src/test/java/bigwarp/SerializationTest.java create mode 100644 src/test/resources/compareKnownXml.bigwarp.settings.xml diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index bd87f090..b3829e0e 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3396,8 +3396,17 @@ protected void saveSettings() proposedSettingsFile = fileChooser.getSelectedFile(); try { - saveSettings( proposedSettingsFile.getCanonicalPath() ); - } catch ( final IOException e ) + final String canonicalPath = proposedSettingsFile.getCanonicalPath(); + if ( canonicalPath.endsWith( ".json" ) ) + { + saveSettingsJson( canonicalPath ); + } + else + { + saveSettings( canonicalPath ); + } + } + catch ( final IOException e ) { e.printStackTrace(); } @@ -3442,6 +3451,26 @@ protected void saveSettings( final String xmlFilename ) throws IOException xout.output( doc, new FileWriter( xmlFilename ) ); } + protected void saveSettingsJson( final String jsonFilename ) throws IOException + { + BigwarpSettings settings = getSettings(); + settings.serialize( jsonFilename ); + } + + public BigwarpSettings getSettings() + { + BigwarpSettings settings = new BigwarpSettings( + this, + viewerP, + viewerQ, + setupAssignments, + bookmarks, + autoSaver, + tpsMask.getRandomAccessible() + ); + return settings; + } + protected void loadSettings() { final JFileChooser fileChooser = new JFileChooser( getLastDirectory() ); @@ -3462,29 +3491,35 @@ protected void loadSettings() } } - protected void loadSettings( final String xmlFilename ) throws IOException, + protected void loadSettings( final String jsonOrXmlFilename ) throws IOException, JDOMException { - final SAXBuilder sax = new SAXBuilder(); - final Document doc = sax.build( xmlFilename ); - final Element root = doc.getRootElement(); - viewerP.stateFromXml( root.getChild( "viewerP" ) ); - viewerQ.stateFromXml( root.getChild( "viewerQ" ) ); - setupAssignments.restoreFromXml( root ); - bookmarks.restoreFromXml( root ); - activeSourcesDialogP.update(); - activeSourcesDialogQ.update(); - - // auto-save settings - Element autoSaveElem = root.getChild( "autosave" ); - final String autoSavePath = autoSaveElem.getChild( "location" ).getText(); - final long autoSavePeriod = Integer.parseInt( autoSaveElem.getChild( "period" ).getText()); - setAutosaveFolder( new File( autoSavePath )); - BigWarpAutoSaver.setAutosaveOptions( this, autoSavePeriod, autoSavePath ); - - final Element maskSettings = root.getChild( "transform-mask" ); - if( maskSettings != null ) - tpsMask.getRandomAccessible().fromXml( maskSettings ); + if (jsonOrXmlFilename.endsWith( ".json" )) { + getSettings().read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); + activeSourcesDialogP.update(); + activeSourcesDialogQ.update(); + } else { + final SAXBuilder sax = new SAXBuilder(); + final Document doc = sax.build( jsonOrXmlFilename ); + final Element root = doc.getRootElement(); + viewerP.stateFromXml( root.getChild( "viewerP" ) ); + viewerQ.stateFromXml( root.getChild( "viewerQ" ) ); + setupAssignments.restoreFromXml( root ); + bookmarks.restoreFromXml( root ); + activeSourcesDialogP.update(); + activeSourcesDialogQ.update(); + + // auto-save settings + Element autoSaveElem = root.getChild( "autosave" ); + final String autoSavePath = autoSaveElem.getChild( "location" ).getText(); + final long autoSavePeriod = Integer.parseInt( autoSaveElem.getChild( "period" ).getText() ); + BigWarpAutoSaver.setAutosaveOptions( this, autoSavePeriod, autoSavePath ); + + final Element maskSettings = root.getChild( "transform-mask" ); + if ( maskSettings != null ) + tpsMask.getRandomAccessible().fromXml( maskSettings ); + } + viewerFrameP.repaint(); viewerFrameQ.repaint(); diff --git a/src/main/java/bigwarp/BigWarpAutoSaver.java b/src/main/java/bigwarp/BigWarpAutoSaver.java index cff4e800..6eda2626 100644 --- a/src/main/java/bigwarp/BigWarpAutoSaver.java +++ b/src/main/java/bigwarp/BigWarpAutoSaver.java @@ -37,14 +37,19 @@ */ public class BigWarpAutoSaver { - private final BigWarp bw; + transient private final BigWarp bw; - final Timer timer; + transient final Timer timer; - final AutoSave saveTask; + transient final AutoSave saveTask; final long period; + @SerializedName("location") + @JsonAdapter( BigwarpSettings.FileAdapter.class ) + protected File autoSaveDirectory; + + public BigWarpAutoSaver( final BigWarp bw, final long period ) { this.bw = bw; diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java new file mode 100644 index 00000000..cff049c0 --- /dev/null +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -0,0 +1,712 @@ +package bigwarp; + +import bdv.tools.bookmarks.Bookmarks; +import bdv.tools.brightness.ConverterSetup; +import bdv.tools.brightness.MinMaxGroup; +import bdv.tools.brightness.SetupAssignments; +import bdv.viewer.BigWarpViewerPanel; +import bdv.viewer.DisplayMode; +import bdv.viewer.Interpolation; +import bdv.viewer.SynchronizedViewerState; +import bdv.viewer.ViewerPanel; +import bdv.viewer.state.SourceGroup; +import bdv.viewer.state.SourceState; +import bdv.viewer.state.ViewerState; +import bdv.viewer.state.XmlIoViewerState; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.type.numeric.ARGBType; +import org.scijava.listeners.Listeners; + +import static bdv.viewer.Interpolation.NEARESTNEIGHBOR; + +public class BigwarpSettings extends TypeAdapter< BigwarpSettings > +{ + + public static Gson gson = new GsonBuilder() + .registerTypeAdapter( AffineTransform3D.class, new AffineTransform3dAdapter() ) + .setPrettyPrinting() + .create(); + + transient private final BigWarp< ? > bigWarp; + + BigWarpViewerPanel viewerP; + + BigWarpViewerPanel viewerQ; + + SetupAssignments setupAssignments; + + Bookmarks bookmarks; + + BigWarpAutoSaver autoSaver; + + final PlateauSphericalMaskRealRandomAccessible tpsMask; + + public BigwarpSettings( BigWarp bigWarp, final BigWarpViewerPanel viewerP, final BigWarpViewerPanel viewerQ, final SetupAssignments setupAssignments, final Bookmarks bookmarks, final BigWarpAutoSaver autoSaver, final PlateauSphericalMaskRealRandomAccessible tpsMask ) + { + + this.bigWarp = bigWarp; + this.viewerP = viewerP; + this.viewerQ = viewerQ; + this.setupAssignments = setupAssignments; + this.bookmarks = bookmarks; + this.autoSaver = autoSaver; + this.tpsMask = tpsMask; + } + + public void serialize( String jsonFilename ) throws IOException + { + write( new JsonWriter( new FileWriter( jsonFilename ) ), this ); + } + + @Override + public void write( final JsonWriter out, final BigwarpSettings value ) throws IOException + { + out.beginObject(); + out.name( "ViewerP" ); + new BigWarpViewerPanelAdapter( viewerP ).write( out, viewerP ); + out.name( "ViewerQ" ); + new BigWarpViewerPanelAdapter( viewerQ ).write( out, viewerQ ); + out.name( "SetupAssignments" ); + new SetupAssignmentsAdapter( setupAssignments ).write( out, setupAssignments ); + out.name( "Bookmarks" ); + gson.toJson( bookmarks, Bookmarks.class, out ); + out.name( "Autosave" ); + gson.toJson( autoSaver, BigWarpAutoSaver.class, out ); + out.name( "TPSMask" ); + gson.toJson( tpsMask, PlateauSphericalMaskRealRandomAccessible.class, out ); + out.endObject(); + } + + @Override + public BigwarpSettings read( final JsonReader in ) throws IOException + { + in.beginObject(); + while ( in.hasNext() ) + { + final String nextName = in.nextName(); + switch ( nextName ) + { + case "ViewerP": + new BigWarpViewerPanelAdapter( viewerP ).read( in ); + break; + case "ViewerQ": + new BigWarpViewerPanelAdapter( viewerQ ).read( in ); + break; + case "SetupAssignments": + new SetupAssignmentsAdapter( setupAssignments ).read( in ); + break; + case "Bookmarks": + bookmarks = gson.fromJson( in, Bookmarks.class ); + bigWarp.setBookmarks( bookmarks ); + break; + case "Autosave": + autoSaver = gson.fromJson( in, BigWarpAutoSaver.class ); + bigWarp.setAutoSaver( autoSaver ); + break; + case "TPSMask": + final PlateauSphericalMaskRealRandomAccessible maskFromJson = gson.fromJson( in, PlateauSphericalMaskRealRandomAccessible.class ); + tpsMask.setFalloffShape( maskFromJson.getFallOffShape() ); + tpsMask.setSquaredRadius( maskFromJson.getSquaredRadius() ); + tpsMask.setCenter( maskFromJson.getCenter() ); + break; + default: + throw new RuntimeException( "Unknown BigWarpSetting: " + nextName ); + } + } + in.endObject(); + return this; + } + + public static class BigWarpViewerPanelAdapter extends TypeAdapter< BigWarpViewerPanel > + { + + private final BigWarpViewerPanel panel; + + private final ViewerState state; + + public BigWarpViewerPanelAdapter( final BigWarpViewerPanel viewerP ) + { + this.panel = viewerP; + try + { + final Field stateField = ViewerPanel.class.getDeclaredField( "state" ); + stateField.setAccessible( true ); + this.state = ( ViewerState ) stateField.get( panel ); + } + catch ( NoSuchFieldException | IllegalAccessException e ) + { + throw new RuntimeException( e ); + } + } + + @Override + public void write( final JsonWriter out, final BigWarpViewerPanel value ) throws IOException + { + out.beginObject(); + + out.name( XmlIoViewerState.VIEWERSTATE_SOURCES_TAG ); + writeSources( out, value ); + out.name( XmlIoViewerState.VIEWERSTATE_GROUPS_TAG ); + writeGroups( out, value ); + out.name( XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_TAG ); + writeDisplayMode( out, value ); + out.name( XmlIoViewerState.VIEWERSTATE_INTERPOLATION_TAG ); + writeInterpolationMode( out, value ); + out.name( XmlIoViewerState.VIEWERSTATE_CURRENTSOURCE_TAG ).value( value.getState().getCurrentSource() ); + out.name( XmlIoViewerState.VIEWERSTATE_CURRENTGROUP_TAG ).value( value.getState().getCurrentGroup() ); + out.name( XmlIoViewerState.VIEWERSTATE_CURRENTTIMEPOINT_TAG ).value( value.getState().getCurrentTimepoint() ); + + out.endObject(); + } + + private void writeInterpolationMode( final JsonWriter out, final BigWarpViewerPanel value ) throws IOException + { + final Interpolation interpolation = value.getState().getInterpolation(); + switch ( interpolation ) + { + case NLINEAR: + out.value( XmlIoViewerState.VIEWERSTATE_INTERPOLATION_VALUE_NLINEAR ); + break; + case NEARESTNEIGHBOR: + default: + out.value( XmlIoViewerState.VIEWERSTATE_INTERPOLATION_VALUE_NEARESTNEIGHBOR ); + } + } + + private void readInterpolationMode( final JsonReader in ) throws IOException + { + switch ( in.nextString() ) + { + case XmlIoViewerState.VIEWERSTATE_INTERPOLATION_VALUE_NLINEAR: + state.setInterpolation( Interpolation.NLINEAR ); + break; + case XmlIoViewerState.VIEWERSTATE_INTERPOLATION_VALUE_NEARESTNEIGHBOR: + default: + state.setInterpolation( NEARESTNEIGHBOR ); + } + } + + private void writeDisplayMode( final JsonWriter out, final ViewerPanel value ) throws IOException + { + switch ( value.getState().getDisplayMode() ) + { + case GROUP: + out.value( XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_GROUP ); + break; + case FUSED: + out.value( XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_FUSED ); + break; + case FUSEDGROUP: + out.value( XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_FUSEDGROUP ); + break; + case SINGLE: + default: + out.value( XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_SINGLE ); + } + } + + private void readDisplayMode( final JsonReader in ) throws IOException + { + switch ( in.nextString() ) + { + case XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_GROUP: + state.setDisplayMode( DisplayMode.GROUP ); + break; + case XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_FUSED: + state.setDisplayMode( DisplayMode.FUSED ); + break; + case XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_FUSEDGROUP: + state.setDisplayMode( DisplayMode.FUSEDGROUP ); + break; + case XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_SINGLE: + default: + state.setDisplayMode( DisplayMode.SINGLE ); + } + } + + private void writeGroups( final JsonWriter out, final ViewerPanel value ) throws IOException + { + + out.beginArray(); + final List< SourceGroup > sourceGroups = value.getState().getSourceGroups(); + for ( final SourceGroup sourceGroup : sourceGroups ) + { + out.beginObject(); + out.name( XmlIoViewerState.VIEWERSTATE_GROUP_ACTIVE_TAG ).value( sourceGroup.isActive() ); + out.name( XmlIoViewerState.VIEWERSTATE_GROUP_NAME_TAG ).value( sourceGroup.getName() ); + out.name( XmlIoViewerState.VIEWERSTATE_GROUP_SOURCEID_TAG ); + out.beginArray(); + for ( final Integer sourceId : sourceGroup.getSourceIds() ) + { + out.value( sourceId ); + } + out.endArray(); + out.endObject(); + } + out.endArray(); + } + + private void readGroups( final JsonReader in ) throws IOException + { + in.beginArray(); + int i = 0; + while ( in.hasNext() ) + { + in.beginObject(); + final SynchronizedViewerState state = panel.state(); + final bdv.viewer.SourceGroup group = state.getGroups().get( i++ ); + + while ( in.hasNext() ) + { + + switch ( in.nextName() ) + { + case XmlIoViewerState.VIEWERSTATE_GROUP_ACTIVE_TAG: + state.setGroupActive( group, in.nextBoolean() ); + break; + case XmlIoViewerState.VIEWERSTATE_GROUP_NAME_TAG: + state.setGroupName( group, in.nextString() ); + break; + case XmlIoViewerState.VIEWERSTATE_GROUP_SOURCEID_TAG: + state.removeSourcesFromGroup( new ArrayList<>( state.getSourcesInGroup( group ) ), group ); + in.beginArray(); + while ( in.hasNext() ) + { + state.addSourceToGroup( state.getSources().get( in.nextInt() ), group ); + } + in.endArray(); + break; + } + } + in.endObject(); + } + in.endArray(); + } + + private void writeSources( final JsonWriter out, final ViewerPanel value ) throws IOException + { + + out.beginArray(); + final List< SourceState< ? > > sources = value.getState().getSources(); + for ( final SourceState< ? > source : sources ) + { + out.value( source.isActive() ); + } + out.endArray(); + } + + private void readSources( final JsonReader in ) throws IOException + { + final List< SourceState< ? > > sources = state.getSources(); + in.beginArray(); + int i = 0; + while ( in.hasNext() ) + { + final boolean isActive = in.nextBoolean(); + final SourceState< ? > source = sources.get( i++ ); + source.setActive( isActive ); + } + in.endArray(); + } + + @Override + public BigWarpViewerPanel read( final JsonReader in ) throws IOException + { + + in.beginObject(); + while ( in.hasNext() ) + { + final String nextName = in.nextName(); + switch ( nextName ) + { + case XmlIoViewerState.VIEWERSTATE_SOURCES_TAG: + readSources( in ); + break; + case XmlIoViewerState.VIEWERSTATE_GROUPS_TAG: + readGroups( in ); + break; + case XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_TAG: + readDisplayMode( in ); + break; + case XmlIoViewerState.VIEWERSTATE_INTERPOLATION_TAG: + readInterpolationMode( in ); + break; + case XmlIoViewerState.VIEWERSTATE_CURRENTSOURCE_TAG: + state.setCurrentSource( in.nextInt() ); + break; + case XmlIoViewerState.VIEWERSTATE_CURRENTGROUP_TAG: + state.setCurrentGroup( in.nextInt() ); + break; + case XmlIoViewerState.VIEWERSTATE_CURRENTTIMEPOINT_TAG: + state.setCurrentTimepoint( in.nextInt() ); + break; + } + } + in.endObject(); + return panel; + } + } + + public static class SetupAssignmentsAdapter extends TypeAdapter< SetupAssignments > + { + + private final SetupAssignments setupAssignments; + + public SetupAssignmentsAdapter( final SetupAssignments setupAssignments ) + { + this.setupAssignments = setupAssignments; + } + + @Override + public void write( final JsonWriter out, final SetupAssignments value ) throws IOException + { + out.beginObject(); + out.name( "ConverterSetups" ); + out.beginArray(); + final List< ConverterSetup > converterSetups = value.getConverterSetups(); + final ConverterSetupAdapter converterSetupAdapter = new ConverterSetupAdapter( value ); + for ( final ConverterSetup converterSetup : converterSetups ) + { + out.beginObject(); + converterSetupAdapter.write( out, converterSetup ); + out.endObject(); + } + out.endArray(); + final List< MinMaxGroup > minMaxGroups = value.getMinMaxGroups(); + out.name( "MinMaxGroups" ); + new MinMaxGroupsAdapter().write( out, minMaxGroups ); + out.endObject(); + } + + @Override + public SetupAssignments read( final JsonReader in ) throws IOException + { + final List< ConverterSetupDTO > converters = new ArrayList<>(); + final ArrayList< MinMaxGroup > minMaxGroups; + try + { + final Field minMaxGroupsField = setupAssignments.getClass().getDeclaredField( "minMaxGroups" ); + minMaxGroupsField.setAccessible( true ); + //noinspection unchecked + minMaxGroups = ( ArrayList< MinMaxGroup > ) minMaxGroupsField.get( setupAssignments ); + } + catch ( NoSuchFieldException | IllegalAccessException e ) + { + throw new RuntimeException( e ); + } + + minMaxGroups.clear(); + + in.beginObject(); + while ( in.hasNext() ) + { + final String name = in.nextName(); + switch ( name ) + { + case "ConverterSetups": + in.beginArray(); + while ( in.hasNext() ) + { + in.beginObject(); + final ConverterSetupDTO dto = ( ConverterSetupDTO ) new ConverterSetupAdapter( setupAssignments ).read( in ); + converters.add( dto ); + in.endObject(); + } + in.endArray(); + break; + case "MinMaxGroups": + minMaxGroups.addAll( new MinMaxGroupsAdapter().read( in ) ); + break; + default: + throw new RuntimeException( "Unknown SetupAssignment Key: " + name ); + } + } + in.endObject(); + + for ( final ConverterSetupDTO setupDto : converters ) + { + final ConverterSetup setup = setupAssignments.getConverterSetups().stream().filter( it -> it.getSetupId() == setupDto.getSetupId() ).findFirst().get(); + setup.setDisplayRange( setupDto.getDisplayRangeMin(), setupDto.getDisplayRangeMax() ); + setup.setColor( setupDto.getColor() ); + final MinMaxGroup group = minMaxGroups.get( setupDto.getGroupId() ); + setupAssignments.moveSetupToGroup( setup, group ); + + } + return setupAssignments; + } + } + + public static class MinMaxGroupsAdapter extends TypeAdapter< List< MinMaxGroup > > + { + + @Override + public void write( final JsonWriter out, final List< MinMaxGroup > value ) throws IOException + { + out.beginArray(); + for ( int i = 0; i < value.size(); i++ ) + { + out.beginObject(); + out.name( "id" ).value( i ); + out.name( "fullRangeMin" ).value( value.get( i ).getFullRangeMin() ); + out.name( "fullRangeMax" ).value( value.get( i ).getFullRangeMax() ); + out.name( "rangeMin" ).value( value.get( i ).getRangeMin() ); + out.name( "rangeMax" ).value( value.get( i ).getRangeMax() ); + out.name( "currentMin" ).value( value.get( i ).getMinBoundedValue().getCurrentValue() ); + out.name( "currentMax" ).value( value.get( i ).getMaxBoundedValue().getCurrentValue() ); + out.endObject(); + } + out.endArray(); + } + + @Override + public List< MinMaxGroup > read( final JsonReader in ) throws IOException + { + final HashMap< Integer, MinMaxGroup > groupMap = new HashMap<>(); + final ArrayList< MinMaxGroup > groups = new ArrayList<>(); + in.beginArray(); + while ( in.hasNext() ) + { + int id = 0; + double fullRangeMin = 0; + double fullRangeMax = 0; + double rangeMin = 0; + double rangeMax = 0; + double currentMin = 0; + double currentMax = 0; + in.beginObject(); + while ( in.hasNext() ) + { + switch ( in.nextName() ) + { + case "id": + id = in.nextInt(); + break; + case "fullRangeMin": + fullRangeMin = in.nextDouble(); + break; + case "fullRangeMax": + fullRangeMax = in.nextDouble(); + break; + case "rangeMin": + rangeMin = in.nextDouble(); + break; + case "rangeMax": + rangeMax = in.nextDouble(); + break; + case "currentMin": + currentMin = in.nextDouble(); + break; + case "currentMax": + currentMax = in.nextDouble(); + break; + } + } + + /* Note: Currently, this MinMaxGroup constructor always passes in a private static final `0` for minIntervalSize */ + final double minIntervalSize = 0; + final MinMaxGroup group = new MinMaxGroup( fullRangeMin, + fullRangeMax, + rangeMin, + rangeMax, + currentMin, + currentMax, + minIntervalSize ); + groupMap.put( id, group ); + in.endObject(); + } + in.endArray(); + for ( int i = 0; i < groupMap.size(); i++ ) + { + /* We require that the `id` of the deserialized group matches the index of the returned list. */ + groups.add( groupMap.get( i ) ); + } + return groups; + } + } + + public static class ConverterSetupAdapter extends TypeAdapter< ConverterSetup > + { + private final SetupAssignments setupAssignments; + + public ConverterSetupAdapter( final SetupAssignments setupAssignments ) + { + this.setupAssignments = setupAssignments; + } + + @Override + public void write( final JsonWriter out, final ConverterSetup value ) throws IOException + { + final List< MinMaxGroup > minMaxGroups = setupAssignments.getMinMaxGroups(); + out.name( "id" ).value( value.getSetupId() ); + out.name( "min" ).value( value.getDisplayRangeMin() ); + out.name( "max" ).value( value.getDisplayRangeMax() ); + out.name( "color" ).value( value.getColor().get() ); + out.name( "groupId" ).value( minMaxGroups.indexOf( setupAssignments.getMinMaxGroup( value ) ) ); + } + + @Override + public ConverterSetup read( final JsonReader in ) throws IOException + { + int tmpid = 0; + double tmpmin = 0; + double tmpmax = 0; + int tmpcolor = 0; + int tmpgroupId = 0; + while ( in.hasNext() ) + { + switch ( in.nextName() ) + { + case "id": + tmpid = in.nextInt(); + break; + case "min": + tmpmin = in.nextDouble(); + break; + case "max": + tmpmax = in.nextDouble(); + break; + case "color": + tmpcolor = in.nextInt(); + break; + case "groupId": + tmpgroupId = in.nextInt(); + break; + } + } + + final int id = tmpid; + final double min = tmpmin; + final double max = tmpmax; + final int color = tmpcolor; + final int groupId = tmpgroupId; + + final ConverterSetup converterSetupDTO = new ConverterSetupDTO() + { + + @Override + public int getGroupId() + { + return groupId; + } + + @Override + public Listeners< SetupChangeListener > setupChangeListeners() + { + return null; + } + + @Override + public int getSetupId() + { + return id; + } + + @Override + public void setDisplayRange( final double min, final double max ) + { + } + + @Override + public void setColor( final ARGBType color ) + { + } + + @Override + public boolean supportsColor() + { + return false; + } + + @Override + public double getDisplayRangeMin() + { + return min; + } + + @Override + public double getDisplayRangeMax() + { + return max; + } + + @Override + public ARGBType getColor() + { + return new ARGBType( color ); + } + }; + return converterSetupDTO; + } + } + + public static class FileAdapter extends TypeAdapter< File > + { + @Override + public void write( final JsonWriter out, final File value ) throws IOException + { + out.value( value.getCanonicalPath() ); + } + + @Override + public File read( final JsonReader in ) throws IOException + { + return new File( in.nextString() ); + } + } + + public static class AffineTransform3dAdapter extends TypeAdapter< AffineTransform3D > + { + + @Override + public void write( final JsonWriter out, final AffineTransform3D value ) throws IOException + { + assert value.numDimensions() == 3; + + final double[] values = value.getRowPackedCopy(); + out.beginArray(); + for ( final double v : values ) + { + out.value( v ); + } + out.endArray(); + } + + @Override + public AffineTransform3D read( final JsonReader in ) throws IOException + { + final AffineTransform3D affine = new AffineTransform3D(); + + final double[] values = new double[ 12 ]; + in.beginArray(); + for ( int i = 0; i < values.length; i++ ) + { + values[ i ] = in.nextDouble(); + } + in.endArray(); + + affine.set( values ); + return affine; + } + } + + private static interface ConverterSetupDTO extends ConverterSetup + { + + int getGroupId(); + + } +} + diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index c777065f..9bff3a79 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -1,5 +1,13 @@ package bigwarp.transforms.io; +import bdv.gui.TransformTypeSelectDialog; +import bigwarp.BigWarp; +import bigwarp.BigwarpSettings; +import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.transforms.BigWarpTransform; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; import java.io.File; import java.io.IOException; import java.io.Reader; @@ -12,25 +20,8 @@ import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - -import bdv.gui.TransformTypeSelectDialog; -import bigwarp.BigWarp; -import bigwarp.landmarks.LandmarkTableModel; -import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; -import bigwarp.transforms.BigWarpTransform; - public class TransformWriterJson { - private final Gson gson; - - public TransformWriterJson() - { - gson = new Gson(); - } - public void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) { JsonObject transformObj = new JsonObject(); @@ -39,20 +30,15 @@ public void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) if( bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS) ) { - JsonObject maskObj = new JsonObject(); PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); - maskObj.add("type", new JsonPrimitive("gaussianSphericalPlateau")); - maskObj.add("center", gson.toJsonTree(mask.getCenter().positionAsDoubleArray())); - maskObj.add("squaredRadius", new JsonPrimitive(mask.getSquaredRadius())); - maskObj.add("squaredSigma", new JsonPrimitive(mask.getSquaredSigma())); - transformObj.add( "mask", maskObj ); + transformObj.add("mask", BigwarpSettings.gson.toJsonTree( mask )); } try { final Path path = Paths.get(f.getCanonicalPath()); final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE}; final Writer writer = Channels.newWriter(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); - gson.toJson(transformObj, writer); + BigwarpSettings.gson.toJson(transformObj, writer); writer.flush(); } catch (IOException e) { e.printStackTrace(); @@ -66,7 +52,7 @@ public void read( final File f, final BigWarp bw ) final Path path = Paths.get(f.getCanonicalPath()); final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; final Reader reader = Channels.newReader(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); - JsonObject json = gson.fromJson( reader, JsonObject.class ); + JsonObject json = BigwarpSettings.gson.fromJson( reader, JsonObject.class ); if( json.has( "landmarks" )) bw.getLandmarkPanel().getTableModel().fromJson( json ); @@ -75,7 +61,7 @@ public void read( final File f, final BigWarp bw ) { JsonObject maskParams = json.get("mask").getAsJsonObject(); final PlateauSphericalMaskRealRandomAccessible mask = bw.getTpsMaskSource().getRandomAccessible(); - mask.setCenter( gson.fromJson( maskParams.get( "center" ), double[].class )); + mask.setCenter( BigwarpSettings.gson.fromJson( maskParams.get( "center" ), double[].class )); mask.setSquaredRadius( maskParams.get("squaredRadius").getAsDouble() ); mask.setSquaredSigma( maskParams.get("squaredSigma").getAsDouble() ); } diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java new file mode 100644 index 00000000..a6b7580c --- /dev/null +++ b/src/test/java/bigwarp/SerializationTest.java @@ -0,0 +1,177 @@ +package bigwarp; + +import bdv.gui.BigWarpViewerOptions; +import bdv.tools.bookmarks.Bookmarks; +import bigwarp.source.PlateauSphericalMaskSource; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import ij.ImagePlus; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.nio.file.Files; +import mpicbg.spim.data.SpimDataException; +import net.imglib2.FinalInterval; +import net.imglib2.RealPoint; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.position.FunctionRandomAccessible; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.type.numeric.integer.UnsignedByteType; +import net.imglib2.view.Views; +import org.custommonkey.xmlunit.XMLAssert; +import org.custommonkey.xmlunit.XMLUnit; +import org.jdom2.JDOMException; +import org.junit.Test; +import org.xml.sax.SAXException; + +public class SerializationTest +{ + + public void maskTest() + { + PlateauSphericalMaskSource mask = PlateauSphericalMaskSource.build( new RealPoint( 3 ), new FinalInterval( 5, 10, 20 ) ); + Gson gson = BigwarpSettings.gson; + prettyPrint( gson.toJson( mask.getRandomAccessible() )); + } + + public void bookmarksTest() + { + final Bookmarks bookmarks = new Bookmarks(); + bookmarks.put( "identity", new AffineTransform3D() ); + final AffineTransform3D scale = new AffineTransform3D(); + scale.scale( 1.0, 2.0, 3.0 ); + bookmarks.put( "scale", scale ); + + final AffineTransform3D translate = new AffineTransform3D(); + bookmarks.put( "translate", translate ); + translate.translate( Math.random(), Math.random(), Math.random(), Math.random() ); + + Gson gson = BigwarpSettings.gson; + final String json = gson.toJson( bookmarks ); + prettyPrint( json ); + } + + public void autoSaverTest() throws SpimDataException + { + final BigWarpAutoSaver saver = new BigWarpAutoSaver( null, 1000 ); + saver.autoSaveDirectory = new File("/tmp"); + final String json = BigwarpSettings.gson.toJson( saver ); + prettyPrint( json ); + + } + + + public void setupAssignmentsTest() throws SpimDataException, IOException + { + final BigWarp bw = createBigWarp(); + final StringWriter stringWriter = new StringWriter(); + final JsonWriter out = new JsonWriter( stringWriter ); + new BigwarpSettings.SetupAssignmentsAdapter(bw.setupAssignments).write( out, bw.setupAssignments ); + + prettyPrint( stringWriter.toString()); + + } + + + public void viewerPanelTest() throws SpimDataException, IOException + { + final BigWarp bw = createBigWarp(); + final StringWriter stringWriter = new StringWriter(); + final JsonWriter out = new JsonWriter( stringWriter ); + new BigwarpSettings.BigWarpViewerPanelAdapter( bw.viewerP).write( out, bw.viewerP ); + + prettyPrint( stringWriter); + + } + + + public void BigWarpSettingsTest() throws SpimDataException, IOException + { + final BigWarp bw = createBigWarp(); + bw.setAutoSaver( new BigWarpAutoSaver( bw, 10000 ) ); + final BigwarpSettings settings = bw.getSettings(); + + final StringWriter stringWriter = new StringWriter(); + final JsonWriter out = new JsonWriter( stringWriter ); + + settings.write( out, settings ); + settings.read( new JsonReader( new StringReader( stringWriter.toString() ) ) ); + prettyPrint( stringWriter); + + } + + + @Test + public void compareKnownXmlComparisonTest() throws SpimDataException, IOException, JDOMException, SAXException + { + BigWarp bw = createBigWarp(); + + final String originalXmlSettings = "src/test/resources/compareKnownXml.bigwarp.settings.xml"; + bw.loadSettings( originalXmlSettings ); + final BigwarpSettings settings = bw.getSettings(); + + final StringWriter stringWriter = new StringWriter(); + final JsonWriter out = new JsonWriter( stringWriter ); + + settings.write( out, settings ); + final File tmpJsonFile = Files.createTempFile( "json-settings", ".json" ).toFile(); + final FileWriter fileWriter = new FileWriter( tmpJsonFile ); + fileWriter.write( stringWriter.toString() ); + fileWriter.flush(); + fileWriter.close(); + + bw.closeAll(); + + bw = createBigWarp(); + bw.loadSettings(tmpJsonFile.getAbsolutePath()); + + final File tmpXmlFile = Files.createTempFile( "xml-settings", ".xml" ).toFile(); + bw.saveSettings(tmpXmlFile.getAbsolutePath()); + XMLUnit.setIgnoreWhitespace( true ); + XMLUnit.setIgnoreComments( true ); + XMLAssert.assertXMLEqual( new FileReader( originalXmlSettings ), new FileReader( tmpXmlFile ) ); + + } + + + + private static void prettyPrint(StringWriter json) { + prettyPrint( json.toString() ); + } + + private static void prettyPrint(String json) { + final JsonParser jsonParser = new JsonParser(); + final JsonElement parse = jsonParser.parse( json ); + final JsonObject asJsonObject = parse.getAsJsonObject(); + + System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson( asJsonObject )); + } + + private static BigWarp< ? > createBigWarp() throws SpimDataException + { + final BigWarp.BigWarpData< Object > data = BigWarpInit.initData(); + FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( + 2, + ( l, v ) -> { + v.setOne(); + }, + UnsignedByteType::new ); + ImagePlus imp = ImageJFunctions.wrap( Views.interval( fimg, new FinalInterval( 32, 32 ) ), "img" ); + int i = 0; + BigWarpInit.add( data, imp, i++, 0, true); + BigWarpInit.add( data, imp, i++, 0, false); + BigWarpInit.add( data, imp, i++, 0, false); + BigWarpInit.add( data, imp, i++, 0, false); + data.wrapUp(); + BigWarpViewerOptions opts = BigWarpViewerOptions.options( true ); + return new BigWarp( data, "bigwarp", opts, null ); + } +} diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index d6303d4f..a2e92633 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -23,6 +23,7 @@ import bdv.viewer.animate.AbstractTransformAnimator; import bdv.viewer.animate.SimilarityModel3D; import bdv.viewer.animate.SimilarityTransformAnimator; +import bigwarp.BigwarpSettings; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; import bigwarp.source.PlateauSphericalMaskSource; @@ -98,9 +99,9 @@ public static void expSeq( String imgFile, String jsonFile ) { // RandomAccessibleInterval img = Views.translateInverse( imgBase, 252, 76, 70 ); AffineTransform3D identity = new AffineTransform3D(); + //TODO Caleb: John, what interval should we be using here? FinalInterval bigItvl = Intervals.createMinMax(0, -200, 0, 1000, 1000, 150); - Gson gson = new Gson(); final Path path = Paths.get( jsonFile ); final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; Reader reader; @@ -108,7 +109,7 @@ public static void expSeq( String imgFile, String jsonFile ) { try { reader = Channels.newReader(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); - json = gson.fromJson( reader, JsonObject.class ); + json = BigwarpSettings.gson.fromJson( reader, JsonObject.class ); } catch ( IOException e ) { e.printStackTrace(); @@ -120,10 +121,13 @@ public static void expSeq( String imgFile, String jsonFile ) { ltm.fromJson( json ); - PlateauSphericalMaskSource tpsMask = PlateauSphericalMaskSource.build( 3, new RealPoint( 3 ), bigItvl ); + + final JsonObject maskJson = json.getAsJsonObject( "mask" ); + PlateauSphericalMaskRealRandomAccessible mask = BigwarpSettings.gson.fromJson( maskJson, PlateauSphericalMaskRealRandomAccessible.class); + + + PlateauSphericalMaskSource tpsMask = PlateauSphericalMaskSource.build( mask, bigItvl ); PlateauSphericalMaskRealRandomAccessible lambda = tpsMask.getRandomAccessible(); - tpsMask.getRandomAccessible().fromJson( json.getAsJsonObject( "mask" ) ); - // build transformations final double[][] mvgPts; @@ -249,9 +253,12 @@ public static void showSeq( String imgFile, String jsonFile ) { ltm.fromJson( json ); - PlateauSphericalMaskSource tpsMask = PlateauSphericalMaskSource.build( 3, new RealPoint( 3 ), bigItvl ); + final JsonObject mask = json.getAsJsonObject( "mask" ); + PlateauSphericalMaskRealRandomAccessible maskRA = BigwarpSettings.gson.fromJson( mask, PlateauSphericalMaskRealRandomAccessible.class); + + + PlateauSphericalMaskSource tpsMask = PlateauSphericalMaskSource.build( maskRA, bigItvl ); PlateauSphericalMaskRealRandomAccessible lambda = tpsMask.getRandomAccessible(); - tpsMask.getRandomAccessible().fromJson( json.getAsJsonObject( "mask" ) ); // build transformations diff --git a/src/test/resources/compareKnownXml.bigwarp.settings.xml b/src/test/resources/compareKnownXml.bigwarp.settings.xml new file mode 100644 index 00000000..34ff8d2d --- /dev/null +++ b/src/test/resources/compareKnownXml.bigwarp.settings.xml @@ -0,0 +1,248 @@ + + + + + + + true + + + false + + + true + + + false + + + false + + + false + + + false + + + false + + + + + true + moving images + 0 + 1 + + + true + fixed images + 2 + 3 + + + ss + nlinear + 0 + 0 + 0 + + + + + + + true + + + false + + + true + + + false + + + false + + + false + + + false + + + false + + + + + true + moving images + 0 + 1 + + + true + fixed images + 2 + 3 + + + fs + nearestneighbor + 2 + 1 + 0 + + + + + + 0 + 0.0 + 860.4 + -10027213 + 0 + + + 1 + 0.0 + 255.0 + 0 + 1 + + + 2 + 0.0 + 2000.0 + -39169 + 2 + + + 3 + 0.0 + 433.408 + -1 + 3 + + + 956736363 + 0.0 + 65535.0 + -1 + 4 + + + 1006827158 + 0.0 + 65535.0 + -1 + 5 + + + 1696993146 + 0.0 + 65535.0 + -1 + 6 + + + 33872301 + 0.0 + 65535.0 + -1 + 7 + + + + + 0 + -2.147483648E9 + 2.147483647E9 + 0.0 + 4000.0 + 0.0 + 860.4 + + + 1 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + 2 + -2.147483648E9 + 2.147483647E9 + 0.0 + 2000.0 + 0.0 + 2000.0 + + + 3 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + 4 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 5 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 6 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 7 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + + + + /tmp/.bigwarp + 180000 + + + plateau-spherical +

0.0 0.0
+ + 64.0 + 100.0 + + + From 57a325af1e5378252940a0971ec2a99b10ece0bc Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 15:18:04 -0400 Subject: [PATCH 046/282] style: cleanup --- src/main/java/bigwarp/BigWarp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index b3829e0e..1c047131 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3290,7 +3290,7 @@ public void stopAutosave() { if( autoSaver != null ) { - autoSaver.stop();; + autoSaver.stop(); autoSaver = null; } } From 92ee445a2ed8b538f15fc6ff89287cd4f0867f63 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 2 Sep 2022 15:18:33 -0400 Subject: [PATCH 047/282] refactor: imports --- .../java/bdv/gui/AutosaveOptionsPanel.java | 6 +- src/main/java/bigwarp/BigWarp.java | 139 +++++++++--------- ...milarityTransformInterpolationExample.java | 31 ++-- 3 files changed, 85 insertions(+), 91 deletions(-) diff --git a/src/main/java/bdv/gui/AutosaveOptionsPanel.java b/src/main/java/bdv/gui/AutosaveOptionsPanel.java index c141ed22..01107601 100644 --- a/src/main/java/bdv/gui/AutosaveOptionsPanel.java +++ b/src/main/java/bdv/gui/AutosaveOptionsPanel.java @@ -1,5 +1,7 @@ package bdv.gui; +import bigwarp.BigWarp; +import bigwarp.BigWarpAutoSaver; import java.awt.Container; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; @@ -7,7 +9,6 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.File; - import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; @@ -20,9 +21,6 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import bigwarp.BigWarp; -import bigwarp.BigWarpAutoSaver; - public class AutosaveOptionsPanel extends JPanel { private static final long serialVersionUID = 2449704984531905538L; diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 1c047131..623543bb 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -21,73 +21,6 @@ */ package bigwarp; -import bdv.viewer.ConverterSetups; -import bdv.viewer.DisplayMode; -import bdv.viewer.TransformListener; -import bdv.viewer.ViewerState; -import java.awt.Color; -import java.awt.Component; -import java.awt.Cursor; -import java.awt.FileDialog; -import java.awt.KeyEventPostProcessor; -import java.awt.KeyboardFocusManager; -import java.awt.Point; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.Field; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; - -import javax.swing.ActionMap; -import javax.swing.InputMap; -import javax.swing.JCheckBox; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JTable; -import javax.swing.KeyStroke; -import javax.swing.SwingUtilities; -import javax.swing.Timer; -import javax.swing.event.TableModelEvent; -import javax.swing.event.TableModelListener; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.TableCellEditor; - -import mpicbg.spim.data.SpimData; -import mpicbg.spim.data.XmlIoSpimData; -import mpicbg.spim.data.registration.ViewTransformAffine; - -import org.janelia.saalfeldlab.n5.Compression; -import org.janelia.saalfeldlab.n5.ij.N5Exporter; -import org.janelia.utility.geom.BoundingSphereRitter; -import org.janelia.utility.geom.Sphere; -import org.janelia.utility.ui.RepeatingReleasedEventsFixer; -import org.jdom2.Document; -import org.jdom2.Element; -import org.jdom2.JDOMException; -import org.jdom2.input.SAXBuilder; -import org.jdom2.output.Format; -import org.jdom2.output.XMLOutputter; -import org.scijava.ui.behaviour.io.InputTriggerConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import bdv.BigDataViewer; import bdv.cache.CacheControl; import bdv.export.ProgressWriter; @@ -118,13 +51,17 @@ import bdv.viewer.BigWarpOverlay; import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.BigWarpViewerSettings; +import bdv.viewer.ConverterSetups; +import bdv.viewer.DisplayMode; import bdv.viewer.Interpolation; import bdv.viewer.LandmarkPointMenu; import bdv.viewer.MultiBoxOverlay2d; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bdv.viewer.SynchronizedViewerState; +import bdv.viewer.TransformListener; import bdv.viewer.ViewerPanel; +import bdv.viewer.ViewerState; import bdv.viewer.VisibilityAndGrouping; import bdv.viewer.WarpNavigationActions; import bdv.viewer.animate.SimilarityModel3D; @@ -142,10 +79,53 @@ import bigwarp.transforms.WrappedCoordinateTransform; import bigwarp.transforms.io.TransformWriterJson; import bigwarp.util.BigWarpUtils; +import com.google.gson.stream.JsonReader; import fiji.util.gui.GenericDialogPlus; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.FileDialog; +import java.awt.KeyEventPostProcessor; +import java.awt.KeyboardFocusManager; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Field; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JCheckBox; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTable; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellEditor; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import jitk.spline.XfmUtils; import mpicbg.models.AbstractModel; @@ -160,7 +140,10 @@ import mpicbg.models.SimilarityModel2D; import mpicbg.models.TranslationModel2D; import mpicbg.models.TranslationModel3D; +import mpicbg.spim.data.SpimData; import mpicbg.spim.data.SpimDataException; +import mpicbg.spim.data.XmlIoSpimData; +import mpicbg.spim.data.registration.ViewTransformAffine; import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; @@ -177,6 +160,20 @@ import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; +import org.janelia.saalfeldlab.n5.Compression; +import org.janelia.saalfeldlab.n5.ij.N5Exporter; +import org.janelia.utility.geom.BoundingSphereRitter; +import org.janelia.utility.geom.Sphere; +import org.janelia.utility.ui.RepeatingReleasedEventsFixer; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.JDOMException; +import org.jdom2.input.SAXBuilder; +import org.jdom2.output.Format; +import org.jdom2.output.XMLOutputter; +import org.scijava.ui.behaviour.io.InputTriggerConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class BigWarp< T > { @@ -582,6 +579,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie SwingUtilities.invokeLater( new Runnable() { + @Override public void run() { data.transferChannelSettings( viewerFrameP ); @@ -1112,6 +1110,7 @@ public void exportAsImagePlus( boolean virtual, String path ) // export async new Thread() { + @Override public void run() { progressWriter.setProgress( 0.01 ); @@ -2043,7 +2042,7 @@ public void autoEstimateMask() public enum WarpVisType { NONE, WARPMAG, JACDET, GRID - }; + } public void setWarpVisMode( final WarpVisType type, BigWarpViewerFrame viewerFrame, final boolean both ) { diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index a2e92633..817b13b3 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -1,21 +1,5 @@ package net.imglib2.realtransform; -import java.io.IOException; -import java.io.Reader; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.charset.StandardCharsets; -import java.nio.file.OpenOption; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; - import bdv.util.Affine3DHelpers; import bdv.util.BdvFunctions; import bdv.util.BdvOptions; @@ -31,13 +15,26 @@ import bigwarp.transforms.ModelTransformSolver; import bigwarp.transforms.TpsTransformSolver; import bigwarp.transforms.WrappedCoordinateTransform; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import ij.IJ; import ij.ImagePlus; +import java.io.IOException; +import java.io.Reader; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import mpicbg.models.AbstractAffineModel3D; import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; -import net.imglib2.RealPoint; import net.imglib2.RealRandomAccessible; import net.imglib2.img.Img; import net.imglib2.img.display.imagej.ImageJFunctions; From 616b1828fc23a1b1662bb8fdeca8f6366ec92831 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 23 Sep 2022 14:30:27 -0400 Subject: [PATCH 048/282] build(deps): update realtransform version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6801fb1b..8606d001 100644 --- a/pom.xml +++ b/pom.xml @@ -114,7 +114,7 @@ 1.48 1.4.1 3.0.2 - 3.1.2 + 4.0.0 2.5.1 3.2.1 From acf977d42be78dc7a0b204899dc77a31326b8cf6 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 23 Sep 2022 14:40:46 -0400 Subject: [PATCH 049/282] fix: serialization test --- ...teauSphericalMaskRealRandomAccessible.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 9cf8c53b..9fc60ae3 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -5,6 +5,7 @@ import java.util.function.BiConsumer; import java.util.function.Function; +import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import org.jdom2.Element; import com.google.gson.JsonArray; @@ -14,39 +15,39 @@ import com.google.gson.annotations.SerializedName; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; -import java.io.IOException; - -import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import mpicbg.spim.data.XmlHelpers; -import net.imglib2.Interval; -import net.imglib2.RealInterval; -import net.imglib2.RealLocalizable; -import net.imglib2.RealPoint; -import net.imglib2.RealRandomAccess; -import net.imglib2.RealRandomAccessible; +import net.imglib2.*; import net.imglib2.position.FunctionRealRandomAccessible; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.util.Intervals; +import org.jdom2.Element; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Function; public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAccessible< DoubleType > { transient private BiConsumer< RealLocalizable, DoubleType > pfun; transient private FunctionRealRandomAccessible< DoubleType > rra; - private List overlays; + transient private List overlays; private FalloffShape fallOffShape; transient private int nd; transient private double plateauR; - transient private double plateauR2; + @SerializedName(SQUARED_RADIUS) + private double plateauR2; transient private double sigma; @SerializedName( SQUARED_SIGMA ) private double sqrSigma; transient private double invSqrSigma; - private double gaussInvSqrSigma; + transient private double gaussInvSqrSigma; @JsonAdapter( RealPointToDoubleArray.class ) private RealPoint center; From 2e60e34101bd942bf4bfa8d92560d3d49f71c671 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Fri, 23 Sep 2022 15:53:40 -0400 Subject: [PATCH 050/282] feat: move transform type to main options dialog --- src/main/java/bdv/gui/TransformTypePanel.java | 111 ++++++++++++++++++ .../bdv/gui/TransformTypeSelectDialog.java | 26 +++- src/main/java/bigwarp/BigWarp.java | 39 +++++- src/main/java/bigwarp/WarpVisFrame.java | 25 ++-- 4 files changed, 187 insertions(+), 14 deletions(-) create mode 100644 src/main/java/bdv/gui/TransformTypePanel.java diff --git a/src/main/java/bdv/gui/TransformTypePanel.java b/src/main/java/bdv/gui/TransformTypePanel.java new file mode 100644 index 00000000..93ce1160 --- /dev/null +++ b/src/main/java/bdv/gui/TransformTypePanel.java @@ -0,0 +1,111 @@ +package bdv.gui; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import bigwarp.BigWarp; +import bigwarp.transforms.BigWarpTransform; + +public class TransformTypePanel extends JPanel +{ + private static final long serialVersionUID = 3285885870885172257L; + + private static final String TRANSFORM_TYPE_HELP_TEXT = "Select the type of transformation."; + + public static final String[] TRANSFORM_TYPE_STRINGS = new String[] { + BigWarpTransform.TPS, BigWarpTransform.AFFINE, + BigWarpTransform.SIMILARITY, BigWarpTransform.ROTATION, BigWarpTransform.TRANSLATION }; + + private final BigWarp< ? > bw; + + private final JLabel transformTypeLabel; + private final JComboBox< String > transformTypeDropdown; + + private boolean active; + + public TransformTypePanel( BigWarp bw ) + { + super( new GridBagLayout() ); + this.bw = bw; + active = true; + + setBorder( BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), + BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "Transformation options" ), + BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); + + transformTypeLabel = new JLabel( "Transform type"); + transformTypeLabel.setToolTipText( TRANSFORM_TYPE_HELP_TEXT ); + transformTypeDropdown = new JComboBox<>( TRANSFORM_TYPE_STRINGS ); + getTransformTypeDropdown().setToolTipText( TRANSFORM_TYPE_HELP_TEXT ); + getTransformTypeDropdown().addActionListener( new ActionListener() { + @Override + public void actionPerformed( ActionEvent e ) + { + if( active ) + { + final String type = (String)transformTypeDropdown.getSelectedItem(); + bw.setTransformType( type ); + bw.updateTransformTypeDialog( type ); + } + } + }); + + // layout + final GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 1; + gbc.gridheight = 1; + gbc.weightx = 0.0; + gbc.weighty = 0.0; + gbc.anchor = GridBagConstraints.LINE_END; + gbc.fill = GridBagConstraints.NONE; + gbc.insets = new Insets( 5, 5, 5, 5 ); + add( transformTypeLabel, gbc ); + + gbc.gridx = 2; + gbc.weightx = 0.0; + gbc.anchor = GridBagConstraints.LINE_START; + add( getTransformTypeDropdown(), gbc ); + + } + + public JComboBox< String > getTransformTypeDropdown() + { + return transformTypeDropdown; + } + + public void setType( String type ) + { + transformTypeDropdown.setSelectedItem( type ); + } + + /** + * After calling deactivate, updates to this panel won't affect Bigwarp. + */ + public void deactivate() + { + active = false; + } + + /** + * After calling activate, updates to this panel will affect Bigwarp. + */ + public void activate() + { + active = true; + } + +} diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index d9d9955c..87f5c5af 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -65,6 +65,8 @@ public class TransformTypeSelectDialog extends JDialog private final JRadioButton rotationButton; private final JRadioButton translationButton; + private boolean active; + /** * Instantiates and displays a JFrame that enables * the selection of the transformation type. @@ -77,6 +79,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) super( owner, "Transform Type select", false ); this.bw = bw; + active = true; this.setLayout( new BorderLayout() ); transformType = bw.getTransformType(); @@ -148,7 +151,12 @@ public void addActionListender( final JRadioButton button ) button.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - bw.setTransformType( button.getText() ); + if( active ) + { + final String type = button.getText(); + bw.setTransformType( type ); + bw.updateTransformTypePanel( type ); + } } }); } @@ -175,4 +183,20 @@ public void setTransformType( String transformType ) this.repaint(); } + /** + * After calling deactivate, updates to this panel won't affect Bigwarp. + */ + public void deactivate() + { + active = false; + } + + /** + * After calling activate, updates to this panel will affect Bigwarp. + */ + public void activate() + { + active = true; + } + } diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 2a248065..c450b587 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -31,7 +31,6 @@ import java.awt.FileDialog; import java.awt.KeyEventPostProcessor; import java.awt.KeyboardFocusManager; -import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; @@ -1764,13 +1763,11 @@ public boolean toggleMovingImageDisplay() public void toggleMaskOverlayVisibility() { - getViewerFrameP().getViewerPanel().getMaskOverlay().toggleVisible(); getViewerFrameQ().getViewerPanel().getMaskOverlay().toggleVisible(); } public void setMaskOverlayVisibility( final boolean visible ) { - getViewerFrameP().getViewerPanel().getMaskOverlay().setVisible( visible ); getViewerFrameQ().getViewerPanel().getMaskOverlay().setVisible( visible ); } @@ -1783,7 +1780,7 @@ protected void addDefaultTableMouseListener() protected void addMaskMouseListener() { final Color[] maskColors = new Color[]{ Color.ORANGE, Color.YELLOW }; - viewerP.setMaskOverlay( new BigWarpMaskSphereOverlay( viewerP, maskColors, numDimensions() == 3 )); + // only render mask overlay on target window viewerQ.setMaskOverlay( new BigWarpMaskSphereOverlay( viewerQ, maskColors, numDimensions() == 3 )); maskSourceMouseListenerP = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerP ); @@ -1794,7 +1791,7 @@ protected void addMaskMouseListener() maskSourceMouseListenerQ.setActive( false ); maskSourceMouseListenerQ.setMask( tpsMask.getRandomAccessible() ); - tpsMask.getRandomAccessible().setOverlays( Arrays.asList( viewerP.getMaskOverlay(), viewerQ.getMaskOverlay() )); + tpsMask.getRandomAccessible().setOverlays( Arrays.asList( viewerQ.getMaskOverlay() )); } public void setGridType( final GridSource.GRID_TYPE method ) @@ -3006,11 +3003,41 @@ public void mouseReleased( final MouseEvent e ) public void setTransformType( final String type ) { - transformSelector.setTransformType( type ); bwTransform.setTransformType( type ); this.restimateTransformation(); } + public void setTransformTypeUpdateUI( final String type ) + { + setTransformType( type ); + updateTransformTypeDialog( type ); + updateTransformTypePanel( type ); + } + + /** + * Update the transformation selection dialog to reflect the given transform type selection. + * + * @param type the transformation type + */ + public void updateTransformTypeDialog( final String type ) + { + transformSelector.deactivate(); + transformSelector.setTransformType( type ); + transformSelector.activate(); + } + + /** + * Update the transformation selection panel in the options dialog to reflect the given transform type selection. + * + * @param type the transformation type + */ + public void updateTransformTypePanel( final String type ) + { + warpVisDialog.transformTypePanel.deactivate(); + warpVisDialog.transformTypePanel.setType( type ); + warpVisDialog.transformTypePanel.activate(); + } + public String getTransformType() { return bwTransform.getTransformType(); diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index 7df448d1..774abb89 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -66,6 +66,7 @@ import bdv.gui.AutosaveOptionsPanel; import bdv.gui.MaskOptionsPanel; +import bdv.gui.TransformTypePanel; import bdv.viewer.BigWarpViewerSettings; import bigwarp.source.GridSource; import net.imglib2.realtransform.BoundingBoxEstimation; @@ -117,6 +118,9 @@ public class WarpVisFrame extends JDialog // mask final MaskOptionsPanel maskOptionsPanel; + // transform type + final TransformTypePanel transformTypePanel; + // autosave private final AutosaveOptionsPanel autoSaveOptionsPanel; @@ -343,6 +347,9 @@ public void stateChanged( ChangeEvent e ) // mask options maskOptionsPanel = new MaskOptionsPanel( bw ); + // type options + transformTypePanel = new TransformTypePanel( bw ); + // autosaver options autoSaveOptionsPanel = new AutosaveOptionsPanel( bw, content ); @@ -357,38 +364,42 @@ public void stateChanged( ChangeEvent e ) gbcContent.weightx = 1.0; gbcContent.weighty = 1.0; gbcContent.insets = new Insets( 1, 1, 1, 1 ); - content.add( landmarkPointOptionsPanel, gbcContent ); + + content.add( transformTypePanel, gbcContent ); gbcContent.gridx = 0; gbcContent.gridy = 1; + content.add( landmarkPointOptionsPanel, gbcContent ); + + gbcContent.gridx = 0; + gbcContent.gridy = 2; gbcContent.gridwidth = 1; gbcContent.anchor = GridBagConstraints.WEST; content.add( visTypePanel, gbcContent ); - gbcContent.gridy = 1; gbcContent.gridx = 1; gbcContent.gridwidth = 2; gbcContent.anchor = GridBagConstraints.EAST; content.add( typeOptionPanel, gbcContent ); gbcContent.gridx = 0; - gbcContent.gridy = 2; + gbcContent.gridy = 3; gbcContent.gridwidth = 3; content.add( inverseOptionsPanel, gbcContent ); gbcContent.gridx = 0; - gbcContent.gridy = 3; + gbcContent.gridy = 4; gbcContent.gridwidth = 3; content.add( bboxPanel, gbcContent ); - gbcContent.gridy = 4; + gbcContent.gridy = 5; content.add( maskOptionsPanel, gbcContent ); - gbcContent.gridy = 5; + gbcContent.gridy = 6; content.add( getAutoSaveOptionsPanel(), gbcContent ); setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE ); - + addListeners(); updateOptions(); } From 24a4402ea907fb68dcb389a60def735a967472a9 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 28 Sep 2022 14:49:12 -0400 Subject: [PATCH 051/282] WIP: no more warnings after keymap update * many actions are in too many contexts --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 2 +- .../java/bdv/viewer/BigWarpLandmarkFrame.java | 18 +- .../java/bdv/viewer/LandmarkPointMenu.java | 4 +- src/main/java/bigwarp/BigWarpActions.java | 115 ++++- .../java/bigwarp/ui/keymap/KeymapManager.java | 3 +- .../bigwarp/ui/keymap/NavigationKeys.java | 74 ++- .../ui/keymap/UnmappedNavigationActions.java | 64 +++ .../resources/bigwarp/ui/keymap/default.yaml | 474 +++++++++++++++++- 8 files changed, 720 insertions(+), 34 deletions(-) create mode 100644 src/main/java/bigwarp/ui/keymap/UnmappedNavigationActions.java diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 9a431fc5..4e6318de 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -177,7 +177,7 @@ public void valueChanged( ListSelectionEvent e ) mouseAndKeyHandler.setKeypressManager( optional.values.getKeyPressedManager(), viewer.getDisplayComponent() ); viewer.getDisplay().addHandler( mouseAndKeyHandler ); - transformBehaviours = new Behaviours( optional.values.getInputTriggerConfig(), "bdv" ); + transformBehaviours = new Behaviours( optional.values.getInputTriggerConfig(), "bigwarp", "navigation" ); transformBehaviours.install( triggerbindings, "transform" ); final TransformEventHandler tfHandler = viewer.getTransformEventHandler(); diff --git a/src/main/java/bdv/viewer/BigWarpLandmarkFrame.java b/src/main/java/bdv/viewer/BigWarpLandmarkFrame.java index ca6c26f5..1b3ba12d 100644 --- a/src/main/java/bdv/viewer/BigWarpLandmarkFrame.java +++ b/src/main/java/bdv/viewer/BigWarpLandmarkFrame.java @@ -31,9 +31,11 @@ import javax.swing.WindowConstants; import org.scijava.ui.behaviour.util.InputActionBindings; +import org.scijava.ui.behaviour.util.TriggerBehaviourBindings; import bdv.gui.BigWarpLandmarkPanel; import bigwarp.BigWarp; +import bigwarp.ui.keymap.KeymapManager; public class BigWarpLandmarkFrame extends JFrame { @@ -43,16 +45,21 @@ public class BigWarpLandmarkFrame extends JFrame { private BigWarpLandmarkPanel lmPanel; + private final KeymapManager keymapManager; + private final InputActionBindings keybindings; - public BigWarpLandmarkFrame( String name, BigWarpLandmarkPanel panel, BigWarp bw ) + private final TriggerBehaviourBindings triggerbindings; + + public BigWarpLandmarkFrame( String name, BigWarpLandmarkPanel panel, BigWarp< ? > bw, KeymapManager keymapManager ) { super( name, AWTUtils.getSuitableGraphicsConfiguration( AWTUtils.RGB_COLOR_MODEL ) ); this.bw = bw; + this.keymapManager = keymapManager; setLandmarkPanel( panel ); keybindings = new InputActionBindings(); - + triggerbindings = new TriggerBehaviourBindings(); // do nothing because the closeAll method in bigWarp is responsible for calling dispose and cleaning up setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); @@ -63,11 +70,11 @@ public void windowClosing( final WindowEvent e ) BigWarpLandmarkFrame.this.bw.closeAll(); } } ); - + SwingUtilities.replaceUIActionMap( lmPanel.getJTable(), keybindings.getConcatenatedActionMap() ); - SwingUtilities.replaceUIInputMap( lmPanel.getJTable(), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keybindings.getConcatenatedInputMap() ); + SwingUtilities.replaceUIInputMap( lmPanel.getJTable(), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keybindings.getConcatenatedInputMap() ); } - + public void setLandmarkPanel( BigWarpLandmarkPanel panel ) { this.lmPanel = panel; @@ -81,5 +88,4 @@ public InputActionBindings getKeybindings() return keybindings; } - } diff --git a/src/main/java/bdv/viewer/LandmarkPointMenu.java b/src/main/java/bdv/viewer/LandmarkPointMenu.java index 89d3162e..a70a15e1 100644 --- a/src/main/java/bdv/viewer/LandmarkPointMenu.java +++ b/src/main/java/bdv/viewer/LandmarkPointMenu.java @@ -358,8 +358,10 @@ public AddToSelection( final String name, final boolean before, final boolean al @Override public void actionPerformed( ActionEvent e ) { - System.out.println( "add to selection " + before + " " + all ); final int[] selectedRows = landmarkPanel.getJTable().getSelectedRows(); + if( selectedRows.length == 0 ) + return; + Arrays.sort( selectedRows ); int i; diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 2f7a481e..c3ef04cb 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -11,7 +11,7 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public @@ -53,11 +53,15 @@ public class BigWarpActions extends Actions { public static final CommandDescriptionProvider.Scope BIGWARP = new CommandDescriptionProvider.Scope( "bigwarp" ); public static final String BIGWARP_CTXT = "bigwarp"; + public static final String NOT_MAPPED = "not mapped"; public static final String LANDMARK_MODE_ON = "landmark mode on"; public static final String LANDMARK_MODE_OFF = "landmark mode off"; // General options + public static final String CLOSE_DIALOG = "close dialog window"; + public static final String[] CLOSE_DIALOG_KEYS = new String[] { NOT_MAPPED }; + public static final String EXPAND_CARDS = "expand and focus cards panel"; public static final String[] EXPAND_CARDS_KEYS = new String[] { "P" }; @@ -90,13 +94,13 @@ public class BigWarpActions extends Actions public static final String[] PRINT_TRANSFORM_KEYS = new String[]{ "control shift T" }; public static final String TOGGLE_ESTIMATE_WARP_ONDRAG = "toggle estimate warp on drag"; - public static final String[] TOGGLE_ESTIMATE_WARP_ONDRAG_KEYS = new String[]{}; + public static final String[] TOGGLE_ESTIMATE_WARP_ONDRAG_KEYS = new String[]{ NOT_MAPPED }; public static final String SAVE_SETTINGS = "save settings"; - public static final String[] SAVE_SETTINGS_KEYS = new String[]{}; + public static final String[] SAVE_SETTINGS_KEYS = new String[]{ NOT_MAPPED }; public static final String LOAD_SETTINGS = "load settings"; - public static final String[] LOAD_SETTINGS_KEYS = new String[]{}; + public static final String[] LOAD_SETTINGS_KEYS = new String[]{ NOT_MAPPED }; public static final String BRIGHTNESS_SETTINGS = "brightness settings"; public static final String[] BRIGHTNESS_SETTINGS_KEYS = new String[]{ "S" }; @@ -221,12 +225,37 @@ public class BigWarpActions extends Actions public static final String[] EXPORT_AFFINE_KEYS = new String[] { "ctrl A" }; + public static final String CLEAR_MOVING = "table clear moving"; + public static final String[] CLEAR_MOVING_KEYS = new String[] { NOT_MAPPED }; + + public static final String CLEAR_FIXED = "table clear fixed"; + public static final String[] CLEAR_FIXED_KEYS = new String[] { NOT_MAPPED }; + + public static final String CLEAR_SELECTED_MOVING = "table clear selected moving"; + public static final String[] CLEAR_SELECTED_MOVING_KEYS = new String[] { NOT_MAPPED }; + + public static final String CLEAR_SELECTED_FIXED = "table clear selected fixed"; + public static final String[] CLEAR_SELECTED_FIXED_KEYS = new String[] { NOT_MAPPED }; + + public static final String DELETE = "table delete"; + public static final String[] DELETE_KEYS = new String[] { NOT_MAPPED }; + + public static final String DELETE_SELECTED = "table delete selected "; + public static final String[] DELETE_SELECTED_KEYS = new String[] { NOT_MAPPED }; + + public static final String ACTIVATE_SELECTED = "table activate selected"; + public static final String[] ACTIVATE_SELECTED_KEYS = new String[] { NOT_MAPPED }; + + public static final String DEACTIVATE_SELECTED = "table deactivate selected "; + public static final String[] DEACTIVATE_SELECTED_KEYS = new String[]{ NOT_MAPPED }; + + public static final String DEBUG = "debug"; public static final String GARBAGE_COLLECTION = "garbage collection"; public BigWarpActions( final KeyStrokeAdder.Factory keyConfig, String name ) { - this( keyConfig, "bw", name ); + this( keyConfig, "bigwarp", name ); } public BigWarpActions( final KeyStrokeAdder.Factory keyConfig, String context, String name ) @@ -242,12 +271,14 @@ public static class Descriptions extends CommandDescriptionProvider { public Descriptions() { - super( BIGWARP, "bigwarp" ); + super( BIGWARP, "bigwarp", "bw-table", "navigation" ); } @Override public void getCommandDescriptions( final CommandDescriptions descriptions ) { + descriptions.add( CLOSE_DIALOG, CLOSE_DIALOG_KEYS, "Close bigwarp." ); + descriptions.add( TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS, "Toggle landmark mode." ); descriptions.add( TOGGLE_MOVING_IMAGE_DISPLAY, TOGGLE_MOVING_IMAGE_DISPLAY_KEYS, "Toggle landmark mode." ); @@ -282,6 +313,7 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) descriptions.add( SAVE_WARPED_XML, SAVE_WARPED_XML_KEYS, "Export moving image to BigDataViewer xml/h5." ); descriptions.add( EXPORT_WARP, EXPORT_WARP_KEYS, "Show the dialog to export the displacement field." ); descriptions.add( EXPORT_AFFINE, EXPORT_AFFINE_KEYS, "Print the affine transformation." ); + descriptions.add( PRINT_TRANSFORM,PRINT_TRANSFORM_KEYS, "Prints the current transformation." ); // landmarks descriptions.add( LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS, "Load landmark from a file." ); @@ -301,12 +333,23 @@ public static class TableDescriptions extends CommandDescriptionProvider { public TableDescriptions() { - super( BIGWARP, "bw-table" ); + super( BIGWARP, "bw-table", "bigwarp", "navigation" ); } @Override public void getCommandDescriptions( final CommandDescriptions descriptions ) { + descriptions.add( CLEAR_MOVING, CLEAR_MOVING_KEYS, "Clears moving landmark under the mouse cursor." ); + descriptions.add( CLEAR_FIXED, CLEAR_FIXED_KEYS, "Clears fixed landmark under the mouse cursor." ); + descriptions.add( CLEAR_SELECTED_MOVING, CLEAR_SELECTED_MOVING_KEYS, "Clears moving landmark for currently selected row." ); + descriptions.add( CLEAR_SELECTED_FIXED, CLEAR_SELECTED_FIXED_KEYS, "Clears fixed landmark for currently selected row." ); + + descriptions.add( DELETE, DELETE_KEYS, "Delete table row under the mouse cursor" ); + descriptions.add( DELETE_SELECTED, DELETE_SELECTED_KEYS, "Delete all selected rows in the table" ); + + descriptions.add( ACTIVATE_SELECTED, ACTIVATE_SELECTED_KEYS, "Activate all selected rows in the table" ); + descriptions.add( DEACTIVATE_SELECTED, DEACTIVATE_SELECTED_KEYS, "Deactivate all selected rows in the table" ); + descriptions.add( LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS, "Load landmark from a file." ); descriptions.add( SAVE_LANDMARKS, SAVE_LANDMARKS_KEYS, "Save landmark from a file." ); descriptions.add( QUICK_SAVE_LANDMARKS, QUICK_SAVE_LANDMARKS_KEYS, "Quick save landmarks."); @@ -371,7 +414,21 @@ public static void installViewerActions( actions.namedAction( new ToggleDialogAction( SHOW_WARPTYPE_DIALOG, bw.warpVisDialog ), SHOW_WARPTYPE_DIALOG_KEYS ); actions.namedAction( new ToggleDialogAction( PREFERENCES_DIALOG, bw.preferencesDialog ), PREFERENCES_DIALOG_KEYS ); - // landmarks + // landmarks unbound + actions.runnableAction( () -> { bw.getLandmarkPanel().getJTable().selectAll(); }, LANDMARK_SELECT_ALL, NOT_MAPPED ); + actions.runnableAction( () -> { bw.getLandmarkPanel().getJTable().clearSelection(); }, LANDMARK_DESELECT_ALL, NOT_MAPPED ); + + actions.namedAction( bw.landmarkPopupMenu.deleteSelectedHandler, NOT_MAPPED ); + + actions.namedAction( bw.landmarkPopupMenu.activateSelectedHandler, NOT_MAPPED ); + actions.namedAction( bw.landmarkPopupMenu.deactivateSelectedHandler, NOT_MAPPED ); + + actions.namedAction( bw.landmarkPopupMenu.addAboveHandler, NOT_MAPPED ); + actions.namedAction( bw.landmarkPopupMenu.addAllAboveHandler, NOT_MAPPED ); + actions.namedAction( bw.landmarkPopupMenu.addBelowHandler, NOT_MAPPED ); + actions.namedAction( bw.landmarkPopupMenu.addAllBelowHandler, NOT_MAPPED ); + + // landmarks bound actions.runnableAction( bw::loadLandmarks, LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS ); actions.runnableAction( bw::saveLandmarks, SAVE_LANDMARKS, SAVE_LANDMARKS_KEYS ); actions.runnableAction( bw::quickSaveLandmarks, QUICK_SAVE_LANDMARKS, QUICK_SAVE_LANDMARKS_KEYS ); @@ -388,11 +445,41 @@ public static void installTableActions( { actions.install( inputActionBindings, "bw-table" ); - // landmarks - actions.runnableAction( bw::loadLandmarks, LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS ); - actions.runnableAction( bw::saveLandmarks, SAVE_LANDMARKS, SAVE_LANDMARKS_KEYS ); - actions.runnableAction( bw::quickSaveLandmarks, QUICK_SAVE_LANDMARKS, QUICK_SAVE_LANDMARKS_KEYS ); + // unmapped + actions.runnableAction( () -> { bw.getBwTransform().transformToString(); }, PRINT_TRANSFORM, PRINT_TRANSFORM_KEYS); + actions.runnableAction( bw::toggleInLandmarkMode, TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS); + actions.runnableAction( bw::toggleMovingImageDisplay, TOGGLE_MOVING_IMAGE_DISPLAY, TOGGLE_MOVING_IMAGE_DISPLAY_KEYS ); + + // navigation + actions.runnableAction( bw::resetView, RESET_VIEWER, NOT_MAPPED ); + actions.runnableAction( bw::matchOtherViewerPanelToActive, ALIGN_OTHER_TO_ACTIVE, NOT_MAPPED ); + actions.runnableAction( bw::matchActiveViewerPanelToOther, ALIGN_ACTIVE_TO_OTHER, NOT_MAPPED ); + actions.runnableAction( bw::warpToSelectedLandmark, WARP_TO_SELECTED_POINT, NOT_MAPPED ); + actions.runnableAction( bw::warpToNearestLandmark, WARP_TO_NEAREST_POINT, NOT_MAPPED ); + actions.runnableAction( bw::warpToNextLandmark, WARP_TO_NEXT_POINT, NOT_MAPPED ); + actions.runnableAction( bw::warpToPrevLandmark, WARP_TO_PREV_POINT, NOT_MAPPED ); + + // bookmarks + actions.runnableAction( bw::goToBookmark, GO_TO_BOOKMARK, NOT_MAPPED ); + actions.runnableAction( bw::goToBookmarkRotation, GO_TO_BOOKMARK_ROTATION, NOT_MAPPED ); + actions.runnableAction( bw::setBookmark, SET_BOOKMARK, NOT_MAPPED ); + + // cards + actions.runnableAction( ()->{}, EXPAND_CARDS, NOT_MAPPED ); + actions.runnableAction( ()->{}, COLLAPSE_CARDS, NOT_MAPPED ); + + // export + actions.runnableAction( bw::exportWarpField, EXPORT_WARP, EXPORT_WARP_KEYS ); + actions.runnableAction( () -> { bw.getBwTransform().printAffine(); }, EXPORT_AFFINE, EXPORT_AFFINE_KEYS ); + // dialogs + actions.namedAction( new ToggleDialogAction( SHOW_HELP, bw.helpDialog ), SHOW_HELP_KEYS ); + actions.namedAction( new ToggleDialogAction( VISIBILITY_AND_GROUPING_MVG, bw.activeSourcesDialogP ), VISIBILITY_AND_GROUPING_MVG_KEYS ); + actions.namedAction( new ToggleDialogAction( VISIBILITY_AND_GROUPING_TGT, bw.activeSourcesDialogQ ), VISIBILITY_AND_GROUPING_TGT_KEYS ); + actions.namedAction( new ToggleDialogAction( SHOW_WARPTYPE_DIALOG, bw.warpVisDialog ), SHOW_WARPTYPE_DIALOG_KEYS ); + actions.namedAction( new ToggleDialogAction( PREFERENCES_DIALOG, bw.preferencesDialog ), PREFERENCES_DIALOG_KEYS ); + + // landmarks actions.runnableAction( () -> { bw.getLandmarkPanel().getJTable().selectAll(); }, LANDMARK_SELECT_ALL, LANDMARK_SELECT_ALL_KEYS ); actions.runnableAction( () -> { bw.getLandmarkPanel().getJTable().clearSelection(); }, LANDMARK_DESELECT_ALL, LANDMARK_DESELECT_ALL_KEYS ); @@ -406,6 +493,10 @@ public static void installTableActions( actions.namedAction( bw.landmarkPopupMenu.addBelowHandler, LANDMARK_SELECT_BELOW_KEYS ); actions.namedAction( bw.landmarkPopupMenu.addAllBelowHandler, LANDMARK_SELECT_ALL_BELOW_KEYS ); + actions.runnableAction( bw::loadLandmarks, LOAD_LANDMARKS, LOAD_LANDMARKS_KEYS ); + actions.runnableAction( bw::saveLandmarks, SAVE_LANDMARKS, SAVE_LANDMARKS_KEYS ); + actions.runnableAction( bw::quickSaveLandmarks, QUICK_SAVE_LANDMARKS, QUICK_SAVE_LANDMARKS_KEYS ); + actions.namedAction( new UndoRedoAction( UNDO, bw ), UNDO_KEYS ); actions.namedAction( new UndoRedoAction( REDO, bw ), REDO_KEYS ); } diff --git a/src/main/java/bigwarp/ui/keymap/KeymapManager.java b/src/main/java/bigwarp/ui/keymap/KeymapManager.java index 7de6859c..1a2cb2b0 100644 --- a/src/main/java/bigwarp/ui/keymap/KeymapManager.java +++ b/src/main/java/bigwarp/ui/keymap/KeymapManager.java @@ -48,7 +48,6 @@ public KeymapManager() private KeymapManager( final boolean loadStyles, final String configDir ) { - System.out.println( "configDir: " + configDir ); configFile = configDir == null ? null : configDir + "/" + CONFIG_FILE_NAME; if ( loadStyles ) loadStyles(); @@ -144,7 +143,6 @@ public void loadStyles() @Override public void saveStyles() { - System.out.println( "saveStyles" ); try { saveStyles( new File( configFile ) ); @@ -154,4 +152,5 @@ public void saveStyles() e.printStackTrace(); } } + } diff --git a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java index f574d5ee..ab6e8d89 100644 --- a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java +++ b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java @@ -7,6 +7,10 @@ import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import bdv.KeyConfigContexts; +import bdv.KeyConfigScopes; +import bdv.TransformEventHandler2D; +import bdv.TransformEventHandler3D; import bdv.viewer.NavigationActions; import bigwarp.BigWarpActions; @@ -26,7 +30,7 @@ public static class Descriptions extends CommandDescriptionProvider { public Descriptions() { - super( BigWarpActions.BIGWARP, BigWarpActions.BIGWARP_CTXT ); + super( BigWarpActions.BIGWARP, BigWarpActions.BIGWARP_CTXT, "navigation", "bw-table" ); } @Override @@ -47,7 +51,75 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) descriptions.add( ALIGN_XY_PLANE, ALIGN_XY_PLANE_KEYS, "TODO" ); descriptions.add( ALIGN_ZY_PLANE, ALIGN_ZY_PLANE_KEYS, "TODO" ); descriptions.add( ALIGN_XZ_PLANE, ALIGN_XZ_PLANE_KEYS, "TODO" ); + + // from TransformEventHandler3D + descriptions.add( TransformEventHandler3D.DRAG_TRANSLATE, TransformEventHandler3D.DRAG_TRANSLATE_KEYS, "Pan the view by mouse-dragging." ); + descriptions.add( TransformEventHandler3D.ZOOM_NORMAL, TransformEventHandler3D.ZOOM_NORMAL_KEYS, "Zoom in by scrolling." ); + + descriptions.add( TransformEventHandler3D.SELECT_AXIS_X, TransformEventHandler3D.SELECT_AXIS_X_KEYS, "Select X as the rotation axis for keyboard rotation." ); + descriptions.add( TransformEventHandler3D.SELECT_AXIS_Y, TransformEventHandler3D.SELECT_AXIS_Y_KEYS, "Select Y as the rotation axis for keyboard rotation." ); + descriptions.add( TransformEventHandler3D.SELECT_AXIS_Z, TransformEventHandler3D.SELECT_AXIS_Z_KEYS, "Select Z as the rotation axis for keyboard rotation." ); + + descriptions.add( TransformEventHandler3D.DRAG_ROTATE, TransformEventHandler3D.DRAG_ROTATE_KEYS, "Rotate the view by mouse-dragging." ); + descriptions.add( TransformEventHandler3D.SCROLL_Z, TransformEventHandler3D.SCROLL_Z_KEYS, "Translate in Z by scrolling." ); + descriptions.add( TransformEventHandler3D.ROTATE_LEFT, TransformEventHandler3D.ROTATE_LEFT_KEYS, "Rotate left (counter-clockwise) by 1 degree." ); + descriptions.add( TransformEventHandler3D.ROTATE_RIGHT, TransformEventHandler3D.ROTATE_RIGHT_KEYS, "Rotate right (clockwise) by 1 degree." ); + descriptions.add( TransformEventHandler3D.KEY_ZOOM_IN, TransformEventHandler3D.KEY_ZOOM_IN_KEYS, "Zoom in." ); + descriptions.add( TransformEventHandler3D.KEY_ZOOM_OUT, TransformEventHandler3D.KEY_ZOOM_OUT_KEYS, "Zoom out." ); + descriptions.add( TransformEventHandler3D.KEY_FORWARD_Z, TransformEventHandler3D.KEY_FORWARD_Z_KEYS, "Translate forward in Z." ); + descriptions.add( TransformEventHandler3D.KEY_BACKWARD_Z, TransformEventHandler3D.KEY_BACKWARD_Z_KEYS, "Translate backward in Z." ); + + descriptions.add( TransformEventHandler3D.DRAG_ROTATE_FAST, TransformEventHandler3D.DRAG_ROTATE_FAST_KEYS, "Rotate the view by mouse-dragging (fast)." ); + descriptions.add( TransformEventHandler3D.SCROLL_Z_FAST, TransformEventHandler3D.SCROLL_Z_FAST_KEYS, "Translate in Z by scrolling (fast)." ); + descriptions.add( TransformEventHandler3D.ROTATE_LEFT_FAST, TransformEventHandler3D.ROTATE_LEFT_FAST_KEYS, "Rotate left (counter-clockwise) by 10 degrees." ); + descriptions.add( TransformEventHandler3D.ROTATE_RIGHT_FAST, TransformEventHandler3D.ROTATE_RIGHT_FAST_KEYS, "Rotate right (clockwise) by 10 degrees." ); + descriptions.add( TransformEventHandler3D.KEY_ZOOM_IN_FAST, TransformEventHandler3D.KEY_ZOOM_IN_FAST_KEYS, "Zoom in (fast)." ); + descriptions.add( TransformEventHandler3D.KEY_ZOOM_OUT_FAST, TransformEventHandler3D.KEY_ZOOM_OUT_FAST_KEYS, "Zoom out (fast)." ); + descriptions.add( TransformEventHandler3D.KEY_FORWARD_Z_FAST, TransformEventHandler3D.KEY_FORWARD_Z_FAST_KEYS, "Translate forward in Z (fast)." ); + descriptions.add( TransformEventHandler3D.KEY_BACKWARD_Z_FAST, TransformEventHandler3D.KEY_BACKWARD_Z_FAST_KEYS, "Translate backward in Z (fast)." ); + + descriptions.add( TransformEventHandler3D.DRAG_ROTATE_SLOW, TransformEventHandler3D.DRAG_ROTATE_SLOW_KEYS, "Rotate the view by mouse-dragging (slow)." ); + descriptions.add( TransformEventHandler3D.SCROLL_Z_SLOW, TransformEventHandler3D.SCROLL_Z_SLOW_KEYS, "Translate in Z by scrolling (slow)." ); + descriptions.add( TransformEventHandler3D.ROTATE_LEFT_SLOW, TransformEventHandler3D.ROTATE_LEFT_SLOW_KEYS, "Rotate left (counter-clockwise) by 0.1 degree." ); + descriptions.add( TransformEventHandler3D.ROTATE_RIGHT_SLOW, TransformEventHandler3D.ROTATE_RIGHT_SLOW_KEYS, "Rotate right (clockwise) by 0.1 degree." ); + descriptions.add( TransformEventHandler3D.KEY_ZOOM_IN_SLOW, TransformEventHandler3D.KEY_ZOOM_IN_SLOW_KEYS, "Zoom in (slow)." ); + descriptions.add( TransformEventHandler3D.KEY_ZOOM_OUT_SLOW, TransformEventHandler3D.KEY_ZOOM_OUT_SLOW_KEYS, "Zoom out (slow)." ); + descriptions.add( TransformEventHandler3D.KEY_FORWARD_Z_SLOW, TransformEventHandler3D.KEY_FORWARD_Z_SLOW_KEYS, "Translate forward in Z (slow)." ); + descriptions.add( TransformEventHandler3D.KEY_BACKWARD_Z_SLOW, TransformEventHandler3D.KEY_BACKWARD_Z_SLOW_KEYS, "Translate backward in Z (slow)." ); + + + // from TransformEventHandler2D +// descriptions.add( TransformEventHandler2D.DRAG_TRANSLATE, TransformEventHandler2D.DRAG_TRANSLATE_KEYS, "Pan the view by mouse-dragging. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.DRAG_ROTATE, TransformEventHandler2D.DRAG_ROTATE_KEYS, "Rotate the view by mouse-dragging. Active in 2D mode." ); +// +// descriptions.add( TransformEventHandler2D.ZOOM_NORMAL, TransformEventHandler2D.ZOOM_NORMAL_KEYS, "Zoom in by scrolling. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.ZOOM_FAST, TransformEventHandler2D.ZOOM_FAST_KEYS, "Zoom in by scrolling (fast). Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.ZOOM_SLOW, TransformEventHandler2D.ZOOM_SLOW_KEYS, "Zoom in by scrolling (slow). Active in 2D mode." ); +// +// descriptions.add( TransformEventHandler2D.SCROLL_TRANSLATE, TransformEventHandler2D.SCROLL_TRANSLATE_KEYS, "Translate by scrolling. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.SCROLL_TRANSLATE_FAST, TransformEventHandler2D.SCROLL_TRANSLATE_FAST_KEYS, "Translate by scrolling (fast). Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.SCROLL_TRANSLATE_SLOW, TransformEventHandler2D.SCROLL_TRANSLATE_SLOW_KEYS, "Translate by scrolling (slow). Active in 2D mode." ); +// +// descriptions.add( TransformEventHandler2D.ROTATE_LEFT, TransformEventHandler2D.ROTATE_LEFT_KEYS, "Rotate left (counter-clockwise) by 1 degree. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.ROTATE_RIGHT, TransformEventHandler2D.ROTATE_RIGHT_KEYS, "Rotate right (clockwise) by 1 degree. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.KEY_ZOOM_IN, TransformEventHandler2D.KEY_ZOOM_IN_KEYS, "Zoom in. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.KEY_ZOOM_OUT, TransformEventHandler2D.KEY_ZOOM_OUT_KEYS, "Zoom out. Active in 2D mode." ); +// +// descriptions.add( TransformEventHandler2D.ROTATE_LEFT_FAST, TransformEventHandler2D.ROTATE_LEFT_FAST_KEYS, "Rotate left (counter-clockwise) by 10 degrees. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.ROTATE_RIGHT_FAST, TransformEventHandler2D.ROTATE_RIGHT_FAST_KEYS, "Rotate right (clockwise) by 10 degrees. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.KEY_ZOOM_IN_FAST, TransformEventHandler2D.KEY_ZOOM_IN_FAST_KEYS, "Zoom in (fast). Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.KEY_ZOOM_OUT_FAST, TransformEventHandler2D.KEY_ZOOM_OUT_FAST_KEYS, "Zoom out (fast). Active in 2D mode." ); +// +// descriptions.add( TransformEventHandler2D.ROTATE_LEFT_SLOW, TransformEventHandler2D.ROTATE_LEFT_SLOW_KEYS, "Rotate left (counter-clockwise) by 0.1 degree. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.ROTATE_RIGHT_SLOW, TransformEventHandler2D.ROTATE_RIGHT_SLOW_KEYS, "Rotate right (clockwise) by 0.1 degree. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.KEY_ZOOM_IN_SLOW, TransformEventHandler2D.KEY_ZOOM_IN_SLOW_KEYS, "Zoom in (slow). Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.KEY_ZOOM_OUT_SLOW, TransformEventHandler2D.KEY_ZOOM_OUT_SLOW_KEYS, "Zoom out (slow). Active in 2D mode." ); +// +// descriptions.add( TransformEventHandler2D.SCROLL_ROTATE, TransformEventHandler2D.SCROLL_ROTATE_KEYS, "Rotate by scrolling. Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.SCROLL_ROTATE_FAST, TransformEventHandler2D.SCROLL_ROTATE_FAST_KEYS, "Rotate by scrolling (fast). Active in 2D mode." ); +// descriptions.add( TransformEventHandler2D.SCROLL_ROTATE_SLOW, TransformEventHandler2D.SCROLL_ROTATE_SLOW_KEYS, "Rotate by scrolling (slow). Active in 2D mode." ); } } + } diff --git a/src/main/java/bigwarp/ui/keymap/UnmappedNavigationActions.java b/src/main/java/bigwarp/ui/keymap/UnmappedNavigationActions.java new file mode 100644 index 00000000..3df4d08f --- /dev/null +++ b/src/main/java/bigwarp/ui/keymap/UnmappedNavigationActions.java @@ -0,0 +1,64 @@ +package bigwarp.ui.keymap; + +import java.util.stream.IntStream; + +import org.scijava.ui.behaviour.KeyStrokeAdder.Factory; +import org.scijava.ui.behaviour.util.Actions; + +import bdv.viewer.AbstractViewerPanel; +import bdv.viewer.AbstractViewerPanel.AlignPlane; +import bdv.viewer.NavigationActions; +import bdv.viewer.ViewerState; +import bigwarp.BigWarpActions; + +public class UnmappedNavigationActions extends NavigationActions { + + public UnmappedNavigationActions(Factory keyConfig) { + super(keyConfig); + } + + public static void install( final Actions actions, boolean is2D ) + { + installModeActions( actions ); + installSourceActions( actions ); + installTimeActions( actions ); + installAlignPlaneActions( actions, is2D ); + } + + public static void installModeActions( final Actions actions ) + { + actions.runnableAction( () -> {}, TOGGLE_INTERPOLATION, BigWarpActions.NOT_MAPPED ); + actions.runnableAction( () -> {}, TOGGLE_FUSED_MODE, BigWarpActions.NOT_MAPPED ); + actions.runnableAction( () -> {}, TOGGLE_GROUPING, BigWarpActions.NOT_MAPPED ); + } + + public static void installTimeActions( final Actions actions ) + { + actions.runnableAction( () -> {}, NEXT_TIMEPOINT, BigWarpActions.NOT_MAPPED ); + actions.runnableAction( () -> {}, PREVIOUS_TIMEPOINT, BigWarpActions.NOT_MAPPED ); + } + + public static void installSourceActions( final Actions actions ) + { + final String[] numkeys = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" }; + IntStream.range( 0, numkeys.length ).forEach( i -> { + actions.runnableAction( () -> {}, + String.format( SET_CURRENT_SOURCE, i ), + String.format( SET_CURRENT_SOURCE_KEYS_FORMAT, numkeys[ i ] ) ); + actions.runnableAction( () -> {}, + String.format( TOGGLE_SOURCE_VISIBILITY, i ), + String.format( TOGGLE_SOURCE_VISIBILITY_KEYS_FORMAT, numkeys[ i ] ) ); + } ); + } + + public static void installAlignPlaneActions( final Actions actions, boolean is2D ) + { + actions.runnableAction( () -> {}, ALIGN_XY_PLANE, BigWarpActions.NOT_MAPPED ); + if ( !is2D ) + { + actions.runnableAction( () -> {}, ALIGN_ZY_PLANE, BigWarpActions.NOT_MAPPED ); + actions.runnableAction( () -> {}, ALIGN_XZ_PLANE, BigWarpActions.NOT_MAPPED ); + } + } + +} diff --git a/src/main/resources/bigwarp/ui/keymap/default.yaml b/src/main/resources/bigwarp/ui/keymap/default.yaml index 381c3012..d321488f 100644 --- a/src/main/resources/bigwarp/ui/keymap/default.yaml +++ b/src/main/resources/bigwarp/ui/keymap/default.yaml @@ -1,45 +1,497 @@ --- +- !mapping + action: close dialog window + contexts: [bigwarp, navigation, bw-table] + triggers: [not mapped] - !mapping action: Preferences - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [ctrl COMMA, meta COMMA] - !mapping action: brightness settings - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [S] - !mapping action: go to bookmark - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [B] - !mapping action: go to bookmark rotation - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [shift ctrl B] - !mapping action: help - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [F1] - !mapping action: landmark mode toggle - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [SPACE] - !mapping action: set bookmark - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [shift B] - !mapping action: visibility and grouping moving - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [F3] - !mapping action: visibility and grouping target - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [F4] - !mapping action: save settings - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] triggers: [not mapped] - !mapping action: load settings - contexts: [bigwarp] + contexts: [bigwarp, navigation, bw-table] + triggers: [not mapped] +- !mapping + action: activate selected landmarks + contexts: [bw-table, navigation, bw-table] + triggers: [ctrl BACK_SPACE] +- !mapping + action: table activate selected + contexts: [bw-table, navigation, bw-table] + triggers: [not mapped] +- !mapping + action: align XY plane + contexts: [bigwarp, navigation, bw-table] + triggers: [shift Z] +- !mapping + action: align XZ plane + contexts: [bigwarp, navigation, bw-table] + triggers: [shift A, shift Y] +- !mapping + action: align ZY plane + contexts: [bigwarp, navigation, bw-table] + triggers: [shift X] +- !mapping + action: align view transforms ACTIVE_TO_OTHER + contexts: [bigwarp, navigation, bw-table] + triggers: [W] +- !mapping + action: align view transforms OTHER_TO_ACTIVE + contexts: [bigwarp, navigation, bw-table] + triggers: [Q] +- !mapping + action: center on nearest landmark + contexts: [bigwarp, navigation, bw-table] + triggers: [Y] +- !mapping + action: center on next landmark + contexts: [bigwarp, navigation, bw-table] + triggers: [ctrl D] +- !mapping + action: center on prev landmark + contexts: [bigwarp, navigation, bw-table] + triggers: [shift ctrl D] +- !mapping + action: center on selected landmark + contexts: [bigwarp, navigation, bw-table] + triggers: [E] +- !mapping + action: expand and focus cards panel + contexts: [bigwarp, navigation, bw-table] + triggers: [P] +- !mapping + action: collapse cards panel + contexts: [bigwarp, navigation, bw-table] + triggers: [shift ESCAPE, shift P] +- !mapping + action: deactivate selected landmarks + contexts: [bw-table, navigation, bw-table] + triggers: [BACK_SPACE] +- !mapping + action: delete selected landmarks + contexts: [bw-table, navigation, bw-table] + triggers: [DELETE] +- !mapping + action: deselect all landmarks + contexts: [bw-table, navigation, bw-table] + triggers: [ESCAPE, Q] +- !mapping + action: export affine + contexts: [bigwarp, navigation, bw-table] + triggers: [ctrl A] +- !mapping + action: export imageplus + contexts: [bigwarp, navigation, bw-table] + triggers: [shift ctrl W] +- !mapping + action: export warp field + contexts: [bigwarp, navigation, bw-table] + triggers: [ctrl W] +- !mapping + action: load landmarks + contexts: [bw-table, bigwarp, navigation] + triggers: [ctrl O] +- !mapping + action: next timepoint + contexts: [bigwarp, navigation, bw-table] + triggers: [CLOSE_BRACKET, R] +- !mapping + action: previous timepoint + contexts: [bigwarp, navigation, bw-table] + triggers: [N, OPEN_BRACKET] +- !mapping + action: quick save landmarks + contexts: [bw-table, bigwarp, navigation] + triggers: [ctrl Q] +- !mapping + action: redo + contexts: [bw-table, bigwarp, navigation] + triggers: [ctrl Y, shift ctrl Z] +- !mapping + action: reset active viewer + contexts: [bigwarp, navigation, bw-table] + triggers: [R] +- !mapping + action: save landmarks + contexts: [bw-table, bigwarp, navigation] + triggers: [ctrl S] +- !mapping + action: save warped xml + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl E] +- !mapping + action: select all landmarks + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl A] +- !mapping + action: select all landmarks above + contexts: [bigwarp, bw-table, navigation] + triggers: [shift ctrl UP] +- !mapping + action: select all landmarks below + contexts: [bigwarp, bw-table, navigation] + triggers: [shift ctrl DOWN] +- !mapping + action: select landmark above + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl UP] +- !mapping + action: select landmark below + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl DOWN] +- !mapping + action: set current source 0 + contexts: [bigwarp, bw-table, navigation] + triggers: ['1'] +- !mapping + action: set current source 1 + contexts: [bigwarp, bw-table, navigation] + triggers: ['2'] +- !mapping + action: set current source 2 + contexts: [bigwarp, bw-table, navigation] + triggers: ['3'] +- !mapping + action: set current source 3 + contexts: [bigwarp, bw-table, navigation] + triggers: ['4'] +- !mapping + action: set current source 4 + contexts: [bigwarp, bw-table, navigation] + triggers: ['5'] +- !mapping + action: set current source 5 + contexts: [bigwarp, bw-table, navigation] + triggers: ['6'] +- !mapping + action: set current source 6 + contexts: [bigwarp, bw-table, navigation] + triggers: ['7'] +- !mapping + action: set current source 7 + contexts: [bigwarp, bw-table, navigation] + triggers: ['8'] +- !mapping + action: set current source 8 + contexts: [bigwarp, bw-table, navigation] + triggers: ['9'] +- !mapping + action: set current source 9 + contexts: [bigwarp, bw-table, navigation] + triggers: ['0'] +- !mapping + action: show warp vis dialog + contexts: [bigwarp, bw-table, navigation] + triggers: [U] +- !mapping + action: toggle fused mode + contexts: [bigwarp, bw-table, navigation] + triggers: [F] +- !mapping + action: toggle grouping + contexts: [bigwarp, bw-table, navigation] + triggers: [G] +- !mapping + action: toggle interpolation + contexts: [bigwarp, bw-table, navigation] + triggers: [I] +- !mapping + action: toggle moving image display + contexts: [bigwarp, bw-table, navigation] + triggers: [T] +- !mapping + action: toggle point names visible + contexts: [bigwarp, bw-table, navigation] + triggers: [N] +- !mapping + action: toggle points visible + contexts: [bigwarp, bw-table, navigation] + triggers: [V] +- !mapping + action: toggle source visibility 0 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 1] +- !mapping + action: toggle source visibility 1 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 2] +- !mapping + action: toggle source visibility 2 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 3] +- !mapping + action: toggle source visibility 3 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 4] +- !mapping + action: toggle source visibility 4 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 5] +- !mapping + action: toggle source visibility 5 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 6] +- !mapping + action: toggle source visibility 6 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 7] +- !mapping + action: toggle source visibility 7 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 8] +- !mapping + action: toggle source visibility 8 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 9] +- !mapping + action: toggle source visibility 9 + contexts: [bigwarp, bw-table, navigation] + triggers: [shift 0] +- !mapping + action: undo + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl Z] +- !mapping + action: drag translate + contexts: [bigwarp, bw-table, navigation] + triggers: [button2, button3] +- !mapping + action: scroll zoom + contexts: [bigwarp, bw-table, navigation] + triggers: [meta scroll, shift ctrl scroll] +- !mapping + action: axis x + contexts: [bigwarp, bw-table, navigation] + triggers: [X] +- !mapping + action: axis y + contexts: [bigwarp, bw-table, navigation] + triggers: [Y] +- !mapping + action: axis z + contexts: [bigwarp, bw-table, navigation] + triggers: [Z] +- !mapping + action: drag rotate + contexts: [bigwarp, bw-table, navigation] + triggers: [button1] +- !mapping + action: scroll browse z + contexts: [bigwarp, bw-table, navigation] + triggers: [scroll] +- !mapping + action: rotate left + contexts: [bigwarp, bw-table, navigation] + triggers: [LEFT] +- !mapping + action: rotate right + contexts: [bigwarp, bw-table, navigation] + triggers: [RIGHT] +- !mapping + action: zoom in + contexts: [bigwarp, bw-table, navigation] + triggers: [UP] +- !mapping + action: zoom out + contexts: [bigwarp, bw-table, navigation] + triggers: [DOWN] +- !mapping + action: forward z + contexts: [bigwarp, bw-table, navigation] + triggers: [COMMA] +- !mapping + action: backward z + contexts: [bigwarp, bw-table, navigation] + triggers: [PERIOD] +- !mapping + action: drag rotate fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift button1] +- !mapping + action: scroll browse z fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift scroll] +- !mapping + action: rotate left fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift LEFT] +- !mapping + action: rotate right fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift RIGHT] +- !mapping + action: zoom in fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift UP] +- !mapping + action: zoom out fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift DOWN] +- !mapping + action: forward z fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift COMMA] +- !mapping + action: backward z fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift PERIOD] +- !mapping + action: drag rotate slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl button1] +- !mapping + action: scroll browse z slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl scroll] +- !mapping + action: rotate left slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl LEFT] +- !mapping + action: rotate right slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl RIGHT] +- !mapping + action: zoom in slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl UP] +- !mapping + action: zoom out slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl DOWN] +- !mapping + action: forward z slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl COMMA] +- !mapping + action: backward z slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl PERIOD] +- !mapping + action: 2d drag translate + contexts: [bigwarp, bw-table, navigation] + triggers: [button2, button3] +- !mapping + action: 2d drag rotate + contexts: [bigwarp, bw-table, navigation] + triggers: [button1] +- !mapping + action: 2d scroll zoom + contexts: [bigwarp, bw-table, navigation] + triggers: [meta scroll, scroll, shift ctrl scroll] +- !mapping + action: 2d scroll zoom fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift scroll] +- !mapping + action: 2d scroll zoom slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl scroll] +- !mapping + action: 2d scroll translate + contexts: [bigwarp, bw-table, navigation] + triggers: [not mapped] +- !mapping + action: 2d scroll translate fast + contexts: [bigwarp, bw-table, navigation] + triggers: [not mapped] +- !mapping + action: 2d scroll translate slow + contexts: [bigwarp, bw-table, navigation] + triggers: [not mapped] +- !mapping + action: 2d rotate left + contexts: [bigwarp, bw-table, navigation] + triggers: [LEFT] +- !mapping + action: 2d rotate right + contexts: [bigwarp, bw-table, navigation] + triggers: [RIGHT] +- !mapping + action: 2d zoom in + contexts: [bigwarp, bw-table, navigation] + triggers: [UP] +- !mapping + action: 2d zoom out + contexts: [bigwarp, bw-table, navigation] + triggers: [DOWN] +- !mapping + action: 2d rotate left fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift LEFT] +- !mapping + action: 2d rotate right fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift RIGHT] +- !mapping + action: 2d zoom in fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift UP] +- !mapping + action: 2d zoom out fast + contexts: [bigwarp, bw-table, navigation] + triggers: [shift DOWN] +- !mapping + action: 2d rotate left slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl LEFT] +- !mapping + action: 2d rotate right slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl RIGHT] +- !mapping + action: 2d zoom in slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl UP] +- !mapping + action: 2d zoom out slow + contexts: [bigwarp, bw-table, navigation] + triggers: [ctrl DOWN] +- !mapping + action: 2d scroll rotate + contexts: [bigwarp, bw-table, navigation] + triggers: [not mapped] +- !mapping + action: 2d scroll rotate fast + contexts: [bigwarp, bw-table, navigation] + triggers: [not mapped] +- !mapping + action: 2d scroll rotate slow + contexts: [bigwarp, bw-table, navigation] triggers: [not mapped] From a7487c8999c8972eea141742370699e1ee47f961 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 29 Sep 2022 15:01:34 -0400 Subject: [PATCH 052/282] WIP: start cleaning up actions --- src/main/java/bigwarp/BigWarp.java | 53 +--- .../bigwarp/ui/keymap/NavigationKeys.java | 2 - .../resources/bigwarp/ui/keymap/default.yaml | 294 +++++++++--------- 3 files changed, 158 insertions(+), 191 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 187860ca..a4c23d4e 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -55,7 +55,6 @@ import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JCheckBox; -import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; @@ -84,14 +83,11 @@ import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import org.scijava.ui.behaviour.io.InputTriggerConfig; -import org.scijava.ui.behaviour.io.gui.CommandDescriptions; import org.scijava.ui.behaviour.util.Actions; -import org.scijava.ui.behaviour.util.InputActionBindings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import bdv.BigDataViewer; -import bdv.KeyConfigContexts; import bdv.cache.CacheControl; import bdv.export.ProgressWriter; import bdv.export.ProgressWriterConsole; @@ -149,6 +145,7 @@ import bigwarp.transforms.WrappedCoordinateTransform; import bigwarp.ui.keymap.KeymapManager; import bigwarp.ui.keymap.NavigationKeys; +import bigwarp.ui.keymap.UnmappedNavigationActions; import bigwarp.util.BigWarpUtils; import dev.dirs.ProjectDirectories; import fiji.util.gui.GenericDialogPlus; @@ -361,7 +358,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, final Progr public BigWarp( final BigWarpData data, final String windowTitle, BigWarpViewerOptions options, final ProgressWriter progressWriter ) throws SpimDataException { - System.out.println( "BigWarp actions"); final KeymapManager optionsKeymapManager = options.getValues().getKeymapManager(); final AppearanceManager optionsAppearanceManager = options.values.getAppearanceManager(); keymapManager = optionsKeymapManager != null ? optionsKeymapManager : new KeymapManager( configDir ); @@ -406,7 +402,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie landmarkTable.setDefaultRenderer( Object.class, new WarningTableCellRenderer() ); addDefaultTableMouseListener(); - landmarkFrame = new BigWarpLandmarkFrame( "Landmarks", landmarkPanel, this ); + landmarkFrame = new BigWarpLandmarkFrame( "Landmarks", landmarkPanel, this, keymapManager ); baseXfmList = new AbstractModel< ? >[ 3 ]; setupWarpMagBaselineOptions( baseXfmList, ndims ); @@ -545,24 +541,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // dialogs have to be constructed before action maps are made warpVisDialog = new WarpVisFrame( viewerFrameQ, this ); -// WarpNavigationActions.installActionBindings( getViewerFrameP().getKeybindings(), viewerFrameP, inputTriggerConfig, ( ndims == 2 ) ); -// BigWarpActions.installActionBindings( getViewerFrameP().getKeybindings(), this, inputTriggerConfig ); -// -// WarpNavigationActions.installActionBindings( getViewerFrameQ().getKeybindings(), viewerFrameQ, inputTriggerConfig, ( ndims == 2 ) ); -// BigWarpActions.installActionBindings( getViewerFrameQ().getKeybindings(), this, inputTriggerConfig ); -// -// BigWarpActions.installLandmarkPanelActionBindings( landmarkFrame.getKeybindings(), this, landmarkTable, inputTriggerConfig ); - - -// System.out.println( "install actions" ); - - Descriptions desc = new BigWarpActions.Descriptions(); - CommandDescriptions bwDesc = new CommandDescriptions(); - bwDesc.setKeyconfigContext( "bigwarp" ); - desc.getCommandDescriptions( bwDesc ); - - desc.getCommandDescriptions( keymapManager.getCommandDescriptions() ); - preferencesDialog = new PreferencesDialog( viewerFrameP, keymap, new String[] { KeyConfigContexts.BIGDATAVIEWER, "bigwarp", "bw", "navigation", "bw-table" } ); + preferencesDialog = new PreferencesDialog( landmarkFrame, keymap, new String[] { "bigwarp", "navigation", "bw-table" } ); preferencesDialog.addPage( new AppearanceSettingsPage( "Appearance", appearanceManager ) ); preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", this.keymapManager, new KeymapManager(), this.keymapManager.getCommandDescriptions() ) ); @@ -570,40 +549,31 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // appearanceManager.addLafComponent( fileChooser ); // SwingUtilities.invokeLater(() -> appearanceManager.updateLookAndFeel()); - - final Actions navigationActions = new Actions( inputTriggerConfig, "bigwarp", "navigation" ); + final Actions navigationActions = new Actions( inputTriggerConfig, "navigation" ); navigationActions.install( getViewerFrameP().getKeybindings(), "navigation" ); NavigationKeys.install( navigationActions, getViewerFrameP().getViewerPanel(), options.values.is2D() ); - navigationActions.install( getViewerFrameQ().getKeybindings(), "bigwarp" ); + navigationActions.install( getViewerFrameQ().getKeybindings(), "navigation" ); NavigationKeys.install( navigationActions, getViewerFrameQ().getViewerPanel(), options.values.is2D() ); - BigWarpActions bwActions = new BigWarpActions( inputTriggerConfig, "bw", "bw-general" ); + final BigWarpActions bwActions = new BigWarpActions( inputTriggerConfig, "bigwarp" ); BigWarpActions.installViewerActions( bwActions, getViewerFrameP(), this ); BigWarpActions.installViewerActions( bwActions, getViewerFrameQ(), this ); - BigWarpActions tableActions = new BigWarpActions( inputTriggerConfig, "bw", "bw-table" ); + final BigWarpActions tableActions = new BigWarpActions( inputTriggerConfig, "bw-table" ); BigWarpActions.installTableActions( tableActions, getLandmarkFrame().getKeybindings(), this ); + UnmappedNavigationActions.install( tableActions, options.values.is2D() ); keymap.updateListeners().add( () -> { + navigationActions.updateKeyConfig( keymap.getConfig() ); bwActions.updateKeyConfig( keymap.getConfig() ); tableActions.updateKeyConfig( keymap.getConfig() ); + viewerFrameP.getTransformBehaviours().updateKeyConfig( keymap.getConfig() ); + viewerFrameQ.getTransformBehaviours().updateKeyConfig( keymap.getConfig() ); } ); - -// bwActions.installViewerActions( getViewerFrameQ().getKeybindings(), this ); -// BigWarpActions.install( bwActions, ) - -// BigWarpActions.installViewerActions( getViewerFrameP().getKeybindings(), this, inputTriggerConfig ); -// BigWarpActions.installViewerActions( getViewerFrameQ().getKeybindings(), this, inputTriggerConfig ); - - -// final Actions navigationActions = new Actions( inputTriggerConfig, "bw-bdv", "navigation" ); -// navigationActions.install( viewerFrameP.getKeybindings(), "navigation" ); -// NavigationActions.install( navigationActions, viewerP, options.values.is2D() ); - // this call has to come after the actions are set warpVisDialog.setActions(); warpVisDialog.toleranceSpinner.setValue( bwTransform.getInverseTolerance() ); @@ -1750,7 +1720,6 @@ public void warpToSelectedLandmark() public void warpToLandmark( int row, BigWarpViewerPanel viewer ) { - System.out.println( "warp to landmark " + row ); if( inLandmarkMode ) { message.showMessage( "Can't move viewer in landmark mode." ); diff --git a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java index ab6e8d89..5bd2831b 100644 --- a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java +++ b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java @@ -7,8 +7,6 @@ import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; import org.scijava.ui.behaviour.io.gui.CommandDescriptions; -import bdv.KeyConfigContexts; -import bdv.KeyConfigScopes; import bdv.TransformEventHandler2D; import bdv.TransformEventHandler3D; import bdv.viewer.NavigationActions; diff --git a/src/main/resources/bigwarp/ui/keymap/default.yaml b/src/main/resources/bigwarp/ui/keymap/default.yaml index d321488f..7bc15cc6 100644 --- a/src/main/resources/bigwarp/ui/keymap/default.yaml +++ b/src/main/resources/bigwarp/ui/keymap/default.yaml @@ -1,497 +1,497 @@ --- - !mapping action: close dialog window - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [not mapped] - !mapping action: Preferences - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [ctrl COMMA, meta COMMA] - !mapping action: brightness settings - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [S] - !mapping action: go to bookmark - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [B] - !mapping action: go to bookmark rotation - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [shift ctrl B] - !mapping action: help - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [F1] - !mapping action: landmark mode toggle - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [SPACE] - !mapping action: set bookmark - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [shift B] - !mapping action: visibility and grouping moving - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [F3] - !mapping action: visibility and grouping target - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [F4] - !mapping action: save settings - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [not mapped] - !mapping action: load settings - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, bw-table] triggers: [not mapped] - !mapping action: activate selected landmarks - contexts: [bw-table, navigation, bw-table] + contexts: [bw-table] triggers: [ctrl BACK_SPACE] - !mapping action: table activate selected - contexts: [bw-table, navigation, bw-table] + contexts: [bw-table] triggers: [not mapped] - !mapping action: align XY plane - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [shift Z] - !mapping action: align XZ plane - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation ] triggers: [shift A, shift Y] - !mapping action: align ZY plane - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [shift X] - !mapping action: align view transforms ACTIVE_TO_OTHER - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [W] - !mapping action: align view transforms OTHER_TO_ACTIVE - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [Q] - !mapping action: center on nearest landmark - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [Y] - !mapping action: center on next landmark - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [ctrl D] - !mapping action: center on prev landmark - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [shift ctrl D] - !mapping action: center on selected landmark - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [E] - !mapping action: expand and focus cards panel - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp] triggers: [P] - !mapping action: collapse cards panel - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp] triggers: [shift ESCAPE, shift P] - !mapping action: deactivate selected landmarks - contexts: [bw-table, navigation, bw-table] + contexts: [bw-table] triggers: [BACK_SPACE] - !mapping action: delete selected landmarks - contexts: [bw-table, navigation, bw-table] + contexts: [bw-table] triggers: [DELETE] - !mapping action: deselect all landmarks - contexts: [bw-table, navigation, bw-table] - triggers: [ESCAPE, Q] + contexts: [bw-table] + triggers: [ESCAPE] - !mapping action: export affine - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp] triggers: [ctrl A] - !mapping action: export imageplus - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp] triggers: [shift ctrl W] - !mapping action: export warp field - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp] triggers: [ctrl W] - !mapping action: load landmarks - contexts: [bw-table, bigwarp, navigation] + contexts: [bw-table, bigwarp] triggers: [ctrl O] - !mapping action: next timepoint - contexts: [bigwarp, navigation, bw-table] - triggers: [CLOSE_BRACKET, R] + contexts: [bigwarp, navigation] + triggers: [CLOSE_BRACKET] - !mapping action: previous timepoint - contexts: [bigwarp, navigation, bw-table] - triggers: [N, OPEN_BRACKET] + contexts: [bigwarp, navigation] + triggers: [OPEN_BRACKET] - !mapping action: quick save landmarks - contexts: [bw-table, bigwarp, navigation] + contexts: [bw-table, bigwarp] triggers: [ctrl Q] - !mapping action: redo - contexts: [bw-table, bigwarp, navigation] + contexts: [bw-table, bigwarp] triggers: [ctrl Y, shift ctrl Z] - !mapping action: reset active viewer - contexts: [bigwarp, navigation, bw-table] + contexts: [bigwarp, navigation] triggers: [R] - !mapping action: save landmarks - contexts: [bw-table, bigwarp, navigation] + contexts: [bw-table, bigwarp] triggers: [ctrl S] - !mapping action: save warped xml - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, bw-table] triggers: [ctrl E] - !mapping action: select all landmarks - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, bw-table] triggers: [ctrl A] - !mapping action: select all landmarks above - contexts: [bigwarp, bw-table, navigation] + contexts: [bw-table] triggers: [shift ctrl UP] - !mapping action: select all landmarks below - contexts: [bigwarp, bw-table, navigation] + contexts: [bw-table] triggers: [shift ctrl DOWN] - !mapping action: select landmark above - contexts: [bigwarp, bw-table, navigation] + contexts: [bw-table] triggers: [ctrl UP] - !mapping action: select landmark below - contexts: [bigwarp, bw-table, navigation] + contexts: [bw-table] triggers: [ctrl DOWN] - !mapping action: set current source 0 - contexts: [bigwarp, bw-table, navigation] - triggers: ['1'] + contexts: [bigwarp, navigation] + triggers: ['0'] - !mapping action: set current source 1 - contexts: [bigwarp, bw-table, navigation] - triggers: ['2'] + contexts: [bigwarp, navigation] + triggers: ['1'] - !mapping action: set current source 2 - contexts: [bigwarp, bw-table, navigation] - triggers: ['3'] + contexts: [bigwarp, navigation] + triggers: ['2'] - !mapping action: set current source 3 - contexts: [bigwarp, bw-table, navigation] - triggers: ['4'] + contexts: [bigwarp, navigation] + triggers: ['3'] - !mapping action: set current source 4 - contexts: [bigwarp, bw-table, navigation] - triggers: ['5'] + contexts: [bigwarp, navigation] + triggers: ['4'] - !mapping action: set current source 5 - contexts: [bigwarp, bw-table, navigation] - triggers: ['6'] + contexts: [bigwarp, navigation] + triggers: ['5'] - !mapping action: set current source 6 - contexts: [bigwarp, bw-table, navigation] - triggers: ['7'] + contexts: [bigwarp, navigation] + triggers: ['6'] - !mapping action: set current source 7 - contexts: [bigwarp, bw-table, navigation] - triggers: ['8'] + contexts: [bigwarp, navigation] + triggers: ['7'] - !mapping action: set current source 8 - contexts: [bigwarp, bw-table, navigation] - triggers: ['9'] + contexts: [bigwarp, navigation] + triggers: ['8'] - !mapping action: set current source 9 - contexts: [bigwarp, bw-table, navigation] - triggers: ['0'] + contexts: [bigwarp, navigation] + triggers: ['9'] - !mapping action: show warp vis dialog - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, bw-table] triggers: [U] - !mapping action: toggle fused mode - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp] triggers: [F] - !mapping action: toggle grouping - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp] triggers: [G] - !mapping action: toggle interpolation - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp] triggers: [I] - !mapping action: toggle moving image display - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp] triggers: [T] - !mapping action: toggle point names visible - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp] triggers: [N] - !mapping action: toggle points visible - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp] triggers: [V] - !mapping action: toggle source visibility 0 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 1] + contexts: [bigwarp] + triggers: [shift 0] - !mapping action: toggle source visibility 1 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 2] + contexts: [bigwarp] + triggers: [shift 1] - !mapping action: toggle source visibility 2 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 3] + contexts: [bigwarp] + triggers: [shift 2] - !mapping action: toggle source visibility 3 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 4] + contexts: [bigwarp] + triggers: [shift 3] - !mapping action: toggle source visibility 4 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 5] + contexts: [bigwarp] + triggers: [shift 4] - !mapping action: toggle source visibility 5 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 6] + contexts: [bigwarp] + triggers: [shift 5] - !mapping action: toggle source visibility 6 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 7] + contexts: [bigwarp] + triggers: [shift 6] - !mapping action: toggle source visibility 7 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 8] + contexts: [bigwarp] + triggers: [shift 7] - !mapping action: toggle source visibility 8 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 9] + contexts: [bigwarp] + triggers: [shift 8] - !mapping action: toggle source visibility 9 - contexts: [bigwarp, bw-table, navigation] - triggers: [shift 0] + contexts: [bigwarp] + triggers: [shift 9] - !mapping action: undo - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, bw-table] triggers: [ctrl Z] - !mapping action: drag translate - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [button2, button3] - !mapping action: scroll zoom - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [meta scroll, shift ctrl scroll] - !mapping action: axis x - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [X] - !mapping action: axis y - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [Y] - !mapping action: axis z - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [Z] - !mapping action: drag rotate - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [button1] - !mapping action: scroll browse z - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [scroll] - !mapping action: rotate left - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [LEFT] - !mapping action: rotate right - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [RIGHT] - !mapping action: zoom in - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [UP] - !mapping action: zoom out - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [DOWN] - !mapping action: forward z - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [COMMA] - !mapping action: backward z - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [PERIOD] - !mapping action: drag rotate fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift button1] - !mapping action: scroll browse z fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift scroll] - !mapping action: rotate left fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift LEFT] - !mapping action: rotate right fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift RIGHT] - !mapping action: zoom in fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift UP] - !mapping action: zoom out fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift DOWN] - !mapping action: forward z fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift COMMA] - !mapping action: backward z fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift PERIOD] - !mapping action: drag rotate slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl button1] - !mapping action: scroll browse z slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl scroll] - !mapping action: rotate left slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl LEFT] - !mapping action: rotate right slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl RIGHT] - !mapping action: zoom in slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl UP] - !mapping action: zoom out slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl DOWN] - !mapping action: forward z slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl COMMA] - !mapping action: backward z slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl PERIOD] - !mapping action: 2d drag translate - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [button2, button3] - !mapping action: 2d drag rotate - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [button1] - !mapping action: 2d scroll zoom - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [meta scroll, scroll, shift ctrl scroll] - !mapping action: 2d scroll zoom fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift scroll] - !mapping action: 2d scroll zoom slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl scroll] - !mapping action: 2d scroll translate - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [not mapped] - !mapping action: 2d scroll translate fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [not mapped] - !mapping action: 2d scroll translate slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [not mapped] - !mapping action: 2d rotate left - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [LEFT] - !mapping action: 2d rotate right - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [RIGHT] - !mapping action: 2d zoom in - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [UP] - !mapping action: 2d zoom out - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [DOWN] - !mapping action: 2d rotate left fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift LEFT] - !mapping action: 2d rotate right fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift RIGHT] - !mapping action: 2d zoom in fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift UP] - !mapping action: 2d zoom out fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [shift DOWN] - !mapping action: 2d rotate left slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl LEFT] - !mapping action: 2d rotate right slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl RIGHT] - !mapping action: 2d zoom in slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl UP] - !mapping action: 2d zoom out slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [ctrl DOWN] - !mapping action: 2d scroll rotate - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [not mapped] - !mapping action: 2d scroll rotate fast - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [not mapped] - !mapping action: 2d scroll rotate slow - contexts: [bigwarp, bw-table, navigation] + contexts: [bigwarp, navigation] triggers: [not mapped] From c26efb6b42d73df0a2768cff4497625db853a8ca Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 30 Sep 2022 09:24:26 -0400 Subject: [PATCH 053/282] wip: toward working appearance manager --- .../java/bdv/viewer/BigWarpViewerPanel.java | 34 +++++++------- .../overlay/BigWarpSourceOverlayRenderer.java | 44 +++++++++++++++++-- src/main/java/bigwarp/BigWarp.java | 5 ++- src/main/java/bigwarp/BigWarpActions.java | 12 +++-- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index dce3dac9..5d884972 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -63,9 +63,9 @@ public class BigWarpViewerPanel extends ViewerPanel final protected int[] targetSourceIndexList; - protected boolean boxOverlayVisible = true; - - protected boolean textOverlayVisible = true; +// protected boolean boxOverlayVisible = true; +// +// protected boolean textOverlayVisible = true; protected ArrayList< AffineTransform3D > orthoTransforms; @@ -128,15 +128,15 @@ public void precomputeRotations2d( final AffineTransform3D initialViewTransform } } - public void toggleTextOverlayVisible() - { - textOverlayVisible = !textOverlayVisible; - } - - public void toggleBoxOverlayVisible() - { - boxOverlayVisible = !boxOverlayVisible; - } +// public void toggleTextOverlayVisible() +// { +// textOverlayVisible = !textOverlayVisible; +// } +// +// public void toggleBoxOverlayVisible() +// { +// boxOverlayVisible = !boxOverlayVisible; +// } public void setHoveredIndex( int index ) { @@ -369,12 +369,12 @@ public void drawOverlays( final Graphics g ) final boolean prefsShowTextOverlay = Prefs.showTextOverlay(); final boolean prefsShowMultibox = Prefs.showMultibox(); - Prefs.showTextOverlay( textOverlayVisible ); - Prefs.showMultibox( boxOverlayVisible ); +// Prefs.showTextOverlay( textOverlayVisible ); +// Prefs.showMultibox( boxOverlayVisible ); super.drawOverlays( g ); - // restore Prefs settings - Prefs.showTextOverlay( prefsShowTextOverlay ); - Prefs.showMultibox( prefsShowMultibox ); +// // restore Prefs settings +// Prefs.showTextOverlay( prefsShowTextOverlay ); +// Prefs.showMultibox( prefsShowMultibox ); } } diff --git a/src/main/java/bdv/viewer/overlay/BigWarpSourceOverlayRenderer.java b/src/main/java/bdv/viewer/overlay/BigWarpSourceOverlayRenderer.java index 076b9f77..40d7e507 100644 --- a/src/main/java/bdv/viewer/overlay/BigWarpSourceOverlayRenderer.java +++ b/src/main/java/bdv/viewer/overlay/BigWarpSourceOverlayRenderer.java @@ -24,23 +24,61 @@ import java.awt.Font; import java.awt.Graphics2D; +import bdv.viewer.SourceAndConverter; +import bdv.viewer.ViewerState; + public class BigWarpSourceOverlayRenderer extends SourceInfoOverlayRenderer { + private boolean indicateTransformed = true; + + // are any visible source in this viewer transformed + private boolean anyTransformed = false; @Override public synchronized void paint( final Graphics2D g ) { g.setFont( new Font( "Monospaced", Font.PLAIN, 12 ) ); - int actual_width = g.getFontMetrics().stringWidth( sourceName ); - g.drawString( sourceName, ( int ) g.getClipBounds().getWidth() - actual_width - 10, 12 ); + int actualWidth = g.getFontMetrics().stringWidth( sourceName ); + g.drawString( sourceName, ( int ) g.getClipBounds().getWidth() - actualWidth - 10, 12 ); if( !groupName.isEmpty() ) { String groupStringBracket = "[ " + groupName + " ]"; int actual_width_group = g.getFontMetrics().stringWidth( groupStringBracket ); g.drawString( groupStringBracket, - ( int ) g.getClipBounds().getWidth() - actual_width - actual_width_group - 20, 12 ); + ( int ) g.getClipBounds().getWidth() - actualWidth - actual_width_group - 20, 12 ); + } + + if( indicateTransformed ) + { + g.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); + int tformedWidth = g.getFontMetrics().stringWidth( "TRANSFORMED" ); + g.drawString( "TRANSFORMED", + ( int ) ( g.getClipBounds().getWidth() - tformedWidth ) / 2, + ( int ) g.getClipBounds().getHeight() - 24 ); } } + +// /** +// * Update data to show in the overlay. +// */ +// @Override +// public synchronized void setViewerState( final ViewerState state ) +// { +// super.setViewerState( state ); +// +// anyTransformed = false; +// +// for( SourceAndConverter vs : state.getVisibleSources()) +// { +// vs.getSpimSource(); +// } +// +// } + + public void indicateTransformed( final boolean indicateTransformed ) + { + this.indicateTransformed = indicateTransformed; + } } diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index a4c23d4e..4c934d46 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -545,9 +545,10 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie preferencesDialog.addPage( new AppearanceSettingsPage( "Appearance", appearanceManager ) ); preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", this.keymapManager, new KeymapManager(), this.keymapManager.getCommandDescriptions() ) ); -// appearanceManager.appearance().updateListeners().add( viewerFrame::repaint ); + appearanceManager.appearance().updateListeners().add( viewerFrameP::repaint ); + appearanceManager.appearance().updateListeners().add( viewerFrameQ::repaint ); // appearanceManager.addLafComponent( fileChooser ); -// SwingUtilities.invokeLater(() -> appearanceManager.updateLookAndFeel()); + SwingUtilities.invokeLater(() -> appearanceManager.updateLookAndFeel()); final Actions navigationActions = new Actions( inputTriggerConfig, "navigation" ); navigationActions.install( getViewerFrameP().getKeybindings(), "navigation" ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index c3ef04cb..09c92096 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -41,6 +41,7 @@ import bdv.gui.BigWarpViewerFrame; import bdv.tools.ToggleDialogAction; +import bdv.util.Prefs; import bdv.viewer.SourceAndConverter; import bigwarp.BigWarp.BigWarpData; import bigwarp.landmarks.LandmarkGridGenerator; @@ -1009,10 +1010,13 @@ public ToggleBoxAndTexOverlayVisibility( final String name, final BigWarp< ? > b @Override public void actionPerformed( ActionEvent e ) { - bw.getViewerFrameP().getViewerPanel().toggleBoxOverlayVisible(); - bw.getViewerFrameQ().getViewerPanel().toggleBoxOverlayVisible(); - bw.getViewerFrameP().getViewerPanel().toggleTextOverlayVisible(); - bw.getViewerFrameQ().getViewerPanel().toggleTextOverlayVisible(); +// bw.getViewerFrameP().getViewerPanel().toggleBoxOverlayVisible(); +// bw.getViewerFrameQ().getViewerPanel().toggleBoxOverlayVisible(); +// bw.getViewerFrameP().getViewerPanel().toggleTextOverlayVisible(); +// bw.getViewerFrameQ().getViewerPanel().toggleTextOverlayVisible(); + Prefs.showTextOverlay(!Prefs.showTextOverlay()); + Prefs.showMultibox(!Prefs.showMultibox()); + bw.getViewerFrameP().repaint(); bw.getViewerFrameQ().repaint(); } From 8d37d4ad7b288c134b27433559f7b5e6f8e3e409 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Fri, 30 Sep 2022 10:14:39 -0400 Subject: [PATCH 054/282] wip: indicate that a source is transformed in src info overlay * and a little clean up --- .../overlay/BigWarpSourceOverlayRenderer.java | 65 +++++++++---------- src/main/java/bigwarp/BigWarp.java | 38 +++++++++-- src/main/java/bigwarp/BigWarpActions.java | 1 - 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/src/main/java/bdv/viewer/overlay/BigWarpSourceOverlayRenderer.java b/src/main/java/bdv/viewer/overlay/BigWarpSourceOverlayRenderer.java index 40d7e507..826f18e9 100644 --- a/src/main/java/bdv/viewer/overlay/BigWarpSourceOverlayRenderer.java +++ b/src/main/java/bdv/viewer/overlay/BigWarpSourceOverlayRenderer.java @@ -24,6 +24,8 @@ import java.awt.Font; import java.awt.Graphics2D; +import bdv.img.WarpedSource; +import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bdv.viewer.ViewerState; @@ -37,47 +39,44 @@ public class BigWarpSourceOverlayRenderer extends SourceInfoOverlayRenderer @Override public synchronized void paint( final Graphics2D g ) { - g.setFont( new Font( "Monospaced", Font.PLAIN, 12 ) ); - - int actualWidth = g.getFontMetrics().stringWidth( sourceName ); - g.drawString( sourceName, ( int ) g.getClipBounds().getWidth() - actualWidth - 10, 12 ); - - if( !groupName.isEmpty() ) - { - String groupStringBracket = "[ " + groupName + " ]"; - int actual_width_group = g.getFontMetrics().stringWidth( groupStringBracket ); - g.drawString( groupStringBracket, - ( int ) g.getClipBounds().getWidth() - actualWidth - actual_width_group - 20, 12 ); - } - - if( indicateTransformed ) + super.paint( g ); + if( indicateTransformed && anyTransformed ) { - g.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); + g.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); int tformedWidth = g.getFontMetrics().stringWidth( "TRANSFORMED" ); g.drawString( "TRANSFORMED", ( int ) ( g.getClipBounds().getWidth() - tformedWidth ) / 2, - ( int ) g.getClipBounds().getHeight() - 24 ); + ( int ) g.getClipBounds().getHeight() - 16 ); } } -// /** -// * Update data to show in the overlay. -// */ -// @Override -// public synchronized void setViewerState( final ViewerState state ) -// { -// super.setViewerState( state ); -// -// anyTransformed = false; -// -// for( SourceAndConverter vs : state.getVisibleSources()) -// { -// vs.getSpimSource(); -// } -// -// } + /** + * Update data to show in the overlay. + * + * Checks whether any sources in this viewer are transformed in order to indicate that fact. + */ + @Override + public synchronized void setViewerState( final ViewerState state ) + { + super.setViewerState( state ); + + anyTransformed = false; + for( SourceAndConverter vs : state.getVisibleSources()) + { + Source< ? > src = vs.getSpimSource(); + if( src instanceof WarpedSource ) + { + WarpedSource ws = (WarpedSource)src; + if( ws.isTransformed() ) + { + anyTransformed = true; + break; + } + } + } + } - public void indicateTransformed( final boolean indicateTransformed ) + public void setIndicateTransformed( final boolean indicateTransformed ) { this.indicateTransformed = indicateTransformed; } diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 4c934d46..6e605c9c 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -66,6 +66,7 @@ import javax.swing.Timer; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; +import javax.swing.filechooser.FileFilter; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; @@ -124,18 +125,14 @@ import bdv.viewer.Interpolation; import bdv.viewer.LandmarkPointMenu; import bdv.viewer.MultiBoxOverlay2d; -import bdv.viewer.NavigationActions; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; -import bdv.viewer.SynchronizedViewerState; import bdv.viewer.ViewerPanel; import bdv.viewer.VisibilityAndGrouping; -import bdv.viewer.WarpNavigationActions; import bdv.viewer.animate.SimilarityModel3D; import bdv.viewer.animate.TranslationAnimator; import bdv.viewer.overlay.BigWarpSourceOverlayRenderer; import bdv.viewer.overlay.MultiBoxOverlayRenderer; -import bigwarp.BigWarpActions.Descriptions; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.loader.ImagePlusLoader.ColorSettings; import bigwarp.source.GridSource; @@ -323,6 +320,8 @@ public class BigWarp< T > final FileDialog fileDialog; + final JFileChooser fileChooser; + protected File autoSaveDirectory; protected File lastDirectory; @@ -545,9 +544,38 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie preferencesDialog.addPage( new AppearanceSettingsPage( "Appearance", appearanceManager ) ); preferencesDialog.addPage( new KeymapSettingsPage( "Keymap", this.keymapManager, new KeymapManager(), this.keymapManager.getCommandDescriptions() ) ); + fileChooser = new JFileChooser(); + fileChooser.setFileFilter( new FileFilter() + { + @Override + public String getDescription() + { + return "xml files"; + } + + @Override + public boolean accept( final File f ) + { + if ( f.isDirectory() ) + return true; + if ( f.isFile() ) + { + final String s = f.getName(); + final int i = s.lastIndexOf( '.' ); + if ( i > 0 && i < s.length() - 1 ) + { + final String ext = s.substring( i + 1 ).toLowerCase(); + return ext.equals( "xml" ); + } + } + return false; + } + } ); + appearanceManager.appearance().updateListeners().add( viewerFrameP::repaint ); appearanceManager.appearance().updateListeners().add( viewerFrameQ::repaint ); -// appearanceManager.addLafComponent( fileChooser ); + appearanceManager.appearance().updateListeners().add( landmarkFrame::repaint ); + appearanceManager.addLafComponent( fileChooser ); SwingUtilities.invokeLater(() -> appearanceManager.updateLookAndFeel()); final Actions navigationActions = new Actions( inputTriggerConfig, "navigation" ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 09c92096..e52e3335 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -379,7 +379,6 @@ public static void installViewerActions( { final InputActionBindings inputActionBindings = bwFrame.getKeybindings(); - System.out.println( "install viewer actions" ); actions.install( inputActionBindings, "bw" ); actions.runnableAction( () -> { bw.getBwTransform().transformToString(); }, PRINT_TRANSFORM, PRINT_TRANSFORM_KEYS); From efe3def509847535dd70883d24187230bd061175 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Fri, 30 Sep 2022 10:45:36 -0400 Subject: [PATCH 055/282] wip: fix current source triggers --- .../bigwarp/ui/keymap/NavigationKeys.java | 1 - .../resources/bigwarp/ui/keymap/default.yaml | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java index 5bd2831b..3a8e387c 100644 --- a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java +++ b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java @@ -7,7 +7,6 @@ import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; import org.scijava.ui.behaviour.io.gui.CommandDescriptions; -import bdv.TransformEventHandler2D; import bdv.TransformEventHandler3D; import bdv.viewer.NavigationActions; import bigwarp.BigWarpActions; diff --git a/src/main/resources/bigwarp/ui/keymap/default.yaml b/src/main/resources/bigwarp/ui/keymap/default.yaml index 7bc15cc6..196ac448 100644 --- a/src/main/resources/bigwarp/ui/keymap/default.yaml +++ b/src/main/resources/bigwarp/ui/keymap/default.yaml @@ -178,43 +178,43 @@ - !mapping action: set current source 0 contexts: [bigwarp, navigation] - triggers: ['0'] + triggers: ['1'] - !mapping action: set current source 1 contexts: [bigwarp, navigation] - triggers: ['1'] + triggers: ['2'] - !mapping action: set current source 2 contexts: [bigwarp, navigation] - triggers: ['2'] + triggers: ['3'] - !mapping action: set current source 3 contexts: [bigwarp, navigation] - triggers: ['3'] + triggers: ['4'] - !mapping action: set current source 4 contexts: [bigwarp, navigation] - triggers: ['4'] + triggers: ['5'] - !mapping action: set current source 5 contexts: [bigwarp, navigation] - triggers: ['5'] + triggers: ['6'] - !mapping action: set current source 6 contexts: [bigwarp, navigation] - triggers: ['6'] + triggers: ['7'] - !mapping action: set current source 7 contexts: [bigwarp, navigation] - triggers: ['7'] + triggers: ['8'] - !mapping action: set current source 8 contexts: [bigwarp, navigation] - triggers: ['8'] + triggers: ['9'] - !mapping action: set current source 9 contexts: [bigwarp, navigation] - triggers: ['9'] + triggers: ['0'] - !mapping action: show warp vis dialog contexts: [bigwarp, bw-table] From ff354f65a70b03abba91dd5757faa5942a7d875b Mon Sep 17 00:00:00 2001 From: bogovicj Date: Fri, 7 Oct 2022 15:57:38 -0400 Subject: [PATCH 056/282] wip: use new displacement field framework --- pom.xml | 8 ++ .../ij/BigWarpToDeformationFieldPlugIn.java | 103 +++++++++++++++--- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index 257c40ae..ddf18b47 100644 --- a/pom.xml +++ b/pom.xml @@ -110,6 +110,10 @@ BigWarp plugin for Fiji. **/resources/*.xml + 6.0.0 + 4.0.0 + 5.0.0-SNAPSHOT + 1.48 1.4.1 @@ -202,6 +206,10 @@ org.janelia.saalfeldlab n5 + + org.janelia.saalfeldlab + n5-imglib2 + org.janelia.saalfeldlab n5-blosc diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 506338f8..276f485c 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -64,14 +64,18 @@ import net.imglib2.img.imageplus.FloatImagePlus; import net.imglib2.img.imageplus.ImagePlusImgs; import net.imglib2.iterator.IntervalIterator; +import net.imglib2.loops.LoopBuilder; +import net.imglib2.parallel.TaskExecutors; import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.AffineTransform2D; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.DisplacementFieldTransform; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.Scale2D; import net.imglib2.realtransform.Scale3D; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.type.numeric.RealType; +import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.util.Util; import net.imglib2.view.IntervalView; @@ -125,22 +129,25 @@ public void runFromBigWarpInstance( final RandomAccessibleInterval< ? > tgtInterval = sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getSource( 0, 0 ); int ndims = landmarkModel.getNumdims(); - long[] dims; - if ( ndims <= 2 ) - { - dims = new long[ 3 ]; - dims[ 0 ] = tgtInterval.dimension( 0 ); - dims[ 1 ] = tgtInterval.dimension( 1 ); - dims[ 2 ] = 2; - } - else - { - dims = new long[ 4 ]; - dims[ 0 ] = tgtInterval.dimension( 0 ); - dims[ 1 ] = tgtInterval.dimension( 1 ); - dims[ 2 ] = 3; - dims[ 3 ] = tgtInterval.dimension( 2 ); - } + // dimensions of the output image plus +// long[] dims; +// if ( ndims <= 2 ) +// { +// dims = new long[ 3 ]; +// dims[ 0 ] = tgtInterval.dimension( 0 ); +// dims[ 1 ] = tgtInterval.dimension( 1 ); +// dims[ 2 ] = 2; +// } +// else +// { +// dims = new long[ 4 ]; +// dims[ 0 ] = tgtInterval.dimension( 0 ); +// dims[ 1 ] = tgtInterval.dimension( 1 ); +// dims[ 2 ] = 3; +// dims[ 3 ] = tgtInterval.dimension( 2 ); +// } + + long[] dims = tgtInterval.dimensionsAsLongArray(); double[] spacing = new double[ 3 ]; VoxelDimensions voxelDim = sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getVoxelDimensions(); @@ -206,12 +213,36 @@ public void run( final String arg ) } } } + + public static ImagePlus toImagePlus( + final LandmarkTableModel ltm, + final boolean ignoreAffine, + final long[] dims, + final double[] spacing, + final int nThreads ) + { + final double[] offset = new double[ spacing.length ]; + return toImagePlus( ltm, ignoreAffine, dims, spacing, offset, nThreads ); + } + /** + * Create an {@link ImagePlus} that holds the displacement field. + *

+ * + * @param ltm the {@link LandmarkTableModel} + * @param ignoreAffine whether to omit the affine part of the transformation + * @param dims the dimensions of the output {@link ImagePlus}'s spatial dimensions + * @param spacing the pixel spacing of the output field + * @param offset the physical offset (origin) of the output field + * @param nThreads number of threads for copying + * @return an image holding the displacement field + */ public static ImagePlus toImagePlus( final LandmarkTableModel ltm, final boolean ignoreAffine, final long[] dims, final double[] spacing, + final double[] offset, final int nThreads ) { final BigWarpTransform bwXfm = new BigWarpTransform( ltm, TransformTypeSelectDialog.TPS ); @@ -223,15 +254,42 @@ public static ImagePlus toImagePlus( pixelToPhysical = new Scale2D( spacing ); } else if( spacing.length == 3) - { + { pixelToPhysical = new Scale3D( spacing ); } else { return null; } + + int nd = dims.length; + long[] ipDims = null; + if ( nd == 2) + { + ipDims = new long[ 4 ]; + ipDims[ 0 ] = dims[ 0 ]; + ipDims[ 1 ] = dims[ 1 ]; + ipDims[ 2 ] = 2; + ipDims[ 3 ] = 1; + } + else if ( nd == 3 ) + { + ipDims = new long[ 4 ]; + ipDims[ 0 ] = dims[ 0 ]; + ipDims[ 1 ] = dims[ 1 ]; + ipDims[ 2 ] = 3; + ipDims[ 3 ] = dims[ 2 ]; + } + else + return null; - FloatImagePlus< FloatType > dfield = convertToDeformationField( dims, tps, pixelToPhysical, nThreads ); + System.out.println("new dfield"); + final RandomAccessibleInterval< DoubleType > dfieldVirt = DisplacementFieldTransform.createDisplacementField( tps, new FinalInterval( dims ), spacing, offset ); + final FloatImagePlus< FloatType > dfield = ImagePlusImgs.floats( ipDims ); + + // make the "vector" axis the first dimension + RandomAccessibleInterval< FloatType > dfieldImpPerm = Views.moveAxis( dfield, 2, 0 ); + LoopBuilder.setImages( dfieldVirt, dfieldImpPerm ).multiThreaded( TaskExecutors.fixedThreadPool( nThreads ) ).forEachPixel( (x,y) -> { y.setReal(x.get()); }); String title = "bigwarp dfield"; if ( ignoreAffine ) @@ -243,8 +301,14 @@ else if( spacing.length == 3) dfieldIp.getCalibration().pixelWidth = spacing[ 0 ]; dfieldIp.getCalibration().pixelHeight = spacing[ 1 ]; + dfieldIp.getCalibration().xOrigin = offset[ 0 ]; + dfieldIp.getCalibration().yOrigin = offset[ 1 ]; + if( spacing.length > 2 ) + { dfieldIp.getCalibration().pixelDepth = spacing[ 2 ]; + dfieldIp.getCalibration().zOrigin = offset[ 2 ]; + } dfieldIp.show(); return dfieldIp; @@ -395,6 +459,7 @@ public static long[] dimensionsFromImagePlus( final ImagePlus ref_imp ) return dims; } + @Deprecated public static FloatImagePlus< FloatType > convertToDeformationField( final long[] dims, final RealTransform transform, @@ -458,6 +523,7 @@ public static boolean areTransformsTheSame( RealTransform xfm1, RealTransform xf * the {@link RandomAccessibleInterval} into which the * displacement field will be written */ + @Deprecated public static < T extends RealType< T > > void fromRealTransform( final RealTransform transform, final AffineGet pixelToPhysical, @@ -509,6 +575,7 @@ public static < T extends RealType< T > > void fromRealTransform( * @param nThreads * the number of threads */ + @Deprecated public static < T extends RealType< T > > void fromRealTransform( final RealTransform transform, final AffineGet pixelToPhysical, final RandomAccessibleInterval< T > deformationField, From 38d45807f0f806077aa280c6603f59399cd1c789 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 20 Oct 2022 14:38:28 -0400 Subject: [PATCH 057/282] feat: use DisplacementFieldTransform refactor!: rename `ignoreAffine` to `splitAffine`, deprecate some methods fix: use provided dataset path instead of "dfield" --- .../ij/BigWarpToDeformationFieldPlugIn.java | 130 ++++++++++-------- 1 file changed, 72 insertions(+), 58 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 276f485c..fa0cc5e4 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -77,7 +77,6 @@ import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.util.Util; import net.imglib2.view.IntervalView; import net.imglib2.view.Views; import net.imglib2.view.composite.CompositeIntervalView; @@ -161,13 +160,13 @@ public void runFromBigWarpInstance( if( params.n5Base.isEmpty() ) { - toImagePlus( landmarkModel, params.ignoreAffine, dims, spacing, params.nThreads ); + toImagePlus( landmarkModel, params.splitAffine, dims, spacing, params.nThreads ); } else { try { - writeN5( params.n5Base, landmarkModel, dims, spacing, params.blockSize, params.compression, params.nThreads ); + writeN5( params.n5Base, params.n5Dataset, landmarkModel, dims, spacing, params.blockSize, params.compression, params.nThreads, params.splitAffine ); } catch ( IOException e ) { @@ -199,13 +198,13 @@ public void run( final String arg ) if( params.n5Base.isEmpty() ) { - toImagePlus( ltm, params.ignoreAffine, params.size, params.spacing, params.nThreads ); + toImagePlus( ltm, params.splitAffine, params.size, params.spacing, params.nThreads ); } else { try { - writeN5( params.n5Base, params.n5Dataset, ltm, params.size, params.spacing, params.blockSize, params.compression, params.nThreads ); + writeN5( params.n5Base, params.n5Dataset, ltm, params.size, params.spacing, params.blockSize, params.compression, params.nThreads, params.splitAffine ); } catch ( IOException e ) { @@ -213,16 +212,15 @@ public void run( final String arg ) } } } - public static ImagePlus toImagePlus( final LandmarkTableModel ltm, - final boolean ignoreAffine, + final boolean splitAffine, final long[] dims, final double[] spacing, final int nThreads ) { final double[] offset = new double[ spacing.length ]; - return toImagePlus( ltm, ignoreAffine, dims, spacing, offset, nThreads ); + return toImagePlus( ltm, splitAffine, dims, spacing, offset, nThreads ); } /** @@ -230,7 +228,7 @@ public static ImagePlus toImagePlus( *

* * @param ltm the {@link LandmarkTableModel} - * @param ignoreAffine whether to omit the affine part of the transformation + * @param splitAffine whether to omit the affine part of the transformation * @param dims the dimensions of the output {@link ImagePlus}'s spatial dimensions * @param spacing the pixel spacing of the output field * @param offset the physical offset (origin) of the output field @@ -239,28 +237,14 @@ public static ImagePlus toImagePlus( */ public static ImagePlus toImagePlus( final LandmarkTableModel ltm, - final boolean ignoreAffine, + final boolean splitAffine, final long[] dims, final double[] spacing, final double[] offset, final int nThreads ) { final BigWarpTransform bwXfm = new BigWarpTransform( ltm, TransformTypeSelectDialog.TPS ); - final RealTransform tps = getTpsAffineToggle( bwXfm, ignoreAffine ); - - AffineGet pixelToPhysical = null; - if( spacing.length == 2) - { - pixelToPhysical = new Scale2D( spacing ); - } - else if( spacing.length == 3) - { - pixelToPhysical = new Scale3D( spacing ); - } - else - { - return null; - } + final RealTransform tps = getTpsAffineToggle( bwXfm, splitAffine ); int nd = dims.length; long[] ipDims = null; @@ -292,7 +276,7 @@ else if ( nd == 3 ) LoopBuilder.setImages( dfieldVirt, dfieldImpPerm ).multiThreaded( TaskExecutors.fixedThreadPool( nThreads ) ).forEachPixel( (x,y) -> { y.setReal(x.get()); }); String title = "bigwarp dfield"; - if ( ignoreAffine ) + if ( splitAffine ) title += " (no affine)"; ImagePlus dfieldIp = dfield.getImagePlus(); @@ -326,57 +310,86 @@ public static void writeN5( writeN5( n5BasePath, "dfield", ltm, dims, spacing, spatialBlockSize, compression, nThreads ); } - public static void writeN5( final String n5BasePath, final String n5Dataset, + public static void writeN5( + final String n5BasePath, + final String n5Dataset, final LandmarkTableModel ltm, final long[] dims, final double[] spacing, final int[] spatialBlockSize, final Compression compression, - final int nThreads ) throws IOException + final int nThreads ) throws IOException { - final BigWarpTransform bwXfm = new BigWarpTransform( ltm, TransformTypeSelectDialog.TPS ); - final RealTransform tpsTotal = getTpsAffineToggle( bwXfm, false ); + writeN5( n5BasePath, n5Dataset, ltm, dims, spacing, spatialBlockSize, compression, nThreads, false ); + } + + public static void writeN5( + final String n5BasePath, + final String n5Dataset, + final LandmarkTableModel ltm, + final long[] dims, + final double[] spacing, + final int[] spatialBlockSize, + final Compression compression, + final int nThreads, + final boolean splitAffine ) throws IOException + { + + final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; - AffineGet pixelToPhysical = null; - if( spacing.length == 2 ) - pixelToPhysical = new Scale2D( spacing ); - else if( spacing.length == 3 ) - pixelToPhysical = new Scale3D( spacing ); + final BigWarpTransform bwXfm = new BigWarpTransform( ltm, TransformTypeSelectDialog.TPS ); + final RealTransform tpsTotal = getTpsAffineToggle( bwXfm, splitAffine ); - FloatImagePlus< FloatType > dfieldRaw = convertToDeformationField( - dims, tpsTotal, pixelToPhysical, nThreads ); + AffineGet affine = null; + if ( splitAffine ) + { + final double[][] affineArray = bwXfm.affinePartOfTpsHC(); + if ( affineArray.length == 2 ) + { + final AffineTransform2D affine2d = new AffineTransform2D(); + affine2d.set( affineArray ); + affine = affine2d; + } + else + { + final AffineTransform3D affine3d = new AffineTransform3D(); + affine3d.set( affineArray ); + affine = affine3d; + } + } - // this works for both 2d and 3d, it turn out - RandomAccessibleInterval< FloatType > dfield = - Views.permute( - Views.permute( dfieldRaw, - 0, 2 ), - 1, 2 ); + RandomAccessibleInterval< DoubleType > dfield = DisplacementFieldTransform.createDisplacementField( + tpsTotal, new FinalInterval( dims ), spacing ); int[] blockSize = new int[ spatialBlockSize.length + 1 ]; blockSize[ 0 ] = spatialBlockSize.length; - for( int i = 0; i < spatialBlockSize.length; i++ ) - { - blockSize[ i + 1 ] = spatialBlockSize[ i ]; - } + System.arraycopy( spatialBlockSize, 0, blockSize, 1, spatialBlockSize.length ); final N5Writer n5 = new N5Factory().openWriter( n5BasePath ); - N5DisplacementField.save( n5, n5Dataset, null, dfield, spacing, blockSize, compression ); + N5DisplacementField.save( n5, dataset, affine, dfield, spacing, blockSize, compression ); n5.close(); } - private static RealTransform getTpsAffineToggle( BigWarpTransform bwXfm, boolean ignoreAffine ) + private static RealTransform getTpsAffineToggle( BigWarpTransform bwXfm, boolean splitAffine ) { - if( ignoreAffine ) + if ( splitAffine ) { final ThinPlateR2LogRSplineKernelTransform tps = bwXfm.getTpsBase(); return new ThinplateSplineTransform( - new ThinPlateR2LogRSplineKernelTransform( tps.getSourceLandmarks(), null, null, tps.getKnotWeights() )); + new ThinPlateR2LogRSplineKernelTransform( tps.getSourceLandmarks(), null, null, tps.getKnotWeights() ) ); } else return bwXfm.getTransformation(); } + /** + * @param tps + * + * @return + * + * @deprecated Use {@link BigWarpTransform} method instead + */ + @Deprecated() public static AffineGet toAffine( final ThinPlateR2LogRSplineKernelTransform tps ) { double[] affineFlat = toFlatAffine( tps ); @@ -599,7 +612,7 @@ public static < T extends RealType< T > > void fromRealTransform( final RealTran dim2split = 2; } - long del = ( long )( N / nThreads ); + long del = ( N / nThreads ); splitPoints[ 0 ] = 0; splitPoints[ nThreads ] = deformationField.dimension( dim2split ); for( int i = 1; i < nThreads; i++ ) @@ -620,6 +633,7 @@ public static < T extends RealType< T > > void fromRealTransform( final RealTran jobs.add( new Callable() { + @Override public Boolean call() { try @@ -698,7 +712,7 @@ private static Compression getCompression( final String compressionArg ) private static class DeformationFieldExportParameters { public final String landmarkPath; - public final boolean ignoreAffine; + public final boolean splitAffine; public final int nThreads; public final long[] size; @@ -711,7 +725,7 @@ private static class DeformationFieldExportParameters public DeformationFieldExportParameters( final String landmarkPath, - final boolean ignoreAffine, + final boolean splitAffine, final int nThreads, final long[] size, final double[] spacing, @@ -721,7 +735,7 @@ public DeformationFieldExportParameters( final Compression compression ) { this.landmarkPath = landmarkPath; - this.ignoreAffine = ignoreAffine; + this.splitAffine = splitAffine; this.nThreads = nThreads; this.size = size; @@ -744,7 +758,7 @@ public static DeformationFieldExportParameters fromDialog( gd.addFileField( "landmarks_image_file", "" ); } - gd.addCheckbox( "Ignore affine part", false ); + gd.addCheckbox( "split affine", false ); gd.addNumericField( "threads", 1, 0 ); gd.addMessage( "Size and spacing" ); @@ -778,7 +792,7 @@ public static DeformationFieldExportParameters fromDialog( if( promptLandmarks ) landmarkPath = gd.getNextString(); - final boolean ignoreAffine = gd.getNextBoolean(); + final boolean splitAffine = gd.getNextBoolean(); final int nThreads = ( int ) gd.getNextNumber(); ImagePlus ref_imp = null; @@ -834,7 +848,7 @@ public static DeformationFieldExportParameters fromDialog( return new DeformationFieldExportParameters( landmarkPath, - ignoreAffine, + splitAffine, nThreads, size, spacing, From 056537f801d95c5b747841990df7dfbf2f24e875 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 25 Oct 2022 13:42:46 -0400 Subject: [PATCH 058/282] test: use same whitespace formatting as comparison test --- .../compareKnownXml.bigwarp.settings.xml | 490 +++++++++--------- 1 file changed, 245 insertions(+), 245 deletions(-) diff --git a/src/test/resources/compareKnownXml.bigwarp.settings.xml b/src/test/resources/compareKnownXml.bigwarp.settings.xml index 34ff8d2d..60d437a4 100644 --- a/src/test/resources/compareKnownXml.bigwarp.settings.xml +++ b/src/test/resources/compareKnownXml.bigwarp.settings.xml @@ -1,248 +1,248 @@ - - - - - true - - - false - - - true - - - false - - - false - - - false - - - false - - - false - - - - - true - moving images - 0 - 1 - - - true - fixed images - 2 - 3 - - - ss - nlinear - 0 - 0 - 0 - - - - - - - true - - - false - - - true - - - false - - - false - - - false - - - false - - - false - - - - - true - moving images - 0 - 1 - - - true - fixed images - 2 - 3 - - - fs - nearestneighbor - 2 - 1 - 0 - - - - - - 0 - 0.0 - 860.4 - -10027213 - 0 - - - 1 - 0.0 - 255.0 - 0 - 1 - - - 2 - 0.0 - 2000.0 - -39169 - 2 - - - 3 - 0.0 - 433.408 - -1 - 3 - - - 956736363 - 0.0 - 65535.0 - -1 - 4 - - - 1006827158 - 0.0 - 65535.0 - -1 - 5 - - - 1696993146 - 0.0 - 65535.0 - -1 - 6 - - - 33872301 - 0.0 - 65535.0 - -1 - 7 - - - - - 0 - -2.147483648E9 - 2.147483647E9 - 0.0 - 4000.0 - 0.0 - 860.4 - - - 1 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 255.0 - - - 2 - -2.147483648E9 - 2.147483647E9 - 0.0 - 2000.0 - 0.0 - 2000.0 - - - 3 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 255.0 - - - 4 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 5 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 6 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 7 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - - - - /tmp/.bigwarp - 180000 - - - plateau-spherical -

0.0 0.0
- - 64.0 - 100.0 - - + + + + + true + + + false + + + true + + + false + + + false + + + false + + + false + + + false + + + + + true + moving images + 0 + 1 + + + true + fixed images + 2 + 3 + + + ss + nlinear + 0 + 0 + 0 + + + + + + + true + + + false + + + true + + + false + + + false + + + false + + + false + + + false + + + + + true + moving images + 0 + 1 + + + true + fixed images + 2 + 3 + + + fs + nearestneighbor + 2 + 1 + 0 + + + + + + 0 + 0.0 + 860.4 + -10027213 + 0 + + + 1 + 0.0 + 255.0 + 0 + 1 + + + 2 + 0.0 + 2000.0 + -39169 + 2 + + + 3 + 0.0 + 433.408 + -1 + 3 + + + 956736363 + 0.0 + 65535.0 + -1 + 4 + + + 1006827158 + 0.0 + 65535.0 + -1 + 5 + + + 1696993146 + 0.0 + 65535.0 + -1 + 6 + + + 33872301 + 0.0 + 65535.0 + -1 + 7 + + + + + 0 + -2.147483648E9 + 2.147483647E9 + 0.0 + 4000.0 + 0.0 + 860.4 + + + 1 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + 2 + -2.147483648E9 + 2.147483647E9 + 0.0 + 2000.0 + 0.0 + 2000.0 + + + 3 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + 4 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 5 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 6 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 7 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + + + + /tmp/.bigwarp + 180000 + + + plateau-spherical +
0.0 0.0 0.0
+ + 64.0 + 100.0 + +
From 3ef954ffc0608e3ae4fb7fb29b521363c5afff34 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 25 Oct 2022 13:43:17 -0400 Subject: [PATCH 059/282] feat: extract read/write from/to JsonObject for serialization --- .../transforms/io/TransformWriterJson.java | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index 9bff3a79..7f7a3650 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -24,15 +24,7 @@ public class TransformWriterJson { public void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) { - JsonObject transformObj = new JsonObject(); - transformObj.add("type", new JsonPrimitive( bwTransform.getTransformType() )); - transformObj.add("landmarks", ltm.toJson()); - - if( bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS) ) - { - PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); - transformObj.add("mask", BigwarpSettings.gson.toJsonTree( mask )); - } + final JsonObject transformObj = write( ltm, bwTransform ); try { final Path path = Paths.get(f.getCanonicalPath()); @@ -44,7 +36,7 @@ public void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) e.printStackTrace(); } } - + public void read( final File f, final BigWarp bw ) { try @@ -53,18 +45,8 @@ public void read( final File f, final BigWarp bw ) final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; final Reader reader = Channels.newReader(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); JsonObject json = BigwarpSettings.gson.fromJson( reader, JsonObject.class ); - - if( json.has( "landmarks" )) - bw.getLandmarkPanel().getTableModel().fromJson( json ); - if( json.has( "mask" )) - { - JsonObject maskParams = json.get("mask").getAsJsonObject(); - final PlateauSphericalMaskRealRandomAccessible mask = bw.getTpsMaskSource().getRandomAccessible(); - mask.setCenter( BigwarpSettings.gson.fromJson( maskParams.get( "center" ), double[].class )); - mask.setSquaredRadius( maskParams.get("squaredRadius").getAsDouble() ); - mask.setSquaredSigma( maskParams.get("squaredSigma").getAsDouble() ); - } + read( bw, json ); } catch ( IOException e ) { @@ -73,4 +55,33 @@ public void read( final File f, final BigWarp bw ) } } + public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransform) { + + JsonObject transformObj = new JsonObject(); + transformObj.add("type", new JsonPrimitive( bwTransform.getTransformType() )); + transformObj.add("landmarks", ltm.toJson()); + + if( bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS) ) + { + PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); + transformObj.add("mask", BigwarpSettings.gson.toJsonTree( mask )); + } + return transformObj; + } + + public static void read( final BigWarp< ? > bw, final JsonObject json ) + { + if( json.has( "landmarks" )) + bw.getLandmarkPanel().getTableModel().fromJson( json ); + + if( json.has( "mask" )) + { + JsonObject maskParams = json.get("mask").getAsJsonObject(); + final PlateauSphericalMaskRealRandomAccessible mask = bw.getTpsMaskSource().getRandomAccessible(); + mask.setCenter( BigwarpSettings.gson.fromJson( maskParams.get( "center" ), double[].class )); + mask.setSquaredRadius( maskParams.get("squaredRadius").getAsDouble() ); + mask.setSquaredSigma( maskParams.get("squaredSigma").getAsDouble() ); + } + } + } From 105a7e1c0d47c2cfcc852d3905f4fb0309af77cb Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 25 Oct 2022 13:43:27 -0400 Subject: [PATCH 060/282] fix: try-with-resource for writing to file --- src/main/java/bigwarp/BigwarpSettings.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index cff049c0..a555cd50 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -68,7 +68,10 @@ public BigwarpSettings( BigWarp bigWarp, final BigWarpViewerPanel viewerP, final public void serialize( String jsonFilename ) throws IOException { - write( new JsonWriter( new FileWriter( jsonFilename ) ), this ); + try ( final FileWriter fileWriter = new FileWriter( jsonFilename ) ) + { + write( new JsonWriter( fileWriter ), this ); + } } @Override From 027aa8ed46487a341ccd5b40e79f250905fd196c Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 25 Oct 2022 13:44:31 -0400 Subject: [PATCH 061/282] feat: serialize landmarks --- src/main/java/bigwarp/BigWarp.java | 7 ++--- src/main/java/bigwarp/BigwarpSettings.java | 30 +++++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 623543bb..1cc6f013 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3458,16 +3458,17 @@ protected void saveSettingsJson( final String jsonFilename ) throws IOException public BigwarpSettings getSettings() { - BigwarpSettings settings = new BigwarpSettings( + return new BigwarpSettings( this, viewerP, viewerQ, setupAssignments, bookmarks, autoSaver, - tpsMask.getRandomAccessible() + tpsMask.getRandomAccessible(), + landmarkModel, + bwTransform ); - return settings; } protected void loadSettings() diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index a555cd50..b6f09429 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -13,9 +13,14 @@ import bdv.viewer.state.SourceState; import bdv.viewer.state.ViewerState; import bdv.viewer.state.XmlIoViewerState; +import bigwarp.landmarks.LandmarkTableModel; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.transforms.BigWarpTransform; +import bigwarp.transforms.io.TransformWriterJson; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; @@ -42,6 +47,10 @@ public class BigwarpSettings extends TypeAdapter< BigwarpSettings > transient private final BigWarp< ? > bigWarp; + private final LandmarkTableModel landmarks; + + private final BigWarpTransform transform; + BigWarpViewerPanel viewerP; BigWarpViewerPanel viewerQ; @@ -54,7 +63,16 @@ public class BigwarpSettings extends TypeAdapter< BigwarpSettings > final PlateauSphericalMaskRealRandomAccessible tpsMask; - public BigwarpSettings( BigWarp bigWarp, final BigWarpViewerPanel viewerP, final BigWarpViewerPanel viewerQ, final SetupAssignments setupAssignments, final Bookmarks bookmarks, final BigWarpAutoSaver autoSaver, final PlateauSphericalMaskRealRandomAccessible tpsMask ) + public BigwarpSettings( BigWarp bigWarp, + final BigWarpViewerPanel viewerP, + final BigWarpViewerPanel viewerQ, + final SetupAssignments setupAssignments, + final Bookmarks bookmarks, + final BigWarpAutoSaver autoSaver, + final PlateauSphericalMaskRealRandomAccessible tpsMask, + final LandmarkTableModel landmarks, + final BigWarpTransform transform + ) { this.bigWarp = bigWarp; @@ -64,6 +82,8 @@ public BigwarpSettings( BigWarp bigWarp, final BigWarpViewerPanel viewerP, final this.bookmarks = bookmarks; this.autoSaver = autoSaver; this.tpsMask = tpsMask; + this.landmarks = landmarks; + this.transform = transform; } public void serialize( String jsonFilename ) throws IOException @@ -90,6 +110,10 @@ public void write( final JsonWriter out, final BigwarpSettings value ) throws IO gson.toJson( autoSaver, BigWarpAutoSaver.class, out ); out.name( "TPSMask" ); gson.toJson( tpsMask, PlateauSphericalMaskRealRandomAccessible.class, out ); + if (landmarks != null) { + out.name( "Transform" ); + out.jsonValue( TransformWriterJson.write( landmarks, transform ).toString() ); + } out.endObject(); } @@ -125,6 +149,10 @@ public BigwarpSettings read( final JsonReader in ) throws IOException tpsMask.setSquaredRadius( maskFromJson.getSquaredRadius() ); tpsMask.setCenter( maskFromJson.getCenter() ); break; + case "Transform": + final JsonObject transformObject = ( JsonObject ) JsonParser.parseReader( in ); + TransformWriterJson.read( bigWarp, transformObject ); + break; default: throw new RuntimeException( "Unknown BigWarpSetting: " + nextName ); } From 928490632432b4841176106ebfafa941695930d0 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 25 Oct 2022 13:46:20 -0400 Subject: [PATCH 062/282] test: fix json comparison test; note a peculiarity --- src/test/java/bigwarp/SerializationTest.java | 90 +++++++++++++------- 1 file changed, 59 insertions(+), 31 deletions(-) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index a6b7580c..6073aed4 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -108,6 +108,34 @@ public void BigWarpSettingsTest() throws SpimDataException, IOException } + /* When creating and closing multiple BigWarp instances, occassionally the comparison test fails. + * It shouldn't be a problem in practice, since this only occurs during testing, but I think it indicates + * there may be a race condidtion somewhere. To duplicate the issue, run this test multiple times, and + * it should eventually fail. It is not consistent. */ + private void repeatComparison() throws Exception + { + for ( int i = 0; i < 20; i++ ) + { + System.out.println( i ); + BigWarp< ? > bw = createBigWarp(); + + /* Load the known good*/ + final String originalXmlSettings = "src/test/resources/compareKnownXml.bigwarp.settings.xml"; + bw.loadSettings( originalXmlSettings ); + + /* save it back out*/ + final File tmpXmlFile = Files.createTempFile( "xml-settings", ".xml" ).toFile(); + bw.saveSettings( tmpXmlFile.getAbsolutePath() ); + + /* compare the original and generated */ + XMLUnit.setIgnoreWhitespace( true ); + XMLUnit.setIgnoreComments( true ); + XMLAssert.assertXMLEqual( new FileReader( originalXmlSettings ), new FileReader( tmpXmlFile ) ); + + bw.closeAll(); + } + + } @Test public void compareKnownXmlComparisonTest() throws SpimDataException, IOException, JDOMException, SAXException @@ -118,27 +146,29 @@ public void compareKnownXmlComparisonTest() throws SpimDataException, IOExceptio bw.loadSettings( originalXmlSettings ); final BigwarpSettings settings = bw.getSettings(); - final StringWriter stringWriter = new StringWriter(); - final JsonWriter out = new JsonWriter( stringWriter ); - - settings.write( out, settings ); final File tmpJsonFile = Files.createTempFile( "json-settings", ".json" ).toFile(); - final FileWriter fileWriter = new FileWriter( tmpJsonFile ); - fileWriter.write( stringWriter.toString() ); - fileWriter.flush(); - fileWriter.close(); - - bw.closeAll(); - - bw = createBigWarp(); - bw.loadSettings(tmpJsonFile.getAbsolutePath()); - + try ( final FileWriter fileWriter = new FileWriter( tmpJsonFile ) ) + { + final JsonWriter out = new JsonWriter( fileWriter ); + settings.write( out, settings ); + } + /* Ideally, we should close the instance, and get a new one for this test, but it's not currently safe to do this. See SerializationTest#repeatComparison*/ +// bw.closeAll(); +// bw = createBigWarp(); + + bw.loadSettings( tmpJsonFile.getAbsolutePath() ); final File tmpXmlFile = Files.createTempFile( "xml-settings", ".xml" ).toFile(); - bw.saveSettings(tmpXmlFile.getAbsolutePath()); + bw.saveSettings( tmpXmlFile.getAbsolutePath() ); XMLUnit.setIgnoreWhitespace( true ); XMLUnit.setIgnoreComments( true ); - XMLAssert.assertXMLEqual( new FileReader( originalXmlSettings ), new FileReader( tmpXmlFile ) ); - + try + { + XMLAssert.assertXMLEqual( new FileReader( originalXmlSettings ), new FileReader( tmpXmlFile ) ); + } + finally + { + bw.closeAll(); + } } @@ -147,9 +177,9 @@ private static void prettyPrint(StringWriter json) { prettyPrint( json.toString() ); } - private static void prettyPrint(String json) { - final JsonParser jsonParser = new JsonParser(); - final JsonElement parse = jsonParser.parse( json ); + private static void prettyPrint( String json ) + { + final JsonElement parse = JsonParser.parseString( json ); final JsonObject asJsonObject = parse.getAsJsonObject(); System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson( asJsonObject )); @@ -159,19 +189,17 @@ private static void prettyPrint(String json) { { final BigWarp.BigWarpData< Object > data = BigWarpInit.initData(); FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( - 2, - ( l, v ) -> { - v.setOne(); - }, + 3, + ( l, v ) -> v.setOne(), UnsignedByteType::new ); - ImagePlus imp = ImageJFunctions.wrap( Views.interval( fimg, new FinalInterval( 32, 32 ) ), "img" ); + ImagePlus imp = ImageJFunctions.wrap( Views.interval( fimg, new FinalInterval( 32, 32, 1 ) ), "img" ); int i = 0; - BigWarpInit.add( data, imp, i++, 0, true); - BigWarpInit.add( data, imp, i++, 0, false); - BigWarpInit.add( data, imp, i++, 0, false); - BigWarpInit.add( data, imp, i++, 0, false); + BigWarpInit.add( data, imp, i++, 0, true ); + BigWarpInit.add( data, imp, i++, 0, false ); + BigWarpInit.add( data, imp, i++, 0, false ); + BigWarpInit.add( data, imp, i, 0, false ); data.wrapUp(); - BigWarpViewerOptions opts = BigWarpViewerOptions.options( true ); - return new BigWarp( data, "bigwarp", opts, null ); + BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); + return new BigWarp<>( data, "bigwarp", opts, null ); } } From 97bd0afe2500d68df4ed1dc1ecdeeaecf3b3dc87 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 25 Oct 2022 15:06:17 -0400 Subject: [PATCH 063/282] test: add landmark serialization test --- src/test/java/bigwarp/SerializationTest.java | 66 ++- .../compareKnownXml.bigwarp.settings.xml | 496 +++++++++--------- src/test/resources/settings/expected.json | 298 +++++++++++ src/test/resources/settings/landmarks.csv | 5 + 4 files changed, 609 insertions(+), 256 deletions(-) rename src/test/resources/{ => settings}/compareKnownXml.bigwarp.settings.xml (96%) create mode 100644 src/test/resources/settings/expected.json create mode 100644 src/test/resources/settings/landmarks.csv diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 6073aed4..7f542cfc 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -3,6 +3,7 @@ import bdv.gui.BigWarpViewerOptions; import bdv.tools.bookmarks.Bookmarks; import bigwarp.source.PlateauSphericalMaskSource; +import com.google.api.client.json.Json; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; @@ -11,13 +12,19 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import ij.ImagePlus; +import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.io.PipedOutputStream; +import java.io.PipedReader; +import java.io.PipedWriter; import java.io.StringReader; import java.io.StringWriter; import java.nio.file.Files; +import java.nio.file.Paths; import mpicbg.spim.data.SpimDataException; import net.imglib2.FinalInterval; import net.imglib2.RealPoint; @@ -29,20 +36,21 @@ import org.custommonkey.xmlunit.XMLAssert; import org.custommonkey.xmlunit.XMLUnit; import org.jdom2.JDOMException; +import org.junit.Assert; import org.junit.Test; import org.xml.sax.SAXException; public class SerializationTest { - public void maskTest() + private void maskTest() { PlateauSphericalMaskSource mask = PlateauSphericalMaskSource.build( new RealPoint( 3 ), new FinalInterval( 5, 10, 20 ) ); Gson gson = BigwarpSettings.gson; prettyPrint( gson.toJson( mask.getRandomAccessible() )); } - public void bookmarksTest() + private void bookmarksTest() { final Bookmarks bookmarks = new Bookmarks(); bookmarks.put( "identity", new AffineTransform3D() ); @@ -59,7 +67,7 @@ public void bookmarksTest() prettyPrint( json ); } - public void autoSaverTest() throws SpimDataException + private void autoSaverTest() { final BigWarpAutoSaver saver = new BigWarpAutoSaver( null, 1000 ); saver.autoSaveDirectory = new File("/tmp"); @@ -69,7 +77,7 @@ public void autoSaverTest() throws SpimDataException } - public void setupAssignmentsTest() throws SpimDataException, IOException + private void setupAssignmentsTest() throws SpimDataException, IOException { final BigWarp bw = createBigWarp(); final StringWriter stringWriter = new StringWriter(); @@ -81,7 +89,7 @@ public void setupAssignmentsTest() throws SpimDataException, IOException } - public void viewerPanelTest() throws SpimDataException, IOException + private void viewerPanelTest() throws SpimDataException, IOException { final BigWarp bw = createBigWarp(); final StringWriter stringWriter = new StringWriter(); @@ -93,7 +101,7 @@ public void viewerPanelTest() throws SpimDataException, IOException } - public void BigWarpSettingsTest() throws SpimDataException, IOException + private void BigWarpSettingsTest() throws SpimDataException, IOException { final BigWarp bw = createBigWarp(); bw.setAutoSaver( new BigWarpAutoSaver( bw, 10000 ) ); @@ -120,7 +128,7 @@ private void repeatComparison() throws Exception BigWarp< ? > bw = createBigWarp(); /* Load the known good*/ - final String originalXmlSettings = "src/test/resources/compareKnownXml.bigwarp.settings.xml"; + final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; bw.loadSettings( originalXmlSettings ); /* save it back out*/ @@ -142,7 +150,7 @@ public void compareKnownXmlComparisonTest() throws SpimDataException, IOExceptio { BigWarp bw = createBigWarp(); - final String originalXmlSettings = "src/test/resources/compareKnownXml.bigwarp.settings.xml"; + final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; bw.loadSettings( originalXmlSettings ); final BigwarpSettings settings = bw.getSettings(); @@ -171,6 +179,43 @@ public void compareKnownXmlComparisonTest() throws SpimDataException, IOExceptio } } + @Test + public void landmarkComparisonTest() throws SpimDataException, IOException, JDOMException, SAXException + { + BigWarp< ? > bw = createBigWarp(); + + final String xmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; + final String csvLandmarks = "src/test/resources/settings/landmarks.csv"; + final String expectedJsonFile = "src/test/resources/settings/expected.json"; + bw.loadSettings( xmlSettings ); + bw.loadLandmarks(csvLandmarks); + + final BigwarpSettings settings = bw.getSettings(); + + final PipedWriter writer = new PipedWriter(); + final PipedReader in = new PipedReader( writer, 10000 ); + + final JsonWriter out = new JsonWriter( writer ); + final JsonReader reader = new JsonReader( in ); + + settings.write( out, settings ); + out.close(); + writer.close(); + + final JsonElement jsonSettingsOut = JsonParser.parseReader( in ); + final JsonElement expectedJson = JsonParser.parseReader( new FileReader(expectedJsonFile)); + + try + { + Assert.assertEquals( expectedJson, jsonSettingsOut ); + } + finally + { + bw.closeAll(); + } + + } + private static void prettyPrint(StringWriter json) { @@ -202,4 +247,9 @@ private static void prettyPrint( String json ) BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); return new BigWarp<>( data, "bigwarp", opts, null ); } + + public static void main( String[] args ) throws SpimDataException + { + createBigWarp(); + } } diff --git a/src/test/resources/compareKnownXml.bigwarp.settings.xml b/src/test/resources/settings/compareKnownXml.bigwarp.settings.xml similarity index 96% rename from src/test/resources/compareKnownXml.bigwarp.settings.xml rename to src/test/resources/settings/compareKnownXml.bigwarp.settings.xml index 60d437a4..be8c3996 100644 --- a/src/test/resources/compareKnownXml.bigwarp.settings.xml +++ b/src/test/resources/settings/compareKnownXml.bigwarp.settings.xml @@ -1,248 +1,248 @@ - - - - - - - true - - - false - - - true - - - false - - - false - - - false - - - false - - - false - - - - - true - moving images - 0 - 1 - - - true - fixed images - 2 - 3 - - - ss - nlinear - 0 - 0 - 0 - - - - - - - true - - - false - - - true - - - false - - - false - - - false - - - false - - - false - - - - - true - moving images - 0 - 1 - - - true - fixed images - 2 - 3 - - - fs - nearestneighbor - 2 - 1 - 0 - - - - - - 0 - 0.0 - 860.4 - -10027213 - 0 - - - 1 - 0.0 - 255.0 - 0 - 1 - - - 2 - 0.0 - 2000.0 - -39169 - 2 - - - 3 - 0.0 - 433.408 - -1 - 3 - - - 956736363 - 0.0 - 65535.0 - -1 - 4 - - - 1006827158 - 0.0 - 65535.0 - -1 - 5 - - - 1696993146 - 0.0 - 65535.0 - -1 - 6 - - - 33872301 - 0.0 - 65535.0 - -1 - 7 - - - - - 0 - -2.147483648E9 - 2.147483647E9 - 0.0 - 4000.0 - 0.0 - 860.4 - - - 1 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 255.0 - - - 2 - -2.147483648E9 - 2.147483647E9 - 0.0 - 2000.0 - 0.0 - 2000.0 - - - 3 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 255.0 - - - 4 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 5 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 6 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 7 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - - - - /tmp/.bigwarp - 180000 - - - plateau-spherical -
0.0 0.0 0.0
- - 64.0 - 100.0 - -
-
+ + + + + + + true + + + false + + + true + + + false + + + false + + + false + + + false + + + false + + + + + true + moving images + 0 + 1 + + + true + fixed images + 2 + 3 + + + ss + nlinear + 0 + 0 + 0 + + + + + + + true + + + false + + + true + + + false + + + false + + + false + + + false + + + false + + + + + true + moving images + 0 + 1 + + + true + fixed images + 2 + 3 + + + fs + nearestneighbor + 2 + 1 + 0 + + + + + + 0 + 0.0 + 860.4 + -10027213 + 0 + + + 1 + 0.0 + 255.0 + 0 + 1 + + + 2 + 0.0 + 2000.0 + -39169 + 2 + + + 3 + 0.0 + 433.408 + -1 + 3 + + + 956736363 + 0.0 + 65535.0 + -1 + 4 + + + 1006827158 + 0.0 + 65535.0 + -1 + 5 + + + 1696993146 + 0.0 + 65535.0 + -1 + 6 + + + 33872301 + 0.0 + 65535.0 + -1 + 7 + + + + + 0 + -2.147483648E9 + 2.147483647E9 + 0.0 + 4000.0 + 0.0 + 860.4 + + + 1 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + 2 + -2.147483648E9 + 2.147483647E9 + 0.0 + 2000.0 + 0.0 + 2000.0 + + + 3 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + 4 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 5 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 6 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + 7 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 512.0 + + + + + + /tmp/.bigwarp + 180000 + + + plateau-spherical +
0.0 0.0 0.0
+ + 64.0 + 100.0 + +
+
diff --git a/src/test/resources/settings/expected.json b/src/test/resources/settings/expected.json new file mode 100644 index 00000000..b5044be1 --- /dev/null +++ b/src/test/resources/settings/expected.json @@ -0,0 +1,298 @@ +{ + "ViewerP": { + "Sources": [ + true, + false, + true, + false, + false, + false, + false, + false + ], + "SourceGroups": [ + { + "active": true, + "name": "moving images", + "id": [ + 0, + 1 + ] + }, + { + "active": true, + "name": "fixed images", + "id": [ + 2, + 3 + ] + } + ], + "DisplayMode": "ss", + "Interpolation": "nlinear", + "CurrentSource": 0, + "CurrentGroup": 0, + "CurrentTimePoint": 0 + }, + "ViewerQ": { + "Sources": [ + true, + false, + true, + false, + false, + false, + false, + false + ], + "SourceGroups": [ + { + "active": true, + "name": "moving images", + "id": [ + 0, + 1 + ] + }, + { + "active": true, + "name": "fixed images", + "id": [ + 2, + 3 + ] + } + ], + "DisplayMode": "fs", + "Interpolation": "nearestneighbor", + "CurrentSource": 2, + "CurrentGroup": 1, + "CurrentTimePoint": 0 + }, + "SetupAssignments": { + "ConverterSetups": [ + { + "id": 0, + "min": 0.0, + "max": 860.4, + "color": -10027213, + "groupId": 0 + }, + { + "id": 1, + "min": 0.0, + "max": 255.0, + "color": 0, + "groupId": 1 + }, + { + "id": 2, + "min": 0.0, + "max": 2000.0, + "color": -39169, + "groupId": 2 + }, + { + "id": 3, + "min": 0.0, + "max": 433.408, + "color": -1, + "groupId": 3 + }, + { + "id": 956736363, + "min": 0.0, + "max": 65535.0, + "color": -1, + "groupId": 4 + }, + { + "id": 1006827158, + "min": 0.0, + "max": 65535.0, + "color": -1, + "groupId": 5 + }, + { + "id": 1696993146, + "min": 0.0, + "max": 65535.0, + "color": -1, + "groupId": 6 + }, + { + "id": 33872301, + "min": 0.0, + "max": 65535.0, + "color": -1, + "groupId": 7 + } + ], + "MinMaxGroups": [ + { + "id": 0, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 4000.0, + "currentMin": 0.0, + "currentMax": 860.4 + }, + { + "id": 1, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 255.0 + }, + { + "id": 2, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 2000.0, + "currentMin": 0.0, + "currentMax": 2000.0 + }, + { + "id": 3, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 255.0 + }, + { + "id": 4, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 512.0 + }, + { + "id": 5, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 512.0 + }, + { + "id": 6, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 512.0 + }, + { + "id": 7, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 512.0 + } + ] + }, + "Bookmarks": { + "bookmarks": {} + }, + "Autosave": { + "period": 180000, + "location": "/tmp/.bigwarp" + }, + "TPSMask": { + "fallOffShape": "COSINE", + "squaredRadius": 64.0, + "squaredSigma": 100.0, + "center": [ + 0.0, + 0.0, + 0.0 + ] + }, + "Transform": { + "type": "Thin Plate Spline", + "landmarks": { + "type": "BigWarpLandmarks", + "numDimensions": 3, + "movingPoints": [ + [ + 193.1527102803737, + 163.57943925233658, + 130.00000000000003 + ], + [ + 132.8910280373831, + 248.17757009345803, + 130.00000000000003 + ], + [ + 222.70411214953256, + 272.51401869158883, + 130.00000000000003 + ], + [ + 182.72280373831765, + 159.52336448598143, + 170.5607476635514 + ], + [ + 176.92841121495317, + 255.1308411214954, + 170.5607476635514 + ] + ], + "fixedPoints": [ + [ + 216.01797508417232, + 233.3341910984992, + 126.86263579832789 + ], + [ + 145.77520051769838, + 213.26482693664948, + 126.8626357983279 + ], + [ + 146.49196352347872, + 298.5596246245108, + 126.86263579832789 + ], + [ + 182.72280373831765, + 159.52336448598143, + 170.5607476635514 + ], + [ + 176.92841121495317, + 255.1308411214954, + 170.5607476635514 + ] + ], + "active": [ + true, + true, + true, + true, + true + ], + "names": [ + "Pt-0", + "Pt-1", + "Pt-2", + "Pt-3", + "Pt-4" + ] + } + } +} \ No newline at end of file diff --git a/src/test/resources/settings/landmarks.csv b/src/test/resources/settings/landmarks.csv new file mode 100644 index 00000000..707b6fee --- /dev/null +++ b/src/test/resources/settings/landmarks.csv @@ -0,0 +1,5 @@ +"Pt-0","true","193.1527102803737","163.57943925233658","130.00000000000003","216.01797508417232","233.3341910984992","126.86263579832789" +"Pt-1","true","132.8910280373831","248.17757009345803","130.00000000000003","145.77520051769838","213.26482693664948","126.8626357983279" +"Pt-2","true","222.70411214953256","272.51401869158883","130.00000000000003","146.49196352347872","298.5596246245108","126.86263579832789" +"Pt-3","true","182.72280373831765","159.52336448598143","170.5607476635514","182.72280373831765","159.52336448598143","170.5607476635514" +"Pt-4","true","176.92841121495317","255.1308411214954","170.5607476635514","176.92841121495317","255.1308411214954","170.5607476635514" From 142e5e1ec9f91de27bcf292b7f3da2929f371e10 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 26 Oct 2022 14:05:56 -0400 Subject: [PATCH 064/282] feat!: migrate TransformWriterJson methods to static --- src/main/java/bigwarp/BigWarp.java | 4 ++-- .../java/bigwarp/transforms/io/TransformWriterJson.java | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 1cc6f013..ddbd973d 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3324,7 +3324,7 @@ protected void saveLandmarks( final String filename ) throws IOException if( filename.endsWith("csv")) landmarkModel.save(new File( filename )); else if( filename.endsWith("json")) - new TransformWriterJson().write(landmarkModel, bwTransform, new File( filename )); + TransformWriterJson.write(landmarkModel, bwTransform, new File( filename )); } protected void loadLandmarks() @@ -3365,7 +3365,7 @@ public void loadLandmarks( final String filename ) } else if( filename.endsWith( "json" )) { - new TransformWriterJson().read( file, this ); + TransformWriterJson.read( file, this ); } boolean didCompute = restimateTransformation(); diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index 7f7a3650..eb6088c1 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -1,6 +1,5 @@ package bigwarp.transforms.io; -import bdv.gui.TransformTypeSelectDialog; import bigwarp.BigWarp; import bigwarp.BigwarpSettings; import bigwarp.landmarks.LandmarkTableModel; @@ -22,7 +21,7 @@ public class TransformWriterJson { - public void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) { + public static void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) { final JsonObject transformObj = write( ltm, bwTransform ); @@ -37,7 +36,7 @@ public void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, File f ) } } - public void read( final File f, final BigWarp bw ) + public static void read( final File f, final BigWarp bw ) { try { @@ -61,7 +60,7 @@ public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransf transformObj.add("type", new JsonPrimitive( bwTransform.getTransformType() )); transformObj.add("landmarks", ltm.toJson()); - if( bwTransform.getTransformType().equals( TransformTypeSelectDialog.MASKEDTPS) ) + if( bwTransform.isMasked() ) { PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); transformObj.add("mask", BigwarpSettings.gson.toJsonTree( mask )); From 67bb04cede943867e0cb8e5c171fd0bae08f80ca Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 26 Oct 2022 14:06:16 -0400 Subject: [PATCH 065/282] feat: remove redundant transform serialization --- src/main/java/bigwarp/BigwarpSettings.java | 10 +++++----- src/test/resources/settings/expected.json | 10 ---------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index b6f09429..a9f64651 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -63,7 +63,8 @@ public class BigwarpSettings extends TypeAdapter< BigwarpSettings > final PlateauSphericalMaskRealRandomAccessible tpsMask; - public BigwarpSettings( BigWarp bigWarp, + public BigwarpSettings( + final BigWarp bigWarp, final BigWarpViewerPanel viewerP, final BigWarpViewerPanel viewerQ, final SetupAssignments setupAssignments, @@ -108,9 +109,8 @@ public void write( final JsonWriter out, final BigwarpSettings value ) throws IO gson.toJson( bookmarks, Bookmarks.class, out ); out.name( "Autosave" ); gson.toJson( autoSaver, BigWarpAutoSaver.class, out ); - out.name( "TPSMask" ); - gson.toJson( tpsMask, PlateauSphericalMaskRealRandomAccessible.class, out ); - if (landmarks != null) { + if ( landmarks != null ) + { out.name( "Transform" ); out.jsonValue( TransformWriterJson.write( landmarks, transform ).toString() ); } @@ -733,7 +733,7 @@ public AffineTransform3D read( final JsonReader in ) throws IOException } } - private static interface ConverterSetupDTO extends ConverterSetup + private interface ConverterSetupDTO extends ConverterSetup { int getGroupId(); diff --git a/src/test/resources/settings/expected.json b/src/test/resources/settings/expected.json index b5044be1..b357d2aa 100644 --- a/src/test/resources/settings/expected.json +++ b/src/test/resources/settings/expected.json @@ -210,16 +210,6 @@ "period": 180000, "location": "/tmp/.bigwarp" }, - "TPSMask": { - "fallOffShape": "COSINE", - "squaredRadius": 64.0, - "squaredSigma": 100.0, - "center": [ - 0.0, - 0.0, - 0.0 - ] - }, "Transform": { "type": "Thin Plate Spline", "landmarks": { From e4cac0c5b6b9501cab6e839506cd4bfecbc04cf4 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 27 Oct 2022 11:59:32 -0400 Subject: [PATCH 066/282] refactor: rename tps related fields --- .../bdv/gui/TransformTypeSelectDialog.java | 2 +- src/main/java/bdv/ij/ApplyBigwarpPlugin.java | 12 +++--- src/main/java/bigwarp/BigWarp.java | 41 +++++++++---------- src/main/java/bigwarp/BigwarpSettings.java | 6 +-- src/test/java/bigwarp/ExportTester.java | 33 +++++++-------- ...milarityTransformInterpolationExample.java | 8 ++-- 6 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index 8b2ce818..cc4d6249 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -160,7 +160,7 @@ public void addFalloffActionListender( final JRadioButton button ) @Override public void actionPerformed( ActionEvent e ) { - bw.getTpsMaskSource().getRandomAccessible().setFalloffShape( button.getText() ); + bw.getTransformMaskSource().getRandomAccessible().setFalloffShape( button.getText() ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } diff --git a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java index 174cc8c1..7f9b5673 100644 --- a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java +++ b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java @@ -1067,12 +1067,12 @@ public void run( String arg ) gd.addChoice( "Transform type", new String[] { - TransformTypeSelectDialog.TPS, - TransformTypeSelectDialog.AFFINE, - TransformTypeSelectDialog.SIMILARITY, - TransformTypeSelectDialog.ROTATION, - TransformTypeSelectDialog.TRANSLATION }, - TransformTypeSelectDialog.TPS); + BigWarpTransform.TPS, + BigWarpTransform.AFFINE, + BigWarpTransform.SIMILARITY, + BigWarpTransform.ROTATION, + BigWarpTransform.TRANSLATION }, + BigWarpTransform.TPS); gd.addMessage( "Field of view and resolution:" ); gd.addChoice( "Resolution", diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index ddbd973d..e7d3f2de 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -188,7 +188,7 @@ public class BigWarp< T > public static final int JACDET_SOURCE_ID = 1006827158; - public static final int TPSMASK_SOURCE_ID = 33872301; + public static final int TRANSFORM_MASK_SOURCE_ID = 33872301; protected BigWarpViewerOptions options; @@ -287,9 +287,9 @@ public class BigWarp< T > protected final SourceAndConverter< FloatType > jacDetSource; - protected final SourceAndConverter< DoubleType > tpsMaskSource; + protected final SourceAndConverter< DoubleType > transformMaskSource; - protected PlateauSphericalMaskSource tpsMask; + protected PlateauSphericalMaskSource transformMask; protected final AbstractModel< ? >[] baseXfmList; @@ -400,7 +400,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie warpMagSource = addWarpMagnitudeSource( data, "WarpMagnitudeSource" ); jacDetSource = addJacobianDeterminantSource( data, "JacobianDeterminantSource" ); gridSource = addGridSource( data, "GridSource" ); - tpsMaskSource = addTpsMaskSource( data, ndims, "TPS Mask Source" ); + transformMaskSource = addTransformMaskSource( data, ndims, "Transform Mask Source" ); this.sources = this.data.sources; final List< ConverterSetup > converterSetups = data.converterSetups; @@ -505,7 +505,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie bwTransform = new BigWarpTransform( landmarkModel ); bwTransform.initializeInverseParameters(data); - bwTransform.setLambda( tpsMask.getRandomAccessible() ); + bwTransform.setLambda( transformMask.getRandomAccessible() ); solverThread = new SolveThread( this ); solverThread.start(); @@ -531,7 +531,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie // dialogs have to be constructed before action maps are made warpVisDialog = new WarpVisFrame( viewerFrameQ, this ); - warpVisDialog.maskOptionsPanel.setMask( tpsMask ); + warpVisDialog.maskOptionsPanel.setMask( transformMask ); WarpNavigationActions.installActionBindings( getViewerFrameP().getKeybindings(), viewerFrameP, keyProperties, ( ndims == 2 ) ); BigWarpActions.installActionBindings( getViewerFrameP().getKeybindings(), this, keyProperties ); @@ -1785,13 +1785,13 @@ protected void addMaskMouseListener() maskSourceMouseListenerP = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerP ); maskSourceMouseListenerP.setActive( false ); - maskSourceMouseListenerP.setMask( tpsMask.getRandomAccessible() ); + maskSourceMouseListenerP.setMask( transformMask.getRandomAccessible() ); maskSourceMouseListenerQ = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerQ ); maskSourceMouseListenerQ.setActive( false ); - maskSourceMouseListenerQ.setMask( tpsMask.getRandomAccessible() ); + maskSourceMouseListenerQ.setMask( transformMask.getRandomAccessible() ); - tpsMask.getRandomAccessible().setOverlays( Arrays.asList( viewerP.getMaskOverlay(), viewerQ.getMaskOverlay() )); + transformMask.getRandomAccessible().setOverlays( Arrays.asList( viewerP.getMaskOverlay(), viewerQ.getMaskOverlay() )); } public void setGridType( final GridSource.GRID_TYPE method ) @@ -1874,24 +1874,24 @@ private static < T > SourceAndConverter< FloatType > addGridSource( final BigWar } @SuppressWarnings( { "unchecked", "rawtypes" } ) - private SourceAndConverter< DoubleType > addTpsMaskSource( final BigWarpData< T > data, final int ndims, final String name ) + private SourceAndConverter< DoubleType > addTransformMaskSource( final BigWarpData< T > data, final int ndims, final String name ) { // TODO think about whether its worth it to pass a type parameter. // or should we just stick with Floats? FinalInterval itvl = new FinalInterval( data.sources.get( data.targetSourceIndices[0] ).getSpimSource().getSource( 0, 0 )); - tpsMask = PlateauSphericalMaskSource.build( new RealPoint( ndims ), itvl ); + transformMask = PlateauSphericalMaskSource.build( new RealPoint( ndims ), itvl ); final RealARGBColorConverter< DoubleType > converter = RealARGBColorConverter.create( new DoubleType(), 0, 1 ); converter.setColor( new ARGBType( 0xffffffff ) ); - final SourceAndConverter< DoubleType > soc = new SourceAndConverter( tpsMask, converter, null ); - data.converterSetups.add( BigDataViewer.createConverterSetup( soc, TPSMASK_SOURCE_ID ) ); + final SourceAndConverter< DoubleType > soc = new SourceAndConverter( transformMask, converter, null ); + data.converterSetups.add( BigDataViewer.createConverterSetup( soc, TRANSFORM_MASK_SOURCE_ID ) ); data.sources.add( ( SourceAndConverter ) soc ); return soc; } - public PlateauSphericalMaskSource getTpsMaskSource() + public PlateauSphericalMaskSource getTransformMaskSource() { - return tpsMask; + return transformMask; } private static < T > SourceAndConverter< T > wrapSourceAsTransformed( final SourceAndConverter< T > src, final String name, final int ndims ) @@ -2034,8 +2034,8 @@ public void autoEstimateMask() if( warpVisDialog.autoEstimateMask() && bwTransform.isMasked() ) { final Sphere sph = BoundingSphereRitter.boundingSphere(landmarkModel.getFixedPointsCopy()); - tpsMask.getRandomAccessible().setCenter(sph.getCenter()); - tpsMask.getRandomAccessible().setRadius(sph.getRadius()); + transformMask.getRandomAccessible().setCenter(sph.getCenter()); + transformMask.getRandomAccessible().setRadius(sph.getRadius()); } } @@ -2550,7 +2550,6 @@ public static class BigWarpData< T > public final HashMap< Integer, ColorSettings > setupSettings; public final HashMap< SourceAndConverter, ColorSettings > sourceColorSettings; - public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, final CacheControl cache, int[] movingSourceIndices, int[] targetSourceIndices ) { this.sources = sources; @@ -3443,7 +3442,7 @@ protected void saveSettings( final String xmlFilename ) throws IOException autoSaveNode.addContent( autoSavePeriod ); root.addContent( autoSaveNode ); - root.addContent( tpsMask.getRandomAccessible().toXml() ); + root.addContent( transformMask.getRandomAccessible().toXml() ); final Document doc = new Document( root ); final XMLOutputter xout = new XMLOutputter( Format.getPrettyFormat() ); @@ -3465,7 +3464,7 @@ public BigwarpSettings getSettings() setupAssignments, bookmarks, autoSaver, - tpsMask.getRandomAccessible(), + transformMask.getRandomAccessible(), landmarkModel, bwTransform ); @@ -3517,7 +3516,7 @@ protected void loadSettings( final String jsonOrXmlFilename ) throws IOException final Element maskSettings = root.getChild( "transform-mask" ); if ( maskSettings != null ) - tpsMask.getRandomAccessible().fromXml( maskSettings ); + transformMask.getRandomAccessible().fromXml( maskSettings ); } diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index a9f64651..2b111a25 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -61,7 +61,7 @@ public class BigwarpSettings extends TypeAdapter< BigwarpSettings > BigWarpAutoSaver autoSaver; - final PlateauSphericalMaskRealRandomAccessible tpsMask; + final PlateauSphericalMaskRealRandomAccessible transformMask; public BigwarpSettings( final BigWarp bigWarp, @@ -70,7 +70,7 @@ public BigwarpSettings( final SetupAssignments setupAssignments, final Bookmarks bookmarks, final BigWarpAutoSaver autoSaver, - final PlateauSphericalMaskRealRandomAccessible tpsMask, + final PlateauSphericalMaskRealRandomAccessible transformMask, final LandmarkTableModel landmarks, final BigWarpTransform transform ) @@ -82,7 +82,7 @@ public BigwarpSettings( this.setupAssignments = setupAssignments; this.bookmarks = bookmarks; this.autoSaver = autoSaver; - this.tpsMask = tpsMask; + this.transformMask = transformMask; this.landmarks = landmarks; this.transform = transform; } diff --git a/src/test/java/bigwarp/ExportTester.java b/src/test/java/bigwarp/ExportTester.java index 45fc96c1..068dd193 100644 --- a/src/test/java/bigwarp/ExportTester.java +++ b/src/test/java/bigwarp/ExportTester.java @@ -21,6 +21,7 @@ */ package bigwarp; +import bigwarp.transforms.BigWarpTransform; import java.io.File; import java.io.IOException; import java.util.List; @@ -90,7 +91,7 @@ public static void main( String[] args ) throws IOException public static void pix_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.SPECIFIED_PIXEL; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.SPECIFIED; @@ -126,7 +127,7 @@ public static void pix_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void v_spc_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.SPECIFIED_PHYSICAL; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.SPECIFIED; @@ -160,7 +161,7 @@ public static void v_spc_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel public static void spc_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.SPECIFIED_PHYSICAL; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.SPECIFIED; @@ -194,7 +195,7 @@ public static void spc_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void pspc_pspc( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.SPECIFIED_PIXEL; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.SPECIFIED; @@ -228,7 +229,7 @@ public static void pspc_pspc( ImagePlus impm, ImagePlus impt, LandmarkTableModel public static void lmk_mvg( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.LANDMARK_POINTS; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.MOVING; @@ -262,7 +263,7 @@ public static void lmk_mvg( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void lmk_tgt( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.LANDMARK_POINTS; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.TARGET; @@ -296,7 +297,7 @@ public static void lmk_tgt( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void lmk_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.LANDMARK_POINTS; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.SPECIFIED; @@ -331,7 +332,7 @@ public static void lmk_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void mvg_mvg( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.MOVING_WARPED; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.MOVING; @@ -365,7 +366,7 @@ public static void mvg_mvg( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void mvg_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.MOVING_WARPED; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.SPECIFIED; @@ -399,7 +400,7 @@ public static void mvg_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void mvg_tgt( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.MOVING_WARPED; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.TARGET; @@ -433,7 +434,7 @@ public static void mvg_tgt( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void tgt_tgt( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.TARGET; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.TARGET; @@ -467,7 +468,7 @@ public static void tgt_tgt( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void v_tgt_tgt( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.TARGET; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.TARGET; @@ -503,7 +504,7 @@ public static void v_tgt_tgt( ImagePlus impm, ImagePlus impt, LandmarkTableModel public static void tgt_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.TARGET; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.SPECIFIED; @@ -537,7 +538,7 @@ public static void tgt_spc( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void tgt_mvg( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.TARGET; String fieldOfViewPointFilter = ""; String resolutionOption = ApplyBigwarpPlugin.MOVING; @@ -571,7 +572,7 @@ public static void tgt_mvg( ImagePlus impm, ImagePlus impt, LandmarkTableModel l public static void tgt_lmpix( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.LANDMARK_POINT_CUBE_PIXEL; String fieldOfViewPointFilter = ".*5"; String resolutionOption = ApplyBigwarpPlugin.TARGET; @@ -605,7 +606,7 @@ public static void tgt_lmpix( ImagePlus impm, ImagePlus impt, LandmarkTableModel public static void tgt_lmphy( ImagePlus impm, ImagePlus impt, LandmarkTableModel landmarks ) { - String transformType = TransformTypeSelectDialog.TPS; + String transformType = BigWarpTransform.TPS; String fieldOfViewOption = ApplyBigwarpPlugin.LANDMARK_POINT_CUBE_PHYSICAL; String fieldOfViewPointFilter = ".*5"; String resolutionOption = ApplyBigwarpPlugin.TARGET; diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index 817b13b3..db958d8d 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -123,8 +123,8 @@ public static void expSeq( String imgFile, String jsonFile ) { PlateauSphericalMaskRealRandomAccessible mask = BigwarpSettings.gson.fromJson( maskJson, PlateauSphericalMaskRealRandomAccessible.class); - PlateauSphericalMaskSource tpsMask = PlateauSphericalMaskSource.build( mask, bigItvl ); - PlateauSphericalMaskRealRandomAccessible lambda = tpsMask.getRandomAccessible(); + PlateauSphericalMaskSource transformMask = PlateauSphericalMaskSource.build( mask, bigItvl ); + PlateauSphericalMaskRealRandomAccessible lambda = transformMask.getRandomAccessible(); // build transformations final double[][] mvgPts; @@ -254,8 +254,8 @@ public static void showSeq( String imgFile, String jsonFile ) { PlateauSphericalMaskRealRandomAccessible maskRA = BigwarpSettings.gson.fromJson( mask, PlateauSphericalMaskRealRandomAccessible.class); - PlateauSphericalMaskSource tpsMask = PlateauSphericalMaskSource.build( maskRA, bigItvl ); - PlateauSphericalMaskRealRandomAccessible lambda = tpsMask.getRandomAccessible(); + PlateauSphericalMaskSource transformMask = PlateauSphericalMaskSource.build( maskRA, bigItvl ); + PlateauSphericalMaskRealRandomAccessible lambda = transformMask.getRandomAccessible(); // build transformations From 5ed1c07694efdc2368300af32c28d6042d8b6c25 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 27 Oct 2022 12:03:58 -0400 Subject: [PATCH 067/282] refactor!: rename mask to maskInterpolation --- src/main/java/bdv/gui/MaskOptionsPanel.java | 2 +- ...teauSphericalMaskRealRandomAccessible.java | 2 +- .../bigwarp/transforms/BigWarpTransform.java | 20 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index f0f38bd2..8d728790 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -98,7 +98,7 @@ public void stateChanged( ChangeEvent e ) public void actionPerformed( ActionEvent e ) { bw.setMaskOverlayVisibility( autoEstimateMaskButton.isSelected() && isMask() ); - bw.getBwTransform().setMask( maskTypeDropdown.getItemAt( maskTypeDropdown.getSelectedIndex() ) ); + bw.getBwTransform().setMaskInterpolationType( maskTypeDropdown.getItemAt( maskTypeDropdown.getSelectedIndex() ) ); bw.restimateTransformation(); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 9fc60ae3..930b7b6f 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -123,7 +123,7 @@ public static void main( String[] args ) //// bdv.getBdvHandle().getTriggerbindings().removeInputTriggerMap( "block_transform" ); // // final MaskedSourceEditorMouseListener ml = new MaskedSourceEditorMouseListener( 3, null, bdv.getBdvHandle().getViewerPanel() ); -// ml.setMask( img ); +// ml.setMaskInterpolationType( img ); //// bdv.getBdvHandle().getViewerPanel().getDisplay().addMouseListener( ml ); // double x = 50; diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index d38542a5..ead3cd59 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -73,7 +73,7 @@ public class BigWarpTransform private String transformType; - private String maskType; + private String maskInterpolationType; private InvertibleRealTransform currentTransform; @@ -95,7 +95,7 @@ public BigWarpTransform( final LandmarkTableModel tableModel, final String trans this.tableModel = tableModel; this.ndims = tableModel.getNumdims(); this.transformType = transformType; - this.maskType = "NONE"; + this.maskInterpolationType = "NONE"; updateSolver(); } @@ -105,20 +105,20 @@ public void setTransformType( final String transformType ) updateSolver(); } - public void setMask( String maskType ) + public void setMaskInterpolationType( String maskType ) { - this.maskType = maskType; + this.maskInterpolationType = maskType; updateSolver(); } - public String getMask() + public String getMaskInterpolationType() { - return maskType; + return maskInterpolationType; } public boolean isMasked() { - return maskType.equals( MASK_INTERP ) || maskType.equals( ROT_MASK_INTERP ) || maskType.equals( SIM_MASK_INTERP ); + return maskInterpolationType.equals( MASK_INTERP ) || maskInterpolationType.equals( ROT_MASK_INTERP ) || maskInterpolationType.equals( SIM_MASK_INTERP ); } public void updateSolver() @@ -132,11 +132,11 @@ public void updateSolver() solver = new ModelTransformSolver( getModelType() ); } - if ( maskType.equals( MASK_INTERP ) ) + if ( maskInterpolationType.equals( MASK_INTERP ) ) { solver = new MaskedTransformSolver( solver, lambda ); } - else if ( maskType.equals( ROT_MASK_INTERP ) || maskType.equals( SIM_MASK_INTERP ) ) + else if ( maskInterpolationType.equals( ROT_MASK_INTERP ) || maskInterpolationType.equals( SIM_MASK_INTERP ) ) { final double[] center = new double[ 3 ]; if ( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) @@ -144,7 +144,7 @@ else if ( maskType.equals( ROT_MASK_INTERP ) || maskType.equals( SIM_MASK_INTERP ((PlateauSphericalMaskRealRandomAccessible) lambda).getCenter() .localize( center ); } - solver = new MaskedSimRotTransformSolver( solver, lambda, center, Interpolators.valueOf( maskType ) ); + solver = new MaskedSimRotTransformSolver( solver, lambda, center, Interpolators.valueOf( maskInterpolationType ) ); } } From 45bc4682028eb64c4a2057d5c8aeaac04e56fbda Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 27 Oct 2022 12:04:17 -0400 Subject: [PATCH 068/282] feat: serialize maskInterpolationType --- src/main/java/bigwarp/BigwarpSettings.java | 6 ------ .../transforms/io/TransformWriterJson.java | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 2b111a25..86b62e8e 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -143,12 +143,6 @@ public BigwarpSettings read( final JsonReader in ) throws IOException autoSaver = gson.fromJson( in, BigWarpAutoSaver.class ); bigWarp.setAutoSaver( autoSaver ); break; - case "TPSMask": - final PlateauSphericalMaskRealRandomAccessible maskFromJson = gson.fromJson( in, PlateauSphericalMaskRealRandomAccessible.class ); - tpsMask.setFalloffShape( maskFromJson.getFallOffShape() ); - tpsMask.setSquaredRadius( maskFromJson.getSquaredRadius() ); - tpsMask.setCenter( maskFromJson.getCenter() ); - break; case "Transform": final JsonObject transformObject = ( JsonObject ) JsonParser.parseReader( in ); TransformWriterJson.read( bigWarp, transformObject ); diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index eb6088c1..fca47338 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -6,7 +6,6 @@ import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; import bigwarp.transforms.BigWarpTransform; import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; import java.io.File; import java.io.IOException; import java.io.Reader; @@ -57,7 +56,8 @@ public static void read( final File f, final BigWarp bw ) public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransform) { JsonObject transformObj = new JsonObject(); - transformObj.add("type", new JsonPrimitive( bwTransform.getTransformType() )); + transformObj.addProperty("type", bwTransform.getTransformType() ); + transformObj.addProperty("maskInterpolationType", bwTransform.getMaskInterpolationType() ); transformObj.add("landmarks", ltm.toJson()); if( bwTransform.isMasked() ) @@ -65,6 +65,7 @@ public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransf PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); transformObj.add("mask", BigwarpSettings.gson.toJsonTree( mask )); } + return transformObj; } @@ -73,13 +74,18 @@ public static void read( final BigWarp< ? > bw, final JsonObject json ) if( json.has( "landmarks" )) bw.getLandmarkPanel().getTableModel().fromJson( json ); + final String maskInterpolationType = json.get( "maskInterpolationType" ).getAsString(); + bw.getBwTransform().setMaskInterpolationType( maskInterpolationType ); + if( json.has( "mask" )) { JsonObject maskParams = json.get("mask").getAsJsonObject(); - final PlateauSphericalMaskRealRandomAccessible mask = bw.getTpsMaskSource().getRandomAccessible(); - mask.setCenter( BigwarpSettings.gson.fromJson( maskParams.get( "center" ), double[].class )); - mask.setSquaredRadius( maskParams.get("squaredRadius").getAsDouble() ); - mask.setSquaredSigma( maskParams.get("squaredSigma").getAsDouble() ); + final PlateauSphericalMaskRealRandomAccessible maskFromJson = BigwarpSettings.gson.fromJson( maskParams, PlateauSphericalMaskRealRandomAccessible.class ); + + final PlateauSphericalMaskRealRandomAccessible mask = bw.getTransformMaskSource().getRandomAccessible(); + mask.setFalloffShape( maskFromJson.getFallOffShape() ); + mask.setSquaredRadius( maskFromJson.getSquaredRadius() ); + mask.setCenter( maskFromJson.getCenter() ); } } From 39382f1a70307d1b0fbe1d24a13eaa8cf1d97fb2 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 27 Oct 2022 12:04:26 -0400 Subject: [PATCH 069/282] refactor: use api instead of reflection --- .../bigwarp/transforms/BigWarpTransform.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index ead3cd59..d9809d47 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -332,22 +332,7 @@ public ThinPlateR2LogRSplineKernelTransform getTpsBase() return null; else { - // TODO add get method in ThinplateSplineTransform to avoid reflection here - final Class< ThinplateSplineTransform > c_tps = ThinplateSplineTransform.class; - try - { - final Field tpsField = c_tps.getDeclaredField( "tps" ); - tpsField.setAccessible( true ); - ThinPlateR2LogRSplineKernelTransform tpsbase = (ThinPlateR2LogRSplineKernelTransform)tpsField.get( tps ); - tpsField.setAccessible( false ); - - return tpsbase; - } - catch(Exception e ) - { - e.printStackTrace(); - return null; - } + return tps.getKernelTransform(); } } From d6facf13043f7b89cb8d3039fea03049913288f4 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 28 Oct 2022 09:42:51 -0400 Subject: [PATCH 070/282] test: add more json serialization tests --- src/test/java/bigwarp/SerializationTest.java | 264 ++++++++++++----- src/test/resources/settings/expected.json | 1 + .../settings/expected_with_dfield.json | 267 ++++++++++++++++++ 3 files changed, 467 insertions(+), 65 deletions(-) create mode 100644 src/test/resources/settings/expected_with_dfield.json diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 7f542cfc..768cecda 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -2,29 +2,29 @@ import bdv.gui.BigWarpViewerOptions; import bdv.tools.bookmarks.Bookmarks; +import bdv.tools.brightness.ConverterSetup; +import bdv.tools.brightness.MinMaxGroup; +import bdv.viewer.BigWarpViewerPanel; +import bdv.viewer.state.SourceGroup; +import bdv.viewer.state.XmlIoViewerState; import bigwarp.source.PlateauSphericalMaskSource; -import com.google.api.client.json.Json; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import ij.ImagePlus; -import java.io.BufferedInputStream; -import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; -import java.io.PipedOutputStream; import java.io.PipedReader; import java.io.PipedWriter; -import java.io.StringReader; import java.io.StringWriter; import java.nio.file.Files; -import java.nio.file.Paths; +import java.util.List; import mpicbg.spim.data.SpimDataException; import net.imglib2.FinalInterval; import net.imglib2.RealPoint; @@ -43,17 +43,32 @@ public class SerializationTest { - private void maskTest() + @Test + public void maskTest() { PlateauSphericalMaskSource mask = PlateauSphericalMaskSource.build( new RealPoint( 3 ), new FinalInterval( 5, 10, 20 ) ); Gson gson = BigwarpSettings.gson; - prettyPrint( gson.toJson( mask.getRandomAccessible() )); + final JsonElement actual = gson.toJsonTree( mask.getRandomAccessible() ); + + final JsonObject expected = new JsonObject(); + expected.addProperty( "fallOffShape", "COSINE" ); + expected.addProperty( "squaredRadius", 64.0 ); + expected.addProperty( "squaredSigma", 100.0 ); + final JsonArray center = new JsonArray( 3 ); + center.add( 0.0 ); + center.add( 0.0 ); + center.add( 0.0 ); + expected.add( "center", center ); + + Assert.assertEquals( expected, actual ); } - private void bookmarksTest() + @Test + public void bookmarksTest() { final Bookmarks bookmarks = new Bookmarks(); - bookmarks.put( "identity", new AffineTransform3D() ); + final AffineTransform3D identity = new AffineTransform3D(); + bookmarks.put( "identity", identity ); final AffineTransform3D scale = new AffineTransform3D(); scale.scale( 1.0, 2.0, 3.0 ); bookmarks.put( "scale", scale ); @@ -63,56 +78,143 @@ private void bookmarksTest() translate.translate( Math.random(), Math.random(), Math.random(), Math.random() ); Gson gson = BigwarpSettings.gson; - final String json = gson.toJson( bookmarks ); - prettyPrint( json ); + final JsonElement actual = gson.toJsonTree( bookmarks ); + + final JsonObject expected = new JsonObject(); + final JsonObject bookmarksObj = new JsonObject(); + expected.add( "bookmarks", bookmarksObj ); + final JsonArray identityArray = new JsonArray( 3 ); + for ( final double val : identity.getRowPackedCopy() ) + { + identityArray.add( val ); + } + final JsonArray scaleArray = new JsonArray( 3 ); + for ( final double val : scale.getRowPackedCopy() ) + { + scaleArray.add( val ); + } + final JsonArray translateArray = new JsonArray( 3 ); + for ( final double val : translate.getRowPackedCopy() ) + { + translateArray.add( val ); + } + bookmarksObj.add("identity", identityArray); + bookmarksObj.add("scale", scaleArray); + bookmarksObj.add("translate", translateArray); + + Assert.assertEquals( expected, actual ); } - private void autoSaverTest() + @Test + public void autoSaverTest() { final BigWarpAutoSaver saver = new BigWarpAutoSaver( null, 1000 ); - saver.autoSaveDirectory = new File("/tmp"); - final String json = BigwarpSettings.gson.toJson( saver ); - prettyPrint( json ); + saver.autoSaveDirectory = new File( "/tmp" ); + final JsonElement actual = BigwarpSettings.gson.toJsonTree( saver ); - } + final JsonObject expected = new JsonObject(); + expected.addProperty( "period", 1000 ); + expected.addProperty( "location", "/tmp" ); + Assert.assertEquals( expected, actual ); + } - private void setupAssignmentsTest() throws SpimDataException, IOException + @Test + public void setupAssignmentsTest() throws SpimDataException, IOException { - final BigWarp bw = createBigWarp(); - final StringWriter stringWriter = new StringWriter(); - final JsonWriter out = new JsonWriter( stringWriter ); - new BigwarpSettings.SetupAssignmentsAdapter(bw.setupAssignments).write( out, bw.setupAssignments ); + final BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); - prettyPrint( stringWriter.toString()); + final PipedWriter writer = new PipedWriter(); + final PipedReader in = new PipedReader( writer, 10000 ); - } + final JsonWriter out = new JsonWriter( writer ); + new BigwarpSettings.SetupAssignmentsAdapter( bw.setupAssignments ).write( out, bw.setupAssignments ); + out.close(); + writer.close(); + final JsonElement actual = JsonParser.parseReader( in ); - private void viewerPanelTest() throws SpimDataException, IOException + final JsonObject expected = new JsonObject(); + final JsonArray setups = new JsonArray(); + expected.add( "ConverterSetups", setups ); + final List< MinMaxGroup > minMaxGroups = bw.setupAssignments.getMinMaxGroups(); + for ( final ConverterSetup setup : bw.setupAssignments.getConverterSetups() ) + { + final JsonObject setupObj = new JsonObject(); + setupObj.addProperty( "id" , setup.getSetupId() ); + setupObj.addProperty( "min" , setup.getDisplayRangeMin() ); + setupObj.addProperty( "max" , setup.getDisplayRangeMax() ); + setupObj.addProperty( "color" , setup.getColor().get() ); + setupObj.addProperty( "groupId" , minMaxGroups.indexOf( bw.setupAssignments.getMinMaxGroup( setup ) ) ); + setups.add( setupObj ); + } + final JsonArray groups = new JsonArray(); + expected.add( "MinMaxGroups", groups ); + for ( int i = 0; i < minMaxGroups.size(); i++ ) + { + final MinMaxGroup minMaxGroup = minMaxGroups.get( i ); + final JsonObject groupObj = new JsonObject(); + groupObj.addProperty( "id" , i ); + groupObj.addProperty( "fullRangeMin" , minMaxGroup.getFullRangeMin() ); + groupObj.addProperty( "fullRangeMax" , minMaxGroup.getFullRangeMax() ); + groupObj.addProperty( "rangeMin" , minMaxGroup.getRangeMin() ); + groupObj.addProperty( "rangeMax" , minMaxGroup.getRangeMax() ); + groupObj.addProperty( "currentMin" , minMaxGroup.getMinBoundedValue().getCurrentValue() ); + groupObj.addProperty( "currentMax" , minMaxGroup.getMaxBoundedValue().getCurrentValue() ); + groups.add( groupObj ); + } + Assert.assertEquals( expected , actual); + + } + + @Test + public void viewerPanelTest() throws SpimDataException, IOException { - final BigWarp bw = createBigWarp(); - final StringWriter stringWriter = new StringWriter(); - final JsonWriter out = new JsonWriter( stringWriter ); - new BigwarpSettings.BigWarpViewerPanelAdapter( bw.viewerP).write( out, bw.viewerP ); + final BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); - prettyPrint( stringWriter); + final PipedWriter writer = new PipedWriter(); + final PipedReader in = new PipedReader( writer, 10000 ); - } + final JsonWriter out = new JsonWriter( writer ); + new BigwarpSettings.BigWarpViewerPanelAdapter( bw.viewerP ).write( out, bw.viewerP ); + out.close(); + writer.close(); + final JsonElement actual = JsonParser.parseReader( in ); - private void BigWarpSettingsTest() throws SpimDataException, IOException - { - final BigWarp bw = createBigWarp(); - bw.setAutoSaver( new BigWarpAutoSaver( bw, 10000 ) ); - final BigwarpSettings settings = bw.getSettings(); + final JsonObject expected = new JsonObject(); - final StringWriter stringWriter = new StringWriter(); - final JsonWriter out = new JsonWriter( stringWriter ); + final JsonArray sources = new JsonArray(); + expected.add( XmlIoViewerState.VIEWERSTATE_SOURCES_TAG, sources ); + /* All sources are active */ + bw.viewerP.getState().getSources().forEach( source -> sources.add(source.isActive()) ); + + final JsonArray groups = new JsonArray(); + expected.add( XmlIoViewerState.VIEWERSTATE_GROUPS_TAG, groups ); + + final BigWarpViewerPanel value = bw.viewerP; + final List< SourceGroup > sourceGroups = value.getState().getSourceGroups(); + for ( final SourceGroup sourceGroup : sourceGroups ) + { + final JsonObject sourceGroupObj = new JsonObject(); + sourceGroupObj.addProperty( XmlIoViewerState.VIEWERSTATE_GROUP_ACTIVE_TAG, sourceGroup.isActive() ); + sourceGroupObj.addProperty( XmlIoViewerState.VIEWERSTATE_GROUP_NAME_TAG, sourceGroup.getName() ); + final JsonArray sourceIds = new JsonArray(); + sourceGroupObj.add( XmlIoViewerState.VIEWERSTATE_GROUP_SOURCEID_TAG, sourceIds ); + for ( final Integer sourceId : sourceGroup.getSourceIds() ) + { + sourceIds.add( sourceId ); + } + groups.add( sourceGroupObj ); + } + expected.addProperty( XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_TAG, XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_GROUP); + expected.addProperty( XmlIoViewerState.VIEWERSTATE_INTERPOLATION_TAG, XmlIoViewerState.VIEWERSTATE_INTERPOLATION_VALUE_NEARESTNEIGHBOR ); + expected.addProperty( XmlIoViewerState.VIEWERSTATE_CURRENTSOURCE_TAG, value.getState().getCurrentSource() ); + expected.addProperty( XmlIoViewerState.VIEWERSTATE_CURRENTGROUP_TAG, value.getState().getCurrentGroup() ); + expected.addProperty( XmlIoViewerState.VIEWERSTATE_CURRENTTIMEPOINT_TAG, value.getState().getCurrentTimepoint() ); + + Assert.assertEquals( prettyPrint(expected), prettyPrint( actual.getAsJsonObject()) ); - settings.write( out, settings ); - settings.read( new JsonReader( new StringReader( stringWriter.toString() ) ) ); - prettyPrint( stringWriter); } @@ -125,7 +227,7 @@ private void repeatComparison() throws Exception for ( int i = 0; i < 20; i++ ) { System.out.println( i ); - BigWarp< ? > bw = createBigWarp(); + BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); /* Load the known good*/ final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; @@ -148,7 +250,7 @@ private void repeatComparison() throws Exception @Test public void compareKnownXmlComparisonTest() throws SpimDataException, IOException, JDOMException, SAXException { - BigWarp bw = createBigWarp(); + BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; bw.loadSettings( originalXmlSettings ); @@ -162,7 +264,7 @@ public void compareKnownXmlComparisonTest() throws SpimDataException, IOExceptio } /* Ideally, we should close the instance, and get a new one for this test, but it's not currently safe to do this. See SerializationTest#repeatComparison*/ // bw.closeAll(); -// bw = createBigWarp(); +// bw = createBigWarp(new boolean[]{true, false, false, false}); bw.loadSettings( tmpJsonFile.getAbsolutePath() ); final File tmpXmlFile = Files.createTempFile( "xml-settings", ".xml" ).toFile(); @@ -180,15 +282,46 @@ public void compareKnownXmlComparisonTest() throws SpimDataException, IOExceptio } @Test - public void landmarkComparisonTest() throws SpimDataException, IOException, JDOMException, SAXException + public void jsonLoadSaveComparisonTest() throws SpimDataException, IOException, JDOMException + { + BigWarp< ? > bw = createBigWarp( new boolean[] { true, false } ); + + final String expectedJsonFile = "src/test/resources/settings/expected_with_dfield.json"; + bw.loadSettings( expectedJsonFile ); + final BigwarpSettings settings = bw.getSettings(); + + final PipedWriter writer = new PipedWriter(); + final PipedReader in = new PipedReader( writer, 10000 ); + + final JsonWriter out = new JsonWriter( writer ); + + settings.write( out, settings ); + out.close(); + writer.close(); + + final JsonElement jsonSettingsOut = JsonParser.parseReader( in ); + final JsonElement expectedJson = JsonParser.parseReader( new FileReader( expectedJsonFile ) ); + + try + { + Assert.assertEquals( expectedJson, jsonSettingsOut ); + } + finally + { + bw.closeAll(); + } + } + + @Test + public void landmarkComparisonTest() throws SpimDataException, IOException, JDOMException { - BigWarp< ? > bw = createBigWarp(); + BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); final String xmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; final String csvLandmarks = "src/test/resources/settings/landmarks.csv"; final String expectedJsonFile = "src/test/resources/settings/expected.json"; bw.loadSettings( xmlSettings ); - bw.loadLandmarks(csvLandmarks); + bw.loadLandmarks( csvLandmarks ); final BigwarpSettings settings = bw.getSettings(); @@ -196,14 +329,12 @@ public void landmarkComparisonTest() throws SpimDataException, IOException, JDOM final PipedReader in = new PipedReader( writer, 10000 ); final JsonWriter out = new JsonWriter( writer ); - final JsonReader reader = new JsonReader( in ); - settings.write( out, settings ); out.close(); writer.close(); final JsonElement jsonSettingsOut = JsonParser.parseReader( in ); - final JsonElement expectedJson = JsonParser.parseReader( new FileReader(expectedJsonFile)); + final JsonElement expectedJson = JsonParser.parseReader( new FileReader( expectedJsonFile ) ); try { @@ -216,33 +347,36 @@ public void landmarkComparisonTest() throws SpimDataException, IOException, JDOM } - - - private static void prettyPrint(StringWriter json) { - prettyPrint( json.toString() ); + private static String prettyPrint( StringWriter json ) + { + return prettyPrint( json.toString() ); } - private static void prettyPrint( String json ) + private static String prettyPrint( String json ) { final JsonElement parse = JsonParser.parseString( json ); final JsonObject asJsonObject = parse.getAsJsonObject(); - System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson( asJsonObject )); + return prettyPrint( asJsonObject ); } - private static BigWarp< ? > createBigWarp() throws SpimDataException + private static String prettyPrint (JsonObject json) { + + return new GsonBuilder().setPrettyPrinting().create().toJson( json ); + } + + private static BigWarp< ? > createBigWarp( boolean[] moving ) throws SpimDataException { final BigWarp.BigWarpData< Object > data = BigWarpInit.initData(); FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( 3, - ( l, v ) -> v.setOne(), + ( l, v ) -> v.setOne(), UnsignedByteType::new ); ImagePlus imp = ImageJFunctions.wrap( Views.interval( fimg, new FinalInterval( 32, 32, 1 ) ), "img" ); - int i = 0; - BigWarpInit.add( data, imp, i++, 0, true ); - BigWarpInit.add( data, imp, i++, 0, false ); - BigWarpInit.add( data, imp, i++, 0, false ); - BigWarpInit.add( data, imp, i, 0, false ); + for ( int i = 0; i < moving.length; i++ ) + { + BigWarpInit.add( data, imp, i, 0, moving[ i ] ); + } data.wrapUp(); BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); return new BigWarp<>( data, "bigwarp", opts, null ); @@ -250,6 +384,6 @@ private static void prettyPrint( String json ) public static void main( String[] args ) throws SpimDataException { - createBigWarp(); + createBigWarp( new boolean[] { true, false, false, false } ); } } diff --git a/src/test/resources/settings/expected.json b/src/test/resources/settings/expected.json index b357d2aa..76603352 100644 --- a/src/test/resources/settings/expected.json +++ b/src/test/resources/settings/expected.json @@ -212,6 +212,7 @@ }, "Transform": { "type": "Thin Plate Spline", + "maskInterpolationType": "NONE", "landmarks": { "type": "BigWarpLandmarks", "numDimensions": 3, diff --git a/src/test/resources/settings/expected_with_dfield.json b/src/test/resources/settings/expected_with_dfield.json new file mode 100644 index 00000000..71adf0b9 --- /dev/null +++ b/src/test/resources/settings/expected_with_dfield.json @@ -0,0 +1,267 @@ +{ + "ViewerP": { + "Sources": [ + true, + true, + false, + true, + false, + true + ], + "SourceGroups": [ + { + "active": true, + "name": "moving images", + "id": [ + 0 + ] + }, + { + "active": true, + "name": "fixed images", + "id": [ + 1 + ] + } + ], + "DisplayMode": "ss", + "Interpolation": "nearestneighbor", + "CurrentSource": 0, + "CurrentGroup": 0, + "CurrentTimePoint": 0 + }, + "ViewerQ": { + "Sources": [ + true, + true, + false, + true, + false, + true + ], + "SourceGroups": [ + { + "active": true, + "name": "moving images", + "id": [ + 0 + ] + }, + { + "active": true, + "name": "fixed images", + "id": [ + 1 + ] + } + ], + "DisplayMode": "ss", + "Interpolation": "nearestneighbor", + "CurrentSource": 1, + "CurrentGroup": 1, + "CurrentTimePoint": 0 + }, + "SetupAssignments": { + "ConverterSetups": [ + { + "id": 0, + "min": 0.0, + "max": 255.0, + "color": -1, + "groupId": 0 + }, + { + "id": 1, + "min": 0.0, + "max": 255.0, + "color": -1, + "groupId": 1 + }, + { + "id": 956736363, + "min": 0.0, + "max": 65535.0, + "color": -1, + "groupId": 2 + }, + { + "id": 1006827158, + "min": 0.0, + "max": 65535.0, + "color": -1, + "groupId": 3 + }, + { + "id": 1696993146, + "min": 0.0, + "max": 65535.0, + "color": -1, + "groupId": 4 + }, + { + "id": 33872301, + "min": 0.0, + "max": 65535.0, + "color": -1, + "groupId": 5 + } + ], + "MinMaxGroups": [ + { + "id": 0, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 255.0 + }, + { + "id": 1, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 255.0 + }, + { + "id": 2, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 512.0 + }, + { + "id": 3, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 512.0 + }, + { + "id": 4, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 512.0 + }, + { + "id": 5, + "fullRangeMin": -2.147483648E9, + "fullRangeMax": 2.147483647E9, + "rangeMin": 0.0, + "rangeMax": 65535.0, + "currentMin": 0.0, + "currentMax": 1.0 + } + ] + }, + "Bookmarks": { + "bookmarks": {} + }, + "Transform": { + "type": "Thin Plate Spline", + "maskInterpolationType": "LINEAR", + "landmarks": { + "type": "BigWarpLandmarks", + "numDimensions": 3, + "movingPoints": [ + [ + 138.5264565425024, + 153.68156638013366, + 130.0 + ], + [ + 256.96599808978027, + 260.65921680993307, + 130.0 + ], + [ + 99.04660936007639, + 293.771346704871, + 130.0 + ], + [ + 185.64756446991402, + 222.45291308500472, + 193.67717287488063 + ], + [ + 245.0465937080423, + 187.61109998806953, + 85.38357770940299 + ], + [ + 148.2207748912096, + 228.0398521995533, + 85.38357770940299 + ] + ], + "fixedPoints": [ + [ + 209.84489016236864, + 199.5291308500477, + 130.0 + ], + [ + 171.63858643744027, + 283.5829990448901, + 130.0 + ], + [ + 138.5264565425024, + 200.80267430754532, + 130.0 + ], + [ + 185.64756446991402, + 222.45291308500472, + 193.67717287488063 + ], + [ + 269.7014326647564, + 123.11652340019099, + 91.28427889207263 + ], + [ + 138.5264565425024, + 300.13906399235907, + 91.28427889207263 + ] + ], + "active": [ + true, + true, + true, + true, + true, + true + ], + "names": [ + "Pt-0", + "Pt-1", + "Pt-2", + "Pt-3", + "Pt-4", + "Pt-5" + ] + }, + "mask": { + "fallOffShape": "COSINE", + "squaredRadius": 12135.963559594926, + "squaredSigma": 100.0, + "center": [ + 204.1139446036294, + 211.62779369627503, + 91.28427889207263 + ] + } + } +} \ No newline at end of file From 440f6261230d6ac20d1e9e24c66b7456ec50e100 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 28 Oct 2022 09:54:58 -0400 Subject: [PATCH 071/282] fix: start all default sources inactive --- src/main/java/bigwarp/BigWarp.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index e7d3f2de..e6726b5d 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -79,6 +79,7 @@ import bigwarp.transforms.WrappedCoordinateTransform; import bigwarp.transforms.io.TransformWriterJson; import bigwarp.util.BigWarpUtils; +import com.google.common.collect.Lists; import com.google.gson.stream.JsonReader; import fiji.util.gui.GenericDialogPlus; import ij.IJ; @@ -158,6 +159,7 @@ import net.imglib2.realtransform.inverse.RealTransformFiniteDerivatives; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.ARGBType; +import net.imglib2.type.numeric.real.AbstractRealType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; import org.janelia.saalfeldlab.n5.Compression; @@ -491,12 +493,13 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie activeSourcesDialogQ = new VisibilityAndGroupingDialog( viewerFrameQ, viewerQ.getVisibilityAndGrouping() ); activeSourcesDialogQ.setTitle( "visibility and grouping ( fixed )" ); - // set warp mag source to inactive at the start - viewerP.state().setSourceActive( warpMagSource, false ); - viewerQ.state().setSourceActive( warpMagSource, false ); - // set warp grid source to inactive at the start - viewerP.state().setSourceActive( gridSource, false ); - viewerQ.state().setSourceActive( gridSource, false ); + // set sources to inactive at the start + for ( final SourceAndConverter< ? > source : Arrays.asList( warpMagSource, gridSource, jacDetSource, transformMaskSource ) ) + { + viewerP.state().setSourceActive( source, false ); + viewerQ.state().setSourceActive( source, false ); + } + overlayP = new BigWarpOverlay( viewerP, landmarkPanel ); overlayQ = new BigWarpOverlay( viewerQ, landmarkPanel ); From 84cf1c525c504ac9eb382ee6b98b87254a97339e Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 28 Oct 2022 10:19:43 -0400 Subject: [PATCH 072/282] fix: check autosaver null --- src/main/java/bigwarp/BigWarp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index e6726b5d..e1487983 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3432,7 +3432,7 @@ protected void saveSettings( final String xmlFilename ) throws IOException final Element autoSaveNode = new Element( "autosave" ); final Element autoSaveLocation = new Element( "location" ); - if ( autoSaver.autoSaveDirectory != null ) + if ( autoSaver != null && autoSaver.autoSaveDirectory != null ) autoSaveLocation.setText( autoSaver.autoSaveDirectory.getAbsolutePath() ); else autoSaveLocation.setText( getBigwarpSettingsFolder().getAbsolutePath() ); From 55378ce682ae71c59025bb7017eb8dfda89f7462 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 28 Oct 2022 10:20:25 -0400 Subject: [PATCH 073/282] feat: default to json settings --- src/main/java/bigwarp/BigWarp.java | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index e1487983..f67e2561 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3398,13 +3398,13 @@ protected void saveSettings() try { final String canonicalPath = proposedSettingsFile.getCanonicalPath(); - if ( canonicalPath.endsWith( ".json" ) ) + if ( canonicalPath.endsWith( ".xml" ) ) { - saveSettingsJson( canonicalPath ); + saveSettings( canonicalPath ); } else { - saveSettings( canonicalPath ); + saveSettingsJson( canonicalPath ); } } catch ( final IOException e ) @@ -3496,11 +3496,8 @@ protected void loadSettings() protected void loadSettings( final String jsonOrXmlFilename ) throws IOException, JDOMException { - if (jsonOrXmlFilename.endsWith( ".json" )) { - getSettings().read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); - activeSourcesDialogP.update(); - activeSourcesDialogQ.update(); - } else { + if ( jsonOrXmlFilename.endsWith( ".xml" ) ) + { final SAXBuilder sax = new SAXBuilder(); final Document doc = sax.build( jsonOrXmlFilename ); final Element root = doc.getRootElement(); @@ -3521,7 +3518,12 @@ protected void loadSettings( final String jsonOrXmlFilename ) throws IOException if ( maskSettings != null ) transformMask.getRandomAccessible().fromXml( maskSettings ); } - + else + { + getSettings().read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); + activeSourcesDialogP.update(); + activeSourcesDialogQ.update(); + } viewerFrameP.repaint(); viewerFrameQ.repaint(); From aa1a3d462f49e25e8086c859925b4a35e3ebe4bc Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Fri, 28 Oct 2022 10:20:53 -0400 Subject: [PATCH 074/282] test: stop autosaver when test is done --- src/test/java/bigwarp/SerializationTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 768cecda..87330978 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -115,6 +115,7 @@ public void autoSaverTest() final JsonObject expected = new JsonObject(); expected.addProperty( "period", 1000 ); expected.addProperty( "location", "/tmp" ); + saver.stop(); Assert.assertEquals( expected, actual ); } From fd4940561bee0e0ab3f052e36d9be448728d68ce Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 3 Nov 2022 09:39:19 -0400 Subject: [PATCH 075/282] test: start test for url parsing * tests types of n5readers --- src/test/java/bigwarp/url/UrlParseHelper.java | 26 ++++++++ src/test/java/bigwarp/url/UrlParseTest.java | 59 ++++++++++++++++++ .../resources/bigwarp/url/transformTest.h5 | Bin 0 -> 3264 bytes .../url/transformTest.n5/ant/attributes.json | 10 +++ .../url/transformTest.zarr/ant/.zgroup | 10 +++ 5 files changed, 105 insertions(+) create mode 100644 src/test/java/bigwarp/url/UrlParseHelper.java create mode 100644 src/test/java/bigwarp/url/UrlParseTest.java create mode 100644 src/test/resources/bigwarp/url/transformTest.h5 create mode 100644 src/test/resources/bigwarp/url/transformTest.n5/ant/attributes.json create mode 100644 src/test/resources/bigwarp/url/transformTest.zarr/ant/.zgroup diff --git a/src/test/java/bigwarp/url/UrlParseHelper.java b/src/test/java/bigwarp/url/UrlParseHelper.java new file mode 100644 index 00000000..2b8aef67 --- /dev/null +++ b/src/test/java/bigwarp/url/UrlParseHelper.java @@ -0,0 +1,26 @@ +package bigwarp.url; + +import java.io.IOException; + +import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Writer; + +public class UrlParseHelper +{ + + public static void main( String[] args ) throws IOException + { + final N5HDF5Writer h5 = new N5HDF5Writer("src/test/resources/bigwarp/url/transformTest.h5", 32 ); + final String data = "[\n" + + " {\n" + + " \"type\" : \"scale\",\n" + + " \"scale\" : [1,1,1],\n" + + " \"input\" : \"ant-in\",\n" + + " \"output\" : \"ant-out\"\n" + + " }\n" + + "]" ; + + h5.createGroup( "ant" ); + h5.setAttribute( "ant", "coordinateTransformations", data ); + } + +} diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java new file mode 100644 index 00000000..96c533a2 --- /dev/null +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -0,0 +1,59 @@ +package bigwarp.url; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; + +import org.janelia.saalfeldlab.n5.N5FSReader; +import org.janelia.saalfeldlab.n5.N5Reader; +import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader; +import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Writer; +import org.janelia.saalfeldlab.n5.ij.N5Factory; +import org.janelia.saalfeldlab.n5.zarr.N5ZarrReader; +import org.junit.Before; +import org.junit.Test; + +public class UrlParseTest +{ + + private Class n5Clazz; + private Class zarrClazz; + private Class h5Clazz; + + @Before + public void before() + { + n5Clazz = N5FSReader.class; + zarrClazz = N5ZarrReader.class; + h5Clazz = N5HDF5Reader.class; + } + + @Test + public void testFactories() + { + final String n5Path = new File( "src/test/resources/bigwarp/url/transformTest.n5" ).getAbsolutePath(); + final String zarrPath = new File( "src/test/resources/bigwarp/url/transformTest.zarr" ).getAbsolutePath(); + final String h5Path = new File( "src/test/resources/bigwarp/url/transformTest.h5" ).getAbsolutePath(); + + N5Factory n5Factory = new N5Factory(); + try + { + N5Reader n5 = n5Factory.openReader( n5Path ); + assertEquals( n5Clazz, n5.getClass()); + + n5 = n5Factory.openReader( zarrPath ); + assertEquals( zarrClazz, n5.getClass()); + + n5 = n5Factory.openReader( h5Path ); + assertEquals( h5Clazz, n5.getClass()); + } + catch ( IOException e ) + { + fail( e.getMessage() ); + } + } + +} diff --git a/src/test/resources/bigwarp/url/transformTest.h5 b/src/test/resources/bigwarp/url/transformTest.h5 new file mode 100644 index 0000000000000000000000000000000000000000..a3f126c73ba94b2c98a755a83194de9077c573e2 GIT binary patch literal 3264 zcmeHJu};G<5WNr(r4*@%1(>2t9RN`YB*a$KpbiyOG$0T{AwYmg#i`PCK&X4!_yk5i zfsv6pWj`4TPbf&W#_XXTP6dekXK!PyixXhM5U4n%n%wC= zZPz0COgy6@cwV{WmOS^M=F~k8z!!-!F+bPX@t4v-PWJM5n)q8Wb%0Ca=7xJWM1=!o`}w-H5+z!%b&`CQd62H-Ie1hn7%;E$;53Tjvrza+;Ksgaok#JNpM;TU(R;}J z=wP4U?=Wj&yHQWsvy=C}l2S?zYi~s-t literal 0 HcmV?d00001 diff --git a/src/test/resources/bigwarp/url/transformTest.n5/ant/attributes.json b/src/test/resources/bigwarp/url/transformTest.n5/ant/attributes.json new file mode 100644 index 00000000..77531bb5 --- /dev/null +++ b/src/test/resources/bigwarp/url/transformTest.n5/ant/attributes.json @@ -0,0 +1,10 @@ +{ + "coordinateTransformations" : [ + { + "type" : "scale", + "scale" : [1,1,1], + "input" : "ant-in", + "output" : "ant-out" + } + ] +} diff --git a/src/test/resources/bigwarp/url/transformTest.zarr/ant/.zgroup b/src/test/resources/bigwarp/url/transformTest.zarr/ant/.zgroup new file mode 100644 index 00000000..77531bb5 --- /dev/null +++ b/src/test/resources/bigwarp/url/transformTest.zarr/ant/.zgroup @@ -0,0 +1,10 @@ +{ + "coordinateTransformations" : [ + { + "type" : "scale", + "scale" : [1,1,1], + "input" : "ant-in", + "output" : "ant-out" + } + ] +} From 0a2e112121d890f827d9317baef88ff54881c946 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Thu, 3 Nov 2022 15:06:07 -0400 Subject: [PATCH 076/282] test: skeleton of test for loading sources from urls * add some example data --- src/test/java/bigwarp/url/UrlParseHelper.java | 15 +++ src/test/java/bigwarp/url/UrlParseTest.java | 107 +++++++++++++++--- .../resources/bigwarp/url/transformTest.h5 | Bin 3264 -> 3904 bytes .../url/transformTest.n5/ant/attributes.json | 26 ++++- .../url/transformTest.n5/img/attributes.json | 1 + .../url/transformTest.n5/img2/attributes.json | 1 + .../url/transformTest.zarr/img/.zarray | 1 + .../url/transformTest.zarr/img2/.zarray | 1 + 8 files changed, 134 insertions(+), 18 deletions(-) create mode 100644 src/test/resources/bigwarp/url/transformTest.n5/img/attributes.json create mode 100644 src/test/resources/bigwarp/url/transformTest.n5/img2/attributes.json create mode 100644 src/test/resources/bigwarp/url/transformTest.zarr/img/.zarray create mode 100644 src/test/resources/bigwarp/url/transformTest.zarr/img2/.zarray diff --git a/src/test/java/bigwarp/url/UrlParseHelper.java b/src/test/java/bigwarp/url/UrlParseHelper.java index 2b8aef67..66b67852 100644 --- a/src/test/java/bigwarp/url/UrlParseHelper.java +++ b/src/test/java/bigwarp/url/UrlParseHelper.java @@ -2,13 +2,18 @@ import java.io.IOException; +import org.janelia.saalfeldlab.n5.DataType; +import org.janelia.saalfeldlab.n5.GzipCompression; +import org.janelia.saalfeldlab.n5.N5FSWriter; import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Writer; +import org.janelia.saalfeldlab.n5.zarr.N5ZarrWriter; public class UrlParseHelper { public static void main( String[] args ) throws IOException { + final N5HDF5Writer h5 = new N5HDF5Writer("src/test/resources/bigwarp/url/transformTest.h5", 32 ); final String data = "[\n" + " {\n" @@ -21,6 +26,16 @@ public static void main( String[] args ) throws IOException h5.createGroup( "ant" ); h5.setAttribute( "ant", "coordinateTransformations", data ); + h5.createDataset( "img", new long[]{6, 8, 10}, new int[] {16, 16, 16}, DataType.UINT8, new GzipCompression() ); + h5.createDataset( "img2", new long[]{12, 16, 20}, new int[] {20, 20, 20}, DataType.UINT8, new GzipCompression() ); + + final N5FSWriter n5 = new N5FSWriter("src/test/resources/bigwarp/url/transformTest.n5" ); + n5.createDataset( "img", new long[]{5, 8, 9}, new int[] {16, 16, 16}, DataType.UINT8, new GzipCompression() ); + n5.createDataset( "img2", new long[]{10, 16, 18}, new int[] {18, 18, 18}, DataType.UINT8, new GzipCompression() ); + + final N5ZarrWriter zarr = new N5ZarrWriter("src/test/resources/bigwarp/url/transformTest.zarr" ); + zarr.createDataset( "/img", new long[]{4, 6, 8}, new int[] {16, 16, 16}, DataType.UINT8, new GzipCompression() ); + zarr.createDataset( "/img2", new long[]{8, 12, 16}, new int[] {16, 16, 16}, DataType.UINT8, new GzipCompression() ); } } diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index 96c533a2..3d659694 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -1,21 +1,27 @@ package bigwarp.url; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; +import java.util.HashMap; import org.janelia.saalfeldlab.n5.N5FSReader; -import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader; -import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Writer; import org.janelia.saalfeldlab.n5.ij.N5Factory; import org.janelia.saalfeldlab.n5.zarr.N5ZarrReader; import org.junit.Before; import org.junit.Test; +import bdv.viewer.Source; +import ij.IJ; +import ij.ImagePlus; +import ij.gui.NewImage; + public class UrlParseTest { @@ -23,32 +29,53 @@ public class UrlParseTest private Class zarrClazz; private Class h5Clazz; + private HashMap urlToDimensions; + + private String n5Root, zarrRoot, h5Root; + private String img3dTifPath, img2dPngPath; + @Before public void before() { n5Clazz = N5FSReader.class; zarrClazz = N5ZarrReader.class; h5Clazz = N5HDF5Reader.class; + + n5Root = new File( "src/test/resources/bigwarp/url/transformTest.n5" ).getAbsolutePath(); + zarrRoot = new File( "src/test/resources/bigwarp/url/transformTest.zarr" ).getAbsolutePath(); + h5Root = new File( "src/test/resources/bigwarp/url/transformTest.h5" ).getAbsolutePath(); + + urlToDimensions = new HashMap<>(); + final String h5Root = new File( "src/test/resources/bigwarp/url/transformTest.h5" ).getAbsolutePath(); + urlToDimensions.put( h5Root + "?img", new long[] { 6, 8, 10 } ); + urlToDimensions.put( h5Root + "?img2", new long[] { 12, 16, 20 } ); + + final String n5Root = new File( "src/test/resources/bigwarp/url/transformTest.n5" ).getAbsolutePath(); + urlToDimensions.put( n5Root + "?img", new long[] { 5, 8, 9 } ); + urlToDimensions.put( n5Root + "?img2", new long[] { 10, 16, 18 } ); + + final String zarrRoot = new File( "src/test/resources/bigwarp/url/transformTest.zarr" ).getAbsolutePath(); + urlToDimensions.put( zarrRoot + "?img", new long[] { 4, 6, 8 } ); + urlToDimensions.put( zarrRoot + "?img2", new long[] { 8, 12, 16 } ); + + ImagePlus img3d = NewImage.createByteImage( "img3d", 8, 8, 4, NewImage.FILL_RAMP ); + img3dTifPath = new File( "src/test/resources/bigwarp/url/img.tif").getAbsolutePath(); + IJ.save( img3d, img3dTifPath ); + + ImagePlus img2d = NewImage.createByteImage( "img2d", 8, 8, 1, NewImage.FILL_RAMP ); + img2dPngPath = new File( "src/test/resources/bigwarp/url/img2d.png").getAbsolutePath(); + IJ.save( img2d, img2dPngPath ); } @Test public void testFactories() { - final String n5Path = new File( "src/test/resources/bigwarp/url/transformTest.n5" ).getAbsolutePath(); - final String zarrPath = new File( "src/test/resources/bigwarp/url/transformTest.zarr" ).getAbsolutePath(); - final String h5Path = new File( "src/test/resources/bigwarp/url/transformTest.h5" ).getAbsolutePath(); - N5Factory n5Factory = new N5Factory(); try { - N5Reader n5 = n5Factory.openReader( n5Path ); - assertEquals( n5Clazz, n5.getClass()); - - n5 = n5Factory.openReader( zarrPath ); - assertEquals( zarrClazz, n5.getClass()); - - n5 = n5Factory.openReader( h5Path ); - assertEquals( h5Clazz, n5.getClass()); + assertEquals( n5Clazz, n5Factory.openReader( n5Root ).getClass()); + assertEquals( zarrClazz, n5Factory.openReader( zarrRoot ).getClass()); + assertEquals( h5Clazz, n5Factory.openReader( h5Root ).getClass()); } catch ( IOException e ) { @@ -56,4 +83,56 @@ public void testFactories() } } + public void testUrlSources() + { + final String bdvXmlUrl = new File( "src/test/resources/mri-stack.xml" ).getAbsolutePath(); + + Source bdvXmlSrc = loadSourceFromUrl( bdvXmlUrl ); +// assertNotNull( bdvXmlSrc ); + + Source img3dTif = loadSourceFromUrl( img3dTifPath ); +// assertNotNull( img3dTif ); +// assertArrayEquals( new long[]{8,8,4}, img3dTif.getSource( 0, 0 ).dimensionsAsLongArray() ); + + Source img2dPng = loadSourceFromUrl( img2dPngPath ); +// assertNotNull( img2dPng ); +// assertArrayEquals( new long[]{8,8,1}, img2dPng.getSource( 0, 0 ).dimensionsAsLongArray() ); // TODO I wrote this to expect [8,8,1], but it might need [8,8]. + + for( String url : urlToDimensions.keySet() ) + { + Source src = loadSourceFromUrl( url ); +// assertNotNull( src ); +// assertArrayEquals( urlToDimensions.get( url ), src.getSource( 0, 0 ).dimensionsAsLongArray() ); // TODO I wrote this to expect [8,8,1], but it might need [8,8]. + } + } + + @Test + public void testUrlTransforms() + { + final String n5Path = new File( "src/test/resources/bigwarp/url/transformTest.n5" ).getAbsolutePath(); + + final String s0Url = n5Path + "?ant&transform=[0]"; + final String s0DefaultUrl = n5Path + "?ant&transform=[0]"; + + // TODO when we're ready +// final Object s0 = loadTransformFromUrl( s0Url ); +// final Object s0Default = loadTransformFromUrl( s0DefaultUrl ); + +// assertNotNull( s0 ); +// assertNotNull( s0Default ); +// assertEquals( s0, s0Default ); + } + + private Object loadTransformFromUrl( String url ) + { + // TODO Caleb will remove me and replace calls to me with something real + return null; + } + + private Source loadSourceFromUrl( String url ) + { + // TODO Caleb will remove me and replace calls to me with something real + return null; + } + } diff --git a/src/test/resources/bigwarp/url/transformTest.h5 b/src/test/resources/bigwarp/url/transformTest.h5 index a3f126c73ba94b2c98a755a83194de9077c573e2..457cbc7f627edddb54f5923346521c444eaa3e46 100644 GIT binary patch delta 664 zcmX>gc|dN029pE-M6EVPi;WxEnHU`=?_|=~%*;(^00AIv1f@~_eb9Rnj1#6&i*MiGYMgcR+H22GaqaiCS%p5*s(NGchVm-pQoT$;bc!7Lyx!4L2(>A7Nr-n*5wKaN_n4 OlNFdbHXE={U Date: Fri, 4 Nov 2022 13:14:56 -0400 Subject: [PATCH 077/282] BREAKING CHANGE: wip reworking of BigWarpData class * toward adding sources in an open Bigwarp instance --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 10 +- src/main/java/bdv/ij/ApplyBigwarpPlugin.java | 37 ++-- .../ij/BigWarpToDeformationFieldPlugIn.java | 53 +++-- .../java/bdv/viewer/BigWarpViewerPanel.java | 10 +- src/main/java/bigwarp/BigWarp.java | 194 ++++++++++++++---- .../java/bigwarp/BigWarpARGBExporter.java | 29 ++- src/main/java/bigwarp/BigWarpActions.java | 29 ++- .../bigwarp/BigWarpBatchTransformFOV.java | 8 - src/main/java/bigwarp/BigWarpExporter.java | 99 +++++++-- src/main/java/bigwarp/BigWarpInit.java | 12 +- .../java/bigwarp/BigWarpRealExporter.java | 50 +++-- src/main/java/bigwarp/SourceInfoDialog.java | 8 +- src/main/java/bigwarp/source/GridSource.java | 6 +- .../source/JacobianDeterminantSource.java | 9 +- .../bigwarp/source/WarpMagnitudeSource.java | 7 +- .../bigwarp/transforms/BigWarpTransform.java | 5 +- 16 files changed, 405 insertions(+), 161 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index e7dcba3b..0207afd7 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -80,8 +80,8 @@ public BigWarpViewerFrame( final CacheControl cache, final String title, final boolean isMoving, - final int[] movingIndexList, - final int[] targetIndexList ) + final List movingIndexList, + final List targetIndexList ) { this( bw, width, height, sources, converterSetups, viewerSettings, cache, BigWarpViewerOptions.options(), title, isMoving, movingIndexList, targetIndexList ); } @@ -96,8 +96,8 @@ public BigWarpViewerFrame( final BigWarpViewerOptions optional, final String title, final boolean isMoving, - final int[] movingIndexList, - final int[] targetIndexList ) + final List movingIndexList, + final List targetIndexList ) { super( title, AWTUtils.getSuitableGraphicsConfiguration( AWTUtils.RGB_COLOR_MODEL ) ); this.bw = bw; @@ -118,7 +118,7 @@ public BigWarpViewerFrame( if ( !isMoving ) { - viewer.state().setCurrentSource( viewer.state().getSources().get( bw.getData().targetSourceIndices[ 0 ] )); + viewer.state().setCurrentSource( viewer.state().getSources().get( bw.getData().targetSourceIndexList.get(0))); } keybindings = new InputActionBindings(); diff --git a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java index b25175fa..9d63ea88 100644 --- a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java +++ b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java @@ -167,17 +167,17 @@ public static String getUnit( final BigWarpData bwData, final String resolutionOption ) { String unit = "pix"; - boolean doTargetImagesExist = bwData.targetSourceIndices != null && bwData.targetSourceIndices.length > 0; + boolean doTargetImagesExist = bwData.targetSourceIndexList != null && bwData.targetSourceIndexList.size() > 0; if( resolutionOption.equals( MOVING ) || resolutionOption.equals( MOVING_WARPED ) || !doTargetImagesExist ) { - VoxelDimensions mvgVoxDims = bwData.sources.get( bwData.movingSourceIndices[0] ).getSpimSource().getVoxelDimensions(); + VoxelDimensions mvgVoxDims = bwData.sources.get( bwData.movingSourceIndexList.get( 0 ) ).getSpimSource().getVoxelDimensions(); if( mvgVoxDims != null ) unit = mvgVoxDims.unit(); } else { // use target units even if - VoxelDimensions tgtVoxDims = bwData.sources.get( bwData.targetSourceIndices[0] ).getSpimSource().getVoxelDimensions(); + VoxelDimensions tgtVoxDims = bwData.sources.get( bwData.targetSourceIndexList.get( 0 ) ).getSpimSource().getVoxelDimensions(); if( tgtVoxDims != null ) unit = tgtVoxDims.unit(); } @@ -194,21 +194,21 @@ public static double[] getResolution( if( resolutionOption.equals( TARGET )) { - if( bwData.targetSourceIndices.length <= 0 ) + if( bwData.targetSourceIndexList.size() <= 0 ) return null; Source< ? > spimSource = bwData.sources.get( - bwData.targetSourceIndices[ 0 ]).getSpimSource(); + bwData.targetSourceIndexList.get( 0 )).getSpimSource(); return getResolution( spimSource, resolutionOption, resolutionSpec ); } else if( resolutionOption.equals( MOVING )) { - if( bwData.targetSourceIndices.length <= 0 ) + if( bwData.targetSourceIndexList.size() <= 0 ) return null; Source< ? > spimSource = bwData.sources.get( - bwData.movingSourceIndices[ 0 ]).getSpimSource(); + bwData.movingSourceIndexList.get( 0 )).getSpimSource(); return getResolution( spimSource, resolutionOption, resolutionSpec ); } else if( resolutionOption.equals( SPECIFIED )) @@ -450,26 +450,26 @@ public static List getPixelInterval( final double[] outputResolution) { if (fieldOfViewOption.equals(TARGET)) { - if (bwData.targetSourceIndices.length <= 0) { + if (bwData.targetSourceIndexList.size() <= 0) { System.err.println("Requested target fov but target image is missing."); return null; } return Stream.of( getPixelInterval( - bwData.sources.get(bwData.targetSourceIndices[0]).getSpimSource(), + bwData.sources.get(bwData.targetSourceIndexList.get( 0 )).getSpimSource(), landmarks, transform, fieldOfViewOption, bboxEst, outputResolution)) .collect(Collectors.toList()); } else if (fieldOfViewOption.equals(MOVING_WARPED)) { return Stream.of( getPixelInterval( - bwData.sources.get(bwData.movingSourceIndices[0]).getSpimSource(), + bwData.sources.get(bwData.movingSourceIndexList.get( 0 )).getSpimSource(), landmarks, transform, fieldOfViewOption, bboxEst, outputResolution)) .collect(Collectors.toList()); } else if (fieldOfViewOption.equals(UNION_TARGET_MOVING)) { return Stream.of( getPixelInterval( - bwData.sources.get(bwData.movingSourceIndices[0]).getSpimSource(), + bwData.sources.get(bwData.movingSourceIndexList.get( 0 )).getSpimSource(), landmarks, transform, fieldOfViewOption, bboxEst, outputResolution)) .collect(Collectors.toList()); } else if (fieldOfViewOption.equals(SPECIFIED_PIXEL)) { @@ -820,8 +820,9 @@ public static List apply( final boolean wait, final WriteDestinationOptions writeOpts) { - int numChannels = bwData.movingSourceIndices.length; - int[] movingSourceIndexList = bwData.movingSourceIndices; +// int numChannels = bwData.movingSourceIndexList.size(); + int numChannels = bwData.numMovingSources(); + List movingSourceIndexList = bwData.movingSourceIndexList; List< SourceAndConverter< T >> sourcesxfm = BigWarp.wrapSourcesAsTransformed( bwData.sources, landmarks.getNumdims(), @@ -830,8 +831,8 @@ public static List apply( InvertibleRealTransform invXfm = new BigWarpTransform( landmarks, tranformTypeOption ).getTransformation(); for ( int i = 0; i < numChannels; i++ ) { - ((WarpedSource< ? >) (sourcesxfm.get( movingSourceIndexList[ i ]).getSpimSource())).updateTransform( invXfm ); - ((WarpedSource< ? >) (sourcesxfm.get( movingSourceIndexList[ i ]).getSpimSource())).setIsTransformed( true ); + ((WarpedSource< ? >) (sourcesxfm.get( movingSourceIndexList.get( i )).getSpimSource())).updateTransform( invXfm ); + ((WarpedSource< ? >) (sourcesxfm.get( movingSourceIndexList.get( i )).getSpimSource())).setIsTransformed( true ); } ProgressWriter progressWriter = new ProgressWriterIJ(); @@ -982,10 +983,10 @@ public static & NumericType> void runN5Export( pixelRenderToPhysical.concatenate( offsetTransform ); // render and write - final int N = data.movingSourceIndices.length; + final int N = data.movingSourceIndexList.size(); for ( int i = 0; i < N; i++ ) { - final int movingSourceIndex = data.movingSourceIndices[ i ]; + final int movingSourceIndex = data.movingSourceIndexList.get( i ); @SuppressWarnings( "unchecked" ) final RealRandomAccessible< T > raiRaw = ( RealRandomAccessible< T > )sources.get( movingSourceIndex ).getSpimSource().getInterpolatedSource( 0, 0, interp ); @@ -994,7 +995,7 @@ public static & NumericType> void runN5Export( final IntervalView< T > img = Views.interval( Views.raster( rai ), Intervals.zeroMin( outputInterval ) ); - final String srcName = data.sources.get( data.movingSourceIndices[ i ]).getSpimSource().getName(); + final String srcName = data.sources.get( data.movingSourceIndexList.get( i )).getSpimSource().getName(); String destDataset = dataset; if( N > 1 ) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 276f485c..73caf62e 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -61,6 +61,9 @@ import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealPoint; +import net.imglib2.converter.Converters; +import net.imglib2.converter.RealFloatConverter; +import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.img.imageplus.FloatImagePlus; import net.imglib2.img.imageplus.ImagePlusImgs; import net.imglib2.iterator.IntervalIterator; @@ -77,7 +80,6 @@ import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.util.Util; import net.imglib2.view.IntervalView; import net.imglib2.view.Views; import net.imglib2.view.composite.CompositeIntervalView; @@ -103,8 +105,8 @@ public static void main( final String[] args ) { new ImageJ(); // IJ.run("Boats (356K)"); - ImagePlus imp = IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif" ); -// ImagePlus imp = IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/mri-stack_p2p2p4.tif" ); +// ImagePlus imp = IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif" ); + ImagePlus imp = IJ.openImage( "/home/john/tmp/mri-stack.tif" ); // WindowManager.getActiveWindow(); imp.show(); @@ -115,8 +117,9 @@ public static void main( final String[] args ) public void runFromBigWarpInstance( final LandmarkTableModel landmarkModel, final List> sources, - final int[] targetSourceIndexList ) + final List targetSourceIndexList ) { + System.out.println( "run from instance." ); ImageJ ij = IJ.getInstance(); if ( ij == null ) return; @@ -126,7 +129,7 @@ public void runFromBigWarpInstance( if( params == null ) return; - final RandomAccessibleInterval< ? > tgtInterval = sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getSource( 0, 0 ); + final RandomAccessibleInterval< ? > tgtInterval = sources.get( targetSourceIndexList.get( 0 ) ).getSpimSource().getSource( 0, 0 ); int ndims = landmarkModel.getNumdims(); // dimensions of the output image plus @@ -150,7 +153,7 @@ public void runFromBigWarpInstance( long[] dims = tgtInterval.dimensionsAsLongArray(); double[] spacing = new double[ 3 ]; - VoxelDimensions voxelDim = sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getVoxelDimensions(); + VoxelDimensions voxelDim = sources.get( targetSourceIndexList.get( 0 ) ).getSpimSource().getVoxelDimensions(); voxelDim.dimensions( spacing ); if( params.spacing != null ) @@ -161,7 +164,7 @@ public void runFromBigWarpInstance( if( params.n5Base.isEmpty() ) { - toImagePlus( landmarkModel, params.ignoreAffine, dims, spacing, params.nThreads ); + toImagePlus( landmarkModel, params.ignoreAffine, params.virtual, dims, spacing, params.nThreads ); } else { @@ -199,7 +202,7 @@ public void run( final String arg ) if( params.n5Base.isEmpty() ) { - toImagePlus( ltm, params.ignoreAffine, params.size, params.spacing, params.nThreads ); + toImagePlus( ltm, params.ignoreAffine, params.virtual, params.size, params.spacing, params.nThreads ); } else { @@ -217,12 +220,13 @@ public void run( final String arg ) public static ImagePlus toImagePlus( final LandmarkTableModel ltm, final boolean ignoreAffine, + final boolean virtual, final long[] dims, final double[] spacing, final int nThreads ) { final double[] offset = new double[ spacing.length ]; - return toImagePlus( ltm, ignoreAffine, dims, spacing, offset, nThreads ); + return toImagePlus( ltm, ignoreAffine, virtual, dims, spacing, offset, nThreads ); } /** @@ -240,6 +244,7 @@ public static ImagePlus toImagePlus( public static ImagePlus toImagePlus( final LandmarkTableModel ltm, final boolean ignoreAffine, + final boolean virtual, final long[] dims, final double[] spacing, final double[] offset, @@ -283,19 +288,31 @@ else if ( nd == 3 ) else return null; - System.out.println("new dfield"); final RandomAccessibleInterval< DoubleType > dfieldVirt = DisplacementFieldTransform.createDisplacementField( tps, new FinalInterval( dims ), spacing, offset ); - final FloatImagePlus< FloatType > dfield = ImagePlusImgs.floats( ipDims ); - // make the "vector" axis the first dimension - RandomAccessibleInterval< FloatType > dfieldImpPerm = Views.moveAxis( dfield, 2, 0 ); - LoopBuilder.setImages( dfieldVirt, dfieldImpPerm ).multiThreaded( TaskExecutors.fixedThreadPool( nThreads ) ).forEachPixel( (x,y) -> { y.setReal(x.get()); }); + ImagePlus dfieldIp; + if( virtual ) + { + final RealFloatConverter conv = new RealFloatConverter<>(); + final RandomAccessibleInterval< FloatType > dfieldF = Views.moveAxis( + Converters.convert2( dfieldVirt, conv, FloatType::new ), + 0, 2 ); + dfieldIp = ImageJFunctions.wrap( dfieldF, "" ); // title gets set below + } + else + { + final FloatImagePlus< FloatType > dfield = ImagePlusImgs.floats( ipDims ); + + // make the "vector" axis the first dimension + RandomAccessibleInterval< FloatType > dfieldImpPerm = Views.moveAxis( dfield, 2, 0 ); + LoopBuilder.setImages( dfieldVirt, dfieldImpPerm ).multiThreaded( TaskExecutors.fixedThreadPool( nThreads ) ).forEachPixel( (x,y) -> { y.setReal(x.get()); }); + dfieldIp = dfield.getImagePlus(); + } String title = "bigwarp dfield"; if ( ignoreAffine ) title += " (no affine)"; - ImagePlus dfieldIp = dfield.getImagePlus(); dfieldIp.setTitle( title ); dfieldIp.getCalibration().pixelWidth = spacing[ 0 ]; @@ -699,6 +716,7 @@ private static class DeformationFieldExportParameters { public final String landmarkPath; public final boolean ignoreAffine; + public final boolean virtual; public final int nThreads; public final long[] size; @@ -712,6 +730,7 @@ private static class DeformationFieldExportParameters public DeformationFieldExportParameters( final String landmarkPath, final boolean ignoreAffine, + final boolean virtual, final int nThreads, final long[] size, final double[] spacing, @@ -722,6 +741,7 @@ public DeformationFieldExportParameters( { this.landmarkPath = landmarkPath; this.ignoreAffine = ignoreAffine; + this.virtual = virtual; this.nThreads = nThreads; this.size = size; @@ -745,6 +765,7 @@ public static DeformationFieldExportParameters fromDialog( } gd.addCheckbox( "Ignore affine part", false ); + gd.addCheckbox( "virtual", false ); gd.addNumericField( "threads", 1, 0 ); gd.addMessage( "Size and spacing" ); @@ -779,6 +800,7 @@ public static DeformationFieldExportParameters fromDialog( landmarkPath = gd.getNextString(); final boolean ignoreAffine = gd.getNextBoolean(); + final boolean virtual = gd.getNextBoolean(); final int nThreads = ( int ) gd.getNextNumber(); ImagePlus ref_imp = null; @@ -835,6 +857,7 @@ public static DeformationFieldExportParameters fromDialog( return new DeformationFieldExportParameters( landmarkPath, ignoreAffine, + virtual, nThreads, size, spacing, diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index 1bb9b2cf..a5b90125 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -59,9 +59,9 @@ public class BigWarpViewerPanel extends ViewerPanel protected int ndims; - final protected int[] movingSourceIndexList; + final protected List movingSourceIndexList; - final protected int[] targetSourceIndexList; + final protected List targetSourceIndexList; protected boolean boxOverlayVisible = true; @@ -75,13 +75,13 @@ public class BigWarpViewerPanel extends ViewerPanel ViewerOptions options; public BigWarpViewerPanel( final List< SourceAndConverter< ? > > sources, final BigWarpViewerSettings viewerSettings, final CacheControl cache, boolean isMoving, - int[] movingSourceIndexList, int[] targetSourceIndexList ) + List movingSourceIndexList, List targetSourceIndexList ) { this( sources, viewerSettings, cache, BigWarpViewerOptions.options(), isMoving, movingSourceIndexList, targetSourceIndexList ); } public BigWarpViewerPanel( final List< SourceAndConverter< ? > > sources, final BigWarpViewerSettings viewerSettings, final CacheControl cache, final BigWarpViewerOptions optional, boolean isMoving, - int[] movingSourceIndexList, int[] targetSourceIndexList ) + List movingSourceIndexList, List targetSourceIndexList ) { super( sources, 1, cache, optional.getViewerOptions( isMoving ) ); this.viewerSettings = viewerSettings; @@ -202,7 +202,7 @@ public int updateGrouping() public boolean isInFixedImageSpace() { - return !isMoving || ( ( WarpedSource< ? > ) ( state().getSources().get( movingSourceIndexList[ 0 ] ).getSpimSource() ) ).isTransformed(); + return !isMoving || ( ( WarpedSource< ? > ) ( state().getSources().get( movingSourceIndexList.get( 0 ) ).getSpimSource() ) ).isTransformed(); } public boolean doUpdateOnDrag() diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 52e80812..3981b65c 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -44,6 +44,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -187,12 +188,14 @@ public class BigWarp< T > protected BigWarpData< T > data; // descriptive names for indexing sources - protected int[] movingSourceIndexList; + protected List movingSourceIndexList; - protected int[] targetSourceIndexList; - - protected List< SourceAndConverter< T > > sources; + protected List targetSourceIndexList; + protected List< SourceAndConverter< T > > sources; + + protected HashSet< SourceAndConverter< T >> movingSources; + protected final SetupAssignments setupAssignments; protected final BrightnessDialog brightnessDialog; @@ -380,7 +383,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie fixedViewXfm = new AffineTransform3D(); //sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); - data.sources.get( data.targetSourceIndices[ 0 ] ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); + data.sources.get( data.targetSourceIndexList.get(0) ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); baselineModelIndex = 0; warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "WarpMagnitudeSource" ); @@ -389,12 +392,16 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie this.sources = this.data.sources; final List< ConverterSetup > converterSetups = data.converterSetups; - this.movingSourceIndexList = data.movingSourceIndices; - this.targetSourceIndexList = data.targetSourceIndices; - Arrays.sort( movingSourceIndexList ); - Arrays.sort( targetSourceIndexList ); + this.movingSourceIndexList = data.movingSourceIndexList; + this.targetSourceIndexList = data.movingSourceIndexList; + Collections.sort( movingSourceIndexList ); + Collections.sort( targetSourceIndexList ); +// Arrays.sort( movingSourceIndexList ); +// Arrays.sort( targetSourceIndexList ); sources = wrapSourcesAsTransformed( data.sources, ndims, data ); + // TODO JOHN CHECK THIS!! + data.sources = sources; setGridType( GridSource.GRID_TYPE.LINE ); @@ -634,6 +641,16 @@ public static void initBrightness( final double cumulativeMinCutoff, final doubl setup.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); } + public void addSource( Source source, boolean moving ) + { + + } + + public void addSource( Source source ) + { + addSource( source, false ); + } + public void addKeyEventPostProcessor( final KeyEventPostProcessor ke ) { keyEventPostProcessorSet.add( ke ); @@ -822,7 +839,7 @@ public void exportAsImagePlus( boolean virtual ) public void saveMovingImageToFile() { final JFileChooser fileChooser = new JFileChooser( getLastDirectory() ); - File proposedFile = new File( sources.get( movingSourceIndexList[ 0 ] ).getSpimSource().getName() ); + File proposedFile = new File( sources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getName() ); fileChooser.setSelectedFile( proposedFile ); final int returnVal = fileChooser.showSaveDialog( null ); @@ -1761,13 +1778,14 @@ public static List< SourceAndConverter > wrapSourcesAsTransformed( final { final List< SourceAndConverter> wrappedSource = new ArrayList<>(); - int[] warpUsIndices = data.movingSourceIndices; - HashMap, ColorSettings> colorSettings = data.sourceColorSettings; + final List warpUsIndices = data.movingSourceIndexList; + final HashMap, ColorSettings> colorSettings = data.sourceColorSettings; int i = 0; - for ( final SourceAndConvertersac : sources ) + for ( final SourceAndConverter sac : sources ) { - int idx = Arrays.binarySearch( warpUsIndices, i ); +// int idx = Arrays.binarySearch( warpUsIndices, i ); + int idx = warpUsIndices.indexOf( i ); if ( idx >= 0 ) { SourceAndConverter newSac = wrapSourceAsTransformed( sac, "xfm_" + i, ndims ); @@ -1798,7 +1816,7 @@ private static < T > SourceAndConverter< FloatType > addJacobianDeterminantSourc } @SuppressWarnings( { "rawtypes", "unchecked" } ) - private static < T > SourceAndConverter< FloatType > addWarpMagnitudeSource( final BigWarpData< T > data, final boolean is2D, final String name ) + private static < T > SourceAndConverter< FloatType > addWarpMagnitudeSource( final BigWarpData< T > data, final boolean is2D, final String name ) { // TODO think about whether its worth it to pass a type parameter. final WarpMagnitudeSource< FloatType > magSource = new WarpMagnitudeSource<>( name, data, new FloatType() ); @@ -2096,9 +2114,9 @@ private void setTransformationMovingSourceOnly( final InvertibleRealTransform tr { this.currentTransform = transform; - for ( int i = 0; i < movingSourceIndexList.length; i++ ) + for ( int i = 0; i < movingSourceIndexList.size(); i++ ) { - int idx = movingSourceIndexList [ i ]; + final int idx = movingSourceIndexList.get( i ); // the xfm must always be 3d for bdv to be happy. // when bigwarp has 2d images though, the z- component will be left unchanged @@ -2113,9 +2131,9 @@ private void setTransformationMovingSourceOnly( final InvertibleRealTransform tr public void updateSourceBoundingBoxEstimators() { - for ( int i = 0; i < movingSourceIndexList.length; i++ ) + for ( int i = 0; i < movingSourceIndexList.size(); i++ ) { - int idx = movingSourceIndexList [ i ]; + final int idx = movingSourceIndexList.get( i ); // the xfm must always be 3d for bdv to be happy. // when bigwarp has 2d images though, the z- component will be left unchanged @@ -2194,9 +2212,9 @@ public boolean restimateTransformation() public synchronized void setIsMovingDisplayTransformed( final boolean isTransformed ) { - for( int i = 0 ; i < movingSourceIndexList.length; i ++ ) + for( int i = 0 ; i < movingSourceIndexList.size(); i ++ ) { - int movingSourceIndex = movingSourceIndexList[ i ]; + final int movingSourceIndex = movingSourceIndexList.get( 0 ); ( ( WarpedSource< ? > ) ( sources.get( movingSourceIndex ).getSpimSource() ) ).setIsTransformed( isTransformed ); @@ -2227,7 +2245,7 @@ public boolean isRowIncomplete() public boolean isMovingDisplayTransformed() { // this implementation is okay, so long as all the moving images have the same state of 'isTransformed' - return ( ( WarpedSource< ? > ) ( sources.get( movingSourceIndexList[ 0 ] ).getSpimSource() ) ).isTransformed(); + return ( ( WarpedSource< ? > ) ( sources.get( movingSourceIndexList.get( 0 ) ).getSpimSource() ) ).isTransformed(); } /** @@ -2416,34 +2434,46 @@ public void checkBoxInputMaps() public static class BigWarpData< T > { - public final List< SourceAndConverter< T > > sources; + // TODO JOHN CHECK ME + public List< SourceAndConverter< T > > sources; public final List< ConverterSetup > converterSetups; public final CacheControl cache; - public int[] movingSourceIndices; - - public int[] targetSourceIndices; +// public int[] movingSourceIndices; +// +// public int[] targetSourceIndices; - public final ArrayList< Integer > movingSourceIndexList; + public final List< Integer > movingSourceIndexList; - public final ArrayList< Integer > targetSourceIndexList; + public final List< Integer > targetSourceIndexList; + + public final HashMap< SourceAndConverter, Boolean > isMovingMap; public final HashMap< Integer, ColorSettings > setupSettings; public final HashMap< SourceAndConverter, ColorSettings > sourceColorSettings; - public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, final CacheControl cache, int[] movingSourceIndices, int[] targetSourceIndices ) + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + final CacheControl cache, + final int[] movingIndexes, + final int[] targetIndexes ) + { + this( sources, converterSetups, cache, + listOf( movingIndexes ), + listOf( targetIndexes )); + } + + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + final CacheControl cache ) { this.sources = sources; this.converterSetups = converterSetups; - this.movingSourceIndices = movingSourceIndices; - this.targetSourceIndices = targetSourceIndices; this.movingSourceIndexList = new ArrayList<>(); this.targetSourceIndexList = new ArrayList<>(); - + isMovingMap = new HashMap<>(); if ( cache == null ) this.cache = new CacheControl.Dummy(); @@ -2454,13 +2484,103 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, final List< C sourceColorSettings = new HashMap<>(); } - public void wrapUp() + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + final CacheControl cache, + final List movingIndexes, + final List targetIndexes ) + { + this.sources = sources; + this.converterSetups = converterSetups; +// this.movingSourceIndices = movingSourceIndices; +// this.targetSourceIndices = targetSourceIndices; + + this.movingSourceIndexList = movingIndexes; + this.targetSourceIndexList = targetIndexes; + isMovingMap = new HashMap<>(); + updateIsMovingMap(); + + if ( cache == null ) + this.cache = new CacheControl.Dummy(); + else + this.cache = cache; + + setupSettings = new HashMap<>(); + sourceColorSettings = new HashMap<>(); + } + + private void updateIsMovingMap() { - movingSourceIndices = movingSourceIndexList.stream().mapToInt( x -> x ).toArray(); - targetSourceIndices = targetSourceIndexList.stream().mapToInt( x -> x ).toArray(); + isMovingMap.clear(); + for( Integer i : movingSourceIndexList ) + isMovingMap.put( sources.get( i ), true ); - Arrays.sort( movingSourceIndices ); - Arrays.sort( targetSourceIndices ); + for( Integer i : targetSourceIndexList ) + isMovingMap.put( sources.get( i ), false ); + } + + private static ArrayList listOf( int[] x ) + { + final ArrayList< Integer > out = new ArrayList(); + for( int i : x ) + out.add( i ); + + return out; + } + + public int numMovingSources() + { + return movingSourceIndexList.size(); + } + + public SourceAndConverter< T > getMovingSource( int i ) + { + return sources.get( movingSourceIndexList.get( i ) ); + } + + public int numTargetSources() + { + return targetSourceIndexList.size(); + } + + public SourceAndConverter< T > getTargetSource( int i ) + { + return sources.get( targetSourceIndexList.get( i ) ); + } + + public List getMovingConverterSetups() + { + final ArrayList out = new ArrayList<>(); + for( int i : movingSourceIndexList ) + out.add( converterSetups.get( i ) ); + + return out; + } + + public List getTargetConverterSetups() + { + final ArrayList out = new ArrayList<>(); + for( int i : targetSourceIndexList ) + out.add( converterSetups.get( i ) ); + + return out; + } + + public boolean isMoving( SourceAndConverter sac ) { + if( !isMovingMap.containsKey( sac )) + return false; + else + return isMovingMap.get( sac ); + } + + public void wrapUp() + { +// movingSourceIndices = movingSourceIndexList.stream().mapToInt( x -> x ).toArray(); +// targetSourceIndices = targetSourceIndexList.stream().mapToInt( x -> x ).toArray(); +// +// Arrays.sort( movingSourceIndices ); +// Arrays.sort( targetSourceIndices ); + Collections.sort( movingSourceIndexList ); + Collections.sort( targetSourceIndexList ); } /** diff --git a/src/main/java/bigwarp/BigWarpARGBExporter.java b/src/main/java/bigwarp/BigWarpARGBExporter.java index 168f0bcf..10ca4f8d 100644 --- a/src/main/java/bigwarp/BigWarpARGBExporter.java +++ b/src/main/java/bigwarp/BigWarpARGBExporter.java @@ -56,21 +56,31 @@ import bdv.viewer.ConverterSetups; import bdv.viewer.Interpolation; import bdv.viewer.SourceAndConverter; +import bigwarp.BigWarp.BigWarpData; public class BigWarpARGBExporter extends BigWarpExporter { private Interpolation interp; +// public BigWarpARGBExporter( +// final List< SourceAndConverter< ARGBType >> sources, +// final List< ConverterSetup > convSetups, +// final int[] movingSourceIndexList, +// final int[] targetSourceIndexList, +// final Interpolation interp, +// final ProgressWriter progress ) +// { +// super( sources, convSetups, movingSourceIndexList, targetSourceIndexList, interp, progress ); +// } + public BigWarpARGBExporter( - final List< SourceAndConverter< ARGBType >> sources, + BigWarpData bwData, final List< ConverterSetup > convSetups, - final int[] movingSourceIndexList, - final int[] targetSourceIndexList, final Interpolation interp, final ProgressWriter progress ) { - super( sources, convSetups, movingSourceIndexList, targetSourceIndexList, interp, progress ); + super( bwData, convSetups, interp, progress ); } /** @@ -106,7 +116,7 @@ public RandomAccessibleInterval< ARGBType > exportRai() buildTotalRenderTransform(); - int numChannels = movingSourceIndexList.length; + final int numChannels = bwData.numMovingSources(); VoxelDimensions voxdim = new FinalVoxelDimensions( unit, resolutionTransform.get( 0, 0 ), resolutionTransform.get( 1, 1 ), @@ -114,8 +124,7 @@ public RandomAccessibleInterval< ARGBType > exportRai() for ( int i = 0; i < numChannels; i++ ) { - int movingSourceIndex = movingSourceIndexList[ i ]; - final RealRandomAccessible< ARGBType > raiRaw = ( RealRandomAccessible< ARGBType > )sources.get( movingSourceIndex ).getSpimSource().getInterpolatedSource( 0, 0, interp ); + final RealRandomAccessible< ARGBType > raiRaw = ( RealRandomAccessible< ARGBType > )bwData.getMovingSource( i ).getSpimSource().getInterpolatedSource( 0, 0, interp ); // apply the transformations final AffineRandomAccessible< ARGBType, AffineGet > rai = RealViews.affine( @@ -132,7 +141,7 @@ public ImagePlus export() { buildTotalRenderTransform(); - int numChannels = movingSourceIndexList.length; + final int numChannels = bwData.numMovingSources(); VoxelDimensions voxdim = new FinalVoxelDimensions( unit, resolutionTransform.get( 0, 0 ), resolutionTransform.get( 1, 1 ), @@ -193,8 +202,8 @@ else if ( outputInterval.numDimensions() == 2 ) ip.getCalibration().yOrigin = offsetTransform.get( 1, 3 ); ip.getCalibration().zOrigin = offsetTransform.get( 2, 3 ); } - - ip.setTitle( sources.get( movingSourceIndexList[ 0 ]).getSpimSource().getName() + nameSuffix ); + + ip.setTitle( bwData.getMovingSource( 0 ).getSpimSource().getName() + nameSuffix ); return ip; } diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 372a25e6..50ce7a6e 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -547,21 +547,20 @@ public void actionPerformed( ActionEvent e ) bw.viewerQ.state().getViewerTransform( xfm ); System.out.println( "tgt xfm " + xfm + " DET = " + BigWarpUtils.det( xfm )); - BigWarpData< ? > data = bw.getData(); - for( int mi : data.movingSourceIndices ) - { - ((SourceAndConverter)data.sources.get( mi )).getSpimSource().getSourceTransform( 0, 0, xfm ); - System.out.println( "mvg src xfm " + xfm ); - } - - for( int ti : data.targetSourceIndices ) - { - ((SourceAndConverter)data.sources.get( ti )).getSpimSource().getSourceTransform( 0, 0, xfm ); - System.out.println( "tgt src xfm " + xfm ); - } - - - System.out.println( " " ); +// BigWarpData< ? > data = bw.getData(); +// for( int mi : data.movingSourceIndices ) +// { +// ((SourceAndConverter)data.sources.get( mi )).getSpimSource().getSourceTransform( 0, 0, xfm ); +// System.out.println( "mvg src xfm " + xfm ); +// } +// +// for( int ti : data.targetSourceIndices ) +// { +// ((SourceAndConverter)data.sources.get( ti )).getSpimSource().getSourceTransform( 0, 0, xfm ); +// System.out.println( "tgt src xfm " + xfm ); +// } +// +// System.out.println( " " ); } } diff --git a/src/main/java/bigwarp/BigWarpBatchTransformFOV.java b/src/main/java/bigwarp/BigWarpBatchTransformFOV.java index b25db515..87c9b226 100644 --- a/src/main/java/bigwarp/BigWarpBatchTransformFOV.java +++ b/src/main/java/bigwarp/BigWarpBatchTransformFOV.java @@ -69,12 +69,6 @@ import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; -import net.imglib2.type.numeric.ARGBType; -import net.imglib2.type.numeric.integer.ByteType; -import net.imglib2.type.numeric.integer.IntType; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.type.numeric.integer.UnsignedShortType; -import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.util.ConstantUtils; @@ -339,8 +333,6 @@ public static < T > BigWarpExporter< T > applyBigWarpHelper( AbstractSpimData< ? movingSourceIndexList[ i ] = i; } - int[] targetSourceIndexList = data.targetSourceIndices; - @SuppressWarnings("unchecked") List< SourceAndConverter< T >> sourcesxfm = BigWarp.wrapSourcesAsTransformed( data.sources, diff --git a/src/main/java/bigwarp/BigWarpExporter.java b/src/main/java/bigwarp/BigWarpExporter.java index 2bd86303..994fee69 100644 --- a/src/main/java/bigwarp/BigWarpExporter.java +++ b/src/main/java/bigwarp/BigWarpExporter.java @@ -79,9 +79,10 @@ public abstract class BigWarpExporter private List< ImagePlus > outputList; - final protected int[] movingSourceIndexList; - - final protected int[] targetSourceIndexList; +// final protected int[] movingSourceIndexList; +// +// final protected int[] targetSourceIndexList; + protected final BigWarpData bwData; protected AffineTransform3D pixelRenderToPhysical; @@ -119,17 +120,68 @@ public enum ParallelizationPolicy { private String exportPath; +// public BigWarpExporter( +// final List< SourceAndConverter< T >> sourcesIn, +// final List< ConverterSetup > convSetups, +// final int[] movingSourceIndexList, +// final int[] targetSourceIndexList, +// final Interpolation interp, +// final ProgressWriter progress ) +// { +// this.sources = new ArrayList>(); +// this.convSetups = convSetups; +// for( SourceAndConverter sac : sourcesIn ) +// { +// Source srcCopy = null; +// Source src = sac.getSpimSource(); +// if( src instanceof WarpedSource ) +// { +// WarpedSource ws = (WarpedSource)( sac.getSpimSource() ); +// WarpedSource wsCopy = new WarpedSource<>( ws.getWrappedSource(), ws.getName() ) ; +// +// if( ws.getTransform() != null ) +// { +// wsCopy.updateTransform( ws.getTransform().copy() ); +// wsCopy.setIsTransformed( true ); +// } +// srcCopy = wsCopy; +// } +// else +// srcCopy = src; +// +// SourceAndConverter copy = new SourceAndConverter<>( srcCopy, sac.getConverter() ); +// sources.add( copy ); +// } +// +// this.movingSourceIndexList = movingSourceIndexList; +// this.targetSourceIndexList = targetSourceIndexList; +// +// if( progress == null ) +// this.progress = new ProgressWriterConsole(); +// else +// this.progress = progress; +// +// this.setInterp( interp ); +// +// pixelRenderToPhysical = new AffineTransform3D(); +// resolutionTransform = new AffineTransform3D(); +// offsetTransform = new AffineTransform3D(); +// +// try { +// unit = sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getVoxelDimensions().unit(); +// } catch( Exception e ) {} +// } + public BigWarpExporter( - final List< SourceAndConverter< T >> sourcesIn, + BigWarpData bwData, final List< ConverterSetup > convSetups, - final int[] movingSourceIndexList, - final int[] targetSourceIndexList, final Interpolation interp, final ProgressWriter progress ) { + this.bwData = bwData; this.sources = new ArrayList>(); this.convSetups = convSetups; - for( SourceAndConverter sac : sourcesIn ) + for( SourceAndConverter sac : bwData.sources ) { Source srcCopy = null; Source src = sac.getSpimSource(); @@ -152,9 +204,6 @@ public BigWarpExporter( sources.add( copy ); } - this.movingSourceIndexList = movingSourceIndexList; - this.targetSourceIndexList = targetSourceIndexList; - if( progress == null ) this.progress = new ProgressWriterConsole(); else @@ -167,7 +216,7 @@ public BigWarpExporter( offsetTransform = new AffineTransform3D(); try { - unit = sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getVoxelDimensions().unit(); + unit = bwData.getTargetSource( 0 ).getSpimSource().getVoxelDimensions().unit(); } catch( Exception e ) {} } @@ -285,6 +334,22 @@ public static void updateBrightnessContrast( imp.updateAndDraw(); } } + + public static void updateBrightnessContrast( + final ImagePlus imp, + final List convSetups) + { + for( int i = 0; i < convSetups.size(); i++ ) + { + final ConverterSetup setup = convSetups.get( i ); + double rngmin = setup.getDisplayRangeMin(); + double rngmax = setup.getDisplayRangeMax(); + + imp.setC( i + 1 ); // ImagePlus.setC is one-indexed + imp.setDisplayRange( rngmin, rngmax ); + imp.updateAndDraw(); + } + } public static void updateBrightnessContrast( final ImagePlus imp, @@ -808,7 +873,7 @@ public void run() if (exporter.result != null && exporter.showResult && show ) { if( !exporter.isRGB() ) - BigWarpExporter.updateBrightnessContrast( exporter.result, exporter.convSetups, exporter.movingSourceIndexList ); + BigWarpExporter.updateBrightnessContrast( exporter.result, exporter.bwData.getMovingConverterSetups() ); } @@ -839,17 +904,17 @@ public static BigWarpExporter getExporter( final Interpolation interp, final ProgressWriter progressWriter ) { - int[] movingSourceIndexList = bwData.movingSourceIndices; - int[] targetSourceIndexList = bwData.targetSourceIndices; + List movingSourceIndexList = bwData.movingSourceIndexList; +// List targetSourceIndexList = bwData.targetSourceIndexList; if ( BigWarpRealExporter.isTypeListFullyConsistent( transformedSources, movingSourceIndexList ) ) { - Object baseType = transformedSources.get( movingSourceIndexList[ 0 ] ).getSpimSource().getType(); + Object baseType = transformedSources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getType(); if( baseType instanceof RealType ) - return new BigWarpRealExporter( transformedSources, bwData.converterSetups, movingSourceIndexList, targetSourceIndexList, interp, (RealType)baseType, progressWriter); + return new BigWarpRealExporter( bwData, bwData.converterSetups, interp, (RealType)baseType, progressWriter); else if ( ARGBType.class.isInstance( baseType ) ) { - return new BigWarpARGBExporter( (List)transformedSources, bwData.converterSetups, movingSourceIndexList, targetSourceIndexList, interp, progressWriter ); + return new BigWarpARGBExporter( (BigWarpData)bwData, bwData.converterSetups, interp, progressWriter ); } else { diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 81464eb7..421bc677 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -24,6 +24,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer; import org.janelia.saalfeldlab.n5.N5Reader; @@ -317,7 +319,9 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > data.wrapUp(); - if ( names != null ) { return new BigWarpData( wrapSourcesAsRenamable( data.sources, names ), data.converterSetups, data.cache, data.movingSourceIndices, data.targetSourceIndices ); } + if ( names != null ) { return new BigWarpData( + wrapSourcesAsRenamable( data.sources, names ), data.converterSetups, data.cache, + data.movingSourceIndexList, data.targetSourceIndexList ); } return data; } @@ -558,7 +562,7 @@ public static < T > BigWarpData< T > initData() final ArrayList< ConverterSetup > converterSetups = new ArrayList< ConverterSetup >(); final ArrayList< SourceAndConverter< T > > sources = new ArrayList< SourceAndConverter< T > >(); - return new BigWarpData( sources, converterSetups, null, null, null ); + return new BigWarpData( sources, converterSetups, null ); } /** @@ -721,6 +725,10 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source int[] movingSourceIndices = ImagePlusLoader.range( 0, numMovingSources ); int[] targetSourceIndices = ImagePlusLoader.range( numMovingSources, numTargetSources ); +// List movingSourceIndices = IntStream.range( 0, numMovingSources ).collect( Collectors.toList()); +// List targetSourceIndices = IntStream.range( numMovingSources, numTargetSources + numMovingSources ) +// .collect( Collectors.toList()); + /* Load the second source */ BigWarpInit.initSetups( spimDataQ, converterSetups, sources ); diff --git a/src/main/java/bigwarp/BigWarpRealExporter.java b/src/main/java/bigwarp/BigWarpRealExporter.java index 84f83c4f..2c205b15 100644 --- a/src/main/java/bigwarp/BigWarpRealExporter.java +++ b/src/main/java/bigwarp/BigWarpRealExporter.java @@ -28,6 +28,7 @@ import bdv.tools.brightness.ConverterSetup; import bdv.viewer.Interpolation; import bdv.viewer.SourceAndConverter; +import bigwarp.BigWarp.BigWarpData; import ij.IJ; import ij.ImagePlus; import mpicbg.spim.data.sequence.FinalVoxelDimensions; @@ -59,29 +60,25 @@ public class BigWarpRealExporter< T extends RealType< T > & NativeType< T > > e final private T baseType; public BigWarpRealExporter( - final List< SourceAndConverter< T >> sources, + final BigWarpData bwData, final List< ConverterSetup > convSetups, - final int[] movingSourceIndexList, - final int[] targetSourceIndexList, final Interpolation interp, final T baseType, final boolean needConversion, final ProgressWriter progress ) { - super( sources, convSetups, movingSourceIndexList, targetSourceIndexList, interp, progress ); + super( bwData, convSetups, interp, progress ); this.baseType = baseType; } public BigWarpRealExporter( - final List< SourceAndConverter< T >> sources, + final BigWarpData bwData, final List< ConverterSetup > convSetups, - final int[] movingSourceIndexList, - final int[] targetSourceIndexList, final Interpolation interp, final T baseType, final ProgressWriter progress ) { - this( sources, convSetups, movingSourceIndexList, targetSourceIndexList, interp, baseType, false, progress ); + this( bwData, convSetups, interp, baseType, false, progress ); } /** @@ -108,19 +105,43 @@ public static boolean isTypeListFullyConsistent( List< SourceAndConverter< T return true; } + /** + * Returns true if moving image sources are all of the same type. + * + * @param sources the sources + * @param the type + * @param movingSourceIndexList list of indexes for moving sources + * @return true if all moving sources are of the same type + */ + public static boolean isTypeListFullyConsistent( List< SourceAndConverter< T >> sources, List movingSourceIndexList ) + { + Object baseType = sources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getType(); + + for ( int i = 1; i < movingSourceIndexList.size(); i++ ) + { + int idx = movingSourceIndexList.get( i ); + Object type = sources.get( idx ).getSpimSource().getType(); + + if ( !baseType.getClass().equals( type.getClass() ) ) + return false; + } + + return true; + } + @Override public RandomAccessibleInterval< T > exportRai() { + System.out.println( "RealExporter.exportRai"); ArrayList< RandomAccessibleInterval< T > > raiList = new ArrayList< RandomAccessibleInterval< T > >(); buildTotalRenderTransform(); - final int numChannels = movingSourceIndexList.length; + final int numChannels = bwData.numMovingSources(); for ( int i = 0; i < numChannels; i++ ) { - final int movingSourceIndex = movingSourceIndexList[ i ]; - - final RealRandomAccessible< T > raiRaw = ( RealRandomAccessible< T > )sources.get( movingSourceIndex ).getSpimSource().getInterpolatedSource( 0, 0, interp ); + SourceAndConverter< T > msrcTmp = bwData.getMovingSource( i ); + final RealRandomAccessible< T > raiRaw = ( RealRandomAccessible< T > ) bwData.getMovingSource( i ).getSpimSource().getInterpolatedSource( 0, 0, interp ); // apply the transformations final AffineRandomAccessible< T, AffineGet > rai = RealViews.affine( @@ -142,7 +163,7 @@ public boolean isRGB() @SuppressWarnings("unchecked") public ImagePlus export() { - int numChannels = movingSourceIndexList.length; + final int numChannels = bwData.numMovingSources(); RandomAccessibleInterval< T > raiStack = exportRai(); VoxelDimensions voxdim = new FinalVoxelDimensions( unit, @@ -209,7 +230,8 @@ else if ( outputInterval.numDimensions() == 2 ) ip.getCalibration().zOrigin = offsetTransform.get( 2, 3 ); } - ip.setTitle( sources.get( movingSourceIndexList[ 0 ]).getSpimSource().getName() + nameSuffix ); +// ip.setTitle( sources.get( movingSourceIndexList[ 0 ]).getSpimSource().getName() + nameSuffix ); + ip.setTitle( bwData.getMovingSource( 0 ).getSpimSource().getName() + nameSuffix ); return ip; } diff --git a/src/main/java/bigwarp/SourceInfoDialog.java b/src/main/java/bigwarp/SourceInfoDialog.java index 3b306281..6cd1e124 100644 --- a/src/main/java/bigwarp/SourceInfoDialog.java +++ b/src/main/java/bigwarp/SourceInfoDialog.java @@ -58,9 +58,9 @@ public SourceInfoDialog( final Frame owner, final BigWarpData< ? > bwData ) final StringBuffer infoString = new StringBuffer(); infoString.append( "MOVING:\n" ); - for ( int i = 0; i < bwData.movingSourceIndices.length; i++ ) + for ( int i = 0; i < bwData.movingSourceIndexList.size(); i++ ) { - SourceAndConverter< ? > src = bwData.sources.get( bwData.movingSourceIndices[ i ]); + SourceAndConverter< ? > src = bwData.sources.get( bwData.movingSourceIndexList.get( i )); final String name = src.getSpimSource().getName(); if( name.equals( "WarpMagnitudeSource" ) || name.equals( "JacobianDeterminantSource" ) || @@ -73,9 +73,9 @@ public SourceInfoDialog( final Frame owner, final BigWarpData< ? > bwData ) } infoString.append( "\nTARGET:\n" ); - for ( int i = 0; i < bwData.targetSourceIndices.length; i++ ) + for ( int i = 0; i < bwData.targetSourceIndexList.size(); i++ ) { - SourceAndConverter< ? > src = bwData.sources.get( bwData.targetSourceIndices[ i ]); + SourceAndConverter< ? > src = bwData.sources.get( bwData.targetSourceIndexList.get( i )); final String name = src.getSpimSource().getName(); if( name.equals( "WarpMagnitudeSource" ) || name.equals( "JacobianDeterminantSource" ) || diff --git a/src/main/java/bigwarp/source/GridSource.java b/src/main/java/bigwarp/source/GridSource.java index c626610c..09b0e862 100644 --- a/src/main/java/bigwarp/source/GridSource.java +++ b/src/main/java/bigwarp/source/GridSource.java @@ -78,7 +78,8 @@ private static AffineTransform3D getSourceTransform( BigWarpData data ) private static Interval getInterval( BigWarpData data ) { // return new FinalInterval( data.sources.get( data.targetSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 )); - return new FinalInterval( data.sources.get( data.movingSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 )); +// return new FinalInterval( data.sources.get( data.movingSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 )); + return new FinalInterval( data.getMovingSource( 0 ).getSpimSource().getSource( 0, 0 )); } public void setGridSpacing( double spacing ) @@ -143,7 +144,8 @@ public String getName() @Override public VoxelDimensions getVoxelDimensions() { - return sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getVoxelDimensions(); +// return sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getVoxelDimensions(); + return sourceData.getTargetSource( 0 ).getSpimSource().getVoxelDimensions(); } @Override diff --git a/src/main/java/bigwarp/source/JacobianDeterminantSource.java b/src/main/java/bigwarp/source/JacobianDeterminantSource.java index 6a692458..bc425c4f 100644 --- a/src/main/java/bigwarp/source/JacobianDeterminantSource.java +++ b/src/main/java/bigwarp/source/JacobianDeterminantSource.java @@ -27,8 +27,6 @@ import bdv.viewer.Source; import bigwarp.BigWarp.BigWarpData; import bigwarp.landmarks.LandmarkTableModel; -import jitk.spline.ThinPlateR2LogRSplineKernelTransform; -import mpicbg.models.AbstractModel; import mpicbg.spim.data.sequence.FinalVoxelDimensions; import mpicbg.spim.data.sequence.VoxelDimensions; import net.imglib2.Cursor; @@ -37,7 +35,6 @@ import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; import net.imglib2.realtransform.AffineTransform3D; -import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.inverse.DifferentiableRealTransform; import net.imglib2.type.numeric.RealType; import net.imglib2.view.Views; @@ -64,9 +61,11 @@ public JacobianDeterminantSource( String name, BigWarpData data, T t ) sourceData = data; //RandomAccessibleInterval fixedsrc = sourceData.sources.get( 1 ).getSpimSource().getSource( 0, 0 ); - interval = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 ); +// interval = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 ); + interval = sourceData.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ); - VoxelDimensions srcVoxDims = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getVoxelDimensions(); +// VoxelDimensions srcVoxDims = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getVoxelDimensions(); + VoxelDimensions srcVoxDims = sourceData.getTargetSource( 0 ).getSpimSource().getVoxelDimensions(); String unit = "pix"; if( srcVoxDims != null ) unit = srcVoxDims.unit(); diff --git a/src/main/java/bigwarp/source/WarpMagnitudeSource.java b/src/main/java/bigwarp/source/WarpMagnitudeSource.java index 67915613..ff97728b 100644 --- a/src/main/java/bigwarp/source/WarpMagnitudeSource.java +++ b/src/main/java/bigwarp/source/WarpMagnitudeSource.java @@ -60,8 +60,11 @@ public WarpMagnitudeSource( String name, BigWarpData data, T t ) sourceData = data; - interval = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 ); - VoxelDimensions srcVoxDims = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getVoxelDimensions(); +// interval = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 ); + interval = sourceData.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ); + +// VoxelDimensions srcVoxDims = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getVoxelDimensions(); + final VoxelDimensions srcVoxDims = sourceData.getTargetSource( 0 ).getSpimSource().getVoxelDimensions(); String unit = "pix"; if( srcVoxDims != null ) unit = srcVoxDims.unit(); diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 4b93da12..fb478e35 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -487,14 +487,15 @@ else if( r == c ) public void initializeInverseParameters( BigWarpData bwData ) { - int N = bwData.targetSourceIndices.length; + final int N = bwData.numTargetSources(); double val; double highestResDim = 0; for( int i = 0; i < N; i++ ) { - SourceAndConverter< ? > src = bwData.sources.get( bwData.targetSourceIndices[ i ]); +// SourceAndConverter< ? > src = bwData.sources.get( bwData.targetSourceIndices[ i ]); + final SourceAndConverter< ? > src = bwData.getTargetSource( i ); final String name = src.getSpimSource().getName(); if( name.equals( "WarpMagnitudeSource" ) || From 20fdfe2a83bff7edf79bf95efe257a9732d8c20b Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 4 Nov 2022 13:24:30 -0400 Subject: [PATCH 078/282] refactor: move BigWarpData to its own file --- .../gui/BigwarpLandmarkSelectionPanel.java | 2 +- src/main/java/bdv/ij/ApplyBigwarpPlugin.java | 2 +- src/main/java/bdv/ij/BigWarpBdvCommand.java | 3 +- .../java/bdv/ij/BigWarpImagePlusPlugIn.java | 2 +- src/main/java/bigwarp/BigWarp.java | 188 ---------------- .../java/bigwarp/BigWarpARGBExporter.java | 8 - src/main/java/bigwarp/BigWarpActions.java | 2 - .../bigwarp/BigWarpBatchTransformFOV.java | 1 - src/main/java/bigwarp/BigWarpData.java | 206 ++++++++++++++++++ src/main/java/bigwarp/BigWarpExporter.java | 1 - src/main/java/bigwarp/BigWarpInit.java | 1 - .../java/bigwarp/BigWarpRealExporter.java | 1 - src/main/java/bigwarp/SourceInfoDialog.java | 1 - .../java/bigwarp/loader/ImagePlusLoader.java | 2 +- src/main/java/bigwarp/source/GridSource.java | 3 +- .../source/JacobianDeterminantSource.java | 2 +- .../bigwarp/source/WarpMagnitudeSource.java | 2 +- .../bigwarp/transforms/BigWarpTransform.java | 2 +- src/test/java/bigwarp/SourceTest.java | 1 - src/test/java/bigwarp/Sources2Dtests.java | 2 +- .../java/bigwarp/TransformPoints2DTest.java | 4 +- src/test/java/bigwarp/TransformTests.java | 1 - 22 files changed, 218 insertions(+), 219 deletions(-) create mode 100644 src/main/java/bigwarp/BigWarpData.java diff --git a/src/main/java/bdv/gui/BigwarpLandmarkSelectionPanel.java b/src/main/java/bdv/gui/BigwarpLandmarkSelectionPanel.java index 4c61ae62..8a7b6e6c 100644 --- a/src/main/java/bdv/gui/BigwarpLandmarkSelectionPanel.java +++ b/src/main/java/bdv/gui/BigwarpLandmarkSelectionPanel.java @@ -45,7 +45,7 @@ import bdv.ij.ApplyBigwarpPlugin.WriteDestinationOptions; import bdv.viewer.Interpolation; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import net.imglib2.Interval; public class BigwarpLandmarkSelectionPanel extends JPanel diff --git a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java index 9d63ea88..a316abb0 100644 --- a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java +++ b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java @@ -52,7 +52,7 @@ import bdv.viewer.Interpolation; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import bigwarp.BigWarp; import bigwarp.BigWarpExporter; import bigwarp.BigWarpInit; diff --git a/src/main/java/bdv/ij/BigWarpBdvCommand.java b/src/main/java/bdv/ij/BigWarpBdvCommand.java index 34cd2c6e..91ad4c62 100755 --- a/src/main/java/bdv/ij/BigWarpBdvCommand.java +++ b/src/main/java/bdv/ij/BigWarpBdvCommand.java @@ -23,6 +23,7 @@ import bdv.ij.util.ProgressWriterIJ; import bigwarp.BigWarp; +import bigwarp.BigWarpData; import bigwarp.BigWarpInit; import mpicbg.spim.data.SpimData; import mpicbg.spim.data.SpimDataException; @@ -61,7 +62,7 @@ public void run() final SpimData fixedSpimData = new XmlIoSpimData().load( fixedImageXml.getAbsolutePath() ); final SpimData movingSpimData = new XmlIoSpimData().load( movingImageXml.getAbsolutePath() ); new RepeatingReleasedEventsFixer().install(); - final BigWarp.BigWarpData< ? > bigWarpData = BigWarpInit.createBigWarpData( movingSpimData, fixedSpimData ); + final BigWarpData< ? > bigWarpData = BigWarpInit.createBigWarpData( movingSpimData, fixedSpimData ); bw = new BigWarp( bigWarpData, "Big Warp", new ProgressWriterIJ() ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); diff --git a/src/main/java/bdv/ij/BigWarpImagePlusPlugIn.java b/src/main/java/bdv/ij/BigWarpImagePlusPlugIn.java index 564a1ac0..ae97e441 100755 --- a/src/main/java/bdv/ij/BigWarpImagePlusPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpImagePlusPlugIn.java @@ -28,7 +28,7 @@ import bdv.ij.util.ProgressWriterIJ; import bigwarp.BigWarp; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import bigwarp.BigWarpInit; import fiji.util.gui.GenericDialogPlus; import ij.IJ; diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 3981b65c..0889ee00 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2432,194 +2432,6 @@ public void checkBoxInputMaps() // SwingUtilities.replaceUIInputMap( getRootPane(), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keybindings.getConcatenatedInputMap() ); } - public static class BigWarpData< T > - { - // TODO JOHN CHECK ME - public List< SourceAndConverter< T > > sources; - - public final List< ConverterSetup > converterSetups; - - public final CacheControl cache; - -// public int[] movingSourceIndices; -// -// public int[] targetSourceIndices; - - public final List< Integer > movingSourceIndexList; - - public final List< Integer > targetSourceIndexList; - - public final HashMap< SourceAndConverter, Boolean > isMovingMap; - - public final HashMap< Integer, ColorSettings > setupSettings; - - public final HashMap< SourceAndConverter, ColorSettings > sourceColorSettings; - - public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, - final CacheControl cache, - final int[] movingIndexes, - final int[] targetIndexes ) - { - this( sources, converterSetups, cache, - listOf( movingIndexes ), - listOf( targetIndexes )); - } - - public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, - final CacheControl cache ) - { - this.sources = sources; - this.converterSetups = converterSetups; - - this.movingSourceIndexList = new ArrayList<>(); - this.targetSourceIndexList = new ArrayList<>(); - isMovingMap = new HashMap<>(); - - if ( cache == null ) - this.cache = new CacheControl.Dummy(); - else - this.cache = cache; - - setupSettings = new HashMap<>(); - sourceColorSettings = new HashMap<>(); - } - - public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, - final CacheControl cache, - final List movingIndexes, - final List targetIndexes ) - { - this.sources = sources; - this.converterSetups = converterSetups; -// this.movingSourceIndices = movingSourceIndices; -// this.targetSourceIndices = targetSourceIndices; - - this.movingSourceIndexList = movingIndexes; - this.targetSourceIndexList = targetIndexes; - isMovingMap = new HashMap<>(); - updateIsMovingMap(); - - if ( cache == null ) - this.cache = new CacheControl.Dummy(); - else - this.cache = cache; - - setupSettings = new HashMap<>(); - sourceColorSettings = new HashMap<>(); - } - - private void updateIsMovingMap() - { - isMovingMap.clear(); - for( Integer i : movingSourceIndexList ) - isMovingMap.put( sources.get( i ), true ); - - for( Integer i : targetSourceIndexList ) - isMovingMap.put( sources.get( i ), false ); - } - - private static ArrayList listOf( int[] x ) - { - final ArrayList< Integer > out = new ArrayList(); - for( int i : x ) - out.add( i ); - - return out; - } - - public int numMovingSources() - { - return movingSourceIndexList.size(); - } - - public SourceAndConverter< T > getMovingSource( int i ) - { - return sources.get( movingSourceIndexList.get( i ) ); - } - - public int numTargetSources() - { - return targetSourceIndexList.size(); - } - - public SourceAndConverter< T > getTargetSource( int i ) - { - return sources.get( targetSourceIndexList.get( i ) ); - } - - public List getMovingConverterSetups() - { - final ArrayList out = new ArrayList<>(); - for( int i : movingSourceIndexList ) - out.add( converterSetups.get( i ) ); - - return out; - } - - public List getTargetConverterSetups() - { - final ArrayList out = new ArrayList<>(); - for( int i : targetSourceIndexList ) - out.add( converterSetups.get( i ) ); - - return out; - } - - public boolean isMoving( SourceAndConverter sac ) { - if( !isMovingMap.containsKey( sac )) - return false; - else - return isMovingMap.get( sac ); - } - - public void wrapUp() - { -// movingSourceIndices = movingSourceIndexList.stream().mapToInt( x -> x ).toArray(); -// targetSourceIndices = targetSourceIndexList.stream().mapToInt( x -> x ).toArray(); -// -// Arrays.sort( movingSourceIndices ); -// Arrays.sort( targetSourceIndices ); - Collections.sort( movingSourceIndexList ); - Collections.sort( targetSourceIndexList ); - } - - /** - * @deprecated - */ - public void transferChannelSettings( final SetupAssignments setupAssignments, final VisibilityAndGrouping visibility ) - { - for( Integer key : setupSettings.keySet() ) - setupSettings.get( key ).updateSetup( setupAssignments ); - } - - public void transferChannelSettings( final BigWarpViewerFrame viewer ) - { - SynchronizedViewerState state = viewer.getViewerPanel().state(); - ConverterSetups setups = viewer.getConverterSetups(); - synchronized ( state ) - { - for ( SourceAndConverter< ? > sac : state.getSources() ) - { - if ( sourceColorSettings.containsKey( sac ) ) - { - if ( sourceColorSettings.get( sac ) == null ) - continue; - - sourceColorSettings.get( sac ).updateSetup( setups.getConverterSetup( sac ) ); - } - else - { - final int timepoint = state.getCurrentTimepoint(); - final Bounds bounds = InitializeViewerState.estimateSourceRange( sac.getSpimSource(), timepoint, 0.001, 0.999 ); - ConverterSetup cs = setups.getConverterSetup(sac); - if( cs != null ) - cs.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); - } - } - } - } - } - protected class LandmarkModeListener implements KeyEventPostProcessor { @Override diff --git a/src/main/java/bigwarp/BigWarpARGBExporter.java b/src/main/java/bigwarp/BigWarpARGBExporter.java index 10ca4f8d..f653abe6 100644 --- a/src/main/java/bigwarp/BigWarpARGBExporter.java +++ b/src/main/java/bigwarp/BigWarpARGBExporter.java @@ -29,14 +29,11 @@ import java.util.ArrayList; import java.util.List; -import org.janelia.saalfeldlab.n5.ij.N5IJUtils; - import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RandomAccess; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; -import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; import net.imglib2.exception.ImgLibException; import net.imglib2.img.display.imagej.ImageJFunctions; @@ -44,19 +41,14 @@ import net.imglib2.img.imageplus.ImagePlusImgFactory; import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.AffineRandomAccessible; -import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.RealViews; -import net.imglib2.type.NativeType; import net.imglib2.type.numeric.ARGBType; -import net.imglib2.type.numeric.NumericType; import net.imglib2.view.MixedTransformView; import net.imglib2.view.Views; import bdv.export.ProgressWriter; import bdv.tools.brightness.ConverterSetup; -import bdv.viewer.ConverterSetups; import bdv.viewer.Interpolation; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; public class BigWarpARGBExporter extends BigWarpExporter { diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 50ce7a6e..07b0b31d 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -37,8 +37,6 @@ import bdv.gui.BigWarpViewerFrame; import bdv.tools.ToggleDialogAction; -import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; import bigwarp.landmarks.LandmarkGridGenerator; import bigwarp.source.GridSource; import bigwarp.util.BigWarpUtils; diff --git a/src/main/java/bigwarp/BigWarpBatchTransformFOV.java b/src/main/java/bigwarp/BigWarpBatchTransformFOV.java index 87c9b226..a275291b 100644 --- a/src/main/java/bigwarp/BigWarpBatchTransformFOV.java +++ b/src/main/java/bigwarp/BigWarpBatchTransformFOV.java @@ -42,7 +42,6 @@ import bdv.spimdata.WrapBasicImgLoader; import bdv.viewer.Interpolation; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; import bigwarp.BigWarpExporter.ExportThread; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.loader.ImagePlusLoader; diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java new file mode 100644 index 00000000..80cae95a --- /dev/null +++ b/src/main/java/bigwarp/BigWarpData.java @@ -0,0 +1,206 @@ +package bigwarp; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import bdv.cache.CacheControl; +import bdv.gui.BigWarpViewerFrame; +import bdv.tools.InitializeViewerState; +import bdv.tools.brightness.ConverterSetup; +import bdv.tools.brightness.SetupAssignments; +import bdv.util.Bounds; +import bdv.viewer.ConverterSetups; +import bdv.viewer.SourceAndConverter; +import bdv.viewer.SynchronizedViewerState; +import bdv.viewer.VisibilityAndGrouping; +import bigwarp.loader.ImagePlusLoader.ColorSettings; + +public class BigWarpData< T > +{ + // TODO JOHN CHECK ME + public List< SourceAndConverter< T > > sources; + + public final List< ConverterSetup > converterSetups; + + public final CacheControl cache; + +// public int[] movingSourceIndices; +// +// public int[] targetSourceIndices; + + public final List< Integer > movingSourceIndexList; + + public final List< Integer > targetSourceIndexList; + + public final HashMap< SourceAndConverter, Boolean > isMovingMap; + + public final HashMap< Integer, ColorSettings > setupSettings; + + public final HashMap< SourceAndConverter, ColorSettings > sourceColorSettings; + + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + final CacheControl cache, + final int[] movingIndexes, + final int[] targetIndexes ) + { + this( sources, converterSetups, cache, + listOf( movingIndexes ), + listOf( targetIndexes )); + } + + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + final CacheControl cache ) + { + this.sources = sources; + this.converterSetups = converterSetups; + + this.movingSourceIndexList = new ArrayList<>(); + this.targetSourceIndexList = new ArrayList<>(); + isMovingMap = new HashMap<>(); + + if ( cache == null ) + this.cache = new CacheControl.Dummy(); + else + this.cache = cache; + + setupSettings = new HashMap<>(); + sourceColorSettings = new HashMap<>(); + } + + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + final CacheControl cache, + final List movingIndexes, + final List targetIndexes ) + { + this.sources = sources; + this.converterSetups = converterSetups; +// this.movingSourceIndices = movingSourceIndices; +// this.targetSourceIndices = targetSourceIndices; + + this.movingSourceIndexList = movingIndexes; + this.targetSourceIndexList = targetIndexes; + isMovingMap = new HashMap<>(); + updateIsMovingMap(); + + if ( cache == null ) + this.cache = new CacheControl.Dummy(); + else + this.cache = cache; + + setupSettings = new HashMap<>(); + sourceColorSettings = new HashMap<>(); + } + + private void updateIsMovingMap() + { + isMovingMap.clear(); + for( Integer i : movingSourceIndexList ) + isMovingMap.put( sources.get( i ), true ); + + for( Integer i : targetSourceIndexList ) + isMovingMap.put( sources.get( i ), false ); + } + + private static ArrayList listOf( int[] x ) + { + final ArrayList< Integer > out = new ArrayList(); + for( int i : x ) + out.add( i ); + + return out; + } + + public int numMovingSources() + { + return movingSourceIndexList.size(); + } + + public SourceAndConverter< T > getMovingSource( int i ) + { + return sources.get( movingSourceIndexList.get( i ) ); + } + + public int numTargetSources() + { + return targetSourceIndexList.size(); + } + + public SourceAndConverter< T > getTargetSource( int i ) + { + return sources.get( targetSourceIndexList.get( i ) ); + } + + public List getMovingConverterSetups() + { + final ArrayList out = new ArrayList<>(); + for( int i : movingSourceIndexList ) + out.add( converterSetups.get( i ) ); + + return out; + } + + public List getTargetConverterSetups() + { + final ArrayList out = new ArrayList<>(); + for( int i : targetSourceIndexList ) + out.add( converterSetups.get( i ) ); + + return out; + } + + public boolean isMoving( SourceAndConverter sac ) { + if( !isMovingMap.containsKey( sac )) + return false; + else + return isMovingMap.get( sac ); + } + + public void wrapUp() + { +// movingSourceIndices = movingSourceIndexList.stream().mapToInt( x -> x ).toArray(); +// targetSourceIndices = targetSourceIndexList.stream().mapToInt( x -> x ).toArray(); +// +// Arrays.sort( movingSourceIndices ); +// Arrays.sort( targetSourceIndices ); + Collections.sort( movingSourceIndexList ); + Collections.sort( targetSourceIndexList ); + } + + /** + * @deprecated + */ + public void transferChannelSettings( final SetupAssignments setupAssignments, final VisibilityAndGrouping visibility ) + { + for( Integer key : setupSettings.keySet() ) + setupSettings.get( key ).updateSetup( setupAssignments ); + } + + public void transferChannelSettings( final BigWarpViewerFrame viewer ) + { + SynchronizedViewerState state = viewer.getViewerPanel().state(); + ConverterSetups setups = viewer.getConverterSetups(); + synchronized ( state ) + { + for ( SourceAndConverter< ? > sac : state.getSources() ) + { + if ( sourceColorSettings.containsKey( sac ) ) + { + if ( sourceColorSettings.get( sac ) == null ) + continue; + + sourceColorSettings.get( sac ).updateSetup( setups.getConverterSetup( sac ) ); + } + else + { + final int timepoint = state.getCurrentTimepoint(); + final Bounds bounds = InitializeViewerState.estimateSourceRange( sac.getSpimSource(), timepoint, 0.001, 0.999 ); + ConverterSetup cs = setups.getConverterSetup(sac); + if( cs != null ) + cs.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/bigwarp/BigWarpExporter.java b/src/main/java/bigwarp/BigWarpExporter.java index 994fee69..392226cf 100644 --- a/src/main/java/bigwarp/BigWarpExporter.java +++ b/src/main/java/bigwarp/BigWarpExporter.java @@ -40,7 +40,6 @@ import bdv.viewer.Interpolation; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; import ij.IJ; import ij.ImagePlus; import mpicbg.models.AffineModel2D; diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 421bc677..9cf37a46 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -55,7 +55,6 @@ import bdv.util.RandomAccessibleIntervalMipmapSource; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; import bigwarp.loader.ImagePlusLoader; import bigwarp.loader.Loader; import bigwarp.loader.XMLLoader; diff --git a/src/main/java/bigwarp/BigWarpRealExporter.java b/src/main/java/bigwarp/BigWarpRealExporter.java index 2c205b15..7a67c01a 100644 --- a/src/main/java/bigwarp/BigWarpRealExporter.java +++ b/src/main/java/bigwarp/BigWarpRealExporter.java @@ -28,7 +28,6 @@ import bdv.tools.brightness.ConverterSetup; import bdv.viewer.Interpolation; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; import ij.IJ; import ij.ImagePlus; import mpicbg.spim.data.sequence.FinalVoxelDimensions; diff --git a/src/main/java/bigwarp/SourceInfoDialog.java b/src/main/java/bigwarp/SourceInfoDialog.java index 6cd1e124..4bdd0357 100644 --- a/src/main/java/bigwarp/SourceInfoDialog.java +++ b/src/main/java/bigwarp/SourceInfoDialog.java @@ -38,7 +38,6 @@ import bdv.util.RandomAccessibleIntervalMipmapSource; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; import net.imglib2.realtransform.AffineTransform3D; public class SourceInfoDialog extends JDialog diff --git a/src/main/java/bigwarp/loader/ImagePlusLoader.java b/src/main/java/bigwarp/loader/ImagePlusLoader.java index c1b68465..b2d0c43c 100644 --- a/src/main/java/bigwarp/loader/ImagePlusLoader.java +++ b/src/main/java/bigwarp/loader/ImagePlusLoader.java @@ -50,7 +50,7 @@ import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.SetupAssignments; import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import ij.ImagePlus; import ij.process.LUT; import mpicbg.spim.data.generic.sequence.BasicImgLoader; diff --git a/src/main/java/bigwarp/source/GridSource.java b/src/main/java/bigwarp/source/GridSource.java index 09b0e862..ced14706 100644 --- a/src/main/java/bigwarp/source/GridSource.java +++ b/src/main/java/bigwarp/source/GridSource.java @@ -23,8 +23,7 @@ import bdv.viewer.Interpolation; import bdv.viewer.Source; -import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import mpicbg.spim.data.sequence.VoxelDimensions; import net.imglib2.FinalInterval; import net.imglib2.Interval; diff --git a/src/main/java/bigwarp/source/JacobianDeterminantSource.java b/src/main/java/bigwarp/source/JacobianDeterminantSource.java index bc425c4f..51e9d851 100644 --- a/src/main/java/bigwarp/source/JacobianDeterminantSource.java +++ b/src/main/java/bigwarp/source/JacobianDeterminantSource.java @@ -25,7 +25,7 @@ import bdv.viewer.Interpolation; import bdv.viewer.Source; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import bigwarp.landmarks.LandmarkTableModel; import mpicbg.spim.data.sequence.FinalVoxelDimensions; import mpicbg.spim.data.sequence.VoxelDimensions; diff --git a/src/main/java/bigwarp/source/WarpMagnitudeSource.java b/src/main/java/bigwarp/source/WarpMagnitudeSource.java index ff97728b..92102b58 100644 --- a/src/main/java/bigwarp/source/WarpMagnitudeSource.java +++ b/src/main/java/bigwarp/source/WarpMagnitudeSource.java @@ -25,7 +25,7 @@ import bdv.viewer.Interpolation; import bdv.viewer.Source; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import bigwarp.landmarks.LandmarkTableModel; import mpicbg.spim.data.sequence.FinalVoxelDimensions; import mpicbg.spim.data.sequence.VoxelDimensions; diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index fb478e35..a4a86e1d 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -29,7 +29,7 @@ import bdv.util.RandomAccessibleIntervalMipmapSource; import bdv.viewer.SourceAndConverter; import bdv.viewer.animate.SimilarityModel3D; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import bigwarp.landmarks.LandmarkTableModel; import ij.IJ; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; diff --git a/src/test/java/bigwarp/SourceTest.java b/src/test/java/bigwarp/SourceTest.java index b0bba0a4..698ed63d 100644 --- a/src/test/java/bigwarp/SourceTest.java +++ b/src/test/java/bigwarp/SourceTest.java @@ -30,7 +30,6 @@ import bdv.util.BdvFunctions; import bdv.util.BdvStackSource; import bdv.viewer.Source; -import bigwarp.BigWarp.BigWarpData; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; diff --git a/src/test/java/bigwarp/Sources2Dtests.java b/src/test/java/bigwarp/Sources2Dtests.java index adb5d9d8..16bceb14 100644 --- a/src/test/java/bigwarp/Sources2Dtests.java +++ b/src/test/java/bigwarp/Sources2Dtests.java @@ -23,7 +23,7 @@ import bdv.util.RandomAccessibleIntervalSource; import bdv.viewer.Source; -import bigwarp.BigWarp.BigWarpData; +import bigwarp.BigWarpData; import ij.IJ; import ij.ImagePlus; import mpicbg.spim.data.SpimDataException; diff --git a/src/test/java/bigwarp/TransformPoints2DTest.java b/src/test/java/bigwarp/TransformPoints2DTest.java index cd945cf8..6e8ade7c 100644 --- a/src/test/java/bigwarp/TransformPoints2DTest.java +++ b/src/test/java/bigwarp/TransformPoints2DTest.java @@ -27,15 +27,13 @@ import net.imglib2.RealPoint; import net.imglib2.realtransform.InvertibleRealTransform; -import java.io.File; - public class TransformPoints2DTest { public static void main(String... args) throws Exception { ImagePlus impBlobs = IJ.openImage("https://imagej.nih.gov/ij/images/blobs.gif"); - BigWarp.BigWarpData bwData = BigWarpInit.createBigWarpDataFromImages( impBlobs, impBlobs ); + BigWarpData bwData = BigWarpInit.createBigWarpDataFromImages( impBlobs, impBlobs ); BigWarp bigWarp = new BigWarp(bwData, "2D points transform", null); // bigWarp.getLandmarkPanel().getTableModel().load( new File( "src/test/resources/landmarks2d-blobs.csv" )); diff --git a/src/test/java/bigwarp/TransformTests.java b/src/test/java/bigwarp/TransformTests.java index eeac42e2..3c6a6a01 100644 --- a/src/test/java/bigwarp/TransformTests.java +++ b/src/test/java/bigwarp/TransformTests.java @@ -25,7 +25,6 @@ import bdv.gui.BigWarpViewerOptions; import bdv.gui.TransformTypeSelectDialog; import bdv.viewer.TransformListener; -import bigwarp.BigWarp.BigWarpData; import bigwarp.landmarks.LandmarkTableModel; import ij.ImagePlus; import mpicbg.spim.data.SpimDataException; From 046cf05d3f4428fd5454454d58a9fc6e8c31b653 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 7 Nov 2022 09:25:29 -0500 Subject: [PATCH 079/282] feat: start new init dialog * depend on flatlaf --- pom.xml | 4 + src/main/java/bdv/gui/BigWarpInitDialog.java | 424 ++++++++++++++++++ .../sourceList/BigWarpSourceListPanel.java | 104 +++++ .../sourceList/BigWarpSourceTableModel.java | 290 ++++++++++++ 4 files changed, 822 insertions(+) create mode 100644 src/main/java/bdv/gui/BigWarpInitDialog.java create mode 100644 src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java create mode 100644 src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java diff --git a/pom.xml b/pom.xml index ddf18b47..3a8bd5f7 100644 --- a/pom.xml +++ b/pom.xml @@ -293,6 +293,10 @@ alphanumeric-comparator ${alphanumeric-comparator.version}
+ + com.formdev + flatlaf + diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java new file mode 100644 index 00000000..13bfd368 --- /dev/null +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -0,0 +1,424 @@ +package bdv.gui; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.JTextField; + +import org.janelia.saalfeldlab.n5.ij.N5Importer; +import org.janelia.saalfeldlab.n5.ij.N5Importer.N5BasePathFun; +import org.janelia.saalfeldlab.n5.ij.N5Importer.N5ViewerReaderFun; +import org.janelia.saalfeldlab.n5.metadata.N5Metadata; +import org.janelia.saalfeldlab.n5.metadata.N5MetadataParser; +import org.janelia.saalfeldlab.n5.metadata.canonical.CanonicalDatasetMetadata; +import org.janelia.saalfeldlab.n5.ui.DataSelection; +import org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog; +import org.janelia.saalfeldlab.n5.ui.N5DatasetTreeCellRenderer; + +import com.formdev.flatlaf.util.UIScale; + +import bdv.gui.sourceList.BigWarpSourceListPanel; +import bdv.gui.sourceList.BigWarpSourceTableModel; +import ij.IJ; +import ij.ImagePlus; +import ij.Prefs; +import ij.WindowManager; + + +public class BigWarpInitDialog extends JFrame +{ + + private static final long serialVersionUID = -2914972130819029899L; + private JButton browseBtn; + private JTextField containerPathText; + + private String initialPath; + private JLabel messageLabel; + private JButton okBtn; + private JButton cancelBtn; + private JPanel listPanel; + private JTable sourceTable; + private JButton addN5Button; + private BigWarpSourceTableModel sourceTableModel; + private JComboBox imagePlusDropdown; + private JButton addImageButton; + private JButton addPathButton; + private DatasetSelectorDialog selectionDialog; + + private String lastOpenedContainer = ""; + private ExecutorService exec; + + private static final int DEFAULT_OUTER_PAD = 8; + private static final int DEFAULT_BUTTON_PAD = 3; + private static final int DEFAULT_MID_PAD = 5; + + public BigWarpInitDialog( final String title ) + { + super( title ); + initialPath = ""; + + buildN5SelectionDialog(); + + //Create and set up the content pane. + final Container content = getContentPane(); + content.add( createContent() ); + pack(); + } + + public JPanel createContent() + { + final int OUTER_PAD = DEFAULT_OUTER_PAD; + final int BUTTON_PAD = DEFAULT_BUTTON_PAD; + final int MID_PAD = DEFAULT_MID_PAD; + + final int frameSizeX = getSize().width; + + final JPanel panel = new JPanel(false); + panel.setLayout(new GridBagLayout()); + + containerPathText = new JTextField(); + containerPathText.setText( initialPath ); + containerPathText.setPreferredSize( new Dimension( frameSizeX / 3, containerPathText.getPreferredSize().height ) ); +// containerPathText.addActionListener( e -> openContainer( n5Fun, () -> getN5RootPath(), pathFun ) ); + + final GridBagConstraints ctxt = new GridBagConstraints(); + ctxt.gridx = 0; + ctxt.gridy = 0; + ctxt.gridwidth = 1; + ctxt.gridheight = 1; + ctxt.weightx = 0.0; + ctxt.weighty = 0.0; + ctxt.fill = GridBagConstraints.NONE; + ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); + + final JLabel addFileLabel = new JLabel( "Add file/folder:"); + panel.add(addFileLabel, ctxt); + + ctxt.gridx = 1; + ctxt.gridy = 0; + ctxt.gridwidth = 4; + ctxt.gridheight = 1; + ctxt.weightx = 1.0; + ctxt.fill = GridBagConstraints.HORIZONTAL; + panel.add(containerPathText, ctxt); + + final GridBagConstraints cadd = new GridBagConstraints(); + cadd.gridx = 5; + cadd.gridwidth = 1; + cadd.weightx = 0.0; + cadd.fill = GridBagConstraints.HORIZONTAL; + cadd.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + addPathButton = new JButton("+"); + addPathButton.addActionListener( e -> addPath() ); + panel.add(addPathButton, cadd); + + final GridBagConstraints cbrowse = new GridBagConstraints(); + cbrowse.gridx = 6; + cbrowse.gridwidth = 1; + cbrowse.weightx = 0.0; + cbrowse.anchor = GridBagConstraints.LINE_END; + cbrowse.fill = GridBagConstraints.HORIZONTAL; + cbrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + browseBtn = new JButton("Browse"); + panel.add(browseBtn, cbrowse); + + // add image / n5 + final GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 1; + gbc.weightx = 0.0; + gbc.weighty = 0.0; + gbc.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + panel.add( new JLabel("Add open image"), gbc ); + + // TODO + String[] openImages = new String[]{ "a", "b", "c"}; + gbc.gridx = 1; + gbc.gridwidth = 2; + gbc.weightx = 1.0; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.anchor = GridBagConstraints.EAST; + imagePlusDropdown = new JComboBox<>( openImages ); + panel.add( imagePlusDropdown, gbc ); + + gbc.gridx = 3; + gbc.gridwidth = 1; + gbc.weightx = 0.0; + gbc.fill = GridBagConstraints.NONE; + addImageButton = new JButton("+"); + panel.add( addImageButton, gbc ); + addImageButton.addActionListener( e -> { addImagePlus(); }); + + gbc.gridx = 6; + gbc.gridwidth = 1; + gbc.weightx = 0.0; + gbc.anchor = GridBagConstraints.LINE_END; + gbc.fill = GridBagConstraints.HORIZONTAL; + addN5Button = new JButton( "H5/N5/Zarr" ); + panel.add( addN5Button, gbc ); + + addN5Button.addActionListener( e -> { + selectionDialog.run( this::n5DialogCallback ); + }); + + // source list + final GridBagConstraints clist = new GridBagConstraints(); + clist.gridx = 0; + clist.gridy = 2; + clist.gridwidth = 7; + clist.gridheight = 3; + clist.weightx = 1.0; + clist.weighty = 1.0; + clist.fill = GridBagConstraints.BOTH; + clist.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + + sourceTableModel = new BigWarpSourceTableModel(); + final BigWarpSourceListPanel srcListPanel = new BigWarpSourceListPanel( sourceTableModel ); + sourceTableModel.setContainer( srcListPanel ); + sourceTable = srcListPanel.getJTable(); + panel.add( srcListPanel, clist ); + + // bottom button section + final GridBagConstraints cbot = new GridBagConstraints(); + cbot.gridx = 0; + cbot.gridy = 5; + cbot.gridwidth = 4; + cbot.gridheight = 1; + cbot.weightx = 1.0; + cbot.weighty = 0.0; + cbot.fill = GridBagConstraints.HORIZONTAL; + cbot.anchor = GridBagConstraints.WEST; + cbot.insets = new Insets(OUTER_PAD, OUTER_PAD, OUTER_PAD, OUTER_PAD); + + messageLabel = new JLabel(""); + messageLabel.setVisible(true); + panel.add(messageLabel, cbot); + + okBtn = new JButton("OK"); + cbot.gridx = 5; + cbot.weightx = 0.0; + cbot.gridwidth = 1; + cbot.ipadx = (int)(40); + cbot.fill = GridBagConstraints.HORIZONTAL; + cbot.anchor = GridBagConstraints.EAST; + cbot.insets = new Insets(MID_PAD, OUTER_PAD, OUTER_PAD, BUTTON_PAD); + panel.add(okBtn, cbot); + + cancelBtn = new JButton("Cancel"); + cbot.gridx = 6; + cbot.ipadx = 0; + cbot.gridwidth = 1; + cbot.fill = GridBagConstraints.HORIZONTAL; + cbot.anchor = GridBagConstraints.EAST; + cbot.insets = new Insets(MID_PAD, BUTTON_PAD, OUTER_PAD, OUTER_PAD); + panel.add(cancelBtn, cbot); + + return panel; + } + + public void buildN5SelectionDialog() + { + exec = Executors.newFixedThreadPool( Prefs.getThreads() ); + + selectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), + lastOpenedContainer, new N5MetadataParser[] {}, // no + N5Importer.PARSERS ); + + selectionDialog.setLoaderExecutor( exec ); + selectionDialog.setTreeRenderer( new N5DatasetTreeCellRenderer( true ) ); + + // restrict canonical metadata to those with spatial metadata, but + // without + // multiscale + selectionDialog.getTranslationPanel().setFilter( x -> ( x instanceof CanonicalDatasetMetadata ) ); + + selectionDialog.setContainerPathUpdateCallback( x -> { + if ( x != null ) + lastOpenedContainer = x; + } ); + + // figure this out +// selectionDialog.setCancelCallback( x -> { +// // set back recorder state if canceled +// Recorder.record = initialRecorderState; +// } ); + + selectionDialog.setVirtualOption( true ); + selectionDialog.setCropOption( true ); + } + + public void n5DialogCallback( DataSelection selection ) + { + final String n5RootPath = selectionDialog.getN5RootPath(); + for( N5Metadata m : selection.metadata ) + sourceTableModel.add( m.getPath() ); + + repaint(); + } + + protected void addImagePlus() + { + if ( IJ.getInstance() == null ) + return; + + final String title = (String)(imagePlusDropdown.getSelectedItem()); + final ImagePlus imp = WindowManager.getImage( title ); + + // TODO consider giving the user information if + // an image is not added, and / or updating the dropdown menu periodically + if( !title.isEmpty() && imp != null ) + { + sourceTableModel.add( title ); + repaint(); + } + } + + protected void addPath() + { + final String path = containerPathText.getText(); + if( !path.isEmpty() ) + { + sourceTableModel.add( path ); + repaint(); + } + } + + public void updateImagePlusDropdown() + { + if( IJ.getInstance() == null ) + return; + + // don't need any open windows if we're using N5 + final int[] ids = WindowManager.getIDList(); + + // Find any open images + final int N = ids == null ? 0 : ids.length; + + final String[] titles = new String[ N ]; + for ( int i = 0; i < N; ++i ) + { + titles[ i ] = ( WindowManager.getImage( ids[ i ] )).getTitle(); + } + imagePlusDropdown.setModel( new DefaultComboBoxModel<>( titles )); + } + + private static void createAndShowGUI() { + //Create and set up the window. + BigWarpInitDialog frame = new BigWarpInitDialog("BigWarp"); + frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + + frame.setVisible(true); + } + + public static void main( String[] args ) + { + createAndShowGUI(); + +// final BigWarpInitDialog dialog = new BigWarpInitDialog( "bw dialog" ); +// dialog.createContent(); +// dialog.setVisible( true ); + } + + public JPanel createContent1() + { + final int OUTER_PAD = DEFAULT_OUTER_PAD; + final int BUTTON_PAD = DEFAULT_BUTTON_PAD; + final int MID_PAD = DEFAULT_MID_PAD; + + final int frameSizeX = getSize().width; + + final JPanel panel = new JPanel(false); + panel.setLayout(new GridBagLayout()); + + containerPathText = new JTextField(); + containerPathText.setText( initialPath ); + containerPathText.setPreferredSize( new Dimension( frameSizeX / 3, containerPathText.getPreferredSize().height ) ); +// containerPathText.addActionListener( e -> openContainer( n5Fun, () -> getN5RootPath(), pathFun ) ); + + final GridBagConstraints ctxt = new GridBagConstraints(); + ctxt.gridx = 0; + ctxt.gridy = 0; + ctxt.gridwidth = 3; + ctxt.gridheight = 1; + ctxt.weightx = 1.0; + ctxt.weighty = 0.0; + ctxt.fill = GridBagConstraints.HORIZONTAL; + ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); + panel.add(containerPathText, ctxt); + + browseBtn = new JButton("Browse"); + final GridBagConstraints cbrowse = new GridBagConstraints(); + cbrowse.gridx = 3; + cbrowse.gridwidth = 1; + cbrowse.weightx = 0.0; + cbrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + panel.add(browseBtn, cbrowse); + + + // source list + final GridBagConstraints clist = new GridBagConstraints(); + clist.gridx = 0; + clist.gridy = 1; + clist.gridwidth = 4; + clist.gridheight = 3; + clist.weightx = 1.0; + clist.weighty = 1.0; + clist.fill = GridBagConstraints.BOTH; + clist.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + final BigWarpSourceListPanel srcListPanel = new BigWarpSourceListPanel( new BigWarpSourceTableModel() ); + sourceTable = srcListPanel.getJTable(); + sourceTableModel = srcListPanel.getTableModel(); + + + panel.add( srcListPanel, clist ); + + // bottom button section + final GridBagConstraints cbot = new GridBagConstraints(); + cbot.gridx = 0; + cbot.gridy = 4; + cbot.gridwidth = 2; + cbot.gridheight = 1; + cbot.weightx = 1.0; + cbot.weighty = 0.0; + cbot.fill = GridBagConstraints.HORIZONTAL; + cbot.anchor = GridBagConstraints.WEST; + cbot.insets = new Insets(OUTER_PAD, OUTER_PAD, OUTER_PAD, OUTER_PAD); + + messageLabel = new JLabel(""); + messageLabel.setVisible(true); + panel.add(messageLabel, cbot); + + okBtn = new JButton("OK"); + cbot.gridx = 2; + cbot.weightx = 0.0; + cbot.gridwidth = 1; + cbot.ipadx = (int)(20); + cbot.anchor = GridBagConstraints.EAST; + cbot.fill = GridBagConstraints.NONE; + cbot.insets = new Insets(MID_PAD, OUTER_PAD, OUTER_PAD, BUTTON_PAD); + panel.add(okBtn, cbot); + + cancelBtn = new JButton("Cancel"); + cbot.gridx = 3; + cbot.ipadx = 0; + cbot.anchor = GridBagConstraints.WEST; + cbot.insets = new Insets(MID_PAD, BUTTON_PAD, OUTER_PAD, OUTER_PAD); + panel.add(cancelBtn, cbot); + + return panel; + } + +} diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java new file mode 100644 index 00000000..6b7f5173 --- /dev/null +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java @@ -0,0 +1,104 @@ +/*- + * #%L + * BigWarp plugin for Fiji. + * %% + * Copyright (C) 2015 - 2022 Howard Hughes Medical Institute. + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package bdv.gui.sourceList; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.DefaultCellEditor; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.UIManager; +import javax.swing.table.TableCellRenderer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import bdv.gui.sourceList.BigWarpSourceTableModel.ButtonEditor; +import bdv.gui.sourceList.BigWarpSourceTableModel.ButtonRenderer; +import bdv.gui.sourceList.BigWarpSourceTableModel.RemoveRowButton; + +public class BigWarpSourceListPanel extends JPanel +{ + + private static final long serialVersionUID = 2370565900502584680L; + + protected BigWarpSourceTableModel tableModel; + + protected JTable table; + + public final Logger logger = LoggerFactory.getLogger( BigWarpSourceListPanel.class ); + +// public BigWarpSourceListPanel() + public BigWarpSourceListPanel( BigWarpSourceTableModel tableModel ) + { + super( new GridLayout( 1, 0 ) ); + setTableModel( tableModel ); + + table = new JTable( tableModel ); + table.setPreferredScrollableViewportSize( new Dimension( 500, 70 ) ); + table.setFillsViewportHeight( true ); + + table.getColumn( "remove" ).setCellRenderer( new ButtonRenderer() ); + table.getColumn( "remove" ).setCellEditor( new ButtonEditor( new JCheckBox(), tableModel ) ); + + final JScrollPane scrollPane = new JScrollPane( table ); + add( scrollPane ); + } + + public BigWarpSourceTableModel getTableModel() + { + return tableModel; + } + + public void genJTable() + { + table = new JTable( getTableModel() ); + + table.setPreferredScrollableViewportSize( new Dimension( 400, 800 ) ); + table.setFillsViewportHeight( true ); + table.setShowVerticalLines( false ); + +// table.setDefaultEditor( String.class, +// new TextFieldCellEditor( new TextFieldCell(table), String.class )); + } + + public void setTableModel( BigWarpSourceTableModel tableModel ) + { + this.tableModel = tableModel; + genJTable(); + } + + public JTable getJTable() + { + return table; + } + + +} diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java new file mode 100644 index 00000000..c1058e70 --- /dev/null +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -0,0 +1,290 @@ +package bdv.gui.sourceList; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.DefaultCellEditor; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JTable; +import javax.swing.UIManager; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableCellRenderer; + +public class BigWarpSourceTableModel extends AbstractTableModel +{ + private static final long serialVersionUID = 5923947651732788341L; + + protected final static String[] colNames = new String[] { "Name", "Moving", "Transform", "remove" }; + + protected final String[] columnNames; + protected final ArrayList sources; + protected final ArrayList rmRowButtons; + + private Component container; + + public BigWarpSourceTableModel() + { + super(); + columnNames = colNames; + sources = new ArrayList<>(); + rmRowButtons = new ArrayList<>(); + } + + /** + * Set the {@link Component} to repaint when a row is removed. + * + * @param container the component containing this table + */ + public void setContainer( Component container ) + { + this.container = container; + } + + @Override + public String getColumnName( int col ){ + return columnNames[col]; + } + + @Override + public int getColumnCount() + { + return columnNames.length; + } + + @Override + public int getRowCount() + { + return sources.size(); + } + + @Override + public Object getValueAt( int r, int c ) + { + if( c == 3 ) + return rmRowButtons.get( r ); + else + return sources.get( r ).get( c ); + } + + public Class getColumnClass( int col ){ + if ( col == 1 ) + return Boolean.class; + else if ( col == 3 ) + return JButton.class; + else + return String.class; + } + + @Override + public boolean isCellEditable( int row, int col ) + { + return true; + } + + public void add( String srcName, boolean moving, boolean isImagePlus ) + { + final RemoveRowButton rmButton = new RemoveRowButton( sources.size() ); +// rmButton.addActionListener( e -> { +// System.out.println( "pushed rm row button " + rmButton.getRow() ); +// remove( rmButton.getRow() ); +// }); + + rmRowButtons.add( rmButton ); + sources.add( new SourceRow( srcName, moving, "", isImagePlus )); + } + + public void add( String srcName, boolean moving ) + { + add( srcName, moving, false ); + } + + public void add( String srcName ) + { + add( srcName, false ); + } + + public boolean remove( int i ) + { + System.out.println( "rm " + i ); + System.out.println( "src sz " + sources.size() ); + if( i >= sources.size() ) + { + System.out.println( "not removed " ); + return false; + } + + sources.remove( i ); + rmRowButtons.remove( i ); + updateRmButtonIndexes(); + + if( container != null ) + container.repaint(); + + return true; + } + + private void updateRmButtonIndexes() + { + for( int i = 0; i < rmRowButtons.size(); i++ ) + rmRowButtons.get( i ).setRow( i ); + } + + public static class SourceRow + { + public String srcName; + public boolean moving; + public String transformName; + + public boolean isImagePlus; + + public SourceRow( String srcName, boolean moving, String transformName, boolean isImagePlus ) + { + this.srcName = srcName; + this.moving = moving; + this.transformName = transformName; + this.isImagePlus = isImagePlus; + } + + public SourceRow( String srcName, boolean moving, String transformName ) + { + this( srcName, moving, transformName, false ); + } + + public Object get( int c ) + { + if( c == 0 ) + return srcName; + else if( c == 1 ) + return moving; + else if ( c == 2 ) + return transformName; + else + return null; + } + } + + protected static class RemoveRowButton extends JButton { + private int row; + public RemoveRowButton( int row ) + { + super( "-" ); + setRow( row ); + } + + public int getRow() + { + return row; + } + + public void setRow(int row) + { + this.row = row; + } + } + + /** + * From + * http://www.java2s.com/Code/Java/Swing-Components/ButtonTableExample.htm + */ + protected static class ButtonRenderer extends JButton implements TableCellRenderer + { + public ButtonRenderer() + { + setOpaque( true ); + } + + public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column ) + { + if ( isSelected ) + { + setForeground( table.getSelectionForeground() ); + setBackground( table.getSelectionBackground() ); + } + else + { + setForeground( table.getForeground() ); + setBackground( UIManager.getColor( "Button.background" ) ); + } + setText( ( value == null ) ? "" : ((RemoveRowButton)value).getText()); + return this; + } + } + + /** + * From + * http://www.java2s.com/Code/Java/Swing-Components/ButtonTableExample.htm + */ + protected static class ButtonEditor extends DefaultCellEditor + { + protected JButton button; + + private String label; + + private RemoveRowButton thisButton; + + private BigWarpSourceTableModel model; + + private boolean isPushed; + + public ButtonEditor( JCheckBox checkBox, BigWarpSourceTableModel model ) + { + super( checkBox ); + checkBox.setText( "-" ); + this.model = model; + + button = new JButton(); + button.setOpaque( true ); + button.addActionListener( new ActionListener() + { + public void actionPerformed( ActionEvent e ) + { + fireEditingStopped(); + } + } ); + } + + public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected, int row, int column ) + { + if ( isSelected ) + { + button.setForeground( table.getSelectionForeground() ); + button.setBackground( table.getSelectionBackground() ); + } + else + { + button.setForeground( table.getForeground() ); + button.setBackground( table.getBackground() ); + } + thisButton = ((RemoveRowButton)value); + label = ( value == null ) ? "" : thisButton.getText(); + button.setText( label ); + isPushed = true; + return button; + } + + public Object getCellEditorValue() + { + if ( isPushed ) + { + model.remove( thisButton.getRow() ); + } + isPushed = false; + return new String( label ); + } + + public boolean stopCellEditing() + { + isPushed = false; + return super.stopCellEditing(); + } + + protected void fireEditingStopped() + { + super.fireEditingStopped(); + } + } + +} From aad71e1d118b452545268ad8c16a3d648f759cee Mon Sep 17 00:00:00 2001 From: bogovicj Date: Mon, 7 Nov 2022 13:50:00 -0500 Subject: [PATCH 080/282] feat: improving new init dialog * editable moving checkboxes * can add ImagePlus sources --- src/main/java/bdv/gui/BigWarpInitDialog.java | 136 +++++------------- .../sourceList/BigWarpSourceListPanel.java | 14 -- .../sourceList/BigWarpSourceTableModel.java | 16 ++- 3 files changed, 48 insertions(+), 118 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 13bfd368..e13d93c5 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -32,6 +32,7 @@ import bdv.gui.sourceList.BigWarpSourceListPanel; import bdv.gui.sourceList.BigWarpSourceTableModel; import ij.IJ; +import ij.ImageJ; import ij.ImagePlus; import ij.Prefs; import ij.WindowManager; @@ -71,10 +72,11 @@ public BigWarpInitDialog( final String title ) buildN5SelectionDialog(); - //Create and set up the content pane. final Container content = getContentPane(); content.add( createContent() ); pack(); + + initializeImagePlusSources(); } public JPanel createContent() @@ -144,15 +146,14 @@ public JPanel createContent() gbc.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); panel.add( new JLabel("Add open image"), gbc ); - // TODO - String[] openImages = new String[]{ "a", "b", "c"}; gbc.gridx = 1; gbc.gridwidth = 2; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.EAST; - imagePlusDropdown = new JComboBox<>( openImages ); + imagePlusDropdown = new JComboBox<>( new String[] { "" } ); panel.add( imagePlusDropdown, gbc ); + updateImagePlusDropdown(); gbc.gridx = 3; gbc.gridwidth = 1; @@ -275,6 +276,14 @@ protected void addImagePlus() return; final String title = (String)(imagePlusDropdown.getSelectedItem()); + addImagePlus( title ); + } + + protected void addImagePlus( String title ) + { + if ( IJ.getInstance() == null ) + return; + final ImagePlus imp = WindowManager.getImage( title ); // TODO consider giving the user information if @@ -285,7 +294,7 @@ protected void addImagePlus() repaint(); } } - + protected void addPath() { final String path = containerPathText.getText(); @@ -295,8 +304,8 @@ protected void addPath() repaint(); } } - - public void updateImagePlusDropdown() + + protected void updateImagePlusDropdown() { if( IJ.getInstance() == null ) return; @@ -315,6 +324,22 @@ public void updateImagePlusDropdown() imagePlusDropdown.setModel( new DefaultComboBoxModel<>( titles )); } + /** + * Adds first two image plus images to the sourc list automatically. + * + * Make sure to call {@link updateImagePlusDropdown} before calling this + * method. + */ + public void initializeImagePlusSources() + { + final int N = imagePlusDropdown.getModel().getSize(); + if ( N > 0 ) + addImagePlus( ( String ) imagePlusDropdown.getItemAt( 0 ) ); + + if ( N > 1 ) + addImagePlus( ( String ) imagePlusDropdown.getItemAt( 1 ) ); + } + private static void createAndShowGUI() { //Create and set up the window. BigWarpInitDialog frame = new BigWarpInitDialog("BigWarp"); @@ -325,100 +350,11 @@ private static void createAndShowGUI() { public static void main( String[] args ) { - createAndShowGUI(); - -// final BigWarpInitDialog dialog = new BigWarpInitDialog( "bw dialog" ); -// dialog.createContent(); -// dialog.setVisible( true ); - } - - public JPanel createContent1() - { - final int OUTER_PAD = DEFAULT_OUTER_PAD; - final int BUTTON_PAD = DEFAULT_BUTTON_PAD; - final int MID_PAD = DEFAULT_MID_PAD; + ImageJ ij = new ImageJ(); + IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); + IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); - final int frameSizeX = getSize().width; - - final JPanel panel = new JPanel(false); - panel.setLayout(new GridBagLayout()); - - containerPathText = new JTextField(); - containerPathText.setText( initialPath ); - containerPathText.setPreferredSize( new Dimension( frameSizeX / 3, containerPathText.getPreferredSize().height ) ); -// containerPathText.addActionListener( e -> openContainer( n5Fun, () -> getN5RootPath(), pathFun ) ); - - final GridBagConstraints ctxt = new GridBagConstraints(); - ctxt.gridx = 0; - ctxt.gridy = 0; - ctxt.gridwidth = 3; - ctxt.gridheight = 1; - ctxt.weightx = 1.0; - ctxt.weighty = 0.0; - ctxt.fill = GridBagConstraints.HORIZONTAL; - ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); - panel.add(containerPathText, ctxt); - - browseBtn = new JButton("Browse"); - final GridBagConstraints cbrowse = new GridBagConstraints(); - cbrowse.gridx = 3; - cbrowse.gridwidth = 1; - cbrowse.weightx = 0.0; - cbrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); - panel.add(browseBtn, cbrowse); - - - // source list - final GridBagConstraints clist = new GridBagConstraints(); - clist.gridx = 0; - clist.gridy = 1; - clist.gridwidth = 4; - clist.gridheight = 3; - clist.weightx = 1.0; - clist.weighty = 1.0; - clist.fill = GridBagConstraints.BOTH; - clist.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); - final BigWarpSourceListPanel srcListPanel = new BigWarpSourceListPanel( new BigWarpSourceTableModel() ); - sourceTable = srcListPanel.getJTable(); - sourceTableModel = srcListPanel.getTableModel(); - - - panel.add( srcListPanel, clist ); - - // bottom button section - final GridBagConstraints cbot = new GridBagConstraints(); - cbot.gridx = 0; - cbot.gridy = 4; - cbot.gridwidth = 2; - cbot.gridheight = 1; - cbot.weightx = 1.0; - cbot.weighty = 0.0; - cbot.fill = GridBagConstraints.HORIZONTAL; - cbot.anchor = GridBagConstraints.WEST; - cbot.insets = new Insets(OUTER_PAD, OUTER_PAD, OUTER_PAD, OUTER_PAD); - - messageLabel = new JLabel(""); - messageLabel.setVisible(true); - panel.add(messageLabel, cbot); - - okBtn = new JButton("OK"); - cbot.gridx = 2; - cbot.weightx = 0.0; - cbot.gridwidth = 1; - cbot.ipadx = (int)(20); - cbot.anchor = GridBagConstraints.EAST; - cbot.fill = GridBagConstraints.NONE; - cbot.insets = new Insets(MID_PAD, OUTER_PAD, OUTER_PAD, BUTTON_PAD); - panel.add(okBtn, cbot); - - cancelBtn = new JButton("Cancel"); - cbot.gridx = 3; - cbot.ipadx = 0; - cbot.anchor = GridBagConstraints.WEST; - cbot.insets = new Insets(MID_PAD, BUTTON_PAD, OUTER_PAD, OUTER_PAD); - panel.add(cancelBtn, cbot); - - return panel; + createAndShowGUI(); } } diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java index 6b7f5173..58a4cc2c 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java @@ -21,32 +21,22 @@ */ package bdv.gui.sourceList; -import java.awt.Component; import java.awt.Dimension; import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.DefaultCellEditor; -import javax.swing.JButton; import javax.swing.JCheckBox; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; -import javax.swing.UIManager; -import javax.swing.table.TableCellRenderer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import bdv.gui.sourceList.BigWarpSourceTableModel.ButtonEditor; import bdv.gui.sourceList.BigWarpSourceTableModel.ButtonRenderer; -import bdv.gui.sourceList.BigWarpSourceTableModel.RemoveRowButton; public class BigWarpSourceListPanel extends JPanel { - private static final long serialVersionUID = 2370565900502584680L; protected BigWarpSourceTableModel tableModel; @@ -55,7 +45,6 @@ public class BigWarpSourceListPanel extends JPanel public final Logger logger = LoggerFactory.getLogger( BigWarpSourceListPanel.class ); -// public BigWarpSourceListPanel() public BigWarpSourceListPanel( BigWarpSourceTableModel tableModel ) { super( new GridLayout( 1, 0 ) ); @@ -84,9 +73,6 @@ public void genJTable() table.setPreferredScrollableViewportSize( new Dimension( 400, 800 ) ); table.setFillsViewportHeight( true ); table.setShowVerticalLines( false ); - -// table.setDefaultEditor( String.class, -// new TextFieldCellEditor( new TextFieldCell(table), String.class )); } public void setTableModel( BigWarpSourceTableModel tableModel ) diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index c1058e70..63d5d832 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -23,6 +23,9 @@ public class BigWarpSourceTableModel extends AbstractTableModel protected final ArrayList sources; protected final ArrayList rmRowButtons; + protected static int movingColIdx = 1; + protected static int removeColIdx = 3; + private Component container; public BigWarpSourceTableModel() @@ -81,7 +84,14 @@ else if ( col == 3 ) @Override public boolean isCellEditable( int row, int col ) { - return true; + return ( col == movingColIdx ) || ( col == removeColIdx ); + } + + @Override + public void setValueAt(Object value, int row, int col) + { + if( col == movingColIdx ) + sources.get( row ).moving = (Boolean)value; } public void add( String srcName, boolean moving, boolean isImagePlus ) @@ -108,11 +118,9 @@ public void add( String srcName ) public boolean remove( int i ) { - System.out.println( "rm " + i ); - System.out.println( "src sz " + sources.size() ); if( i >= sources.size() ) { - System.out.println( "not removed " ); + System.out.println( "NOT REMOVED - SHOULD NEVER BE CALLED" ); return false; } From b4b48656229607ad390fbec6d41fe114b66ef13e Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 7 Nov 2022 20:26:15 -0500 Subject: [PATCH 081/282] BREAKING CHANGE: toward starting bigwarp without sources * will be useful for loading a 'project' --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 25 +- .../java/bdv/viewer/BigWarpViewerPanel.java | 29 +-- src/main/java/bigwarp/BigWarp.java | 231 +++++++++++------- src/main/java/bigwarp/BigWarpData.java | 1 + src/main/java/bigwarp/WarpVisFrame.java | 6 +- 5 files changed, 163 insertions(+), 129 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 0207afd7..d583146e 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -79,47 +79,40 @@ public BigWarpViewerFrame( final BigWarpViewerSettings viewerSettings, final CacheControl cache, final String title, - final boolean isMoving, - final List movingIndexList, - final List targetIndexList ) + final boolean isMoving ) { - this( bw, width, height, sources, converterSetups, viewerSettings, cache, BigWarpViewerOptions.options(), title, isMoving, movingIndexList, targetIndexList ); + this( bw, width, height, converterSetups, viewerSettings, cache, BigWarpViewerOptions.options(), title, isMoving ); } public BigWarpViewerFrame( BigWarp bw, final int width, final int height, - final List< SourceAndConverter< ? > > sources, final List< ConverterSetup > converterSetups, final BigWarpViewerSettings viewerSettings, final CacheControl cache, final BigWarpViewerOptions optional, final String title, - final boolean isMoving, - final List movingIndexList, - final List targetIndexList ) + final boolean isMoving ) { super( title, AWTUtils.getSuitableGraphicsConfiguration( AWTUtils.RGB_COLOR_MODEL ) ); this.bw = bw; - viewer = new BigWarpViewerPanel( sources, viewerSettings, cache, optional.size( width / 2, height ), isMoving, movingIndexList, targetIndexList ); + viewer = new BigWarpViewerPanel( bw.getData(), viewerSettings, cache, optional.size( width / 2, height ), isMoving ); setups = new ConverterSetups( viewer.state() ); setups.listeners().add( s -> viewer.requestRepaint() ); - if ( converterSetups.size() != sources.size() ) + if ( converterSetups.size() != bw.getData().sources.size() ) System.err.println( "WARNING! Constructing BigWarp with converterSetups.size() that is not the same as sources.size()." ); - final int numSetups = Math.min( converterSetups.size(), sources.size() ); + final int numSetups = Math.min( converterSetups.size(), bw.getData().sources.size() ); for ( int i = 0; i < numSetups; ++i ) { - final SourceAndConverter< ? > source = sources.get( i ); + final SourceAndConverter< ? > source = bw.getData().sources.get( i ); final ConverterSetup setup = converterSetups.get( i ); if ( setup != null ) setups.put( source, setup ); } - if ( !isMoving ) - { - viewer.state().setCurrentSource( viewer.state().getSources().get( bw.getData().targetSourceIndexList.get(0))); - } + if ( !isMoving && bw.getData().targetSourceIndexList.size() > 0 ) + viewer.state().setCurrentSource( bw.getData().getTargetSource( 0 ) ); keybindings = new InputActionBindings(); triggerbindings = new TriggerBehaviourBindings(); diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index a5b90125..e97a1ff0 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -28,6 +28,7 @@ import bdv.util.Prefs; import bdv.viewer.animate.RotationAnimator; import bdv.viewer.animate.SimilarityTransformAnimator3D; +import bigwarp.BigWarpData; import bigwarp.util.Rotation2DHelpers; import java.awt.Graphics; import java.awt.Graphics2D; @@ -45,6 +46,8 @@ public class BigWarpViewerPanel extends ViewerPanel public static final int TARGET_GROUP_INDEX = 1; + protected final BigWarpData bwData; + protected BigWarpViewerSettings viewerSettings; protected BigWarpOverlay overlay; @@ -59,10 +62,6 @@ public class BigWarpViewerPanel extends ViewerPanel protected int ndims; - final protected List movingSourceIndexList; - - final protected List targetSourceIndexList; - protected boolean boxOverlayVisible = true; protected boolean textOverlayVisible = true; @@ -74,23 +73,20 @@ public class BigWarpViewerPanel extends ViewerPanel ViewerOptions options; - public BigWarpViewerPanel( final List< SourceAndConverter< ? > > sources, final BigWarpViewerSettings viewerSettings, final CacheControl cache, boolean isMoving, - List movingSourceIndexList, List targetSourceIndexList ) + public BigWarpViewerPanel( final BigWarpData bwData , final BigWarpViewerSettings viewerSettings, final CacheControl cache, boolean isMoving ) { - this( sources, viewerSettings, cache, BigWarpViewerOptions.options(), isMoving, movingSourceIndexList, targetSourceIndexList ); + this( bwData, viewerSettings, cache, BigWarpViewerOptions.options(), isMoving ); } - public BigWarpViewerPanel( final List< SourceAndConverter< ? > > sources, final BigWarpViewerSettings viewerSettings, final CacheControl cache, final BigWarpViewerOptions optional, boolean isMoving, - List movingSourceIndexList, List targetSourceIndexList ) + public BigWarpViewerPanel( final BigWarpData bwData, final BigWarpViewerSettings viewerSettings, final CacheControl cache, final BigWarpViewerOptions optional, boolean isMoving ) { - super( sources, 1, cache, optional.getViewerOptions( isMoving ) ); + // TODO compiler complains if the first argument is 'final BigWarpData bwData' + super( bwData.sources, 1, cache, optional.getViewerOptions( isMoving ) ); + this.bwData = bwData; this.viewerSettings = viewerSettings; this.isMoving = isMoving; this.updateOnDrag = !isMoving; // update on drag only for the fixed // image by default - this.movingSourceIndexList = movingSourceIndexList; - this.targetSourceIndexList = targetSourceIndexList; - getDisplay().overlays().add( g -> { if ( null != overlay ) { overlay.setViewerState( state() ); @@ -166,10 +162,10 @@ public int updateGrouping() // and targetSourceIndexList are required, or whether a // List> can be used directly final List< SourceAndConverter< ? > > moving = new ArrayList<>(); - for ( int i : movingSourceIndexList ) + for ( int i : bwData.movingSourceIndexList ) moving.add( state.getSources().get( i ) ); final List< SourceAndConverter< ? > > target = new ArrayList<>(); - for ( int i : targetSourceIndexList ) + for ( int i : bwData.targetSourceIndexList ) target.add( state.getSources().get( i ) ); state.clearGroups(); @@ -202,7 +198,8 @@ public int updateGrouping() public boolean isInFixedImageSpace() { - return !isMoving || ( ( WarpedSource< ? > ) ( state().getSources().get( movingSourceIndexList.get( 0 ) ).getSpimSource() ) ).isTransformed(); +// return !isMoving || ( ( WarpedSource< ? > ) ( state().getSources().get( bwData.movingSourceIndexList.get( 0 ) ).getSpimSource() ) ).isTransformed(); + return !isMoving || ( ( WarpedSource< ? > ) ( ( bwData.getMovingSource( 0 )).getSpimSource() ) ).isTransformed(); } public boolean doUpdateOnDrag() diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 0889ee00..b74c200e 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -187,13 +187,6 @@ public class BigWarp< T > protected BigWarpData< T > data; - // descriptive names for indexing sources - protected List movingSourceIndexList; - - protected List targetSourceIndexList; - - protected List< SourceAndConverter< T > > sources; - protected HashSet< SourceAndConverter< T >> movingSources; protected final SetupAssignments setupAssignments; @@ -272,11 +265,11 @@ public class BigWarp< T > private final RepeatingReleasedEventsFixer repeatedKeyEventsFixer; - protected final SourceAndConverter< FloatType > gridSource; + protected SourceAndConverter< FloatType > gridSource; - protected final SourceAndConverter< FloatType > warpMagSource; + protected SourceAndConverter< FloatType > warpMagSource; - protected final SourceAndConverter< FloatType > jacDetSource; + protected SourceAndConverter< FloatType > jacDetSource; protected final AbstractModel< ? >[] baseXfmList; @@ -382,29 +375,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie setupWarpMagBaselineOptions( baseXfmList, ndims ); fixedViewXfm = new AffineTransform3D(); - //sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); - data.sources.get( data.targetSourceIndexList.get(0) ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); - - baselineModelIndex = 0; - warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "WarpMagnitudeSource" ); - jacDetSource = addJacobianDeterminantSource( data, "JacobianDeterminantSource" ); - gridSource = addGridSource( data, "GridSource" ); - - this.sources = this.data.sources; - final List< ConverterSetup > converterSetups = data.converterSetups; - this.movingSourceIndexList = data.movingSourceIndexList; - this.targetSourceIndexList = data.movingSourceIndexList; - Collections.sort( movingSourceIndexList ); - Collections.sort( targetSourceIndexList ); -// Arrays.sort( movingSourceIndexList ); -// Arrays.sort( targetSourceIndexList ); - - sources = wrapSourcesAsTransformed( data.sources, ndims, data ); - // TODO JOHN CHECK THIS!! - data.sources = sources; - - setGridType( GridSource.GRID_TYPE.LINE ); - viewerSettings = new BigWarpViewerSettings(); // key properties @@ -412,14 +382,14 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie options = options.inputTriggerConfig( keyProperties ); // Viewer frame for the moving image - viewerFrameP = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, (List)sources, converterSetups, viewerSettings, - data.cache, options, "Bigwarp moving image", true, movingSourceIndexList, targetSourceIndexList ); + viewerFrameP = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, data.converterSetups, viewerSettings, + data.cache, options, "Bigwarp moving image", true ); viewerP = getViewerFrameP().getViewerPanel(); // Viewer frame for the fixed image - viewerFrameQ = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, (List)sources, converterSetups, viewerSettings, - data.cache, options, "Bigwarp fixed image", false, movingSourceIndexList, targetSourceIndexList ); + viewerFrameQ = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, data.converterSetups, viewerSettings, + data.cache, options, "Bigwarp fixed image", false ); viewerQ = getViewerFrameQ().getViewerPanel(); @@ -483,22 +453,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie activeSourcesDialogQ = new VisibilityAndGroupingDialog( viewerFrameQ, viewerQ.getVisibilityAndGrouping() ); activeSourcesDialogQ.setTitle( "visibility and grouping ( fixed )" ); - final ARGBType white = new ARGBType( ARGBType.rgba( 255, 255, 255, 255 )); - // set warp mag source to inactive at the start - viewerP.state().setSourceActive( warpMagSource, false ); - viewerQ.state().setSourceActive( warpMagSource, false ); - data.sourceColorSettings.put( warpMagSource, new ImagePlusLoader.ColorSettings( -1, 0, 15, white )); - - // set warp grid source to inactive at the start - viewerP.state().setSourceActive( gridSource, false ); - viewerQ.state().setSourceActive( gridSource, false ); - data.sourceColorSettings.put( gridSource, new ImagePlusLoader.ColorSettings( -1, 0, 255, white )); - - // set jacobian determinant source to inactive at the start - viewerP.state().setSourceActive( jacDetSource, false ); - viewerQ.state().setSourceActive( jacDetSource, false ); - data.sourceColorSettings.put( jacDetSource, new ImagePlusLoader.ColorSettings( -1, 0.0, 1.0, white )); - overlayP = new BigWarpOverlay( viewerP, landmarkPanel ); overlayQ = new BigWarpOverlay( viewerQ, landmarkPanel ); viewerP.addOverlay( overlayP ); @@ -511,7 +465,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie solverThread.start(); bboxOptions = new BoundingBoxEstimation( BoundingBoxEstimation.Method.FACES, 5 ); - updateSourceBoundingBoxEstimators(); dragOverlayP = new BigWarpDragOverlay( this, viewerP, solverThread ); dragOverlayQ = new BigWarpDragOverlay( this, viewerQ, solverThread ); @@ -521,7 +474,7 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie landmarkPopupMenu = new LandmarkPointMenu( this ); landmarkPopupMenu.setupListeners(); - setupAssignments = new SetupAssignments( new ArrayList<>( converterSetups ), 0, 65535 ); + setupAssignments = new SetupAssignments( new ArrayList<>( data.converterSetups ), 0, 65535 ); brightnessDialog = new BrightnessDialog( landmarkFrame, setupAssignments ); helpDialog = new HelpDialog( landmarkFrame ); @@ -575,20 +528,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie landmarkFrame.pack(); landmarkFrame.setVisible( true ); - SwingUtilities.invokeLater( new Runnable() - { - public void run() - { - data.transferChannelSettings( viewerFrameP ); - data.transferChannelSettings( viewerFrameQ ); - - } - } ); - - // set initial transforms so data are visible - InitializeViewerState.initTransform( viewerP ); - InitializeViewerState.initTransform( viewerQ ); - checkBoxInputMaps(); // file selection @@ -612,6 +551,85 @@ public void run() // add landmark mode listener //addKeyEventPostProcessor( new LandmarkModeListener() ); + + if( data.sources.size() > 0 ) + initialize(); + } + + public void initialize() + { + // TODO JOHN CHECK THIS!! +// data.sources = wrapSourcesAsTransformed( data.sources, ndims, data ); + wrapMovingSources( ndims, data ); + + // starting view + data.sources.get( data.targetSourceIndexList.get(0) ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); + List< SourceAndConverter< T > > dSrcs = data.sources; +// List< SourceAndConverter< ? > > pSrcs = viewerP.state().getSources(); +// List< SourceAndConverter< ? > > qSrcs = viewerQ.state().getSources(); +// +// System.out.println("before"); +// for( SourceAndConverter< T > s : data.sources ) +// for( SourceAndConverter< ? > s : pSrcs ) +// { +// System.out.println( data.sourceColorSettings.get( s )); +// } + + viewerP.state().clearSources(); + viewerQ.state().clearSources(); + + final SynchronizedViewerState pState = viewerP.state(); + final SynchronizedViewerState qState = viewerQ.state(); + for( SourceAndConverter sac : dSrcs ) + { + pState.addSource( sac ); + qState.addSource( sac ); + } + +// for( SourceAndConverter< T > s : data.sources ) +// for( SourceAndConverter< ? > s : viewerP.state().getSources() ) +// { +// System.out.println( data.sourceColorSettings.get( s )); +// } + + SwingUtilities.invokeLater( new Runnable() + { + public void run() + { + data.transferChannelSettings( viewerFrameP ); + data.transferChannelSettings( viewerFrameQ ); + + } + } ); + + baselineModelIndex = 0; + warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "WarpMagnitudeSource" ); + jacDetSource = addJacobianDeterminantSource( data, "JacobianDeterminantSource" ); + gridSource = addGridSource( data, "GridSource" ); + setGridType( GridSource.GRID_TYPE.LINE ); + + final ARGBType white = new ARGBType( ARGBType.rgba( 255, 255, 255, 255 )); + // set warp mag source to inactive at the start + viewerP.state().setSourceActive( warpMagSource, false ); + viewerQ.state().setSourceActive( warpMagSource, false ); + data.sourceColorSettings.put( warpMagSource, new ImagePlusLoader.ColorSettings( -1, 0, 15, white )); + + // set warp grid source to inactive at the start + viewerP.state().setSourceActive( gridSource, false ); + viewerQ.state().setSourceActive( gridSource, false ); + data.sourceColorSettings.put( gridSource, new ImagePlusLoader.ColorSettings( -1, 0, 255, white )); + + // set jacobian determinant source to inactive at the start + viewerP.state().setSourceActive( jacDetSource, false ); + viewerQ.state().setSourceActive( jacDetSource, false ); + data.sourceColorSettings.put( jacDetSource, new ImagePlusLoader.ColorSettings( -1, 0.0, 1.0, white )); + + updateSourceBoundingBoxEstimators(); + + // set initial transforms so data are visible + InitializeViewerState.initTransform( viewerP ); + InitializeViewerState.initTransform( viewerQ ); + } public int numDimensions() @@ -839,7 +857,7 @@ public void exportAsImagePlus( boolean virtual ) public void saveMovingImageToFile() { final JFileChooser fileChooser = new JFileChooser( getLastDirectory() ); - File proposedFile = new File( sources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getName() ); + File proposedFile = new File( data.getMovingSource( 0 ).getSpimSource().getName() ); fileChooser.setSelectedFile( proposedFile ); final int returnVal = fileChooser.showSaveDialog( null ); @@ -1100,7 +1118,7 @@ public void exportAsImagePlus( boolean virtual, String path ) if( matchedPtNames.size() > 0 ) { BigwarpLandmarkSelectionPanel selection = new BigwarpLandmarkSelectionPanel<>( - data, sources, fieldOfViewOption, + data, data.sources, fieldOfViewOption, outputIntervalList, matchedPtNames, interp, offsetSpec, res, isVirtual, nThreads, progressWriter ); @@ -1116,7 +1134,7 @@ public void exportAsImagePlus( boolean virtual, String path ) public void run() { progressWriter.setProgress( 0.01 ); - ApplyBigwarpPlugin.runN5Export( data, sources, fieldOfViewOption, + ApplyBigwarpPlugin.runN5Export( data, data.sources, fieldOfViewOption, outputIntervalList.get( 0 ), interp, offsetSpec, res, unit, progressWriter, writeOpts, @@ -1130,7 +1148,7 @@ public void run() { // export final boolean show = ( writeOpts.pathOrN5Root == null || writeOpts.pathOrN5Root.isEmpty() ); - ApplyBigwarpPlugin.runExport( data, sources, fieldOfViewOption, + ApplyBigwarpPlugin.runExport( data, data.sources, fieldOfViewOption, outputIntervalList, matchedPtNames, interp, offsetSpec, res, isVirtual, nThreads, progressWriter, show, false, writeOpts ); @@ -1141,7 +1159,7 @@ public void run() public void exportWarpField() { BigWarpToDeformationFieldPlugIn dfieldExporter = new BigWarpToDeformationFieldPlugIn(); - dfieldExporter.runFromBigWarpInstance( landmarkModel, sources, targetSourceIndexList ); + dfieldExporter.runFromBigWarpInstance( landmarkModel, data.sources, data.targetSourceIndexList ); } protected void setUpLandmarkMenus() @@ -1218,7 +1236,7 @@ public BigWarpData getData() public List< SourceAndConverter< T > > getSources() { - return sources; + return data.sources; } public BigWarpLandmarkFrame getLandmarkFrame() @@ -1772,6 +1790,28 @@ public void setGridType( final GridSource.GRID_TYPE method ) ( ( GridSource< ? > ) gridSource.getSpimSource() ).setMethod( method ); } + public static void wrapMovingSources( final int ndims, final BigWarpData data ) + { + final List warpUsIndices = data.movingSourceIndexList; + final HashMap, ColorSettings> colorSettings = data.sourceColorSettings; +// System.out.println( "before " + colorSettings.keySet().size()); + + int i = 0; + for ( final SourceAndConverter sac : data.sources ) + { +// int idx = Arrays.binarySearch( warpUsIndices, i ); + int idx = warpUsIndices.indexOf( i ); + if ( idx >= 0 ) + { + SourceAndConverter newSac = wrapSourceAsTransformed( sac, "xfm_" + i, ndims ); + colorSettings.put( newSac, colorSettings.get( sac )); + data.sources.set( i, newSac ); + } + i++; + } +// System.out.println( "after " + colorSettings.keySet().size()); + } + public static List< SourceAndConverter > wrapSourcesAsTransformed( final List< SourceAndConverter > sources, final int ndims, final BigWarpData data ) @@ -1780,6 +1820,7 @@ public static List< SourceAndConverter > wrapSourcesAsTransformed( final final List warpUsIndices = data.movingSourceIndexList; final HashMap, ColorSettings> colorSettings = data.sourceColorSettings; +// System.out.println( "before " + colorSettings.keySet().size()); int i = 0; for ( final SourceAndConverter sac : sources ) @@ -1799,6 +1840,7 @@ public static List< SourceAndConverter > wrapSourcesAsTransformed( final i++; } +// System.out.println( "after " + colorSettings.keySet().size()); return wrappedSource; } @@ -2114,35 +2156,35 @@ private void setTransformationMovingSourceOnly( final InvertibleRealTransform tr { this.currentTransform = transform; - for ( int i = 0; i < movingSourceIndexList.size(); i++ ) + for ( int i = 0; i < data.movingSourceIndexList.size(); i++ ) { - final int idx = movingSourceIndexList.get( i ); + final int idx = data.movingSourceIndexList.get( i ); // the xfm must always be 3d for bdv to be happy. // when bigwarp has 2d images though, the z- component will be left unchanged //InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); // the updateTransform method creates a copy of the transform - ( ( WarpedSource< ? > ) ( sources.get( idx ).getSpimSource() ) ).updateTransform( transform ); - if ( sources.get( 0 ).asVolatile() != null ) - ( ( WarpedSource< ? > ) ( sources.get( idx ).asVolatile().getSpimSource() ) ).updateTransform( transform ); + ( ( WarpedSource< ? > ) ( data.sources.get( idx ).getSpimSource() ) ).updateTransform( transform ); + if ( data.sources.get( 0 ).asVolatile() != null ) + ( ( WarpedSource< ? > ) ( data.sources.get( idx ).asVolatile().getSpimSource() ) ).updateTransform( transform ); } } public void updateSourceBoundingBoxEstimators() { - for ( int i = 0; i < movingSourceIndexList.size(); i++ ) + for ( int i = 0; i < data.movingSourceIndexList.size(); i++ ) { - final int idx = movingSourceIndexList.get( i ); + final int idx = data.movingSourceIndexList.get( i ); // the xfm must always be 3d for bdv to be happy. // when bigwarp has 2d images though, the z- component will be left unchanged //InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); // the updateTransform method creates a copy of the transform - ( ( WarpedSource< ? > ) ( sources.get( idx ).getSpimSource() ) ).setBoundingBoxEstimator(bboxOptions.copy()); - if ( sources.get( 0 ).asVolatile() != null ) - ( ( WarpedSource< ? > ) ( sources.get( idx ).asVolatile().getSpimSource() ) ).setBoundingBoxEstimator(bboxOptions.copy()); + ( ( WarpedSource< ? > ) ( data.sources.get( idx ).getSpimSource() ) ).setBoundingBoxEstimator(bboxOptions.copy()); + if ( data.sources.get( 0 ).asVolatile() != null ) + ( ( WarpedSource< ? > ) ( data.sources.get( idx ).asVolatile().getSpimSource() ) ).setBoundingBoxEstimator(bboxOptions.copy()); } } @@ -2212,14 +2254,14 @@ public boolean restimateTransformation() public synchronized void setIsMovingDisplayTransformed( final boolean isTransformed ) { - for( int i = 0 ; i < movingSourceIndexList.size(); i ++ ) + for( int i = 0 ; i < data.movingSourceIndexList.size(); i ++ ) { - final int movingSourceIndex = movingSourceIndexList.get( 0 ); + final int movingSourceIndex = data.movingSourceIndexList.get( 0 ); - ( ( WarpedSource< ? > ) ( sources.get( movingSourceIndex ).getSpimSource() ) ).setIsTransformed( isTransformed ); + ( ( WarpedSource< ? > ) ( data.sources.get( movingSourceIndex ).getSpimSource() ) ).setIsTransformed( isTransformed ); - if ( sources.get( movingSourceIndex ).asVolatile() != null ) - ( ( WarpedSource< ? > ) ( sources.get( movingSourceIndex ).asVolatile().getSpimSource() ) ).setIsTransformed( isTransformed ); + if ( data.sources.get( movingSourceIndex ).asVolatile() != null ) + ( ( WarpedSource< ? > ) ( data.sources.get( movingSourceIndex ).asVolatile().getSpimSource() ) ).setIsTransformed( isTransformed ); } overlayP.setIsTransformed( isTransformed ); @@ -2245,7 +2287,8 @@ public boolean isRowIncomplete() public boolean isMovingDisplayTransformed() { // this implementation is okay, so long as all the moving images have the same state of 'isTransformed' - return ( ( WarpedSource< ? > ) ( sources.get( movingSourceIndexList.get( 0 ) ).getSpimSource() ) ).isTransformed(); +// return ( ( WarpedSource< ? > ) ( data.sources.get( data.movingSourceIndexList.get( 0 ) ).getSpimSource() ) ).isTransformed(); + return ( ( WarpedSource< ? > ) ( data.getMovingSource( 0 ).getSpimSource() ) ).isTransformed(); } /** @@ -2254,7 +2297,7 @@ public boolean isMovingDisplayTransformed() */ protected int detectNumDims() { - return detectNumDims( sources ); + return detectNumDims( data.sources ); } /** @@ -2384,10 +2427,10 @@ else if ( !fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) private void viewerXfmTest() { AffineTransform3D srcTransform0 = new AffineTransform3D(); - sources.get( 0 ).getSpimSource().getSourceTransform(0, 0, srcTransform0 ); + data.sources.get( 0 ).getSpimSource().getSourceTransform(0, 0, srcTransform0 ); AffineTransform3D srcTransform1 = new AffineTransform3D(); - sources.get( 1 ).getSpimSource().getSourceTransform(0, 0, srcTransform1 ); + data.sources.get( 1 ).getSpimSource().getSourceTransform(0, 0, srcTransform1 ); AffineTransform3D viewerTransformM = new AffineTransform3D(); viewerP.state().getViewerTransform( viewerTransformM ); diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 80cae95a..de597bcb 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -190,6 +190,7 @@ public void transferChannelSettings( final BigWarpViewerFrame viewer ) if ( sourceColorSettings.get( sac ) == null ) continue; + System.out.println( setups.getConverterSetup( sac ) ); sourceColorSettings.get( sac ).updateSetup( setups.getConverterSetup( sac ) ); } else diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index e63df4bd..b1f7d742 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -573,9 +573,9 @@ public void stateChanged( ChangeEvent e ) warpGridModButton.setText( "Modulo" ); // turn on the default values - setWarpVisOffButton.doClick(); - warpMagAffineButton.doClick(); - warpGridLineButton.doClick(); +// setWarpVisOffButton.doClick(); +// warpMagAffineButton.doClick(); +// warpGridLineButton.doClick(); } public void addListeners() From a0396ba8c4c9b89622f06c1240cfbc5e1e14d998 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 08:44:25 -0500 Subject: [PATCH 082/282] test: ignore generated files --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index b9bb0f54..dbb66312 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,10 @@ hs_err_pid* /bin/ /target/ +# ignore files generated during test +/src/test/resources/bigwarp/url/imgDir3d/img3d0000.tif +/src/test/resources/bigwarp/url/imgDir3d/img3d0001.tif +/src/test/resources/bigwarp/url/imgDir3d/img3d0002.tif +/src/test/resources/bigwarp/url/imgDir3d/img3d0003.tif +/src/test/resources/bigwarp/url/img.tif +/src/test/resources/bigwarp/url/img2d.png From 1439a7694aafdf7be5d88e9892a7903cd7d320dd Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:46:03 -0500 Subject: [PATCH 083/282] refactor: source serialization adapter --- src/main/java/bigwarp/BigwarpSettings.java | 98 +++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 86b62e8e..ace8fba5 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -7,6 +7,7 @@ import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.DisplayMode; import bdv.viewer.Interpolation; +import bdv.viewer.SourceAndConverter; import bdv.viewer.SynchronizedViewerState; import bdv.viewer.ViewerPanel; import bdv.viewer.state.SourceGroup; @@ -28,11 +29,16 @@ import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import mpicbg.spim.data.SpimDataException; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.type.numeric.ARGBType; +import net.imglib2.util.Pair; import org.scijava.listeners.Listeners; import static bdv.viewer.Interpolation.NEARESTNEIGHBOR; @@ -51,6 +57,8 @@ public class BigwarpSettings extends TypeAdapter< BigwarpSettings > private final BigWarpTransform transform; + private final Map< Integer, Pair, List>>> sourceUrls; + BigWarpViewerPanel viewerP; BigWarpViewerPanel viewerQ; @@ -72,7 +80,8 @@ public BigwarpSettings( final BigWarpAutoSaver autoSaver, final PlateauSphericalMaskRealRandomAccessible transformMask, final LandmarkTableModel landmarks, - final BigWarpTransform transform + final BigWarpTransform transform, + final Map< Integer, Pair, List>>> sourceUrls ) { @@ -85,6 +94,7 @@ public BigwarpSettings( this.transformMask = transformMask; this.landmarks = landmarks; this.transform = transform; + this.sourceUrls = sourceUrls; } public void serialize( String jsonFilename ) throws IOException @@ -98,7 +108,10 @@ public void serialize( String jsonFilename ) throws IOException @Override public void write( final JsonWriter out, final BigwarpSettings value ) throws IOException { + out.beginObject(); + out.name( "Sources" ); + new BigWarpSourcesAdapter( bigWarp.data ).write( out, sourceUrls ); out.name( "ViewerP" ); new BigWarpViewerPanelAdapter( viewerP ).write( out, viewerP ); out.name( "ViewerQ" ); @@ -126,6 +139,9 @@ public BigwarpSettings read( final JsonReader in ) throws IOException final String nextName = in.nextName(); switch ( nextName ) { + case "Sources": + new BigWarpSourcesAdapter( bigWarp.data ).read( in ); + break; case "ViewerP": new BigWarpViewerPanelAdapter( viewerP ).read( in ); break; @@ -155,6 +171,86 @@ public BigwarpSettings read( final JsonReader in ) throws IOException return this; } + public static class BigWarpSourcesAdapter extends TypeAdapter, List>>>> { + + private final BigWarp.BigWarpData data; + + public BigWarpSourcesAdapter( final BigWarp.BigWarpData data ) + { + this.data = data; + } + + @Override + public void write( final JsonWriter out, final Map< Integer, Pair< Supplier< String >, List< SourceAndConverter< ? > > > > value ) throws IOException + { + out.beginObject(); + for ( Map.Entry< Integer, Pair, List>>> entry : value.entrySet() ) + { + Integer id = entry.getKey(); + final Supplier urlSupplier = entry.getValue().getA(); + /* currently we only care about the first source when a single `add` call creates multiple sources. + * This is because they will deserialzie to multiple sources from one url next time as well. */ + final SourceAndConverter< ? > source = entry.getValue().getB().get( 0 ); + out.name( "" + id ); + + out.beginObject(); + + final int sourceIdx = data.sources.indexOf( source ); + final boolean isMoving = data.movingSourceIndexList.contains( sourceIdx ); + + final String url = urlSupplier.get(); + if ( url != null ) + { + out.name( "url" ).value( url ); + } + out.name( "isMoving" ).value( isMoving ); + out.endObject(); + } + out.endObject(); + } + + @Override + public Map< Integer, Pair< Supplier< String >, List< SourceAndConverter< ? > > > > read( final JsonReader in ) throws IOException + { + in.beginObject(); + while ( in.hasNext() ) + { + //TODO Caleb: What to do if `data` alrread has a source for this `id`? + int id = Integer.parseInt( in.nextName() ); + in.beginObject(); + String url = null; + Boolean isMoving = null; + while ( in.hasNext() ) + { + switch ( in.nextName() ) + { + case "url": + url = in.nextString(); + break; + case "isMoving": + isMoving = in.nextBoolean(); + break; + } + } + try + { + if (url != null) { + BigWarpInit.add( data, url, id, isMoving ); + } else { + //TODO Caleb: Prompt? Error? + } + } + catch ( URISyntaxException | SpimDataException e ) + { + throw new IOException("Error Parsing Source by URI", e ); + } + in.endObject(); + } + in.endObject(); + return data.urls; + } + } + public static class BigWarpViewerPanelAdapter extends TypeAdapter< BigWarpViewerPanel > { From fcc62aedfa1785956460119c5962559b141e3652 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:46:28 -0500 Subject: [PATCH 084/282] feat: add source from url --- src/main/java/bigwarp/BigWarpInit.java | 118 ++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 81464eb7..6fb9ea95 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -21,13 +21,22 @@ */ package bigwarp; +import ij.IJ; +import ij.plugin.FolderOpener; +import java.io.File; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; +import ij.io.FileInfo; +import java.util.Objects; +import net.imglib2.util.ValuePair; import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer; import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.N5TreeNode; +import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader; import org.janelia.saalfeldlab.n5.ij.N5Factory; import org.janelia.saalfeldlab.n5.imglib2.N5Utils; import org.janelia.saalfeldlab.n5.metadata.MultiscaleMetadata; @@ -80,6 +89,7 @@ import net.imglib2.type.volatiles.VolatileARGBType; import net.imglib2.util.Util; import net.imglib2.view.Views; +import org.janelia.saalfeldlab.n5.zarr.N5ZarrReader; public class BigWarpInit { @@ -374,7 +384,113 @@ public static < T > int add( BigWarpData bwdata, ImagePlus ip, int setupId, int return bwdata; } - public static SpimData addToData( final BigWarpData bwdata, + + private static String schemeSpecificPartWithoutQuery( URI uri ) + { + return uri.getSchemeSpecificPart().replaceAll( "\\?" + uri.getQuery(), "" ).replaceAll( "//", "" ); + } + + public static Source< ? > add( final BigWarpData< ? > bwData, String uri, int setupId, boolean isMoving ) throws URISyntaxException, IOException, SpimDataException + { + final URI tmpUri = new URI( "TMP", uri, null ); + String encodedUriString = tmpUri.getRawSchemeSpecificPart(); + encodedUriString = encodedUriString.replaceAll( "%23", "#" ); + URI firstUri = new URI( encodedUriString ); + final int prevSacCount = bwData.sources.size(); + Source< ? > source = null; + if ( firstUri.isOpaque() ) + { + URI secondUri = new URI( firstUri.getSchemeSpecificPart() ); + final String firstScheme = firstUri.getScheme().toLowerCase(); + final String secondScheme = secondUri.getScheme(); + final String secondSchemeSpecificMinusQuery = schemeSpecificPartWithoutQuery( secondUri ); + final boolean dontIncludeScheme = secondScheme == null || Objects.equals( secondScheme, "" ) || Objects.equals( secondScheme.toLowerCase(), "file" ); + final String secondSchemeAndPath = dontIncludeScheme ? secondSchemeSpecificMinusQuery : secondScheme + "://" + secondSchemeSpecificMinusQuery; + final String datasetQuery = secondUri.getQuery(); + final String dataset = datasetQuery == null ? "/" : datasetQuery; + final N5Reader n5reader; + switch ( firstScheme ) + { + case "n5": + n5reader = new N5Factory().openReader( secondSchemeAndPath ); + break; + case "zarr": + n5reader = new N5ZarrReader( secondSchemeAndPath ); + break; + case "h5": + case "hdf5": + case "hdf": + n5reader = new N5HDF5Reader( secondSchemeAndPath ); + break; + default: + throw new URISyntaxException( firstScheme, "Unsupported Top Level Protocol" ); + } + + source = loadN5Source( n5reader, dataset ); + add( bwData, source, setupId, 0, isMoving); + } + else + { + firstUri = new URI( encodedUriString.replaceAll( "%23", "#" ) ); + final String firstSchemeSpecificPartMinusQuery = schemeSpecificPartWithoutQuery( firstUri ); + final boolean skipScheme = firstUri.getScheme() == null + || firstUri.getScheme().trim().isEmpty() + || firstUri.getScheme().trim().equalsIgnoreCase( "n5" ) + || firstUri.getScheme().trim().equalsIgnoreCase( "file" ); + final String firstSchemeAndPath = skipScheme ? firstSchemeSpecificPartMinusQuery : firstUri.getScheme() + "://" + firstSchemeSpecificPartMinusQuery; + try + { + final N5Reader n5reader = new N5Factory().openReader( firstSchemeAndPath ); + final String datasetQuery = firstUri.getQuery(); + final String dataset = datasetQuery == null ? "/" : datasetQuery; + source = loadN5Source( n5reader, dataset ); + add( bwData, source, setupId, 0, isMoving); + } + catch ( Exception ignored ) + { + } + if (source == null) { + if ( firstSchemeAndPath.trim().toLowerCase().endsWith( ".xml" ) ) + { + addToData( bwData, isMoving, setupId, firstSchemeAndPath, firstUri.getQuery() ); + return bwData.sources.get( bwData.sources.size() - 1 ).getSpimSource(); + } + else + { + final ImagePlus ijp; + try + { + + if ( new File( uri ).isDirectory() ) + { + ijp = FolderOpener.open( uri ); + } + else + { + ijp = IJ.openImage( uri ); + } + } + catch ( Exception e ) + { + return null; + } + add( bwData, ijp, setupId, 0, isMoving); + source = bwData.sources.get( bwData.sources.size() - 1 ).getSpimSource(); + } + } + + } + + /* override any already set urls with the uri we used to load this source. */ + if (source != null) { + final int postSacCount = bwData.sources.size(); + final List< ? extends SourceAndConverter< ? > > addedSacs = bwData.sources.subList( prevSacCount, postSacCount ); + bwData.urls.put( setupId, new ValuePair<>( () -> uri, new ArrayList<>(addedSacs) ) ); + } + return source; + } + + public static SpimData addToData( final BigWarpData bwdata, final boolean isMoving, final int setupId, final String rootPath, final String dataset ) { if( rootPath.endsWith( "xml" )) From 19837063742c7cbb13828d19601ae8fac859a9ee Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:46:36 -0500 Subject: [PATCH 085/282] feat: load source from N5Reader --- src/main/java/bigwarp/BigWarpInit.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 6fb9ea95..2a3da13b 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -525,7 +525,10 @@ public static Source loadN5Source( final String n5Root, final String n5Datase e.printStackTrace(); return null; } - + return loadN5Source( n5, n5Dataset ); + } + public static Source loadN5Source( final N5Reader n5, final String n5Dataset ) + { final N5MetadataParser[] PARSERS = new N5MetadataParser[]{ new ImagePlusLegacyMetadataParser(), new N5CosemMetadataParser(), From a364f91c403e2e12920813cc2c264d6decb474e3 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:46:43 -0500 Subject: [PATCH 086/282] feat: store url from source --- src/main/java/bigwarp/BigWarp.java | 8 ++++- src/main/java/bigwarp/BigWarpInit.java | 44 ++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 2f14d4bc..c924ace6 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -106,10 +106,12 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; +import java.util.function.Supplier; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JCheckBox; @@ -160,6 +162,7 @@ import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; +import net.imglib2.util.Pair; import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.ij.N5Exporter; import org.janelia.utility.geom.BoundingSphereRitter; @@ -2511,6 +2514,8 @@ public static class BigWarpData< T > { public final List< SourceAndConverter< T > > sources; + public final Map< Integer, Pair, List>>> urls = new HashMap<>(); + public final List< ConverterSetup > converterSetups; public final CacheControl cache; @@ -3472,7 +3477,8 @@ public BigwarpSettings getSettings() autoSaver, transformMask.getRandomAccessible(), landmarkModel, - bwTransform + bwTransform, + data.urls ); } diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 2a3da13b..4ed444a1 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -337,11 +337,32 @@ public static < T > int add( BigWarpData bwdata, ImagePlus ip, int setupId, int { ImagePlusLoader loader = new ImagePlusLoader( ip ); SpimDataMinimal[] dataList = loader.loadAll( setupId ); + final int startSetupId = setupId; + final int prevSacCount = bwdata.sources.size(); for ( SpimDataMinimal data : dataList ) { add( bwdata, data, setupId, numTimepoints, isMoving ); setupId++; } + + final int postSacCount = bwdata.sources.size(); + final List> addedSacs = bwdata.sources.subList( prevSacCount, postSacCount ); + final BigWarpData< ? > bigwarpData = bwdata; + bigwarpData.urls.put( startSetupId, new ValuePair<>(() -> { + final FileInfo originalFileInfo = ip.getOriginalFileInfo(); + if (originalFileInfo != null) { + final String url = originalFileInfo.url; + if ( url != null && !url.isEmpty() ) + { + return url; + } else { + return originalFileInfo.getFilePath(); + } + } + return null; + }, new ArrayList<>(addedSacs)) ); + + loader.update(bwdata); return loader.numSources(); } @@ -498,10 +519,24 @@ public static SpimData addToData( final BigWarpData bwdata, SpimData spimData; try { + final int prevSacCount = bwdata.sources.size(); spimData = new XmlIoSpimData().load( rootPath ); add( bwdata, spimData, setupId, 0, isMoving ); + final int postSacCount = bwdata.sources.size(); + + final List< ? extends SourceAndConverter< ? > > addedSacs = bwdata.sources.subList( prevSacCount, postSacCount ); + bwdata.urls.put( setupId, new ValuePair<>( () -> { + try + { + return spimData.getBasePath().getCanonicalPath(); + } + catch ( IOException e ) + { + return null; + } + }, new ArrayList<>(addedSacs) ) ); - if( isMoving ) + if ( isMoving ) return spimData; } catch ( SpimDataException e ) { e.printStackTrace(); } @@ -509,7 +544,12 @@ public static SpimData addToData( final BigWarpData bwdata, } else { - BigWarpInit.add( bwdata, loadN5Source( rootPath, dataset ), setupId, 0, isMoving ); + final int prevSacCount = bwdata.sources.size(); + BigWarpInit.add(bwdata, loadN5Source(rootPath, dataset), setupId, 0, isMoving); + final int postSacCount = bwdata.sources.size(); + final List< ? extends SourceAndConverter< ? > > addedSacs = bwdata.sources.subList( prevSacCount, postSacCount ); + //TODO Caleb: Canonicalize the URL? + bwdata.urls.put( setupId, new ValuePair<>(() -> rootPath + "?" + dataset, new ArrayList<>(addedSacs))); return null; } } From 89bc3b099e289bfc2fef540fb5355ebd3ec3bf40 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:46:48 -0500 Subject: [PATCH 087/282] refactor: use deprecated `getState()` --- src/main/java/bigwarp/BigwarpSettings.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index ace8fba5..72fe5dfa 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -261,16 +261,7 @@ public static class BigWarpViewerPanelAdapter extends TypeAdapter< BigWarpViewer public BigWarpViewerPanelAdapter( final BigWarpViewerPanel viewerP ) { this.panel = viewerP; - try - { - final Field stateField = ViewerPanel.class.getDeclaredField( "state" ); - stateField.setAccessible( true ); - this.state = ( ViewerState ) stateField.get( panel ); - } - catch ( NoSuchFieldException | IllegalAccessException e ) - { - throw new RuntimeException( e ); - } + this.state = panel.getState(); } @Override From 0fc8a7f42e6f80373c3c4a0ae9d61dbc84410620 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:46:51 -0500 Subject: [PATCH 088/282] test,refactor: add sourceSerializationTest for when supported. --- src/test/java/bigwarp/SerializationTest.java | 68 ++++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 87330978..daaad421 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -36,6 +36,7 @@ import org.custommonkey.xmlunit.XMLAssert; import org.custommonkey.xmlunit.XMLUnit; import org.jdom2.JDOMException; +import org.junit.After; import org.junit.Assert; import org.junit.Test; import org.xml.sax.SAXException; @@ -43,6 +44,16 @@ public class SerializationTest { + private BigWarp< ? > bw; + + @After + public void after() { + if (bw != null) { + bw.closeAll(); + bw = null; + } + } + @Test public void maskTest() { @@ -123,7 +134,7 @@ public void autoSaverTest() @Test public void setupAssignmentsTest() throws SpimDataException, IOException { - final BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); + bw = createBigWarp( new boolean[] { true, false, false, false } ); final PipedWriter writer = new PipedWriter(); final PipedReader in = new PipedReader( writer, 10000 ); @@ -171,7 +182,7 @@ public void setupAssignmentsTest() throws SpimDataException, IOException @Test public void viewerPanelTest() throws SpimDataException, IOException { - final BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); + bw = createBigWarp( new boolean[] { true, false, false, false } ); final PipedWriter writer = new PipedWriter(); final PipedReader in = new PipedReader( writer, 10000 ); @@ -215,8 +226,20 @@ public void viewerPanelTest() throws SpimDataException, IOException expected.addProperty( XmlIoViewerState.VIEWERSTATE_CURRENTTIMEPOINT_TAG, value.getState().getCurrentTimepoint() ); Assert.assertEquals( prettyPrint(expected), prettyPrint( actual.getAsJsonObject()) ); + } - + @Test + public void sourceSerializationTest() throws SpimDataException + { + //TODO Caleb: Currently, Bigwarp cannot be loaded without soruces existing. + // When this is possible, this test should be written to create bigwarp with no initial sources, + // and then import some sources from a settings file, and compare the added sources to the expected. + + // bw = createBigWarp( new boolean[0] ); + // bw.loadSettings("src/test/resources/settings/settingsWithSource.json"); + // Grab the sources + // Compare the ids, urls, isMoving status, and isActive + assert(false); } /* When creating and closing multiple BigWarp instances, occassionally the comparison test fails. @@ -228,7 +251,7 @@ private void repeatComparison() throws Exception for ( int i = 0; i < 20; i++ ) { System.out.println( i ); - BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); + bw = createBigWarp( new boolean[] { true, false, false, false } ); /* Load the known good*/ final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; @@ -272,20 +295,14 @@ public void compareKnownXmlComparisonTest() throws SpimDataException, IOExceptio bw.saveSettings( tmpXmlFile.getAbsolutePath() ); XMLUnit.setIgnoreWhitespace( true ); XMLUnit.setIgnoreComments( true ); - try - { - XMLAssert.assertXMLEqual( new FileReader( originalXmlSettings ), new FileReader( tmpXmlFile ) ); - } - finally - { - bw.closeAll(); - } + XMLAssert.assertXMLEqual( new FileReader( originalXmlSettings ), new FileReader( tmpXmlFile ) ); + } @Test public void jsonLoadSaveComparisonTest() throws SpimDataException, IOException, JDOMException { - BigWarp< ? > bw = createBigWarp( new boolean[] { true, false } ); + bw = createBigWarp( new boolean[] { true, false } ); final String expectedJsonFile = "src/test/resources/settings/expected_with_dfield.json"; bw.loadSettings( expectedJsonFile ); @@ -303,20 +320,13 @@ public void jsonLoadSaveComparisonTest() throws SpimDataException, IOException, final JsonElement jsonSettingsOut = JsonParser.parseReader( in ); final JsonElement expectedJson = JsonParser.parseReader( new FileReader( expectedJsonFile ) ); - try - { - Assert.assertEquals( expectedJson, jsonSettingsOut ); - } - finally - { - bw.closeAll(); - } + Assert.assertEquals( expectedJson, jsonSettingsOut ); } @Test public void landmarkComparisonTest() throws SpimDataException, IOException, JDOMException { - BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); + bw = createBigWarp( new boolean[] { true, false, false, false } ); final String xmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; final String csvLandmarks = "src/test/resources/settings/landmarks.csv"; @@ -337,14 +347,7 @@ public void landmarkComparisonTest() throws SpimDataException, IOException, JDOM final JsonElement jsonSettingsOut = JsonParser.parseReader( in ); final JsonElement expectedJson = JsonParser.parseReader( new FileReader( expectedJsonFile ) ); - try - { - Assert.assertEquals( expectedJson, jsonSettingsOut ); - } - finally - { - bw.closeAll(); - } + Assert.assertEquals( expectedJson, jsonSettingsOut ); } @@ -382,9 +385,4 @@ private static String prettyPrint (JsonObject json) { BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); return new BigWarp<>( data, "bigwarp", opts, null ); } - - public static void main( String[] args ) throws SpimDataException - { - createBigWarp( new boolean[] { true, false, false, false } ); - } } From 708babc10893f02fbd019624d10d3e5355237fe3 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:46:56 -0500 Subject: [PATCH 089/282] test: add source serializer test --- src/test/resources/settings/expected.json | 14 ++++++++++++++ .../resources/settings/expected_with_dfield.json | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/src/test/resources/settings/expected.json b/src/test/resources/settings/expected.json index 76603352..5c77a483 100644 --- a/src/test/resources/settings/expected.json +++ b/src/test/resources/settings/expected.json @@ -1,4 +1,18 @@ { + "Sources": { + "3": { + "isMoving": false + }, + "2": { + "isMoving": false + }, + "1": { + "isMoving": false + }, + "0": { + "isMoving": true + } + }, "ViewerP": { "Sources": [ true, diff --git a/src/test/resources/settings/expected_with_dfield.json b/src/test/resources/settings/expected_with_dfield.json index 71adf0b9..73a769c9 100644 --- a/src/test/resources/settings/expected_with_dfield.json +++ b/src/test/resources/settings/expected_with_dfield.json @@ -1,4 +1,12 @@ { + "Sources": { + "1": { + "isMoving": false + }, + "0": { + "isMoving": true + } + }, "ViewerP": { "Sources": [ true, From f791a5c608c560ed84af8b302060dce1604ad582 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:46:59 -0500 Subject: [PATCH 090/282] test: expect default sources to be inactive --- src/test/resources/settings/expected_with_dfield.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/resources/settings/expected_with_dfield.json b/src/test/resources/settings/expected_with_dfield.json index 73a769c9..89b46cb4 100644 --- a/src/test/resources/settings/expected_with_dfield.json +++ b/src/test/resources/settings/expected_with_dfield.json @@ -12,9 +12,9 @@ true, true, false, - true, false, - true + false, + false ], "SourceGroups": [ { @@ -43,9 +43,9 @@ true, true, false, - true, false, - true + false, + false ], "SourceGroups": [ { From ff9477aea9d8fd2ec31ff3ec058263a04f09f2c3 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 8 Nov 2022 09:47:05 -0500 Subject: [PATCH 091/282] test: initial source from url tests --- src/test/java/bigwarp/url/UrlParseTest.java | 171 +++++++++++++++----- 1 file changed, 131 insertions(+), 40 deletions(-) diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index 3d659694..b447df3b 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -1,42 +1,62 @@ package bigwarp.url; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - +import bdv.tools.transformation.TransformedSource; +import bdv.viewer.Source; +import bdv.viewer.SourceAndConverter; +import bigwarp.BigWarp; +import bigwarp.BigWarpInit; +import ij.IJ; +import ij.ImagePlus; +import ij.gui.NewImage; +import ij.plugin.StackWriter; import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.HashMap; - +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import mpicbg.spim.data.SpimDataException; import org.janelia.saalfeldlab.n5.N5FSReader; import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader; import org.janelia.saalfeldlab.n5.ij.N5Factory; import org.janelia.saalfeldlab.n5.zarr.N5ZarrReader; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.scijava.util.FileUtils; -import bdv.viewer.Source; -import ij.IJ; -import ij.ImagePlus; -import ij.gui.NewImage; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; public class UrlParseTest { - - private Class n5Clazz; - private Class zarrClazz; - private Class h5Clazz; - private HashMap urlToDimensions; + private static final String TIFF_FILE_3D = "src/test/resources/bigwarp/url/img.tif"; + + public static final String PNG_FILE_2D = "src/test/resources/bigwarp/url/img2d.png"; + + public static final String TIFF_STACK_DIR = "src/test/resources/bigwarp/url/imgDir3d/"; + + private Class< N5FSReader > n5Clazz; + + private Class< N5ZarrReader > zarrClazz; + + private Class< N5HDF5Reader > h5Clazz; + + private HashMap< String, long[] > urlToDimensions; private String n5Root, zarrRoot, h5Root; - private String img3dTifPath, img2dPngPath; @Before - public void before() + public void before() throws IOException { + /* Cleanup, to ensure no old test files persist */ + cleanup(); + n5Clazz = N5FSReader.class; zarrClazz = N5ZarrReader.class; h5Clazz = N5HDF5Reader.class; @@ -59,12 +79,20 @@ public void before() urlToDimensions.put( zarrRoot + "?img2", new long[] { 8, 12, 16 } ); ImagePlus img3d = NewImage.createByteImage( "img3d", 8, 8, 4, NewImage.FILL_RAMP ); - img3dTifPath = new File( "src/test/resources/bigwarp/url/img.tif").getAbsolutePath(); - IJ.save( img3d, img3dTifPath ); + IJ.save( img3d, TIFF_FILE_3D ); ImagePlus img2d = NewImage.createByteImage( "img2d", 8, 8, 1, NewImage.FILL_RAMP ); - img2dPngPath = new File( "src/test/resources/bigwarp/url/img2d.png").getAbsolutePath(); - IJ.save( img2d, img2dPngPath ); + IJ.save( img2d, PNG_FILE_2D ); + Files.createDirectory( Paths.get( TIFF_STACK_DIR ) ); + StackWriter.save( img3d , TIFF_STACK_DIR, "format=tif"); + } + + @After + public void cleanup() throws IOException + { + Files.deleteIfExists(Paths.get( TIFF_FILE_3D )); + Files.deleteIfExists(Paths.get( PNG_FILE_2D )); + FileUtils.deleteRecursively( new File(TIFF_STACK_DIR)); } @Test @@ -73,9 +101,9 @@ public void testFactories() N5Factory n5Factory = new N5Factory(); try { - assertEquals( n5Clazz, n5Factory.openReader( n5Root ).getClass()); - assertEquals( zarrClazz, n5Factory.openReader( zarrRoot ).getClass()); - assertEquals( h5Clazz, n5Factory.openReader( h5Root ).getClass()); + assertEquals( n5Clazz, n5Factory.openReader( n5Root ).getClass() ); + assertEquals( zarrClazz, n5Factory.openReader( zarrRoot ).getClass() ); + assertEquals( h5Clazz, n5Factory.openReader( h5Root ).getClass() ); } catch ( IOException e ) { @@ -83,26 +111,31 @@ public void testFactories() } } + @Test public void testUrlSources() { final String bdvXmlUrl = new File( "src/test/resources/mri-stack.xml" ).getAbsolutePath(); - Source bdvXmlSrc = loadSourceFromUrl( bdvXmlUrl ); -// assertNotNull( bdvXmlSrc ); + Source< ? > bdvXmlSrc = loadSourceFromUri( bdvXmlUrl ); + assertNotNull( bdvXmlSrc ); - Source img3dTif = loadSourceFromUrl( img3dTifPath ); -// assertNotNull( img3dTif ); -// assertArrayEquals( new long[]{8,8,4}, img3dTif.getSource( 0, 0 ).dimensionsAsLongArray() ); + Source< ? > img3dTif = loadSourceFromUri( TIFF_FILE_3D ); + assertNotNull( img3dTif ); + assertArrayEquals( new long[]{8,8,4}, img3dTif.getSource( 0, 0 ).dimensionsAsLongArray() ); - Source img2dPng = loadSourceFromUrl( img2dPngPath ); -// assertNotNull( img2dPng ); -// assertArrayEquals( new long[]{8,8,1}, img2dPng.getSource( 0, 0 ).dimensionsAsLongArray() ); // TODO I wrote this to expect [8,8,1], but it might need [8,8]. + Source< ? > img2dPng = loadSourceFromUri( PNG_FILE_2D ); + assertNotNull( img2dPng ); + assertArrayEquals( new long[]{8,8,1}, img2dPng.getSource( 0, 0 ).dimensionsAsLongArray() ); // TODO I wrote this to expect [8,8,1], but it might need [8,8]. - for( String url : urlToDimensions.keySet() ) + Source< ? > img3dTifFromDir = loadSourceFromUri( TIFF_STACK_DIR ); + assertNotNull( img3dTifFromDir ); + assertArrayEquals( new long[]{8,8,4}, img3dTifFromDir.getSource( 0, 0 ).dimensionsAsLongArray() ); + + for ( String url : urlToDimensions.keySet() ) { - Source src = loadSourceFromUrl( url ); -// assertNotNull( src ); -// assertArrayEquals( urlToDimensions.get( url ), src.getSource( 0, 0 ).dimensionsAsLongArray() ); // TODO I wrote this to expect [8,8,1], but it might need [8,8]. + Source< ? > src = loadSourceFromUri( url ); + assertNotNull( src ); + assertArrayEquals( urlToDimensions.get( url ), src.getSource( 0, 0 ).dimensionsAsLongArray() ); // TODO I wrote this to expect [8,8,1], but it might need [8,8]. } } @@ -123,16 +156,74 @@ public void testUrlTransforms() // assertEquals( s0, s0Default ); } + @Test + public void n5FileEquivalencyTest() throws IOException + { + final String relativePath = "src/test/resources/bigwarp/url/transformTest.n5"; + final String absolutePath = Paths.get( relativePath ).toAbsolutePath().toFile().getCanonicalPath(); + final String[] variants = new String[]{ + "n5:file://" + absolutePath + "?img#coordinateTransformations[0]", + "n5:file://" + absolutePath + "?img", + "n5://" + absolutePath + "?img#coordinateTransformations[0]", + "n5://" + absolutePath + "?img", + "file://" + absolutePath + "?img#coordinateTransformations[0]", + "file://" + absolutePath + "?img", + "n5:" + absolutePath + "?img#coordinateTransformations[0]", + "n5:" + absolutePath + "?img", + absolutePath + "?img#coordinateTransformations[0]", + absolutePath + "?img", + "n5:file://" + relativePath + "?img#coordinateTransformations[0]", + "n5:file://" + relativePath + "?img", + "n5://" + relativePath + "?img#coordinateTransformations[0]", + "n5://" + relativePath + "?img", + "file://" + relativePath + "?img#coordinateTransformations[0]", + "file://" + relativePath + "?img", + "n5:" + relativePath + "?img#coordinateTransformations[0]", + "n5:" + relativePath + "?img", + relativePath + "?img#coordinateTransformations[0]", + relativePath + "?img" + }; + + final BigWarp.BigWarpData< Object > data = BigWarpInit.initData(); + try + { + + final AtomicInteger id = new AtomicInteger( 1 ); + for ( String uri : variants) + { + final int setupId = id.getAndIncrement(); + BigWarpInit.add( data, uri, setupId, new Random().nextBoolean() ); + assertEquals( uri, data.urls.get(setupId ).getA().get()); + } + } + catch ( URISyntaxException | IOException | SpimDataException e ) + { + throw new RuntimeException( e ); + } + } + private Object loadTransformFromUrl( String url ) { // TODO Caleb will remove me and replace calls to me with something real return null; } - private Source loadSourceFromUrl( String url ) + private Source< ? > loadSourceFromUri( String uri ) { - // TODO Caleb will remove me and replace calls to me with something real - return null; + + + final BigWarp.BigWarpData< Object > data = BigWarpInit.initData(); + try + { + final Source< ? > source = BigWarpInit.add( data, uri, 0, true ); + data.wrapUp(); + return source; + } + catch ( URISyntaxException | IOException | SpimDataException e ) + { + throw new RuntimeException( e ); + } } + } From 6e3c742a0975b75259a998dcd6e85481234eff09 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 8 Nov 2022 13:28:39 -0500 Subject: [PATCH 092/282] feat/refactor: add InvertibleWrapped2DTransformAs3D * toward optionally adding a transformation to every source --- src/main/java/bigwarp/BigWarp.java | 8 +- src/main/java/bigwarp/BigWarpData.java | 138 +++++++++++++++++- src/main/java/bigwarp/BigWarpInit.java | 10 +- .../bigwarp/landmarks/LandmarkTableModel.java | 6 +- .../bigwarp/transforms/BigWarpTransform.java | 12 +- ... => InvertibleWrapped2DTransformAs3D.java} | 53 +------ 6 files changed, 160 insertions(+), 67 deletions(-) rename src/main/java/net/imglib2/realtransform/{Wrapped2DTransformAs3D.java => InvertibleWrapped2DTransformAs3D.java} (57%) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index b74c200e..10d680ec 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -110,6 +110,7 @@ import bdv.tools.brightness.BrightnessDialog; import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.SetupAssignments; +import bdv.tools.transformation.TransformedSource; import bdv.util.Bounds; import bdv.viewer.BigWarpDragOverlay; import bdv.viewer.BigWarpLandmarkFrame; @@ -164,8 +165,9 @@ import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.BoundingBoxEstimation; import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.ThinplateSplineTransform; -import net.imglib2.realtransform.Wrapped2DTransformAs3D; +import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.real.FloatType; @@ -1406,7 +1408,7 @@ public boolean addPoint( final double[] ptarray, final boolean isMoving ) InvertibleRealTransform transform; if( options.values.is2D() && currentTransform != null ) - transform = ((Wrapped2DTransformAs3D)currentTransform).getTransform(); + transform = ((InvertibleWrapped2DTransformAs3D)currentTransform).getTransform(); else transform = currentTransform; @@ -2162,7 +2164,7 @@ private void setTransformationMovingSourceOnly( final InvertibleRealTransform tr // the xfm must always be 3d for bdv to be happy. // when bigwarp has 2d images though, the z- component will be left unchanged - //InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); + // InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); // the updateTransform method creates a copy of the transform ( ( WarpedSource< ? > ) ( data.sources.get( idx ).getSpimSource() ) ).updateTransform( transform ); diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index de597bcb..8e1d0bf2 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -4,32 +4,41 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.stream.IntStream; import bdv.cache.CacheControl; import bdv.gui.BigWarpViewerFrame; +import bdv.img.WarpedSource; import bdv.tools.InitializeViewerState; import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.SetupAssignments; +import bdv.tools.transformation.TransformedSource; import bdv.util.Bounds; import bdv.viewer.ConverterSetups; +import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bdv.viewer.SynchronizedViewerState; import bdv.viewer.VisibilityAndGrouping; import bigwarp.loader.ImagePlusLoader.ColorSettings; +import net.imglib2.realtransform.AffineGet; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; +import net.imglib2.realtransform.RealTransform; +import net.imglib2.realtransform.RealTransformSequence; +import net.imglib2.realtransform.Wrapped2DTransformAs3D; public class BigWarpData< T > { // TODO JOHN CHECK ME public List< SourceAndConverter< T > > sources; + public List transforms; + public final List< ConverterSetup > converterSetups; public final CacheControl cache; -// public int[] movingSourceIndices; -// -// public int[] targetSourceIndices; - public final List< Integer > movingSourceIndexList; public final List< Integer > targetSourceIndexList; @@ -49,13 +58,31 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, final List< C listOf( movingIndexes ), listOf( targetIndexes )); } + + public BigWarpData( final List< SourceAndConverter< T > > sources, + final List< ConverterSetup > converterSetups, + final CacheControl cache ) + { + this( sources, null, converterSetups, cache ); + } - public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + public BigWarpData( final List< SourceAndConverter< T > > sources, + final List< RealTransform > transforms, + final List< ConverterSetup > converterSetups, final CacheControl cache ) { this.sources = sources; this.converterSetups = converterSetups; + if( transforms != null ) + this.transforms = transforms; + else + { + // fill the initial transform list with nulls + this.transforms = new ArrayList<>(); + IntStream.range( 0, sources.size() ).forEach( i -> this.transforms.add( null )); + } + this.movingSourceIndexList = new ArrayList<>(); this.targetSourceIndexList = new ArrayList<>(); isMovingMap = new HashMap<>(); @@ -76,8 +103,6 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, final List< C { this.sources = sources; this.converterSetups = converterSetups; -// this.movingSourceIndices = movingSourceIndices; -// this.targetSourceIndices = targetSourceIndices; this.movingSourceIndexList = movingIndexes; this.targetSourceIndexList = targetIndexes; @@ -168,6 +193,105 @@ public void wrapUp() Collections.sort( targetSourceIndexList ); } + public void setTransform( int i, RealTransform transform ) + { + transforms.set( i, transform ); + } + + public void applyTransformations() + { +// System.out.println( "before " + colorSettings.keySet().size()); + + int i = 0; + for ( final SourceAndConverter sac : sources ) + { + if ( transforms.get( i ) != null ) + { + SourceAndConverter newSac = inheritConverter( + applyFixedTransform( sac.getSpimSource(), transforms.get( i )), + sac ); + + sourceColorSettings.put( newSac, sourceColorSettings.get( sac )); + sources.set( i, newSac ); + } + i++; + } +// System.out.println( "after " + colorSettings.keySet().size()); + } + + public static < T > SourceAndConverter< T > inheritConverter( final Source src, final SourceAndConverter< T > sac ) + { + if ( sac.asVolatile() == null ) { + return new SourceAndConverter< T >( src, sac.getConverter(), null ); + } + else + { + System.out.println( "Inherit Converter needs to handle volatile"); +// inheritConverter( src, sac ); + return null; +// return new SourceAndConverter< T >( src, sac.getConverter(), wrapSourceAsTransformed( src, name + "_vol", ndims ) ); + } + } + + public Source applyFixedTransform( final Source src, final RealTransform transform ) + { + RealTransform tform = transform; + if( transform.numSourceDimensions() < 3 ) + { + if( transform instanceof InvertibleRealTransform ) + tform = new Wrapped2DTransformAs3D( transform ); + else + tform = new InvertibleWrapped2DTransformAs3D( ( InvertibleRealTransform ) transform ); + } + + if( transform instanceof AffineGet ) + { + // can use TransformedSource + TransformedSource tsrc; + + /* + * UNSURE WHAT TO DO IN THIS CASE + */ +// if( (src instanceof WarpedSource )) +// { +// Source< ? > wsrc = ( ( WarpedSource< ? > ) src ).getWrappedSource(); +// } + + final AffineTransform3D affine3d; + if( transform instanceof AffineTransform3D ) + affine3d = ( AffineTransform3D ) transform; + else + { + affine3d = new AffineTransform3D(); + affine3d.preConcatenate( ( AffineGet ) transform ); + } + + if ( src instanceof TransformedSource ) + { + tsrc = ( TransformedSource ) ( src ); + } + else + { + tsrc = new TransformedSource( src ); + } + tsrc.setFixedTransform( affine3d ); + return ( Source< T > ) tsrc; + } + else + { + // need to use WarpedSource + WarpedSource wsrc; + if( !(src instanceof WarpedSource )) + wsrc = new WarpedSource( src, src.getName() ); + else + wsrc = (WarpedSource)src; + + wsrc.updateTransform( tform ); + wsrc.setIsTransformed( true ); + return ( Source< T > ) wsrc; + } + } + /** * @deprecated */ diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 9cf37a46..6df93311 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -74,6 +74,7 @@ import net.imglib2.display.RealARGBColorConverter; import net.imglib2.display.ScaledARGBConverter; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.RealTransform; import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.NumericType; import net.imglib2.type.numeric.RealType; @@ -339,10 +340,17 @@ public static < T > int add( BigWarpData bwdata, ImagePlus ip, int setupId, int return loader.numSources(); } - @SuppressWarnings( { "unchecked", "rawtypes" } ) + @SuppressWarnings( { "rawtypes" } ) public static < T > BigWarpData< ? > add( BigWarpData bwdata, Source< T > src, int setupId, int numTimepoints, boolean isMoving ) + { + return add( bwdata, src, setupId, numTimepoints, isMoving, null ); + } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + public static < T > BigWarpData< ? > add( BigWarpData bwdata, Source< T > src, int setupId, int numTimepoints, boolean isMoving, RealTransform transform ) { addSourceToListsGenericType( src, setupId, bwdata.converterSetups, bwdata.sources ); + bwdata.transforms.add( transform ); int N = bwdata.sources.size(); if ( isMoving ) diff --git a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java index 78a947de..a489207d 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java +++ b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java @@ -52,7 +52,7 @@ import net.imglib2.RealLocalizable; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.RealTransform; -import net.imglib2.realtransform.Wrapped2DTransformAs3D; +import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import com.opencsv.CSVReader; @@ -880,8 +880,8 @@ public void resetLastPoint() public void updateAllWarpedPoints( final InvertibleRealTransform xfm ) { final InvertibleRealTransform xfmToUse; - if (xfm instanceof Wrapped2DTransformAs3D && ndims == 2) - xfmToUse = ((Wrapped2DTransformAs3D) xfm).transform; + if (xfm instanceof InvertibleWrapped2DTransformAs3D && ndims == 2) + xfmToUse = ((InvertibleWrapped2DTransformAs3D) xfm).transform; else xfmToUse = xfm; diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index a4a86e1d..23118d1c 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -50,7 +50,7 @@ import net.imglib2.realtransform.InverseRealTransform; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.ThinplateSplineTransform; -import net.imglib2.realtransform.Wrapped2DTransformAs3D; +import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; public class BigWarpTransform @@ -139,7 +139,7 @@ public InvertibleRealTransform getTransformation( final int index ) if( tableModel.getNumdims() == 2 ) { - invXfm = new Wrapped2DTransformAs3D( invXfm ); + invXfm = new InvertibleWrapped2DTransformAs3D( invXfm ); } currentTransform = invXfm; @@ -217,8 +217,8 @@ public InvertibleCoordinateTransform getCoordinateTransform() public InvertibleRealTransform unwrap2d( InvertibleRealTransform ixfm ) { - if( ixfm instanceof Wrapped2DTransformAs3D ) - return ((Wrapped2DTransformAs3D)ixfm).getTransform(); + if( ixfm instanceof InvertibleWrapped2DTransformAs3D ) + return ((InvertibleWrapped2DTransformAs3D)ixfm).getTransform(); else return ixfm; } @@ -402,9 +402,9 @@ else if( currentTransform instanceof WrappedCoordinateTransform ) { s = (( WrappedCoordinateTransform ) currentTransform).getTransform().toString(); } - else if( currentTransform instanceof Wrapped2DTransformAs3D ) + else if( currentTransform instanceof InvertibleWrapped2DTransformAs3D ) { - s = ( ( Wrapped2DTransformAs3D) currentTransform ).toString(); + s = ( ( InvertibleWrapped2DTransformAs3D) currentTransform ).toString(); } else { diff --git a/src/main/java/net/imglib2/realtransform/Wrapped2DTransformAs3D.java b/src/main/java/net/imglib2/realtransform/InvertibleWrapped2DTransformAs3D.java similarity index 57% rename from src/main/java/net/imglib2/realtransform/Wrapped2DTransformAs3D.java rename to src/main/java/net/imglib2/realtransform/InvertibleWrapped2DTransformAs3D.java index 4e6eb809..12833be7 100644 --- a/src/main/java/net/imglib2/realtransform/Wrapped2DTransformAs3D.java +++ b/src/main/java/net/imglib2/realtransform/InvertibleWrapped2DTransformAs3D.java @@ -24,14 +24,15 @@ import net.imglib2.RealLocalizable; import net.imglib2.RealPositionable; -public class Wrapped2DTransformAs3D implements InvertibleRealTransform +public class InvertibleWrapped2DTransformAs3D extends Wrapped2DTransformAs3D implements InvertibleRealTransform { public InvertibleRealTransform transform; public double[] tmp; - public Wrapped2DTransformAs3D( final InvertibleRealTransform transform ) + public InvertibleWrapped2DTransformAs3D( final InvertibleRealTransform transform ) { + super( transform ); this.transform = transform; tmp = new double[ 2 ]; } @@ -41,48 +42,6 @@ public InvertibleRealTransform getTransform() return transform; } - @Override - public int numSourceDimensions() - { - return 3; - } - - @Override - public int numTargetDimensions() - { - return 3; - } - - @Override - public void apply( double[] source, double[] target ) - { - // TODO this could be done without tmp if all downstream implementations - // could take source and target inputs with dim larger than the - // transform dim - tmp[ 0 ] = source[ 0 ]; - tmp[ 1 ] = source[ 1 ]; - transform.apply( tmp, tmp ); - target[ 0 ] = tmp[ 0 ]; - target[ 1 ] = tmp[ 1 ]; -// transform.apply( source, target ); - target[ 2 ] = source[ 2 ]; - } - - @Override - public void apply( RealLocalizable source, RealPositionable target ) - { - // TODO this could be done without tmp if all downstream implementations - // could take source and target inputs with dim larger than the - // transform dim - tmp[ 0 ] = source.getDoublePosition( 0 ); - tmp[ 1 ] = source.getDoublePosition( 1 ); - transform.apply( tmp, tmp ); - target.setPosition( tmp[ 0 ], 0 ); - target.setPosition( tmp[ 1 ], 1 ); -// transform.apply( source, target ); - target.setPosition( source.getDoublePosition( 2 ), 2 ); - } - @Override public void applyInverse( double[] source, double[] target ) { @@ -107,15 +66,15 @@ public void applyInverse( RealPositionable source, RealLocalizable target ) source.setPosition( target.getDoublePosition( 2 ), 2 ); } - public InvertibleRealTransform copy() + public InvertibleWrapped2DTransformAs3D copy() { - return new Wrapped2DTransformAs3D( transform.copy() ); + return new InvertibleWrapped2DTransformAs3D( transform.copy() ); } @Override public InvertibleRealTransform inverse() { - return new Wrapped2DTransformAs3D( transform.inverse() ); + return new InvertibleWrapped2DTransformAs3D( transform.inverse() ); } } From b4c878a5465dcf6bd0217cc0b41911a8f97629f7 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 8 Nov 2022 13:35:21 -0500 Subject: [PATCH 093/282] refactor add Wrapped2DTransformAs3D --- .../realtransform/Wrapped2DTransformAs3D.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/main/java/net/imglib2/realtransform/Wrapped2DTransformAs3D.java diff --git a/src/main/java/net/imglib2/realtransform/Wrapped2DTransformAs3D.java b/src/main/java/net/imglib2/realtransform/Wrapped2DTransformAs3D.java new file mode 100644 index 00000000..fafbef66 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/Wrapped2DTransformAs3D.java @@ -0,0 +1,91 @@ +/*- + * #%L + * BigWarp plugin for Fiji. + * %% + * Copyright (C) 2015 - 2022 Howard Hughes Medical Institute. + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package net.imglib2.realtransform; + +import net.imglib2.RealLocalizable; +import net.imglib2.RealPositionable; + +public class Wrapped2DTransformAs3D implements RealTransform +{ + public RealTransform transform; + + public double[] tmp; + + public Wrapped2DTransformAs3D( final RealTransform transform ) + { + this.transform = transform; + tmp = new double[ 2 ]; + } + + public RealTransform getTransform() + { + return transform; + } + + @Override + public int numSourceDimensions() + { + return 3; + } + + @Override + public int numTargetDimensions() + { + return 3; + } + + @Override + public void apply( double[] source, double[] target ) + { + // TODO this could be done without tmp if all downstream implementations + // could take source and target inputs with dim larger than the + // transform dim + tmp[ 0 ] = source[ 0 ]; + tmp[ 1 ] = source[ 1 ]; + transform.apply( tmp, tmp ); + target[ 0 ] = tmp[ 0 ]; + target[ 1 ] = tmp[ 1 ]; +// transform.apply( source, target ); + target[ 2 ] = source[ 2 ]; + } + + @Override + public void apply( RealLocalizable source, RealPositionable target ) + { + // TODO this could be done without tmp if all downstream implementations + // could take source and target inputs with dim larger than the + // transform dim + tmp[ 0 ] = source.getDoublePosition( 0 ); + tmp[ 1 ] = source.getDoublePosition( 1 ); + transform.apply( tmp, tmp ); + target.setPosition( tmp[ 0 ], 0 ); + target.setPosition( tmp[ 1 ], 1 ); +// transform.apply( source, target ); + target.setPosition( source.getDoublePosition( 2 ), 2 ); + } + + public Wrapped2DTransformAs3D copy() + { + return new Wrapped2DTransformAs3D( transform.copy() ); + } + +} From 13e92b371e49e1a2f11188027ac30b9f8ab4bce2 Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 8 Nov 2022 16:12:07 -0500 Subject: [PATCH 094/282] feat: add BigWarpData helper methods * fix viewer converterSetups --- src/main/java/bigwarp/BigWarp.java | 33 ++++++++-------------- src/main/java/bigwarp/BigWarpData.java | 39 ++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 10d680ec..a6482048 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -567,32 +567,23 @@ public void initialize() // starting view data.sources.get( data.targetSourceIndexList.get(0) ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); List< SourceAndConverter< T > > dSrcs = data.sources; -// List< SourceAndConverter< ? > > pSrcs = viewerP.state().getSources(); -// List< SourceAndConverter< ? > > qSrcs = viewerQ.state().getSources(); -// -// System.out.println("before"); -// for( SourceAndConverter< T > s : data.sources ) -// for( SourceAndConverter< ? > s : pSrcs ) -// { -// System.out.println( data.sourceColorSettings.get( s )); -// } viewerP.state().clearSources(); - viewerQ.state().clearSources(); - final SynchronizedViewerState pState = viewerP.state(); + + viewerQ.state().clearSources(); final SynchronizedViewerState qState = viewerQ.state(); - for( SourceAndConverter sac : dSrcs ) + + for( int i = 0; i < dSrcs.size(); i++ ) { + final SourceAndConverter sac = dSrcs.get( i ); pState.addSource( sac ); qState.addSource( sac ); - } -// for( SourceAndConverter< T > s : data.sources ) -// for( SourceAndConverter< ? > s : viewerP.state().getSources() ) -// { -// System.out.println( data.sourceColorSettings.get( s )); -// } + // update the viewer converter setups too + viewerFrameP.getConverterSetups().put( sac, data.converterSetups.get( i ) ); + viewerFrameQ.getConverterSetups().put( sac, data.converterSetups.get( i ) ); + } SwingUtilities.invokeLater( new Runnable() { @@ -661,12 +652,12 @@ public static void initBrightness( final double cumulativeMinCutoff, final doubl setup.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); } - public void addSource( Source source, boolean moving ) + public void addSource( Source source, boolean moving ) { - + data.addSource( source, moving ); } - public void addSource( Source source ) + public void addSource( Source source ) { addSource( source, false ); } diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 8e1d0bf2..56c404ff 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -25,7 +25,6 @@ import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.RealTransform; -import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.Wrapped2DTransformAs3D; public class BigWarpData< T > @@ -193,6 +192,40 @@ public void wrapUp() Collections.sort( targetSourceIndexList ); } + public void addSource( Source src, boolean isMoving ) + { + addSource( src, isMoving ); + } + + public void addSource( Source src, boolean isMoving, RealTransform transform ) + { + // find an unused id + int id = 0; + for( ConverterSetup cs : converterSetups ) + { + if( id == cs.getSetupId() ) + id++; + } + BigWarpInit.add( this, src, id, 0, isMoving, transform ); + } + + public void addSourceAndConverter( SourceAndConverter sac, boolean isMoving ) + { + addSourceAndConverter( sac, isMoving, null ); + } + + public void addSourceAndConverter( SourceAndConverter sac, boolean isMoving, RealTransform transform ) + { + sources.add( sac ); + isMovingMap.put( sac, isMoving ); + transforms.add( transform ); // transform may be null + + if( isMoving ) + movingSourceIndexList.add( sources.size() - 1 ); + else + targetSourceIndexList.add( sources.size() - 1 ); + } + public void setTransform( int i, RealTransform transform ) { transforms.set( i, transform ); @@ -200,8 +233,6 @@ public void setTransform( int i, RealTransform transform ) public void applyTransformations() { -// System.out.println( "before " + colorSettings.keySet().size()); - int i = 0; for ( final SourceAndConverter sac : sources ) { @@ -216,7 +247,6 @@ public void applyTransformations() } i++; } -// System.out.println( "after " + colorSettings.keySet().size()); } public static < T > SourceAndConverter< T > inheritConverter( final Source src, final SourceAndConverter< T > sac ) @@ -314,7 +344,6 @@ public void transferChannelSettings( final BigWarpViewerFrame viewer ) if ( sourceColorSettings.get( sac ) == null ) continue; - System.out.println( setups.getConverterSetup( sac ) ); sourceColorSettings.get( sac ).updateSetup( setups.getConverterSetup( sac ) ); } else From 48ca5fa97c79e1617200586385ef06ca060968bd Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 8 Nov 2022 16:21:03 -0500 Subject: [PATCH 095/282] test: add a test script for transformed sources --- .../BigWarpTransformedSourcesTest.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/test/java/bigwarp/BigWarpTransformedSourcesTest.java diff --git a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java new file mode 100644 index 00000000..dde145b8 --- /dev/null +++ b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java @@ -0,0 +1,57 @@ +package bigwarp; + +import bdv.export.ProgressWriterConsole; +import bdv.viewer.Source; +import ij.IJ; +import ij.ImagePlus; +import mpicbg.spim.data.SpimDataException; +import net.imglib2.realtransform.AffineTransform3D; + +public class BigWarpTransformedSourcesTest +{ + + public static void main( String[] args ) throws SpimDataException + { +// final ImagePlus mr = IJ.openImage("/home/john/tmp/mri-stack.tif"); +// final ImagePlus t1 = IJ.openImage("/home/john/tmp/t1-head.tif"); + + final ImagePlus mr = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif"); + final ImagePlus t1 = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/t1-head.tif"); + + int id = 0; + final BigWarpData< ? > data = BigWarpInit.initData(); + BigWarpInit.add( data, mr, id++, 0, true ); + BigWarpInit.add( data, t1, id++, 0, false ); + BigWarpInit.add( data, t1, id++, 0, false ); + data.wrapUp(); + + AffineTransform3D translation0 = new AffineTransform3D(); + translation0.translate( -50, -50, -10 ); + data.setTransform( 0, translation0 ); + + AffineTransform3D translation = new AffineTransform3D(); + translation.translate( -100, -150, -50 ); + data.setTransform( 2, translation ); + data.applyTransformations(); + +// System.out.println("before"); +// data.testColorSettings(); +// System.out.println(""); + + data.applyTransformations(); + +// System.out.println("after"); +// data.testColorSettings(); + +// Source< ? > tsrc = data.applyFixedTransform( data.getTargetSource( 0 ).getSpimSource(), translation ); +// System.out.println( tsrc ); + + final BigWarp bw = new BigWarp<>( data, "Big Warp", new ProgressWriterConsole()); +// bw.loadLandmarks( "/home/john/tmp/bw_tformTest_landmarks.csv" ); + bw.loadLandmarks( "/groups/saalfeld/home/bogovicj/tmp/bw_tformTest_landmarks.csv" ); + +// bw.getViewerFrameP().getConverterSetups() + + } + +} From f11436789dc0eea0133e6e91b940c2f74c9bd399 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 9 Nov 2022 10:29:19 -0500 Subject: [PATCH 096/282] chore: bump jitk-tps, rm duplicate n5-imglib2 declaration * still using n5-imglib2 snapshot --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3a847328..ce8c098d 100644 --- a/pom.xml +++ b/pom.xml @@ -116,12 +116,11 @@ 1.48 1.4.1 - 3.0.2 + 3.0.3 4.0.0 2.5.1 3.2.1 - 4.3.0 1.4.1 From f5c22783b9a00f32aa06ce4ebd9c4a2a46415b19 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 9 Nov 2022 10:42:50 -0500 Subject: [PATCH 097/282] refactor: tests after BigWarpData change --- src/test/java/bigwarp/SerializationTest.java | 2 +- src/test/java/bigwarp/url/UrlParseTest.java | 5 +++-- .../SimilarityTransformInterpolationExample.java | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index daaad421..b3a7ed8c 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -371,7 +371,7 @@ private static String prettyPrint (JsonObject json) { private static BigWarp< ? > createBigWarp( boolean[] moving ) throws SpimDataException { - final BigWarp.BigWarpData< Object > data = BigWarpInit.initData(); + final BigWarpData< Object > data = BigWarpInit.initData(); FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( 3, ( l, v ) -> v.setOne(), diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index b447df3b..70784820 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -4,6 +4,7 @@ import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bigwarp.BigWarp; +import bigwarp.BigWarpData; import bigwarp.BigWarpInit; import ij.IJ; import ij.ImagePlus; @@ -184,7 +185,7 @@ public void n5FileEquivalencyTest() throws IOException relativePath + "?img" }; - final BigWarp.BigWarpData< Object > data = BigWarpInit.initData(); + final BigWarpData< Object > data = BigWarpInit.initData(); try { @@ -212,7 +213,7 @@ private Object loadTransformFromUrl( String url ) { - final BigWarp.BigWarpData< Object > data = BigWarpInit.initData(); + final BigWarpData< Object > data = BigWarpInit.initData(); try { final Source< ? > source = BigWarpInit.add( data, uri, 0, true ); diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index db958d8d..4b9c6b97 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -355,6 +355,7 @@ public static void show( String imgFile ) { } + @SuppressWarnings( { "rawtypes", "unchecked" } ) public static BdvStackSource makeTimeStack( RealRandomAccessible img, Interval interval, AbstractTransformAnimator interpolator, String name, BdvOptions opts ) { return makeTimeStack( img, interval, new AnimatorTimeVaryingTransformation( interpolator ), name, opts ); From d4b828506f9905ce0e1ace784daab57655a2a8cc Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 9 Nov 2022 10:46:49 -0500 Subject: [PATCH 098/282] feat: reworking source grouping --- .../java/bdv/viewer/BigWarpViewerPanel.java | 8 +- src/main/java/bigwarp/BigWarp.java | 255 +++++++++++------- src/main/java/bigwarp/BigWarpData.java | 26 +- src/main/java/bigwarp/BigWarpInit.java | 8 +- .../BigWarpTransformedSourcesTest.java | 27 +- 5 files changed, 199 insertions(+), 125 deletions(-) diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index 0d881603..26d5da56 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -158,6 +158,8 @@ public void setHoveredIndex( int index ) */ public int updateGrouping() { + // TODO consider deprecating in favor of Bigwarp.createMovingTargetGroups + final SynchronizedViewerState state = state(); synchronized ( state ) { @@ -201,8 +203,10 @@ public int updateGrouping() public boolean isInFixedImageSpace() { -// return !isMoving || ( ( WarpedSource< ? > ) ( state().getSources().get( bwData.movingSourceIndexList.get( 0 ) ).getSpimSource() ) ).isTransformed(); - return !isMoving || ( ( WarpedSource< ? > ) ( ( bwData.getMovingSource( 0 )).getSpimSource() ) ).isTransformed(); + if( bwData.numMovingSources() < 1 ) + return true; + else + return !isMoving || ( ( WarpedSource< ? > ) ( ( bwData.getMovingSource( 0 )).getSpimSource() ) ).isTransformed(); } public boolean doUpdateOnDrag() diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 19564445..4b929283 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -21,10 +21,6 @@ */ package bigwarp; -import bdv.viewer.ConverterSetups; -import bdv.viewer.DisplayMode; -import bdv.viewer.TransformListener; -import bdv.viewer.ViewerState; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; @@ -36,6 +32,7 @@ import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; @@ -68,12 +65,10 @@ import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; -import mpicbg.spim.data.SpimData; -import mpicbg.spim.data.XmlIoSpimData; -import mpicbg.spim.data.registration.ViewTransformAffine; - import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.ij.N5Exporter; +import org.janelia.utility.geom.BoundingSphereRitter; +import org.janelia.utility.geom.Sphere; import org.janelia.utility.ui.RepeatingReleasedEventsFixer; import org.jdom2.Document; import org.jdom2.Element; @@ -85,6 +80,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.stream.JsonReader; + import bdv.BigDataViewer; import bdv.export.ProgressWriter; import bdv.export.ProgressWriterConsole; @@ -114,14 +111,18 @@ import bdv.viewer.BigWarpOverlay; import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.BigWarpViewerSettings; +import bdv.viewer.ConverterSetups; +import bdv.viewer.DisplayMode; import bdv.viewer.Interpolation; import bdv.viewer.LandmarkPointMenu; import bdv.viewer.MultiBoxOverlay2d; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; +import bdv.viewer.SourceGroup; import bdv.viewer.SynchronizedViewerState; +import bdv.viewer.TransformListener; import bdv.viewer.ViewerPanel; -import bdv.viewer.VisibilityAndGrouping; +import bdv.viewer.ViewerState; import bdv.viewer.WarpNavigationActions; import bdv.viewer.animate.SimilarityModel3D; import bdv.viewer.animate.TranslationAnimator; @@ -129,7 +130,6 @@ import bdv.viewer.overlay.BigWarpSourceOverlayRenderer; import bdv.viewer.overlay.MultiBoxOverlayRenderer; import bigwarp.landmarks.LandmarkTableModel; -import bigwarp.loader.ImagePlusLoader; import bigwarp.loader.ImagePlusLoader.ColorSettings; import bigwarp.source.GridSource; import bigwarp.source.JacobianDeterminantSource; @@ -139,12 +139,10 @@ import bigwarp.transforms.WrappedCoordinateTransform; import bigwarp.transforms.io.TransformWriterJson; import bigwarp.util.BigWarpUtils; -import com.google.gson.stream.JsonReader; import fiji.util.gui.GenericDialogPlus; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; -import java.io.FileReader; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import jitk.spline.XfmUtils; import mpicbg.models.AbstractModel; @@ -159,7 +157,10 @@ import mpicbg.models.SimilarityModel2D; import mpicbg.models.TranslationModel2D; import mpicbg.models.TranslationModel3D; +import mpicbg.spim.data.SpimData; import mpicbg.spim.data.SpimDataException; +import mpicbg.spim.data.XmlIoSpimData; +import mpicbg.spim.data.registration.ViewTransformAffine; import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; @@ -168,20 +169,17 @@ import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.BoundingBoxEstimation; import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.realtransform.inverse.RealTransformFiniteDerivatives; -import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; -import org.janelia.utility.geom.BoundingSphereRitter; -import org.janelia.utility.geom.Sphere; public class BigWarp< T > { - protected static final int DEFAULT_WIDTH = 600; protected static final int DEFAULT_HEIGHT = 400; @@ -298,6 +296,8 @@ public class BigWarp< T > private BigWarpTransform bwTransform; + protected SourceGroup mvgGrp, tgtGrp; + private BoundingBoxEstimation bboxOptions; private long keyClickMaxLength = 250; @@ -477,7 +477,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie bwTransform = new BigWarpTransform( landmarkModel ); bwTransform.initializeInverseParameters(data); - bwTransform.setLambda( transformMask.getRandomAccessible() ); solverThread = new SolveThread( this ); solverThread.start(); @@ -529,7 +528,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie landmarkClickListenerP = new MouseLandmarkListener( this.viewerP ); landmarkClickListenerQ = new MouseLandmarkListener( this.viewerQ ); - addMaskMouseListener(); // have to be safe here and use 3dim point for both 3d and 2d currentLandmark = new RealPoint( 3 ); @@ -583,25 +581,38 @@ public void initialize() wrapMovingSources( ndims, data ); // starting view - data.sources.get( data.targetSourceIndexList.get(0) ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); - List< SourceAndConverter< T > > dSrcs = data.sources; + if( data.numTargetSources() > 0 ) + data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); - viewerP.state().clearSources(); - final SynchronizedViewerState pState = viewerP.state(); + baselineModelIndex = 0; + final ARGBType white = new ARGBType( ARGBType.rgba( 255, 255, 255, 255 )); - viewerQ.state().clearSources(); - final SynchronizedViewerState qState = viewerQ.state(); +// warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "Warp magnitude" ); +// jacDetSource = addJacobianDeterminantSource( data, "Jacobian determinant" ); +// gridSource = addGridSource( data, "GridSource" ); +// setGridType( GridSource.GRID_TYPE.LINE ); +// +// transformMaskSource = addTransformMaskSource( data, ndims, "Transform mask" ); +// bwTransform.setLambda( transformMask.getRandomAccessible() ); +// addMaskMouseListener(); +// +// // set warp mag source to inactive at the start +// viewerP.state().setSourceActive( warpMagSource, false ); +// viewerQ.state().setSourceActive( warpMagSource, false ); +// data.sourceColorSettings.put( warpMagSource, new ImagePlusLoader.ColorSettings( -1, 0, 15, white )); +// +// // set warp grid source to inactive at the start +// viewerP.state().setSourceActive( gridSource, false ); +// viewerQ.state().setSourceActive( gridSource, false ); +// data.sourceColorSettings.put( gridSource, new ImagePlusLoader.ColorSettings( -1, 0, 255, white )); - for( int i = 0; i < dSrcs.size(); i++ ) - { - final SourceAndConverter sac = dSrcs.get( i ); - pState.addSource( sac ); - qState.addSource( sac ); + // set jacobian determinant source to inactive at the start +// viewerP.state().setSourceActive( jacDetSource, false ); +// viewerQ.state().setSourceActive( jacDetSource, false ); +// data.sourceColorSettings.put( jacDetSource, new ImagePlusLoader.ColorSettings( -1, 0.0, 1.0, white )); - // update the viewer converter setups too - viewerFrameP.getConverterSetups().put( sac, data.converterSetups.get( i ) ); - viewerFrameQ.getConverterSetups().put( sac, data.converterSetups.get( i ) ); - } + + synchronizeSources(); SwingUtilities.invokeLater( new Runnable() { @@ -613,34 +624,74 @@ public void run() } } ); - baselineModelIndex = 0; - warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "WarpMagnitudeSource" ); - jacDetSource = addJacobianDeterminantSource( data, "JacobianDeterminantSource" ); - gridSource = addGridSource( data, "GridSource" ); - setGridType( GridSource.GRID_TYPE.LINE ); - - final ARGBType white = new ARGBType( ARGBType.rgba( 255, 255, 255, 255 )); - // set warp mag source to inactive at the start - viewerP.state().setSourceActive( warpMagSource, false ); - viewerQ.state().setSourceActive( warpMagSource, false ); - data.sourceColorSettings.put( warpMagSource, new ImagePlusLoader.ColorSettings( -1, 0, 15, white )); - - // set warp grid source to inactive at the start - viewerP.state().setSourceActive( gridSource, false ); - viewerQ.state().setSourceActive( gridSource, false ); - data.sourceColorSettings.put( gridSource, new ImagePlusLoader.ColorSettings( -1, 0, 255, white )); - - // set jacobian determinant source to inactive at the start - viewerP.state().setSourceActive( jacDetSource, false ); - viewerQ.state().setSourceActive( jacDetSource, false ); - data.sourceColorSettings.put( jacDetSource, new ImagePlusLoader.ColorSettings( -1, 0.0, 1.0, white )); - updateSourceBoundingBoxEstimators(); // set initial transforms so data are visible InitializeViewerState.initTransform( viewerP ); InitializeViewerState.initTransform( viewerQ ); + createMovingTargetGroups(); + viewerP.state().setCurrentGroup( mvgGrp ); + viewerP.state().setCurrentGroup( tgtGrp ); + } + + public void synchronizeSources() + { + viewerP.state().clearSources(); + viewerQ.state().clearSources(); + final SynchronizedViewerState pState = viewerP.state(); + final SynchronizedViewerState qState = viewerQ.state(); + for ( int i = 0; i < data.sources.size(); i++ ) + { + final SourceAndConverter< T > sac = data.sources.get( i ); + pState.addSource( sac ); + qState.addSource( sac ); + + // update the viewer converter setups too + viewerFrameP.getConverterSetups().put( sac, data.converterSetups.get( i ) ); + viewerFrameQ.getConverterSetups().put( sac, data.converterSetups.get( i ) ); + } + } + + /** + * Create two source groups - one for moving images, + * and the other for target images, for both viewer frames. + * + * Ensure sources are synchronized with {@link synchronizeSources} + * before calling this method. + */ + public void createMovingTargetGroups() + { + mvgGrp = new SourceGroup(); + tgtGrp = new SourceGroup(); + + final SynchronizedViewerState pState = viewerP.state(); + final SynchronizedViewerState qState = viewerP.state(); + + pState.addGroup( mvgGrp ); + pState.addGroup( tgtGrp ); + + qState.addGroup( mvgGrp ); + qState.addGroup( tgtGrp ); + + pState.setGroupName( mvgGrp, "moving images" ); + pState.setGroupName( tgtGrp, "target images" ); + qState.setGroupName( mvgGrp, "moving images" ); + qState.setGroupName( tgtGrp, "target images" ); + + for ( SourceAndConverter< ? > sac : data.sources ) + { + if ( data.isMoving( sac ) ) + { + viewerP.state().addSourceToGroup( sac, mvgGrp ); + viewerQ.state().addSourceToGroup( sac, mvgGrp ); + } + else + { + viewerP.state().addSourceToGroup( sac, tgtGrp ); + viewerQ.state().addSourceToGroup( sac, tgtGrp ); + } + } } public int numDimensions() @@ -673,6 +724,7 @@ public static void initBrightness( final double cumulativeMinCutoff, final doubl public void addSource( Source source, boolean moving ) { data.addSource( source, moving ); + synchronizeSources(); } public void addSource( Source source ) @@ -680,6 +732,12 @@ public void addSource( Source source ) addSource( source, false ); } + public void removeSource( int i ) + { + data.remove( i ); + synchronizeSources(); + } + public void addKeyEventPostProcessor( final KeyEventPostProcessor ke ) { keyEventPostProcessorSet.add( ke ); @@ -2024,28 +2082,27 @@ protected void fitBaselineWarpMagModel() landmarkModel.copyLandmarks( p, q ); Arrays.fill( w, 1.0 ); - try + if( warpMagSource != null ) { - final AbstractModel< ? > baseline = this.baseXfmList[ baselineModelIndex ]; - - baseline.fit( p, q, w ); // FITBASELINE - WrappedCoordinateTransform baselineTransform = new WrappedCoordinateTransform( - (InvertibleCoordinateTransform)baseline, ndims ); + try + { + final AbstractModel< ? > baseline = this.baseXfmList[ baselineModelIndex ]; + baseline.fit( p, q, w ); // FITBASELINE + WrappedCoordinateTransform baselineTransform = new WrappedCoordinateTransform( + (InvertibleCoordinateTransform)baseline, ndims ); + + // the transform to compare is the inverse (because we use it for rendering) + // so need to give the inverse transform for baseline as well + ( ( WarpMagnitudeSource< ? > ) warpMagSource.getSpimSource() ).setBaseline( baselineTransform.inverse() ); + } + catch ( final IllDefinedDataPointsException | NotEnoughDataPointsException e ) + { + e.printStackTrace(); + } - // the transform to compare is the inverse (because we use it for rendering) - // so need to give the inverse transform for baseline as well - ( ( WarpMagnitudeSource< ? > ) warpMagSource.getSpimSource() ).setBaseline( baselineTransform.inverse() ); + getViewerFrameP().getViewerPanel().requestRepaint(); + getViewerFrameQ().getViewerPanel().requestRepaint(); } - catch ( final NotEnoughDataPointsException e ) - { - e.printStackTrace(); - } - catch ( final IllDefinedDataPointsException e ) - { - e.printStackTrace(); - } - getViewerFrameP().getViewerPanel().requestRepaint(); - getViewerFrameQ().getViewerPanel().requestRepaint(); } public void setMovingSpimData( SpimData movingSpimData, File movingImageXml ) @@ -2289,29 +2346,37 @@ private void setTransformationAll( final InvertibleRealTransform transform ) { setTransformationMovingSourceOnly( transform ); - final WarpMagnitudeSource< ? > wmSrc = ( ( WarpMagnitudeSource< ? > ) warpMagSource.getSpimSource() ); - final JacobianDeterminantSource< ? > jdSrc = ( ( JacobianDeterminantSource< ? > ) jacDetSource.getSpimSource() ); - final GridSource< ? > gSrc = ( ( GridSource< ? > ) gridSource.getSpimSource() ); - - wmSrc.setWarp( transform ); - fitBaselineWarpMagModel(); - - if( transform instanceof ThinplateSplineTransform ) + if( warpMagSource != null ) { - jdSrc.setTransform( (ThinplateSplineTransform)transform ); + final WarpMagnitudeSource< ? > wmSrc = ( ( WarpMagnitudeSource< ? > ) warpMagSource.getSpimSource() ); + wmSrc.setWarp( transform ); + fitBaselineWarpMagModel(); } - else if ( transform instanceof WrappedIterativeInvertibleRealTransform ) + + if( jacDetSource != null ) { - RealTransform xfm = ((WrappedIterativeInvertibleRealTransform)transform).getTransform(); - if( xfm instanceof ThinplateSplineTransform ) - jdSrc.setTransform( (ThinplateSplineTransform) xfm ); + final JacobianDeterminantSource< ? > jdSrc = ( ( JacobianDeterminantSource< ? > ) jacDetSource.getSpimSource() ); + if( transform instanceof ThinplateSplineTransform ) + { + jdSrc.setTransform( (ThinplateSplineTransform)transform ); + } + else if ( transform instanceof WrappedIterativeInvertibleRealTransform ) + { + RealTransform xfm = ((WrappedIterativeInvertibleRealTransform)transform).getTransform(); + if( xfm instanceof ThinplateSplineTransform ) + jdSrc.setTransform( (ThinplateSplineTransform) xfm ); + else + jdSrc.setTransform( new RealTransformFiniteDerivatives( xfm )); + } else - jdSrc.setTransform( new RealTransformFiniteDerivatives( xfm )); + jdSrc.setTransform( null ); } - else - jdSrc.setTransform( null ); - gSrc.setWarp( transform ); + if( gridSource != null ) + { + final GridSource< ? > gSrc = ( ( GridSource< ? > ) gridSource.getSpimSource() ); + gSrc.setWarp( transform ); + } } public boolean restimateTransformation() @@ -2383,7 +2448,13 @@ public boolean isMovingDisplayTransformed() { // this implementation is okay, so long as all the moving images have the same state of 'isTransformed' // return ( ( WarpedSource< ? > ) ( data.sources.get( data.movingSourceIndexList.get( 0 ) ).getSpimSource() ) ).isTransformed(); - return ( ( WarpedSource< ? > ) ( data.getMovingSource( 0 ).getSpimSource() ) ).isTransformed(); + + // TODO better to explicitly keep track of this + + if( data.sources.size() < 1 ) + return true; + else + return ( ( WarpedSource< ? > ) ( data.getMovingSource( 0 ).getSpimSource() ) ).isTransformed(); } /** diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index e96eb3a2..d1cc430c 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -32,7 +32,6 @@ public class BigWarpData< T > { - // TODO JOHN CHECK ME public List< SourceAndConverter< T > > sources; public final Map< Integer, Pair, List>>> urls = new HashMap<>(); @@ -53,6 +52,11 @@ public class BigWarpData< T > public final HashMap< SourceAndConverter, ColorSettings > sourceColorSettings; + public BigWarpData() + { + this( new ArrayList<>(), new ArrayList<>(), null ); + } + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, final CacheControl cache, final int[] movingIndexes, @@ -188,13 +192,9 @@ public boolean isMoving( SourceAndConverter sac ) { public void wrapUp() { -// movingSourceIndices = movingSourceIndexList.stream().mapToInt( x -> x ).toArray(); -// targetSourceIndices = targetSourceIndexList.stream().mapToInt( x -> x ).toArray(); -// -// Arrays.sort( movingSourceIndices ); -// Arrays.sort( targetSourceIndices ); Collections.sort( movingSourceIndexList ); Collections.sort( targetSourceIndexList ); + updateIsMovingMap(); } public void addSource( Source src, boolean isMoving ) @@ -231,6 +231,20 @@ public void addSourceAndConverter( SourceAndConverter sac, boolean isMoving, targetSourceIndexList.add( sources.size() - 1 ); } + public void remove( int i ) + { + SourceAndConverter< T > sac = sources.get( i ); + System.out.println( sac ); + System.out.println( isMovingMap ); + if( isMovingMap.remove( sac ) != null ) + movingSourceIndexList.remove( movingSourceIndexList.indexOf( i ) ); + else + targetSourceIndexList.remove( targetSourceIndexList.indexOf( i ) ); + + sources.remove( i ); + transforms.remove( i ); + } + public void setTransform( int i, RealTransform transform ) { transforms.set( i, transform ); diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index d010617b..23808584 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -725,10 +725,10 @@ public void convert( UnsignedIntType input, ARGBType output ) @SuppressWarnings( { "rawtypes", "unchecked" } ) public static < T > BigWarpData< T > initData() { - final ArrayList< ConverterSetup > converterSetups = new ArrayList< ConverterSetup >(); - final ArrayList< SourceAndConverter< T > > sources = new ArrayList< SourceAndConverter< T > >(); - - return new BigWarpData( sources, converterSetups, null ); +// final ArrayList< ConverterSetup > converterSetups = new ArrayList< ConverterSetup >(); +// final ArrayList< SourceAndConverter< T > > sources = new ArrayList< SourceAndConverter< T > >(); +// return new BigWarpData( sources, converterSetups, null ); + return new BigWarpData(); } /** diff --git a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java index dde145b8..b6cbce37 100644 --- a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java +++ b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java @@ -1,7 +1,6 @@ package bigwarp; import bdv.export.ProgressWriterConsole; -import bdv.viewer.Source; import ij.IJ; import ij.ImagePlus; import mpicbg.spim.data.SpimDataException; @@ -12,11 +11,11 @@ public class BigWarpTransformedSourcesTest public static void main( String[] args ) throws SpimDataException { -// final ImagePlus mr = IJ.openImage("/home/john/tmp/mri-stack.tif"); -// final ImagePlus t1 = IJ.openImage("/home/john/tmp/t1-head.tif"); + final ImagePlus mr = IJ.openImage("/home/john/tmp/mri-stack.tif"); + final ImagePlus t1 = IJ.openImage("/home/john/tmp/t1-head.tif"); - final ImagePlus mr = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif"); - final ImagePlus t1 = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/t1-head.tif"); +// final ImagePlus mr = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif"); +// final ImagePlus t1 = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/t1-head.tif"); int id = 0; final BigWarpData< ? > data = BigWarpInit.initData(); @@ -34,23 +33,9 @@ public static void main( String[] args ) throws SpimDataException data.setTransform( 2, translation ); data.applyTransformations(); -// System.out.println("before"); -// data.testColorSettings(); -// System.out.println(""); - - data.applyTransformations(); - -// System.out.println("after"); -// data.testColorSettings(); - -// Source< ? > tsrc = data.applyFixedTransform( data.getTargetSource( 0 ).getSpimSource(), translation ); -// System.out.println( tsrc ); - final BigWarp bw = new BigWarp<>( data, "Big Warp", new ProgressWriterConsole()); -// bw.loadLandmarks( "/home/john/tmp/bw_tformTest_landmarks.csv" ); - bw.loadLandmarks( "/groups/saalfeld/home/bogovicj/tmp/bw_tformTest_landmarks.csv" ); - -// bw.getViewerFrameP().getConverterSetups() + bw.loadLandmarks( "/home/john/tmp/bw_tformTest_landmarks_simple.csv" ); +// bw.loadLandmarks( "/groups/saalfeld/home/bogovicj/tmp/bw_tformTest_landmarks.csv" ); } From 37a23ec74bfd2f115129e89b30821ff0d160b52c Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 9 Nov 2022 16:22:37 -0500 Subject: [PATCH 099/282] feat: init dialog cleanup, toward adding transformations --- src/main/java/bdv/gui/BigWarpInitDialog.java | 125 +++++++++++------- .../sourceList/BigWarpSourceTableModel.java | 5 + 2 files changed, 81 insertions(+), 49 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index e13d93c5..2dd4e57c 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -42,20 +42,17 @@ public class BigWarpInitDialog extends JFrame { private static final long serialVersionUID = -2914972130819029899L; - private JButton browseBtn; - private JTextField containerPathText; - + private JTextField containerPathText, transformPathText; + private String initialPath; private JLabel messageLabel; - private JButton okBtn; - private JButton cancelBtn; + private JButton okBtn, cancelBtn; private JPanel listPanel; private JTable sourceTable; - private JButton addN5Button; + private JButton browseBtn, addN5Button, browseTransformButton; private BigWarpSourceTableModel sourceTableModel; private JComboBox imagePlusDropdown; - private JButton addImageButton; - private JButton addPathButton; + private JButton addImageButton, addPathButton, addTransformButton; private DatasetSelectorDialog selectionDialog; private String lastOpenedContainer = ""; @@ -90,10 +87,6 @@ public JPanel createContent() final JPanel panel = new JPanel(false); panel.setLayout(new GridBagLayout()); - containerPathText = new JTextField(); - containerPathText.setText( initialPath ); - containerPathText.setPreferredSize( new Dimension( frameSizeX / 3, containerPathText.getPreferredSize().height ) ); -// containerPathText.addActionListener( e -> openContainer( n5Fun, () -> getN5RootPath(), pathFun ) ); final GridBagConstraints ctxt = new GridBagConstraints(); ctxt.gridx = 0; @@ -102,32 +95,45 @@ public JPanel createContent() ctxt.gridheight = 1; ctxt.weightx = 0.0; ctxt.weighty = 0.0; + ctxt.anchor = GridBagConstraints.LINE_END; ctxt.fill = GridBagConstraints.NONE; ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); final JLabel addFileLabel = new JLabel( "Add file/folder:"); panel.add(addFileLabel, ctxt); + + final GridBagConstraints gbcBar = new GridBagConstraints(); + gbcBar.gridx = 1; + gbcBar.gridy = 0; + gbcBar.gridwidth = 4; + gbcBar.gridheight = 1; + gbcBar.weightx = 1.0; + gbcBar.weighty = 0.0; + gbcBar.fill = GridBagConstraints.HORIZONTAL; + gbcBar.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); - ctxt.gridx = 1; - ctxt.gridy = 0; - ctxt.gridwidth = 4; - ctxt.gridheight = 1; - ctxt.weightx = 1.0; - ctxt.fill = GridBagConstraints.HORIZONTAL; - panel.add(containerPathText, ctxt); + containerPathText = new JTextField(); + containerPathText.setText( initialPath ); + containerPathText.setPreferredSize( new Dimension( frameSizeX / 3, containerPathText.getPreferredSize().height ) ); +// containerPathText.addActionListener( e -> openContainer( n5Fun, () -> getN5RootPath(), pathFun ) ); + panel.add(containerPathText, gbcBar); final GridBagConstraints cadd = new GridBagConstraints(); cadd.gridx = 5; + cadd.gridy = 0; cadd.gridwidth = 1; cadd.weightx = 0.0; - cadd.fill = GridBagConstraints.HORIZONTAL; + cadd.fill = GridBagConstraints.NONE; + cadd.anchor = GridBagConstraints.LINE_START; cadd.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + addPathButton = new JButton("+"); addPathButton.addActionListener( e -> addPath() ); panel.add(addPathButton, cadd); final GridBagConstraints cbrowse = new GridBagConstraints(); cbrowse.gridx = 6; + cbrowse.gridy = 0; cbrowse.gridwidth = 1; cbrowse.weightx = 0.0; cbrowse.anchor = GridBagConstraints.LINE_END; @@ -135,50 +141,59 @@ public JPanel createContent() cbrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); browseBtn = new JButton("Browse"); panel.add(browseBtn, cbrowse); - + // add image / n5 + ctxt.gridy = 1; + panel.add( new JLabel("Add open image:"), ctxt ); + final GridBagConstraints gbc = new GridBagConstraints(); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.gridwidth = 1; - gbc.weightx = 0.0; - gbc.weighty = 0.0; - gbc.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); - panel.add( new JLabel("Add open image"), gbc ); - gbc.gridx = 1; - gbc.gridwidth = 2; + gbc.gridy = 1; + gbc.gridwidth = 3; gbc.weightx = 1.0; + gbc.weighty = 0.0; gbc.fill = GridBagConstraints.HORIZONTAL; - gbc.anchor = GridBagConstraints.EAST; + gbc.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + gbc.anchor = GridBagConstraints.LINE_END; imagePlusDropdown = new JComboBox<>( new String[] { "" } ); panel.add( imagePlusDropdown, gbc ); updateImagePlusDropdown(); - - gbc.gridx = 3; - gbc.gridwidth = 1; - gbc.weightx = 0.0; - gbc.fill = GridBagConstraints.NONE; + + cadd.gridy = 1; addImageButton = new JButton("+"); - panel.add( addImageButton, gbc ); + panel.add( addImageButton, cadd ); addImageButton.addActionListener( e -> { addImagePlus(); }); - gbc.gridx = 6; - gbc.gridwidth = 1; - gbc.weightx = 0.0; - gbc.anchor = GridBagConstraints.LINE_END; - gbc.fill = GridBagConstraints.HORIZONTAL; addN5Button = new JButton( "H5/N5/Zarr" ); - panel.add( addN5Button, gbc ); + cbrowse.gridy = 1; + panel.add( addN5Button, cbrowse ); addN5Button.addActionListener( e -> { selectionDialog.run( this::n5DialogCallback ); }); + // add transforms + ctxt.gridy = 2; + panel.add( new JLabel("Add transformation:"), ctxt ); + + transformPathText = new JTextField(); + transformPathText.setPreferredSize( new Dimension( frameSizeX / 3, transformPathText.getPreferredSize().height ) ); + gbcBar.gridy = 2; + panel.add( transformPathText, gbcBar ); + + addTransformButton = new JButton( "+" ); + addTransformButton.addActionListener( e -> addTransform() ); + cadd.gridy = 2; + panel.add( addTransformButton, cadd ); + + browseTransformButton = new JButton("Browse"); + cbrowse.gridy = 2; + panel.add( browseTransformButton, cbrowse ); + // source list final GridBagConstraints clist = new GridBagConstraints(); clist.gridx = 0; - clist.gridy = 2; + clist.gridy = 3; clist.gridwidth = 7; clist.gridheight = 3; clist.weightx = 1.0; @@ -195,7 +210,7 @@ public JPanel createContent() // bottom button section final GridBagConstraints cbot = new GridBagConstraints(); cbot.gridx = 0; - cbot.gridy = 5; + cbot.gridy = 6; cbot.gridwidth = 4; cbot.gridheight = 1; cbot.weightx = 1.0; @@ -242,8 +257,7 @@ public void buildN5SelectionDialog() selectionDialog.setTreeRenderer( new N5DatasetTreeCellRenderer( true ) ); // restrict canonical metadata to those with spatial metadata, but - // without - // multiscale + // without multiscale selectionDialog.getTranslationPanel().setFilter( x -> ( x instanceof CanonicalDatasetMetadata ) ); selectionDialog.setContainerPathUpdateCallback( x -> { @@ -305,6 +319,17 @@ protected void addPath() } } + protected void addTransform() + { + final String path = transformPathText.getText(); + int row = sourceTable.getSelectedRow(); + if( !path.isEmpty() && row >= 0 ) + { + sourceTableModel.setTransform( row, path ); + repaint(); + } + } + protected void updateImagePlusDropdown() { if( IJ.getInstance() == null ) @@ -351,8 +376,10 @@ private static void createAndShowGUI() { public static void main( String[] args ) { ImageJ ij = new ImageJ(); - IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); - IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); +// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); +// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); + IJ.openImage( "/home/john/tmp/boats.tif" ).show(); + IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); createAndShowGUI(); } diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index 63d5d832..676a2634 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -106,6 +106,11 @@ public void add( String srcName, boolean moving, boolean isImagePlus ) sources.add( new SourceRow( srcName, moving, "", isImagePlus )); } + public void setTransform( int i, String transform ) + { + sources.get( i ).transformName = transform; + } + public void add( String srcName, boolean moving ) { add( srcName, moving, false ); From a4456aee66c228fc5a5618659d1764d1d8a112ed Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 9 Nov 2022 17:17:52 -0500 Subject: [PATCH 100/282] feat: partially functional init dialog --- src/main/java/bdv/gui/BigWarpInitDialog.java | 76 ++++++++++++++++++- .../sourceList/BigWarpSourceTableModel.java | 15 ++++ 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 2dd4e57c..020bfc67 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -5,8 +5,11 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.io.IOException; +import java.net.URISyntaxException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.function.Consumer; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; @@ -31,11 +34,17 @@ import bdv.gui.sourceList.BigWarpSourceListPanel; import bdv.gui.sourceList.BigWarpSourceTableModel; +import bdv.gui.sourceList.BigWarpSourceTableModel.SourceRow; +import bdv.ij.util.ProgressWriterIJ; +import bigwarp.BigWarp; +import bigwarp.BigWarpData; +import bigwarp.BigWarpInit; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; import ij.Prefs; import ij.WindowManager; +import mpicbg.spim.data.SpimDataException; public class BigWarpInitDialog extends JFrame @@ -58,6 +67,9 @@ public class BigWarpInitDialog extends JFrame private String lastOpenedContainer = ""; private ExecutorService exec; + private Consumer okayCallback; + private Consumer cancelCallback; + private static final int DEFAULT_OUTER_PAD = 8; private static final int DEFAULT_BUTTON_PAD = 3; private static final int DEFAULT_MID_PAD = 5; @@ -68,12 +80,63 @@ public BigWarpInitDialog( final String title ) initialPath = ""; buildN5SelectionDialog(); - final Container content = getContentPane(); content.add( createContent() ); pack(); initializeImagePlusSources(); + + cancelCallback = x -> {}; + okayCallback = x -> { + runBigWarp( x ); + }; + } + + public static void runBigWarp( BigWarpSourceTableModel sourceTable ) + { + final BigWarpData< ? > data = BigWarpInit.initData(); + final int N = sourceTable.getRowCount(); + + int id = 0; + for( int i = 0; i < N; i++ ) + { + SourceRow tableRow = sourceTable.get( i ); + if( tableRow.isImagePlus ) + { + final ImagePlus imp = WindowManager.getImage( tableRow.srcName ); + id += BigWarpInit.add( data, imp, id, 0, tableRow.moving ); + } + else + { + // TODO deal with exceptions, and possibility of multiplke sources per uri + try + { + BigWarpInit.add( data, tableRow.srcName, id, tableRow.moving ); + } + catch ( URISyntaxException e ) + { + e.printStackTrace(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } + id++; + } + } + + try + { + BigWarp bw = new BigWarp<>( data, "BigWarp", new ProgressWriterIJ() ); + } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } } public JPanel createContent() @@ -224,6 +287,7 @@ public JPanel createContent() panel.add(messageLabel, cbot); okBtn = new JButton("OK"); + okBtn.addActionListener( e -> okayCallback.accept( sourceTableModel )); cbot.gridx = 5; cbot.weightx = 0.0; cbot.gridwidth = 1; @@ -234,6 +298,7 @@ public JPanel createContent() panel.add(okBtn, cbot); cancelBtn = new JButton("Cancel"); + cancelBtn.addActionListener( e -> cancelCallback.accept( sourceTableModel )); cbot.gridx = 6; cbot.ipadx = 0; cbot.gridwidth = 1; @@ -304,7 +369,7 @@ protected void addImagePlus( String title ) // an image is not added, and / or updating the dropdown menu periodically if( !title.isEmpty() && imp != null ) { - sourceTableModel.add( title ); + sourceTableModel.addImagePlus( title ); repaint(); } } @@ -378,8 +443,11 @@ public static void main( String[] args ) ImageJ ij = new ImageJ(); // IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); // IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); - IJ.openImage( "/home/john/tmp/boats.tif" ).show(); - IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); + +// IJ.openImage( "/home/john/tmp/boats.tif" ).show(); +// IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); + + IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); createAndShowGUI(); } diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index 676a2634..054ed0f9 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -46,6 +46,11 @@ public void setContainer( Component container ) this.container = container; } + public SourceRow get( int i ) + { + return sources.get( i ); + } + @Override public String getColumnName( int col ){ return columnNames[col]; @@ -121,6 +126,16 @@ public void add( String srcName ) add( srcName, false ); } + public void addImagePlus( String srcName ) + { + addImagePlus( srcName, false ); + } + + public void addImagePlus( String srcName, boolean isMoving ) + { + add( srcName, isMoving, true ); + } + public boolean remove( int i ) { if( i >= sources.size() ) From 3c65e91e9d507a004965e81e3528d5882d1893bf Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 15 Nov 2022 10:41:09 -0500 Subject: [PATCH 101/282] ui reworking --- src/main/java/bdv/gui/BigWarpInitDialog.java | 105 ++++++++++++------ .../sourceList/BigWarpSourceListPanel.java | 6 +- .../sourceList/BigWarpSourceTableModel.java | 7 +- 3 files changed, 77 insertions(+), 41 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 020bfc67..d49086dc 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -23,6 +23,7 @@ import org.janelia.saalfeldlab.n5.ij.N5Importer; import org.janelia.saalfeldlab.n5.ij.N5Importer.N5BasePathFun; import org.janelia.saalfeldlab.n5.ij.N5Importer.N5ViewerReaderFun; +import org.janelia.saalfeldlab.n5.imglib2.NgffTransformations; import org.janelia.saalfeldlab.n5.metadata.N5Metadata; import org.janelia.saalfeldlab.n5.metadata.N5MetadataParser; import org.janelia.saalfeldlab.n5.metadata.canonical.CanonicalDatasetMetadata; @@ -45,6 +46,7 @@ import ij.Prefs; import ij.WindowManager; import mpicbg.spim.data.SpimDataException; +import net.imglib2.realtransform.RealTransform; public class BigWarpInitDialog extends JFrame @@ -58,7 +60,7 @@ public class BigWarpInitDialog extends JFrame private JButton okBtn, cancelBtn; private JPanel listPanel; private JTable sourceTable; - private JButton browseBtn, addN5Button, browseTransformButton; + private JButton browseBtn, addN5Button, addN5TransformButton, browseTransformButton; private BigWarpSourceTableModel sourceTableModel; private JComboBox imagePlusDropdown; private JButton addImageButton, addPathButton, addTransformButton; @@ -92,6 +94,18 @@ public BigWarpInitDialog( final String title ) }; } + public static void addTransform( BigWarpData data, SourceRow tableRow ) + { + // TODO combine source and transform addition + String tformName = tableRow.transformName; + if( tformName != null && !tformName.isEmpty() ) + { + // TODO generalize to attributes in n5 + final RealTransform tform = NgffTransformations.openJson( tformName ); + data.transforms.set( data.transforms.size() - 1, tform ); + } + } + public static void runBigWarp( BigWarpSourceTableModel sourceTable ) { final BigWarpData< ? > data = BigWarpInit.initData(); @@ -105,13 +119,15 @@ public static void runBigWarp( BigWarpSourceTableModel sourceTable ) { final ImagePlus imp = WindowManager.getImage( tableRow.srcName ); id += BigWarpInit.add( data, imp, id, 0, tableRow.moving ); + addTransform( data, tableRow ); } else { - // TODO deal with exceptions, and possibility of multiplke sources per uri + // TODO deal with exceptions, and possibility of multiple sources per uri try { BigWarpInit.add( data, tableRow.srcName, id, tableRow.moving ); + addTransform( data, tableRow ); } catch ( URISyntaxException e ) { @@ -131,6 +147,7 @@ public static void runBigWarp( BigWarpSourceTableModel sourceTable ) try { + data.applyTransformations(); BigWarp bw = new BigWarp<>( data, "BigWarp", new ProgressWriterIJ() ); } catch ( SpimDataException e ) @@ -161,13 +178,40 @@ public JPanel createContent() ctxt.anchor = GridBagConstraints.LINE_END; ctxt.fill = GridBagConstraints.NONE; ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); + + final GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.gridwidth = 3; + gbc.weightx = 1.0; + gbc.weighty = 0.0; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + gbc.anchor = GridBagConstraints.LINE_END; + imagePlusDropdown = new JComboBox<>( new String[] { "" } ); + panel.add( imagePlusDropdown, gbc ); + updateImagePlusDropdown(); + + final GridBagConstraints cadd = new GridBagConstraints(); + cadd.gridx = 5; + cadd.gridy = 0; + cadd.gridwidth = 1; + cadd.weightx = 0.0; + cadd.fill = GridBagConstraints.NONE; + cadd.anchor = GridBagConstraints.LINE_START; + cadd.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + + cadd.gridy = 0; + addImageButton = new JButton("+"); + panel.add( addImageButton, cadd ); + addImageButton.addActionListener( e -> { addImagePlus(); }); final JLabel addFileLabel = new JLabel( "Add file/folder:"); panel.add(addFileLabel, ctxt); final GridBagConstraints gbcBar = new GridBagConstraints(); gbcBar.gridx = 1; - gbcBar.gridy = 0; + gbcBar.gridy = 1; gbcBar.gridwidth = 4; gbcBar.gridheight = 1; gbcBar.weightx = 1.0; @@ -181,25 +225,16 @@ public JPanel createContent() // containerPathText.addActionListener( e -> openContainer( n5Fun, () -> getN5RootPath(), pathFun ) ); panel.add(containerPathText, gbcBar); - final GridBagConstraints cadd = new GridBagConstraints(); - cadd.gridx = 5; - cadd.gridy = 0; - cadd.gridwidth = 1; - cadd.weightx = 0.0; - cadd.fill = GridBagConstraints.NONE; - cadd.anchor = GridBagConstraints.LINE_START; - cadd.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); - + cadd.gridy = 1; addPathButton = new JButton("+"); addPathButton.addActionListener( e -> addPath() ); panel.add(addPathButton, cadd); final GridBagConstraints cbrowse = new GridBagConstraints(); cbrowse.gridx = 6; - cbrowse.gridy = 0; + cbrowse.gridy = 1; cbrowse.gridwidth = 1; cbrowse.weightx = 0.0; - cbrowse.anchor = GridBagConstraints.LINE_END; cbrowse.fill = GridBagConstraints.HORIZONTAL; cbrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); browseBtn = new JButton("Browse"); @@ -209,27 +244,16 @@ public JPanel createContent() ctxt.gridy = 1; panel.add( new JLabel("Add open image:"), ctxt ); - final GridBagConstraints gbc = new GridBagConstraints(); - gbc.gridx = 1; - gbc.gridy = 1; - gbc.gridwidth = 3; - gbc.weightx = 1.0; - gbc.weighty = 0.0; - gbc.fill = GridBagConstraints.HORIZONTAL; - gbc.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); - gbc.anchor = GridBagConstraints.LINE_END; - imagePlusDropdown = new JComboBox<>( new String[] { "" } ); - panel.add( imagePlusDropdown, gbc ); - updateImagePlusDropdown(); - - cadd.gridy = 1; - addImageButton = new JButton("+"); - panel.add( addImageButton, cadd ); - addImageButton.addActionListener( e -> { addImagePlus(); }); + final GridBagConstraints cn5 = new GridBagConstraints(); + cn5.gridx = 7; + cn5.gridy = 1; + cn5.gridwidth = 1; + cn5.weightx = 0.0; + cn5.fill = GridBagConstraints.HORIZONTAL; + cn5.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); addN5Button = new JButton( "H5/N5/Zarr" ); - cbrowse.gridy = 1; - panel.add( addN5Button, cbrowse ); + panel.add( addN5Button, cn5 ); addN5Button.addActionListener( e -> { selectionDialog.run( this::n5DialogCallback ); @@ -253,11 +277,19 @@ public JPanel createContent() cbrowse.gridy = 2; panel.add( browseTransformButton, cbrowse ); + cn5.gridy = 2; + addN5TransformButton = new JButton( "H5/N5/Zarr" ); + panel.add( addN5TransformButton, cn5 ); + + addN5TransformButton.addActionListener( e -> { + selectionDialog.run( this::n5DialogCallback ); + }); + // source list final GridBagConstraints clist = new GridBagConstraints(); clist.gridx = 0; clist.gridy = 3; - clist.gridwidth = 7; + clist.gridwidth = 8; clist.gridheight = 3; clist.weightx = 1.0; clist.weighty = 1.0; @@ -288,7 +320,7 @@ public JPanel createContent() okBtn = new JButton("OK"); okBtn.addActionListener( e -> okayCallback.accept( sourceTableModel )); - cbot.gridx = 5; + cbot.gridx = 6; cbot.weightx = 0.0; cbot.gridwidth = 1; cbot.ipadx = (int)(40); @@ -299,7 +331,7 @@ public JPanel createContent() cancelBtn = new JButton("Cancel"); cancelBtn.addActionListener( e -> cancelCallback.accept( sourceTableModel )); - cbot.gridx = 6; + cbot.gridx = 7; cbot.ipadx = 0; cbot.gridwidth = 1; cbot.fill = GridBagConstraints.HORIZONTAL; @@ -447,6 +479,7 @@ public static void main( String[] args ) // IJ.openImage( "/home/john/tmp/boats.tif" ).show(); // IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); + IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); createAndShowGUI(); diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java index 58a4cc2c..3d5923e9 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java @@ -54,8 +54,10 @@ public BigWarpSourceListPanel( BigWarpSourceTableModel tableModel ) table.setPreferredScrollableViewportSize( new Dimension( 500, 70 ) ); table.setFillsViewportHeight( true ); - table.getColumn( "remove" ).setCellRenderer( new ButtonRenderer() ); - table.getColumn( "remove" ).setCellEditor( new ButtonEditor( new JCheckBox(), tableModel ) ); + table.getColumn( " " ).setCellRenderer( new ButtonRenderer() ); + table.getColumn( " " ).setCellEditor( new ButtonEditor( new JCheckBox(), tableModel ) ); + table.getColumn( " " ).setPreferredWidth( 24 ); + table.getColumn( " " ).setWidth( 24 ); final JScrollPane scrollPane = new JScrollPane( table ); add( scrollPane ); diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index 054ed0f9..5fe37891 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -17,7 +17,7 @@ public class BigWarpSourceTableModel extends AbstractTableModel { private static final long serialVersionUID = 5923947651732788341L; - protected final static String[] colNames = new String[] { "Name", "Moving", "Transform", "remove" }; + protected final static String[] colNames = new String[] { "Name", "Moving", "Transform", " " }; protected final String[] columnNames; protected final ArrayList sources; @@ -89,7 +89,8 @@ else if ( col == 3 ) @Override public boolean isCellEditable( int row, int col ) { - return ( col == movingColIdx ) || ( col == removeColIdx ); + return true; +// return ( col == movingColIdx ) || ( col == removeColIdx ); } @Override @@ -198,7 +199,7 @@ protected static class RemoveRowButton extends JButton { private int row; public RemoveRowButton( int row ) { - super( "-" ); + super( "remove" ); setRow( row ); } From a73c90bd970348c5d2c99cfeaba6aeb73bd84c9d Mon Sep 17 00:00:00 2001 From: bogovicj Date: Tue, 15 Nov 2022 11:49:34 -0500 Subject: [PATCH 102/282] wip: working browse buttons --- src/main/java/bdv/gui/BigWarpInitDialog.java | 95 ++++++++++++++++++-- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index d49086dc..5b040716 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -5,6 +5,7 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.concurrent.ExecutorService; @@ -14,6 +15,7 @@ import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; +import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; @@ -67,10 +69,12 @@ public class BigWarpInitDialog extends JFrame private DatasetSelectorDialog selectionDialog; private String lastOpenedContainer = ""; + private String lastBrowsePath = ""; private ExecutorService exec; private Consumer okayCallback; private Consumer cancelCallback; + private Consumer< String > imagePathUpdateCallback, transformPathUpdateCallback; private static final int DEFAULT_OUTER_PAD = 8; private static final int DEFAULT_BUTTON_PAD = 3; @@ -92,6 +96,16 @@ public BigWarpInitDialog( final String title ) okayCallback = x -> { runBigWarp( x ); }; + + imagePathUpdateCallback = ( p ) -> { + System.out.println( "add image: " + p ); + addPath(); + }; + + transformPathUpdateCallback = ( p ) -> { + System.out.println( "add transform: " + p ); + addTransform(); + }; } public static void addTransform( BigWarpData data, SourceRow tableRow ) @@ -148,7 +162,7 @@ public static void runBigWarp( BigWarpSourceTableModel sourceTable ) try { data.applyTransformations(); - BigWarp bw = new BigWarp<>( data, "BigWarp", new ProgressWriterIJ() ); + new BigWarp<>( data, "BigWarp", new ProgressWriterIJ() ); } catch ( SpimDataException e ) { @@ -238,8 +252,10 @@ public JPanel createContent() cbrowse.fill = GridBagConstraints.HORIZONTAL; cbrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); browseBtn = new JButton("Browse"); + browseBtn.addActionListener( e -> { browseImageDialog(); } ); panel.add(browseBtn, cbrowse); + // add image / n5 ctxt.gridy = 1; panel.add( new JLabel("Add open image:"), ctxt ); @@ -274,6 +290,7 @@ public JPanel createContent() panel.add( addTransformButton, cadd ); browseTransformButton = new JButton("Browse"); + browseTransformButton.addActionListener( e -> { browseTransformDialog(); } ); cbrowse.gridy = 2; panel.add( browseTransformButton, cbrowse ); @@ -473,16 +490,84 @@ private static void createAndShowGUI() { public static void main( String[] args ) { ImageJ ij = new ImageJ(); -// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); -// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); + IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); + IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); // IJ.openImage( "/home/john/tmp/boats.tif" ).show(); // IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); - IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); - IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); +// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); +// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); createAndShowGUI(); } + private String browseDialogGeneral() + { + + final JFileChooser fileChooser = new JFileChooser(); + /* + * Need to allow files so h5 containers can be opened, and directories + * so that filesystem n5's and zarrs can be opened. + */ + fileChooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES ); + + if ( lastBrowsePath != null && !lastBrowsePath.isEmpty() ) + fileChooser.setCurrentDirectory( new File( lastBrowsePath ) ); + else if ( initialPath != null && !initialPath.isEmpty() ) + fileChooser.setCurrentDirectory( new File( initialPath ) ); + else if ( IJ.getInstance() != null ) + { + File f = null; + + final String currDir = IJ.getDirectory( "current" ); + final String homeDir = IJ.getDirectory( "home" ); + if ( currDir != null ) + f = new File( currDir ); + else if ( homeDir != null ) + f = new File( homeDir ); + + fileChooser.setCurrentDirectory( f ); + } + + final int ret = fileChooser.showOpenDialog( this ); + if ( ret != JFileChooser.APPROVE_OPTION ) + return null; + + final String path = fileChooser.getSelectedFile().getAbsolutePath(); + lastBrowsePath = path; + + return path; + } + + public void setImagePathUpdateCallback( final Consumer< String > callback ) + { + this.imagePathUpdateCallback = callback; + } + + public void setTransformPathUpdateCallback( final Consumer< String > callback ) + { + this.transformPathUpdateCallback = callback; + } + + private String browseImageDialog() + { + final String s = browseDialogGeneral(); + containerPathText.setText( s ); + if ( imagePathUpdateCallback != null ) + imagePathUpdateCallback.accept( s ); + + return s; + } + + private String browseTransformDialog() + { + final String s = browseDialogGeneral(); + transformPathText.setText( s ); + if ( transformPathUpdateCallback != null ) + transformPathUpdateCallback.accept( s ); + + return s; + } + } From c0a2d42c36978c7d4b1931ca64f3529693549e85 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 15 Nov 2022 16:58:12 -0500 Subject: [PATCH 103/282] feat: toward macro recordability and an imagej2 command --- pom.xml | 19 ++-- src/main/java/bdv/gui/BigWarpInitDialog.java | 103 ++++++++++++++----- src/main/java/bdv/ij/BigWarpCommand.java | 24 +++++ 3 files changed, 111 insertions(+), 35 deletions(-) create mode 100644 src/main/java/bdv/ij/BigWarpCommand.java diff --git a/pom.xml b/pom.xml index ce8c098d..9cd8eb68 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,6 @@ 6.0.0 4.0.0 - 5.0.0-SNAPSHOT 1.48 1.4.1 @@ -122,6 +121,7 @@ 2.5.1 3.2.1 1.4.1 + sign,deploy-to-scijava @@ -140,6 +140,10 @@ net.imagej ij + + net.imagej + imagej + @@ -212,10 +216,6 @@ org.janelia.saalfeldlab n5 - - org.janelia.saalfeldlab - n5-imglib2 - org.janelia.saalfeldlab n5-blosc @@ -231,10 +231,6 @@ - - org.janelia.saalfeldlab - n5-imglib2 - @@ -303,6 +299,11 @@ com.formdev flatlaf + + org.janelia.saalfeldlab + n5-imglib2 + 5.0.0-SNAPSHOT + diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 5b040716..47af4a5c 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -32,6 +32,9 @@ import org.janelia.saalfeldlab.n5.ui.DataSelection; import org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog; import org.janelia.saalfeldlab.n5.ui.N5DatasetTreeCellRenderer; +import org.scijava.command.Command; +import org.scijava.plugin.Plugin; +import org.scijava.plugin.SciJavaPlugin; import com.formdev.flatlaf.util.UIScale; @@ -43,20 +46,23 @@ import bigwarp.BigWarpData; import bigwarp.BigWarpInit; import ij.IJ; -import ij.ImageJ; +//import ij.ImageJ; import ij.ImagePlus; import ij.Prefs; import ij.WindowManager; +import ij.plugin.frame.Recorder; import mpicbg.spim.data.SpimDataException; +import net.imagej.ImageJ; import net.imglib2.realtransform.RealTransform; - -public class BigWarpInitDialog extends JFrame +//@Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp 8" ) +public class BigWarpInitDialog extends JFrame //implements Command { - private static final long serialVersionUID = -2914972130819029899L; - private JTextField containerPathText, transformPathText; + private boolean imageJOpen; + + private JTextField containerPathText, transformPathText; private String initialPath; private JLabel messageLabel; private JButton okBtn, cancelBtn; @@ -79,11 +85,17 @@ public class BigWarpInitDialog extends JFrame private static final int DEFAULT_OUTER_PAD = 8; private static final int DEFAULT_BUTTON_PAD = 3; private static final int DEFAULT_MID_PAD = 5; + + public BigWarpInitDialog() + { +// this( "BigWarp" ); + } public BigWarpInitDialog( final String title ) { super( title ); initialPath = ""; + imageJOpen = IJ.getInstance() != null; buildN5SelectionDialog(); final Container content = getContentPane(); @@ -94,6 +106,7 @@ public BigWarpInitDialog( final String title ) cancelCallback = x -> {}; okayCallback = x -> { + macroRecord( x ); runBigWarp( x ); }; @@ -108,6 +121,25 @@ public BigWarpInitDialog( final String title ) }; } + public static void main( String[] args ) + { + ImageJ ij2 = new ImageJ(); + ij2.ui().showUI(); + +// ImageJ ij = new ImageJ(); +// +// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); +// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); +// +//// IJ.openImage( "/home/john/tmp/boats.tif" ).show(); +//// IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); +// +//// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); +//// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); +// +// createAndShowGUI(); + } + public static void addTransform( BigWarpData data, SourceRow tableRow ) { // TODO combine source and transform addition @@ -400,7 +432,7 @@ public void n5DialogCallback( DataSelection selection ) protected void addImagePlus() { - if ( IJ.getInstance() == null ) + if ( !imageJOpen ) return; final String title = (String)(imagePlusDropdown.getSelectedItem()); @@ -409,7 +441,7 @@ protected void addImagePlus() protected void addImagePlus( String title ) { - if ( IJ.getInstance() == null ) + if ( !imageJOpen ) return; final ImagePlus imp = WindowManager.getImage( title ); @@ -446,7 +478,7 @@ protected void addTransform() protected void updateImagePlusDropdown() { - if( IJ.getInstance() == null ) + if( !imageJOpen ) return; // don't need any open windows if we're using N5 @@ -479,29 +511,13 @@ public void initializeImagePlusSources() addImagePlus( ( String ) imagePlusDropdown.getItemAt( 1 ) ); } - private static void createAndShowGUI() { + public static void createAndShow() { //Create and set up the window. BigWarpInitDialog frame = new BigWarpInitDialog("BigWarp"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); - frame.setVisible(true); } - public static void main( String[] args ) - { - ImageJ ij = new ImageJ(); - IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); - IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); - -// IJ.openImage( "/home/john/tmp/boats.tif" ).show(); -// IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); - -// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); -// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); - - createAndShowGUI(); - } - private String browseDialogGeneral() { @@ -516,7 +532,7 @@ private String browseDialogGeneral() fileChooser.setCurrentDirectory( new File( lastBrowsePath ) ); else if ( initialPath != null && !initialPath.isEmpty() ) fileChooser.setCurrentDirectory( new File( initialPath ) ); - else if ( IJ.getInstance() != null ) + else if ( imageJOpen ) { File f = null; @@ -570,4 +586,39 @@ private String browseTransformDialog() return s; } + public String macroRecord( BigWarpSourceTableModel sourceTable ) + { + // make source list + StringBuffer sourceList = new StringBuffer(); + StringBuffer movingList = new StringBuffer(); + StringBuffer transformList = new StringBuffer(); + + final int N = sourceTable.getRowCount(); + for( int i = 0; i < N; i++ ) + { + sourceList.append( sourceTable.get( i ).srcName ); + movingList.append( sourceTable.get( i ).moving ); + transformList.append( sourceTable.get( i ).transformName ); + if( i < N -1 ) + { + sourceList.append( "," ); + movingList.append( "," ); + transformList.append( "," ); + } + } + +// if ( imageJOpen && Recorder.record ) +// { +// Recorder.resetCommandOptions(); +// +//// Recorder.recordOption(n5PathKey, n5RootAndDataset); +//// +//// if (virtual) +//// Recorder.recordOption(virtualKey); +// +// return Recorder.getCommandOptions(); +// } + return ""; + } + } diff --git a/src/main/java/bdv/ij/BigWarpCommand.java b/src/main/java/bdv/ij/BigWarpCommand.java new file mode 100644 index 00000000..e35c0d40 --- /dev/null +++ b/src/main/java/bdv/ij/BigWarpCommand.java @@ -0,0 +1,24 @@ +package bdv.ij; + +import org.scijava.command.Command; +import org.scijava.plugin.Plugin; + +import bdv.gui.BigWarpInitDialog; +import net.imagej.ImageJ; + +@Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp Command" ) +public class BigWarpCommand implements Command +{ + @Override + public void run() + { + BigWarpInitDialog.createAndShow(); + } + + public static void main( String[] args ) + { + ImageJ ij2 = new ImageJ(); + ij2.ui().showUI(); + } + +} From 08368d1e803e8503d5b426c1d8b103106885fb42 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 16 Nov 2022 10:14:49 -0500 Subject: [PATCH 104/282] add logback config --- src/main/resources/logback.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/resources/logback.xml diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 00000000..3c259b6d --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,10 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + From 3f12f6eacf3badf4c3d3401320ae7f4c69aa4050 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:38:15 -0500 Subject: [PATCH 105/282] feat: add files --- src/main/java/bigwarp/source/SourceInfo.java | 125 ++++++++++ src/test/java/bigwarp/BigWarpTestUtils.java | 242 +++++++++++++++++++ 2 files changed, 367 insertions(+) create mode 100644 src/main/java/bigwarp/source/SourceInfo.java create mode 100644 src/test/java/bigwarp/BigWarpTestUtils.java diff --git a/src/main/java/bigwarp/source/SourceInfo.java b/src/main/java/bigwarp/source/SourceInfo.java new file mode 100644 index 00000000..295839fe --- /dev/null +++ b/src/main/java/bigwarp/source/SourceInfo.java @@ -0,0 +1,125 @@ +package bigwarp.source; + +import bdv.viewer.SourceAndConverter; +import bigwarp.loader.ImagePlusLoader.ColorSettings; +import java.util.function.Supplier; +import net.imglib2.realtransform.RealTransform; + +public class SourceInfo +{ + private SourceAndConverter sourceAndConverter = null; + private final int id; + + private String name; + + private Supplier uriSupplier; + + private ColorSettings colorSettings = null; + + private final boolean moving; + + private RealTransform transform; + + boolean serializable = false; + + public SourceInfo( final int id, final boolean moving ) + { + this( id, moving, null, null, null); + } + + public SourceInfo( final int id, final boolean moving, final String name ) + { + this(id, moving, name, () -> null, null); + } + + public SourceInfo( final int id, final boolean moving, final String name, Supplier uriSupplier ) + { + this(id, moving, name, uriSupplier, null); + } + + public SourceInfo( final int id, final boolean moving, final String name, final Supplier< String > uriSupplier, RealTransform transform ) + { + this.id = id; + this.moving = moving; + this.name = name; + this.uriSupplier = uriSupplier; + this.transform = transform; + } + + /** + * Some source origins (url, .xml file, ImagePlus) may lead to multiple Sources being created. + * We only want to setSerializable the initial one which caused the subsequent onces to be created. + * We do this by setting the {@link #serializable} flag to {@code true} for the first source in the sequence. + * + * @param serializable whether to setSerialize this source or not. + */ + public void setSerializable( final boolean serializable ) + { + this.serializable = serializable; + } + + public boolean isSerializable() + { + return serializable; + } + + public String getUri() + { + return uriSupplier.get(); + } + + public void setUriSupplier( final Supplier< String > getUri ) + { + this.uriSupplier = getUri; + } + + public int getId() + { + return id; + } + + public String getName() + { + return name; + } + + public void setName( final String name ) + { + this.name = name; + } + + public void setColorSettings( final ColorSettings colorSettings ) + { + this.colorSettings = colorSettings; + } + + public ColorSettings getColorSettings() + { + return colorSettings; + } + + public boolean isMoving() + { + return moving; + } + + public void setTransform( final RealTransform transform ) + { + this.transform = transform; + } + + public RealTransform getTransform() + { + return transform; + } + + public SourceAndConverter< ? > getSourceAndConverter() + { + return sourceAndConverter; + } + + public void setSourceAndConverter( final SourceAndConverter< ? > sourceAndConverter ) + { + this.sourceAndConverter = sourceAndConverter; + } +} diff --git a/src/test/java/bigwarp/BigWarpTestUtils.java b/src/test/java/bigwarp/BigWarpTestUtils.java new file mode 100644 index 00000000..c0f9e97d --- /dev/null +++ b/src/test/java/bigwarp/BigWarpTestUtils.java @@ -0,0 +1,242 @@ +package bigwarp; + +import bdv.gui.BigWarpViewerOptions; +import bdv.viewer.Source; +import bigwarp.source.SourceInfo; +import com.google.common.collect.MapDifference; +import com.google.common.collect.Maps; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import ij.IJ; +import ij.ImagePlus; +import ij.gui.NewImage; +import ij.plugin.StackWriter; +import java.io.IOException; +import java.io.StringWriter; +import java.lang.reflect.Type; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; +import mpicbg.spim.data.SpimDataException; +import net.imglib2.FinalInterval; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.position.FunctionRandomAccessible; +import net.imglib2.type.numeric.integer.UnsignedByteType; +import net.imglib2.view.Views; +import org.junit.Assert; +import org.scijava.util.FileUtils; + +public class BigWarpTestUtils +{ + + public static String createTemp3DImage( String title, String format ) + { + + final Path tmpImgPath; + try + { + tmpImgPath = Files.createTempFile( title, "." + format ); + tmpImgPath.toFile().delete(); + } + catch ( IOException e ) + { + throw new RuntimeException( e ); + } + + return createTemp3DImage( tmpImgPath ); + } + + public static String createTemp3DImage( Path tmpImgPath ) + { + try + { + return create3DImage( tmpImgPath ); + } + catch ( Exception e ) + { + tmpImgPath.toFile().delete(); + throw new RuntimeException( e ); + } + } + + private static String create3DImage( final Path tmpImgPath ) throws IOException + { + ImagePlus img3d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 4, NewImage.FILL_RAMP ); + IJ.save( img3d, tmpImgPath.toFile().getCanonicalPath() ); + tmpImgPath.toFile().deleteOnExit(); + return tmpImgPath.toString(); + } + + private static String create2DImage( final Path tmpImgPath ) throws IOException + { + ImagePlus img2d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 1, NewImage.FILL_RAMP ); + IJ.save( img2d, tmpImgPath.toFile().getCanonicalPath() ); + tmpImgPath.toFile().deleteOnExit(); + return tmpImgPath.toString(); + } + + public static String createTemp2DImage( String title, String format ) + { + + Path tmpImg = null; + try + { + tmpImg = Files.createTempFile( title, "." + format ); + tmpImg.toFile().delete(); + return create2DImage( tmpImg); + } + catch ( Exception e ) + { + if (tmpImg != null) { + tmpImg.toFile().delete(); + } + throw new RuntimeException( e ); + } + } + + public static String createTemp3DImageStack( String title ) + { + + final ImagePlus img3d = NewImage.createByteImage( title, 8, 8, 4, NewImage.FILL_RAMP ); + + Path tmpStackDir = null; + try + { + + tmpStackDir = Files.createTempDirectory( title ); + StackWriter.save( img3d ,tmpStackDir.toString() + "/", "format=tiff"); + return tmpStackDir.toString(); + } + catch ( IOException e ) + { + if (tmpStackDir != null) { + FileUtils.deleteRecursively( tmpStackDir.toFile() ); + } + throw new RuntimeException( e ); + } + } + + public static void assertJsonDiff( final JsonElement expectedJson, final JsonElement actualJson ) + { + final Gson gson = new Gson(); + Type mapType = new TypeToken< Map< String, Object > >() + { + }.getType(); + Map< String, Object > expectedMap = gson.fromJson( expectedJson, mapType ); + Map< String, Object > actualMap = gson.fromJson( actualJson, mapType ); + final MapDifference< String, Object > difference = Maps.difference( expectedMap, actualMap ); + if ( !difference.areEqual() ) + { + if ( difference.entriesDiffering().size() > 0 ) + { + difference.entriesDiffering().forEach( ( key, value ) -> { + final Object left = value.leftValue(); + final Object right = value.rightValue(); + + if ( left instanceof Map && right instanceof Map ) + { + final Map< ?, ? > leftMap = ( Map< ?, ? > ) value.leftValue(); + final Map< ?, ? > rightMap = ( Map< ?, ? > ) value.rightValue(); + removeEqualKeys( leftMap, rightMap ); + } + } ); + } + Assert.fail( difference.toString() ); + } + + } + + private static void removeEqualKeys( Map< ?, ? > left, Map< ?, ? > right ) + { + final Object[] leftVals = left.values().toArray(); + final boolean hasChildren = leftVals.length > 0; + final boolean childrenIsMap = hasChildren && leftVals[ 0 ] instanceof Map< ?, ? >; + + if ( childrenIsMap ) + { + /* recurse*/ + left.keySet().forEach( key -> { + final Map< ?, ? > innerLeft = ( Map< ?, ? > ) left.get( key ); + final Map< ?, ? > innerRight = ( Map< ?, ? > ) right.get( key ); + removeEqualKeys( innerLeft, innerRight ); + } ); + } + else + { + final ArrayList< Object > keysToRemove = new ArrayList<>(); + left.forEach( ( checkKey, value1 ) -> { + if ( right.containsKey( checkKey ) && right.get( checkKey ).equals( value1 ) ) + { + keysToRemove.add( checkKey ); + } + } ); + keysToRemove.forEach( keyToRemove -> { + left.remove( keyToRemove ); + right.remove( keyToRemove ); + } ); + } + + } + + private static String prettyPrint( StringWriter json ) + { + return prettyPrint( json.toString() ); + } + + private static String prettyPrint( String json ) + { + final JsonElement parse = JsonParser.parseString( json ); + final JsonObject asJsonObject = parse.getAsJsonObject(); + + return prettyPrint( asJsonObject ); + } + + public static String prettyPrint( JsonObject json ) + { + + return new GsonBuilder().setPrettyPrinting().create().toJson( json ); + } + + static < T > BigWarp< T > createBigWarp(boolean... moving ) throws SpimDataException, URISyntaxException, IOException + { + return createBigWarp( null, moving ); + } + + static < T > BigWarp< T > createBigWarp(String sourcePath, boolean... moving ) throws SpimDataException, URISyntaxException, IOException + { + final BigWarpData< T > data = BigWarpInit.initData(); + FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( + 3, + ( l, v ) -> v.setOne(), + UnsignedByteType::new ); + ImagePlus imp = ImageJFunctions.wrap( Views.interval( fimg, new FinalInterval( 32, 32, 1 ) ), "img" ); + + if (sourcePath != null) { + createTemp3DImage( Paths.get(sourcePath) ); + } + + final String tmpPath = sourcePath != null ? sourcePath : createTemp3DImage( "img", "tif" ); + + for ( int i = 0; i < moving.length; i++ ) + { + final LinkedHashMap< Source< T >, SourceInfo > sources = BigWarpInit.createSources( data, tmpPath, i, moving[ i ] ); + BigWarpInit.add( data, sources ); + } + data.wrapUp(); + BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); + return new BigWarp<>( data, opts, null ); + } + + public static void main( String[] args ) throws SpimDataException, URISyntaxException, IOException + { + createBigWarp( true, true, false, false); + } +} From c3ebd53887eb375b0efc967a894340cf4ea48fd6 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:40:38 -0500 Subject: [PATCH 106/282] style: misc --- src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java | 1 + src/main/java/bigwarp/BigWarp.java | 3 ++- src/main/java/bigwarp/BigWarpActions.java | 6 ++++-- src/main/java/bigwarp/BigWarpExporter.java | 4 +++- src/main/java/bigwarp/BigWarpInit.java | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 73caf62e..6f236ba0 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -637,6 +637,7 @@ public static < T extends RealType< T > > void fromRealTransform( final RealTran jobs.add( new Callable() { + @Override public Boolean call() { try diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 4b929283..b0a446f4 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -616,6 +616,7 @@ public void initialize() SwingUtilities.invokeLater( new Runnable() { + @Override public void run() { data.transferChannelSettings( viewerFrameP ); @@ -657,7 +658,7 @@ public void synchronizeSources() * Create two source groups - one for moving images, * and the other for target images, for both viewer frames. * - * Ensure sources are synchronized with {@link synchronizeSources} + * Ensure sources are synchronized with {@link #synchronizeSources()} * before calling this method. */ public void createMovingTargetGroups() diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 9ec48296..bc8173e8 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -684,6 +684,7 @@ public ResetActiveViewerAction( final BigWarp< ? > bw ) this.bw = bw; } + @Override public void actionPerformed( ActionEvent e ) { bw.resetView(); @@ -694,8 +695,8 @@ public static class AlignViewerPanelAction extends AbstractNamedAction { private static final long serialVersionUID = -7023242695323421450L; - public enum TYPE { ACTIVE_TO_OTHER, OTHER_TO_ACTIVE }; - + public enum TYPE { ACTIVE_TO_OTHER, OTHER_TO_ACTIVE } + private BigWarp< ? >bw; private TYPE type; @@ -706,6 +707,7 @@ public AlignViewerPanelAction( final BigWarp< ? > bw, TYPE type ) this.type = type; } + @Override public void actionPerformed( ActionEvent e ) { if( type == TYPE.ACTIVE_TO_OTHER ) diff --git a/src/main/java/bigwarp/BigWarpExporter.java b/src/main/java/bigwarp/BigWarpExporter.java index 392226cf..691d2e57 100644 --- a/src/main/java/bigwarp/BigWarpExporter.java +++ b/src/main/java/bigwarp/BigWarpExporter.java @@ -107,7 +107,7 @@ public abstract class BigWarpExporter public enum ParallelizationPolicy { SLICE, ITER - }; + } public ParallelizationPolicy policy = ParallelizationPolicy.ITER; @@ -480,6 +480,7 @@ public static < T extends NumericType > RandomAccessibleInterval copyToIma jobs.add( new Callable() { + @Override public Boolean call() { try @@ -561,6 +562,7 @@ public static < T extends NumericType > RandomAccessibleInterval copyToIma final int offset = i; jobs.add( new Callable() { + @Override public Boolean call() { try diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 23808584..03ba67d6 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -1129,7 +1129,7 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source /** * Create a {@link String} array of names from two {@link ImagePlus}es, * essentially concatenating the results from calling - * {@link namesFromImagePlus} with each. + * {@link #namesFromImagePlus(ImagePlus)} with each. * * @param impP * first image to generate names from From 80d28ad401bd7072086fca283793059aed93cf93 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:40:51 -0500 Subject: [PATCH 107/282] feat!: remove Brightness Dialog --- src/main/java/bigwarp/BigWarp.java | 6 ------ src/main/java/bigwarp/BigWarpActions.java | 3 --- 2 files changed, 9 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index b0a446f4..b3364709 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -102,7 +102,6 @@ import bdv.tools.VisibilityAndGroupingDialog; import bdv.tools.bookmarks.Bookmarks; import bdv.tools.bookmarks.BookmarksEditor; -import bdv.tools.brightness.BrightnessDialog; import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.SetupAssignments; import bdv.util.Bounds; @@ -493,7 +492,6 @@ public BigWarp( final BigWarpData data, final String windowTitle, BigWarpVie setupAssignments = new SetupAssignments( new ArrayList<>( data.converterSetups ), 0, 65535 ); - brightnessDialog = new BrightnessDialog( landmarkFrame, setupAssignments ); helpDialog = new HelpDialog( landmarkFrame ); sourceInfoDialog = new SourceInfoDialog( landmarkFrame, data ); @@ -882,10 +880,6 @@ protected void setUpViewerMenu( final BigWarpViewerFrame vframe ) toggleAlwaysWarpMenu.setText( "Toggle warp on drag" ); settingsMenu.add( toggleAlwaysWarpMenu ); - final JMenuItem miBrightness = new JMenuItem( actionMap.get( BigWarpActions.BRIGHTNESS_SETTINGS ) ); - miBrightness.setText( "Brightness & Color" ); - settingsMenu.add( miBrightness ); - /* */ final JMenuItem transformTypeMenu = new JMenuItem( actionMap.get( BigWarpActions.TRANSFORM_TYPE ) ); transformTypeMenu.setText( "Transformation Options" ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index bc8173e8..5d8244e5 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -69,7 +69,6 @@ public class BigWarpActions public static final String RESET_VIEWER = "reset active viewer"; public static final String ALIGN_VIEW_TRANSFORMS = "align view transforms %s"; - public static final String BRIGHTNESS_SETTINGS = "brightness settings"; public static final String VISIBILITY_AND_GROUPING = "visibility and grouping %s"; public static final String SHOW_HELP = "help"; public static final String SHOW_SOURCE_INFO = "show source info"; @@ -248,7 +247,6 @@ public static InputMap createInputMap( final KeyStrokeAdder.Factory keyPropertie // map.put( LANDMARK_MODE_OFF, "ctrl shift released SPACE", "released" ); // map.put( LANDMARK_MODE_OFF, "alt ctrl shift released SPACE", "released" ); - map.put( BRIGHTNESS_SETTINGS, "S" ); map.put( SHOW_HELP, "F1", "H" ); map.put( TOGGLE_POINTS_VISIBLE, "V" ); @@ -309,7 +307,6 @@ public static ActionMap createActionMap( final BigWarp< ? > bw ) new ToggleDialogAction( SHOW_WARPTYPE_DIALOG, bw.warpVisDialog ).put( actionMap ); - new ToggleDialogAction( BRIGHTNESS_SETTINGS, bw.brightnessDialog ).put( actionMap ); new ToggleDialogAction( SHOW_HELP, bw.helpDialog ).put( actionMap ); new ToggleDialogAction( SHOW_SOURCE_INFO, bw.sourceInfoDialog ).put( actionMap ); From 9192f994a9ec116ac5a24d01897c0e55c64d1dbf Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:41:06 -0500 Subject: [PATCH 108/282] feat: create source from uri --- src/main/java/bigwarp/BigWarpInit.java | 85 +++++++++++++++++--------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 03ba67d6..8b5bd61b 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -422,14 +422,14 @@ private static String schemeSpecificPartWithoutQuery( URI uri ) return uri.getSchemeSpecificPart().replaceAll( "\\?" + uri.getQuery(), "" ).replaceAll( "//", "" ); } - public static Source< ? > add( final BigWarpData< ? > bwData, String uri, int setupId, boolean isMoving ) throws URISyntaxException, IOException, SpimDataException + public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( final BigWarpData< T > bwData, String uri, int setupId, boolean isMoving ) throws URISyntaxException, IOException, SpimDataException { final URI tmpUri = new URI( "TMP", uri, null ); String encodedUriString = tmpUri.getRawSchemeSpecificPart(); encodedUriString = encodedUriString.replaceAll( "%23", "#" ); URI firstUri = new URI( encodedUriString ); final int prevSacCount = bwData.sources.size(); - Source< ? > source = null; + final LinkedHashMap< Source< T >, SourceInfo > sourceStateMap = new LinkedHashMap<>(); if ( firstUri.isOpaque() ) { URI secondUri = new URI( firstUri.getSchemeSpecificPart() ); @@ -458,8 +458,8 @@ private static String schemeSpecificPartWithoutQuery( URI uri ) throw new URISyntaxException( firstScheme, "Unsupported Top Level Protocol" ); } - source = loadN5Source( n5reader, dataset ); - add( bwData, source, setupId, 0, isMoving); + final Source< T > source = loadN5Source( n5reader, dataset ); + sourceStateMap.put( source, new SourceInfo( setupId, isMoving ) ); } else { @@ -475,51 +475,80 @@ private static String schemeSpecificPartWithoutQuery( URI uri ) final N5Reader n5reader = new N5Factory().openReader( firstSchemeAndPath ); final String datasetQuery = firstUri.getQuery(); final String dataset = datasetQuery == null ? "/" : datasetQuery; - source = loadN5Source( n5reader, dataset ); - add( bwData, source, setupId, 0, isMoving); + final Source< T > source = loadN5Source( n5reader, dataset ); + sourceStateMap.put( source, new SourceInfo( setupId, isMoving ) ); } catch ( Exception ignored ) { } - if (source == null) { + if ( sourceStateMap.isEmpty() ) { if ( firstSchemeAndPath.trim().toLowerCase().endsWith( ".xml" ) ) { - addToData( bwData, isMoving, setupId, firstSchemeAndPath, firstUri.getQuery() ); - return bwData.sources.get( bwData.sources.size() - 1 ).getSpimSource(); + sourceStateMap.putAll( createSources( bwData, isMoving, setupId, firstSchemeAndPath, firstUri.getQuery() ) ); } else { final ImagePlus ijp; - try + if ( Objects.equals( firstUri.getScheme(), "imagej" ) ) { - - if ( new File( uri ).isDirectory() ) - { - ijp = FolderOpener.open( uri ); - } - else - { - ijp = IJ.openImage( uri ); - } + final String title = firstUri.getPath(); + IJ.selectWindow( title ); + ijp = IJ.getImage(); } - catch ( Exception e ) + else if ( new File( uri ).isDirectory() ) { - return null; + ijp = FolderOpener.open( uri ); + } + else + { + ijp = IJ.openImage( uri ); } - add( bwData, ijp, setupId, 0, isMoving); - source = bwData.sources.get( bwData.sources.size() - 1 ).getSpimSource(); + sourceStateMap.putAll( createSources( bwData, ijp, setupId, 0, isMoving ) ); } } } /* override any already set urls with the uri we used to load this source. */ - if (source != null) { - final int postSacCount = bwData.sources.size(); - final List< ? extends SourceAndConverter< ? > > addedSacs = bwData.sources.subList( prevSacCount, postSacCount ); - bwData.urls.put( setupId, new ValuePair<>( () -> uri, new ArrayList<>(addedSacs) ) ); + sourceStateMap.forEach( ( source, state ) -> { + state.setUriSupplier( () -> uri ); + } ); + for ( final Map.Entry< Source< T >, SourceInfo > sourceSourceInfoEntry : sourceStateMap.entrySet() ) + { + sourceSourceInfoEntry.getValue().setSerializable( true ); + /* Always break after the first */ + break; } - return source; + return sourceStateMap; + } + + /** + * @return + * + * @Deprecated Use output froom {@link #createSources(BigWarpData, boolean, int, String, String)} and add with {@link #add(BigWarpData, LinkedHashMap, RealTransform)} instead. + */ + @Deprecated + public static < T > SpimData addToData( + final BigWarpData< T > bwdata, + final boolean isMoving, + final int setupId, + final String rootPath, + final String dataset ) + { + final AtomicReference< SpimData > returnMovingSpimData = new AtomicReference<>(); + final LinkedHashMap< Source< T >, SourceInfo > sources = createSources( bwdata, isMoving, setupId, rootPath, dataset, returnMovingSpimData ); + add( bwdata, sources ); + return returnMovingSpimData.get(); + } + + public static < T > Map< Source< T >, SourceInfo > createSources( + final BigWarpData< T > bwdata, + final boolean isMoving, + final int setupId, + final String rootPath, + final String dataset ) + { + return createSources( bwdata, isMoving, setupId, rootPath, dataset, null ); } public static SpimData addToData( final BigWarpData bwdata, From c2f106e0bf2aabbc9ae4402990e989630e3f29c7 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:41:13 -0500 Subject: [PATCH 109/282] feat!: separate create and add sources --- src/main/java/bigwarp/BigWarpInit.java | 205 +++++++++++++++++-------- 1 file changed, 141 insertions(+), 64 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 8b5bd61b..0b6b589b 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -60,6 +60,7 @@ import bdv.spimdata.SpimDataMinimal; import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.RealARGBColorConverterSetup; +import bdv.tools.brightness.SetupAssignments; import bdv.tools.transformation.TransformedSource; import bdv.util.RandomAccessibleIntervalMipmapSource; import bdv.viewer.Source; @@ -67,7 +68,12 @@ import bigwarp.loader.ImagePlusLoader; import bigwarp.loader.Loader; import bigwarp.loader.XMLLoader; +import bigwarp.source.SourceInfo; import ij.ImagePlus; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import mpicbg.spim.data.SpimData; import mpicbg.spim.data.SpimDataException; import mpicbg.spim.data.XmlIoSpimData; @@ -336,72 +342,134 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > return data; } + /** + * @return + * + * @Deprecated Use {@link #createSources(BigWarpData, ImagePlus, int, int, boolean)} instaed, and pass output to {@link #add(BigWarpData, LinkedHashMap, RealTransform)} + */ @SuppressWarnings( { "rawtypes" } ) - public static < T > int add( BigWarpData bwdata, ImagePlus ip, int setupId, int numTimepoints, boolean isMoving ) + @Deprecated + public static < T > int add( BigWarpData< T > bwdata, ImagePlus ip, int setupId, int numTimepoints, boolean isMoving ) + { + final LinkedHashMap< Source< T >, SourceInfo > sources = createSources( bwdata, ip, setupId, numTimepoints, isMoving ); + add( bwdata, sources ); + return sources.size(); + } + + public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigWarpData< T > bwdata, ImagePlus ip, int setupId, int numTimepoints, boolean isMoving ) { ImagePlusLoader loader = new ImagePlusLoader( ip ); SpimDataMinimal[] dataList = loader.loadAll( setupId ); - final int startSetupId = setupId; - final int prevSacCount = bwdata.sources.size(); + + final LinkedHashMap< Source< T >, SourceInfo > sourceInfoMap = new LinkedHashMap<>(); for ( SpimDataMinimal data : dataList ) { - add( bwdata, data, setupId, numTimepoints, isMoving ); - setupId++; + final LinkedHashMap< Source< T >, SourceInfo > map = createSources( bwdata, data, setupId, isMoving ); + sourceInfoMap.putAll( map ); + setupId += map.values().stream().map( SourceInfo::getId ).max( Integer::compare ).orElseGet( () -> 0 ); } - final int postSacCount = bwdata.sources.size(); - final List> addedSacs = bwdata.sources.subList( prevSacCount, postSacCount ); - final BigWarpData< ? > bigwarpData = bwdata; - bigwarpData.urls.put( startSetupId, new ValuePair<>(() -> { - final FileInfo originalFileInfo = ip.getOriginalFileInfo(); - if (originalFileInfo != null) { - final String url = originalFileInfo.url; - if ( url != null && !url.isEmpty() ) - { - return url; - } else { - return originalFileInfo.getFilePath(); + sourceInfoMap.forEach( ( sac, state ) -> { + state.setUriSupplier(() -> { + final FileInfo originalFileInfo = ip.getOriginalFileInfo(); + if (originalFileInfo != null) { + final String url = originalFileInfo.url; + if ( url != null && !url.isEmpty() ) + { + return url; + } else { + return originalFileInfo.getFilePath(); + } } - } - return null; - }, new ArrayList<>(addedSacs)) ); - + return null; + } ); + final ImagePlusLoader.ColorSettings colorSettings = bwdata.setupSettings.get( state.getId() ); + state.setColorSettings( colorSettings ); + } ); - loader.update(bwdata); - return loader.numSources(); + for ( final Map.Entry< Source< T >, SourceInfo > sourceSourceInfoEntry : sourceInfoMap.entrySet() ) + { + sourceSourceInfoEntry.getValue().setSerializable( true ); + /* Always break after the first */ + break; + } + return sourceInfoMap; } + /** + * @return + * + * @Deprecated Use the output from one of the {{@link #createSources(BigWarpData, String, int, boolean)}} to call {{@link #add(BigWarpData, LinkedHashMap)}} instead + */ @SuppressWarnings( { "rawtypes" } ) - public static < T > BigWarpData< ? > add( BigWarpData bwdata, Source< T > src, int setupId, int numTimepoints, boolean isMoving ) + @Deprecated + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > src, int setupId, int numTimepoints, boolean isMoving ) { return add( bwdata, src, setupId, numTimepoints, isMoving, null ); } + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > source, SourceInfo sourceInfo ) { + return add( bwdata, source, sourceInfo ); + } + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > source, SourceInfo sourceInfo, RealTransform transform) { + final LinkedHashMap< Source< T >, SourceInfo > sourceToInfo = new LinkedHashMap<>(); + sourceToInfo.put( source, sourceInfo ); + return add(bwdata, sourceToInfo, transform); + } + + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap< Source< T >, SourceInfo > sources ) + { + add( bwdata, sources, null ); + return bwdata; + } + + /** + * @return + * + * @Deprecated Use the output from one of the {{@link #createSources(BigWarpData, String, int, boolean)}} to call {{@link #add(BigWarpData, LinkedHashMap, RealTransform)}} instead + */ @SuppressWarnings( { "unchecked", "rawtypes" } ) - public static < T > BigWarpData< ? > add( BigWarpData bwdata, Source< T > src, int setupId, int numTimepoints, boolean isMoving, RealTransform transform ) + @Deprecated + public static < T > BigWarpData< T > add( BigWarpData bwdata, Source< T > src, int setupId, int numTimepoints, boolean isMoving, RealTransform transform ) { addSourceToListsGenericType( src, setupId, bwdata.converterSetups, bwdata.sources ); bwdata.transforms.add( transform ); + return bwdata; + } - int N = bwdata.sources.size(); - if ( isMoving ) - bwdata.movingSourceIndexList.add( N - 1 ); - else - bwdata.targetSourceIndexList.add( N - 1 ); + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap< Source< T >, SourceInfo > sources, RealTransform transform ) + { + sources.forEach( ( source, info ) -> { + addSourceToListsGenericType( source, info.getId(), bwdata.converterSetups, bwdata.sources ); + final SourceAndConverter addedSource = bwdata.sources.get( bwdata.sources.size() -1 ); + info.setSourceAndConverter( addedSource ); + if ( transform != null ) + { + info.setTransform( transform ); + bwdata.transforms.add( transform ); + } + bwdata.sourceInfos.put( info.getId(), info ); + } ); return bwdata; } - @SuppressWarnings( { "unchecked", "rawtypes" } ) - public static < T > BigWarpData< ? > add( BigWarpData bwdata, AbstractSpimData< ? > data, int baseId, int numTimepoints, boolean isMoving ) + @SuppressWarnings( { "rawtypes" } ) + public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigWarpData bwdata, AbstractSpimData< ? > data, int baseId, final boolean isMoving ) { final List> tmpSources = new ArrayList<>(); final List tmpConverterSetups = new ArrayList<>(); initSetups( data, tmpConverterSetups, tmpSources ); + final LinkedHashMap< Source< T >, SourceInfo > sourceInfoMap = new LinkedHashMap<>(); int setupId = baseId; - for( SourceAndConverter sac : tmpSources ) - add( bwdata, sac.getSpimSource(), setupId++, numTimepoints, isMoving ); + for ( SourceAndConverter sac : tmpSources ) + { + final Source source = sac.getSpimSource(); + sourceInfoMap.put( source, new SourceInfo( setupId++, isMoving, source.getName() ) ); + } + + return sourceInfoMap; // int N = bwdata.sources.size(); // final ArrayList idxList; @@ -412,11 +480,8 @@ public static < T > int add( BigWarpData bwdata, ImagePlus ip, int setupId, int // // for( int i = startSize; i < N; i++ ) // idxList.add( i ); -// - return bwdata; } - private static String schemeSpecificPartWithoutQuery( URI uri ) { return uri.getSchemeSpecificPart().replaceAll( "\\?" + uri.getQuery(), "" ).replaceAll( "//", "" ); @@ -551,46 +616,58 @@ public static < T > Map< Source< T >, SourceInfo > createSources( return createSources( bwdata, isMoving, setupId, rootPath, dataset, null ); } - public static SpimData addToData( final BigWarpData bwdata, - final boolean isMoving, final int setupId, final String rootPath, final String dataset ) + private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( + final BigWarpData< T > bwdata, + final boolean isMoving, + final int setupId, + final String rootPath, + final String dataset, + final AtomicReference< SpimData > returnMovingSpimData ) { if( rootPath.endsWith( "xml" )) { SpimData spimData; try { - final int prevSacCount = bwdata.sources.size(); spimData = new XmlIoSpimData().load( rootPath ); - add( bwdata, spimData, setupId, 0, isMoving ); - final int postSacCount = bwdata.sources.size(); - - final List< ? extends SourceAndConverter< ? > > addedSacs = bwdata.sources.subList( prevSacCount, postSacCount ); - bwdata.urls.put( setupId, new ValuePair<>( () -> { - try - { - return spimData.getBasePath().getCanonicalPath(); - } - catch ( IOException e ) - { - return null; - } - }, new ArrayList<>(addedSacs) ) ); - - if ( isMoving ) - return spimData; + if ( returnMovingSpimData != null && isMoving ) + { + returnMovingSpimData.set( spimData ); + } + final LinkedHashMap< Source< T >, SourceInfo > sources = createSources( bwdata, spimData, setupId, isMoving ); + + sources.forEach( ( source, state ) -> { + state.setUriSupplier( () -> { + try + { + return spimData.getBasePath().getCanonicalPath(); + } + catch ( IOException e ) + { + return null; + } + } ); + } ); + + for ( final Map.Entry< Source< T >, SourceInfo > sourceSourceInfoEntry : sources.entrySet() ) + { + sourceSourceInfoEntry.getValue().setSerializable( true ); + /* Always break after the first */ + break; + } + return sources; } catch ( SpimDataException e ) { e.printStackTrace(); } return null; } else { - final int prevSacCount = bwdata.sources.size(); - BigWarpInit.add(bwdata, loadN5Source(rootPath, dataset), setupId, 0, isMoving); - final int postSacCount = bwdata.sources.size(); - final List< ? extends SourceAndConverter< ? > > addedSacs = bwdata.sources.subList( prevSacCount, postSacCount ); - //TODO Caleb: Canonicalize the URL? - bwdata.urls.put( setupId, new ValuePair<>(() -> rootPath + "?" + dataset, new ArrayList<>(addedSacs))); - return null; + final LinkedHashMap< Source< T >, SourceInfo > map = new LinkedHashMap<>(); + final Source< T > source = loadN5Source( rootPath, dataset ); + final SourceInfo info = new SourceInfo( setupId, isMoving, dataset, () -> rootPath + "$" + dataset ); + info.setSerializable( true ); + map.put( source, info ); + return map; } } From 53adc60b92cc8156a87fd44feffb62840e3f1ef3 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:41:23 -0500 Subject: [PATCH 110/282] feat!: generic typics for loading sources --- src/main/java/bigwarp/BigWarpInit.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 0b6b589b..1e3f081b 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -671,7 +671,7 @@ private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( } } - public static Source loadN5Source( final String n5Root, final String n5Dataset ) + public static < T > Source< T > loadN5Source( final String n5Root, final String n5Dataset ) { final N5Reader n5; try @@ -684,7 +684,7 @@ public static Source loadN5Source( final String n5Root, final String n5Datase } return loadN5Source( n5, n5Dataset ); } - public static Source loadN5Source( final N5Reader n5, final String n5Dataset ) + public static < T > Source< T > loadN5Source( final N5Reader n5, final String n5Dataset ) { final N5MetadataParser[] PARSERS = new N5MetadataParser[]{ new ImagePlusLegacyMetadataParser(), @@ -724,7 +724,7 @@ public static Source loadN5Source( final N5Reader n5, final String n5Dataset } @SuppressWarnings( { "unchecked", "rawtypes" } ) - public static Source openAsSource( final N5Reader n5, final T meta, final boolean isVolatile ) + public static < T, M extends N5Metadata > Source< T > openAsSource( final N5Reader n5, final M meta, final boolean isVolatile ) { final RandomAccessibleInterval imageRaw; final RandomAccessibleInterval image; @@ -766,7 +766,7 @@ public static Source openAsSource( final N5Reader n5, return null; } - public static Source openAsSourceMulti( final N5Reader n5, final MultiscaleMetadata multiMeta, final boolean isVolatile ) + public static < T > Source< T > openAsSourceMulti( final N5Reader n5, final MultiscaleMetadata multiMeta, final boolean isVolatile ) { final String[] paths = multiMeta.getPaths(); final AffineTransform3D[] transforms = multiMeta.spatialTransforms3d(); From 7e0e8789a88a01f3d44241b084704b953b5f9437 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:41:50 -0500 Subject: [PATCH 111/282] feat: internal add/remove source logic --- src/main/java/bigwarp/BigWarpData.java | 43 +++++++++++--------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index d1cc430c..7ae2e5e0 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -197,12 +197,12 @@ public void wrapUp() updateIsMovingMap(); } - public void addSource( Source src, boolean isMoving ) + void addSource( Source src, boolean isMoving ) { - addSource( src, isMoving ); + addSource( src, isMoving, null ); } - public void addSource( Source src, boolean isMoving, RealTransform transform ) + void addSource( Source src, boolean isMoving, RealTransform transform ) { // find an unused id int id = 0; @@ -212,37 +212,30 @@ public void addSource( Source src, boolean isMoving, RealTransform transform id++; } BigWarpInit.add( this, src, id, 0, isMoving, transform ); - } + final SourceInfo sourceInfo = + sourceInfos.getOrDefault( id, new SourceInfo( id, isMoving, src.getName(), null, transform )); - public void addSourceAndConverter( SourceAndConverter sac, boolean isMoving ) - { - addSourceAndConverter( sac, isMoving, null ); + sourceInfo.setSourceAndConverter( sources.get( sources.size() -1 ) ); + sourceInfos.putIfAbsent( id, sourceInfo); } - public void addSourceAndConverter( SourceAndConverter sac, boolean isMoving, RealTransform transform ) + int remove( SourceInfo sourceInfo) { - sources.add( sac ); - isMovingMap.put( sac, isMoving ); - transforms.add( transform ); // transform may be null - - if( isMoving ) - movingSourceIndexList.add( sources.size() - 1 ); - else - targetSourceIndexList.add( sources.size() - 1 ); + final int idx = sources.indexOf( sourceInfo.getSourceAndConverter() ); + remove( idx ); + return idx; } - public void remove( int i ) + void remove( int i ) { SourceAndConverter< T > sac = sources.get( i ); - System.out.println( sac ); - System.out.println( isMovingMap ); - if( isMovingMap.remove( sac ) != null ) - movingSourceIndexList.remove( movingSourceIndexList.indexOf( i ) ); - else - targetSourceIndexList.remove( targetSourceIndexList.indexOf( i ) ); - + final int sacId = sourceInfos.entrySet().stream().filter( it -> it.getValue().getSourceAndConverter() == sac ).map( Map.Entry::getKey ).findFirst().get(); + final SourceInfo sourceInfo = sourceInfos.remove( sacId ); sources.remove( i ); - transforms.remove( i ); + transforms.remove( sourceInfo.getTransform() ); + setupSettings.remove( sourceInfo.getId() ); + sourceColorSettings.remove(sac); + converterSetups.remove( i ); } public void setTransform( int i, RealTransform transform ) From f132377cea11e76fa3040e5ec67d2df1ec69d53c Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:42:06 -0500 Subject: [PATCH 112/282] feat: add default source by static id --- src/main/java/bigwarp/BigWarp.java | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index b3364709..ec568cda 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3541,6 +3541,33 @@ protected void loadSettings() } } + private void addInternalSource(int id) { + final boolean sourceWithIdPresent = data.sources.stream().map( it -> it.getConverter()).filter( it -> it instanceof ConverterSetup ).filter( it -> ( ( ConverterSetup ) it ).getSetupId() == id ).findAny().isPresent(); + if (sourceWithIdPresent) { + return; + } + switch ( id ) + { + case GRID_SOURCE_ID: + gridSource = addGridSource( data, "GridSource" ); + setGridType( GridSource.GRID_TYPE.LINE ); + break; + case WARPMAG_SOURCE_ID: + warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "Warp magnitude" ); + break; + case JACDET_SOURCE_ID: + jacDetSource = addJacobianDeterminantSource( data, "Jacobian determinant" ); + break; + case TRANSFORM_MASK_SOURCE_ID: + transformMaskSource = addTransformMaskSource( data, ndims, "Transform mask" ); + bwTransform.setLambda( transformMask.getRandomAccessible() ); + addMaskMouseListener(); + break; + default: + break; + } + } + protected void loadSettings( final String jsonOrXmlFilename ) throws IOException, JDOMException { @@ -3549,6 +3576,16 @@ protected void loadSettings( final String jsonOrXmlFilename ) throws IOException final SAXBuilder sax = new SAXBuilder(); final Document doc = sax.build( jsonOrXmlFilename ); final Element root = doc.getRootElement(); + + /* add default sources if present */ + final List< Element > converterSetups = root.getChild( "SetupAssignments" ).getChild( "ConverterSetups" ).getChildren( "ConverterSetup" ); + for ( Element converterSetup : converterSetups ) + { + final int id = Integer.parseInt( converterSetup.getChild( "id" ).getText() ); + addInternalSource( id ); + } + synchronizeSources(); + viewerP.stateFromXml( root.getChild( "viewerP" ) ); viewerQ.stateFromXml( root.getChild( "viewerQ" ) ); setupAssignments.restoreFromXml( root ); From 7ad539a96b00ccf7d9a12fa9746c219bf49de46c Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:42:13 -0500 Subject: [PATCH 113/282] feat: constructor without unused window title, deprecate old --- src/main/java/bdv/ij/BigWarpBdvCommand.java | 2 +- .../java/bdv/ij/BigWarpImagePlusPlugIn.java | 2 +- src/main/java/bigwarp/BigWarp.java | 17 ++++++++++++++--- .../bigwarp/BigWarpTransformedSourcesTest.java | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpBdvCommand.java b/src/main/java/bdv/ij/BigWarpBdvCommand.java index 91ad4c62..ed6e406f 100755 --- a/src/main/java/bdv/ij/BigWarpBdvCommand.java +++ b/src/main/java/bdv/ij/BigWarpBdvCommand.java @@ -63,7 +63,7 @@ public void run() final SpimData movingSpimData = new XmlIoSpimData().load( movingImageXml.getAbsolutePath() ); new RepeatingReleasedEventsFixer().install(); final BigWarpData< ? > bigWarpData = BigWarpInit.createBigWarpData( movingSpimData, fixedSpimData ); - bw = new BigWarp( bigWarpData, "Big Warp", new ProgressWriterIJ() ); + bw = new BigWarp( bigWarpData, new ProgressWriterIJ() ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); bw.getLandmarkFrame().repaint(); diff --git a/src/main/java/bdv/ij/BigWarpImagePlusPlugIn.java b/src/main/java/bdv/ij/BigWarpImagePlusPlugIn.java index ae97e441..91d275c3 100755 --- a/src/main/java/bdv/ij/BigWarpImagePlusPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpImagePlusPlugIn.java @@ -171,7 +171,7 @@ public void run( final String arg ) try { new RepeatingReleasedEventsFixer().install(); - final BigWarp bw = new BigWarp<>( bigwarpdata, "Big Warp", new ProgressWriterIJ() ); + final BigWarp bw = new BigWarp<>( bigwarpdata, new ProgressWriterIJ() ); if( landmarkPath != null && !landmarkPath.isEmpty()) { diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index ec568cda..e0231fcc 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -344,12 +344,23 @@ public class BigWarp< T > final int ndims; - public BigWarp( final BigWarpData data, final String windowTitle, final ProgressWriter progressWriter ) throws SpimDataException + + @Deprecated + public BigWarp( final BigWarpData< T > data, final String windowTitle, final ProgressWriter progressWriter ) throws SpimDataException { - this( data, windowTitle, BigWarpViewerOptions.options().is2D( detectNumDims( data.sources ) == 2 ), progressWriter ); + this( data, BigWarpViewerOptions.options().is2D( detectNumDims( data.sources ) == 2 ), progressWriter ); + } + + @Deprecated + public BigWarp( final BigWarpData< T > data, final String windowTitle, BigWarpViewerOptions options, final ProgressWriter progressWriter ) throws SpimDataException { + this(data, options, progressWriter ); + } + + public BigWarp( final BigWarpData< T > data, final ProgressWriter progressWriter ) throws SpimDataException { + this( data, BigWarpViewerOptions.options().is2D( detectNumDims( data.sources ) == 2 ), progressWriter ); } - public BigWarp( final BigWarpData data, final String windowTitle, BigWarpViewerOptions options, final ProgressWriter progressWriter ) throws SpimDataException + public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final ProgressWriter progressWriter ) throws SpimDataException { repeatedKeyEventsFixer = RepeatingReleasedEventsFixer.installAnyTime(); diff --git a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java index b6cbce37..bdbdf476 100644 --- a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java +++ b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java @@ -33,7 +33,7 @@ public static void main( String[] args ) throws SpimDataException data.setTransform( 2, translation ); data.applyTransformations(); - final BigWarp bw = new BigWarp<>( data, "Big Warp", new ProgressWriterConsole()); + final BigWarp bw = new BigWarp<>( data, new ProgressWriterConsole()); bw.loadLandmarks( "/home/john/tmp/bw_tformTest_landmarks_simple.csv" ); // bw.loadLandmarks( "/groups/saalfeld/home/bogovicj/tmp/bw_tformTest_landmarks.csv" ); From 0eeac89e2dec770a754315f607f2280c8505ebef Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:42:28 -0500 Subject: [PATCH 114/282] feat!: aggregate SourceInfo --- src/main/java/bigwarp/BigWarp.java | 130 ++++++++++-------- .../bigwarp/BigWarpBatchTransformFOV.java | 2 +- src/main/java/bigwarp/BigWarpData.java | 35 +++-- src/main/java/bigwarp/BigWarpExporter.java | 1 + src/main/java/bigwarp/BigWarpInit.java | 28 +++- src/main/java/bigwarp/BigwarpSettings.java | 125 +++++++++++------ 6 files changed, 209 insertions(+), 112 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index e0231fcc..c8b7a7fb 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -133,6 +133,7 @@ import bigwarp.source.GridSource; import bigwarp.source.JacobianDeterminantSource; import bigwarp.source.PlateauSphericalMaskSource; +import bigwarp.source.SourceInfo; import bigwarp.source.WarpMagnitudeSource; import bigwarp.transforms.BigWarpTransform; import bigwarp.transforms.WrappedCoordinateTransform; @@ -142,6 +143,7 @@ import ij.IJ; import ij.ImageJ; import ij.ImagePlus; +import java.util.LinkedHashMap; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import jitk.spline.XfmUtils; import mpicbg.models.AbstractModel; @@ -336,6 +338,7 @@ public class BigWarp< T > protected static Logger logger = LoggerFactory.getLogger( BigWarp.class ); + //TODO Caleb: John, can this be replaced by info from BigWarpData/SourceInfo url? private SpimData movingSpimData; private File movingImageXml; @@ -731,7 +734,17 @@ public static void initBrightness( final double cumulativeMinCutoff, final doubl setup.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); } - public void addSource( Source source, boolean moving ) + /** + * @param sources to add; typically the output of a {#{@link BigWarpInit#createSources(BigWarpData, String, int, boolean)}} call + */ + public void addSources( LinkedHashMap, SourceInfo> sources) + { + + BigWarpInit.add( data, sources); + synchronizeSources(); + } + + public void addSource( Source< T > source, boolean moving ) { data.addSource( source, moving ); synchronizeSources(); @@ -742,6 +755,13 @@ public void addSource( Source source ) addSource( source, false ); } + public int removeSource( SourceInfo info ) + { + final int removedIdx = data.remove( info ); + synchronizeSources(); + return removedIdx; + } + public void removeSource( int i ) { data.remove( i ); @@ -1894,52 +1914,51 @@ public void setGridType( final GridSource.GRID_TYPE method ) ( ( GridSource< ? > ) gridSource.getSpimSource() ).setMethod( method ); } - public static void wrapMovingSources( final int ndims, final BigWarpData data ) + @SuppressWarnings( "unchecked" ) + public static < T > void wrapMovingSources( final int ndims, final BigWarpData< T > data ) { - final List warpUsIndices = data.movingSourceIndexList; final HashMap, ColorSettings> colorSettings = data.sourceColorSettings; // System.out.println( "before " + colorSettings.keySet().size()); int i = 0; - for ( final SourceAndConverter sac : data.sources ) + + for ( final SourceInfo sourceInfo : data.sourceInfos.values() ) { -// int idx = Arrays.binarySearch( warpUsIndices, i ); - int idx = warpUsIndices.indexOf( i ); - if ( idx >= 0 ) + if ( sourceInfo.isMoving() ) { - SourceAndConverter newSac = wrapSourceAsTransformed( sac, "xfm_" + i, ndims ); - colorSettings.put( newSac, colorSettings.get( sac )); - data.sources.set( i, newSac ); + SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); + final int sourceIdx = data.sources.indexOf( sourceInfo.getSourceAndConverter() ); + sourceInfo.setSourceAndConverter( newSac ); + colorSettings.put( newSac, sourceInfo.getColorSettings()); + data.sources.set( sourceIdx, newSac ); } i++; } // System.out.println( "after " + colorSettings.keySet().size()); } - public static List< SourceAndConverter > wrapSourcesAsTransformed( final List< SourceAndConverter > sources, + @SuppressWarnings( "unchecked" ) + public static < T > List< SourceAndConverter< T > > wrapSourcesAsTransformed( final LinkedHashMap< Integer, SourceInfo > sources, final int ndims, - final BigWarpData data ) + final BigWarpData< T > data ) { final List< SourceAndConverter> wrappedSource = new ArrayList<>(); - final List warpUsIndices = data.movingSourceIndexList; final HashMap, ColorSettings> colorSettings = data.sourceColorSettings; // System.out.println( "before " + colorSettings.keySet().size()); int i = 0; - for ( final SourceAndConverter sac : sources ) + for ( final SourceInfo sourceInfo : sources.values() ) { -// int idx = Arrays.binarySearch( warpUsIndices, i ); - int idx = warpUsIndices.indexOf( i ); - if ( idx >= 0 ) + if ( sourceInfo.isMoving() ) { - SourceAndConverter newSac = wrapSourceAsTransformed( sac, "xfm_" + i, ndims ); + SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); wrappedSource.add( newSac ); - colorSettings.put( newSac, colorSettings.get( sac )); + colorSettings.put( newSac, sourceInfo.getColorSettings() ); } else { - wrappedSource.add( sac ); + wrappedSource.add( ( SourceAndConverter< T > ) sourceInfo.getSourceAndConverter() ); } i++; @@ -2310,36 +2329,36 @@ private void setTransformationMovingSourceOnly( final InvertibleRealTransform tr { this.currentTransform = transform; - for ( int i = 0; i < data.movingSourceIndexList.size(); i++ ) - { - final int idx = data.movingSourceIndexList.get( i ); - - // the xfm must always be 3d for bdv to be happy. - // when bigwarp has 2d images though, the z- component will be left unchanged - // InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); - - // the updateTransform method creates a copy of the transform - ( ( WarpedSource< ? > ) ( data.sources.get( idx ).getSpimSource() ) ).updateTransform( transform ); - if ( data.sources.get( 0 ).asVolatile() != null ) - ( ( WarpedSource< ? > ) ( data.sources.get( idx ).asVolatile().getSpimSource() ) ).updateTransform( transform ); - } + data.sourceInfos.values().forEach( sourceInfo -> { + if ( sourceInfo.isMoving() ) + { + // the xfm must always be 3d for bdv to be happy. + // when bigwarp has 2d images though, the z- component will be left unchanged + // InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); + + // the updateTransform method creates a copy of the transform + ( ( WarpedSource< ? > ) sourceInfo.getSourceAndConverter().getSpimSource() ).updateTransform( transform ); + if ( data.sources.get( 0 ).asVolatile() != null ) + ( ( WarpedSource< ? > ) sourceInfo.getSourceAndConverter().asVolatile().getSpimSource() ).updateTransform( transform ); + } + } ); } public void updateSourceBoundingBoxEstimators() { - for ( int i = 0; i < data.movingSourceIndexList.size(); i++ ) - { - final int idx = data.movingSourceIndexList.get( i ); - - // the xfm must always be 3d for bdv to be happy. - // when bigwarp has 2d images though, the z- component will be left unchanged - //InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); - - // the updateTransform method creates a copy of the transform - ( ( WarpedSource< ? > ) ( data.sources.get( idx ).getSpimSource() ) ).setBoundingBoxEstimator(bboxOptions.copy()); - if ( data.sources.get( 0 ).asVolatile() != null ) - ( ( WarpedSource< ? > ) ( data.sources.get( idx ).asVolatile().getSpimSource() ) ).setBoundingBoxEstimator(bboxOptions.copy()); - } + data.sourceInfos.values().forEach( sourceInfo -> { + if ( sourceInfo.isMoving() ) + { + // the xfm must always be 3d for bdv to be happy. + // when bigwarp has 2d images though, the z- component will be left unchanged + //InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); + + // the updateTransform method creates a copy of the transform + ( ( WarpedSource< ? > ) sourceInfo.getSourceAndConverter().getSpimSource() ).setBoundingBoxEstimator( bboxOptions.copy() ); + if ( data.sources.get( 0 ).asVolatile() != null ) + ( ( WarpedSource< ? > ) sourceInfo.getSourceAndConverter().asVolatile().getSpimSource() ).setBoundingBoxEstimator( bboxOptions.copy() ); + } + } ); } private synchronized void notifyTransformListeners( ) @@ -2420,15 +2439,17 @@ public boolean restimateTransformation() public synchronized void setIsMovingDisplayTransformed( final boolean isTransformed ) { - for( int i = 0 ; i < data.movingSourceIndexList.size(); i ++ ) - { - final int movingSourceIndex = data.movingSourceIndexList.get( 0 ); - ( ( WarpedSource< ? > ) ( data.sources.get( movingSourceIndex ).getSpimSource() ) ).setIsTransformed( isTransformed ); + data.sourceInfos.values().forEach( sourceInfo -> { + if ( sourceInfo.isMoving() ) + { + final SourceAndConverter< ? > sourceAndConverter = sourceInfo.getSourceAndConverter(); + ( ( WarpedSource< ? > ) sourceAndConverter.getSpimSource() ).setIsTransformed( isTransformed ); - if ( data.sources.get( movingSourceIndex ).asVolatile() != null ) - ( ( WarpedSource< ? > ) ( data.sources.get( movingSourceIndex ).asVolatile().getSpimSource() ) ).setIsTransformed( isTransformed ); - } + if ( sourceAndConverter.asVolatile() != null ) + ( ( WarpedSource< ? > ) sourceAndConverter.asVolatile().getSpimSource() ).setIsTransformed( isTransformed ); + } + } ); overlayP.setIsTransformed( isTransformed ); @@ -3525,10 +3546,9 @@ public BigwarpSettings getSettings() setupAssignments, bookmarks, autoSaver, - transformMask.getRandomAccessible(), landmarkModel, bwTransform, - data.urls + data.sourceInfos ); } diff --git a/src/main/java/bigwarp/BigWarpBatchTransformFOV.java b/src/main/java/bigwarp/BigWarpBatchTransformFOV.java index a275291b..fe0a55b3 100644 --- a/src/main/java/bigwarp/BigWarpBatchTransformFOV.java +++ b/src/main/java/bigwarp/BigWarpBatchTransformFOV.java @@ -334,7 +334,7 @@ public static < T > BigWarpExporter< T > applyBigWarpHelper( AbstractSpimData< ? @SuppressWarnings("unchecked") List< SourceAndConverter< T >> sourcesxfm = BigWarp.wrapSourcesAsTransformed( - data.sources, + data.sourceInfos, ltm.getNumdims(), data ); diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 7ae2e5e0..142e1245 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -1,11 +1,12 @@ package bigwarp; +import bigwarp.source.SourceInfo; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.Supplier; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.IntStream; import bdv.cache.CacheControl; @@ -28,13 +29,12 @@ import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.Wrapped2DTransformAs3D; -import net.imglib2.util.Pair; public class BigWarpData< T > { public List< SourceAndConverter< T > > sources; - public final Map< Integer, Pair, List>>> urls = new HashMap<>(); + public final LinkedHashMap< Integer, SourceInfo > sourceInfos = new LinkedHashMap<>(); public List transforms; @@ -112,10 +112,13 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, final List< C this.sources = sources; this.converterSetups = converterSetups; - this.movingSourceIndexList = movingIndexes; - this.targetSourceIndexList = targetIndexes; - isMovingMap = new HashMap<>(); - updateIsMovingMap(); + for ( int i = 0; i < sources.size(); i++ ) + { + final SourceAndConverter< T > sourceAndConverter = sources.get( i ); + final SourceInfo sourceInfo = new SourceInfo( i, movingIndexes.contains( i ), sourceAndConverter.getSpimSource().getName() ); + sourceInfo.setSourceAndConverter( sourceAndConverter ); + sourceInfos.put( i, sourceInfo ); + } if ( cache == null ) this.cache = new CacheControl.Dummy(); @@ -183,6 +186,22 @@ public List getTargetConverterSetups() return out; } + public SourceInfo getSourceInfo( int id ) + { + return sourceInfos.get( id ); + } + + public SourceInfo getSourceInfo( SourceAndConverter< ? > sac ) + { + for ( final SourceInfo info : sourceInfos.values() ) + { + if (info.getSourceAndConverter() == sac) { + return info; + } + } + return null; + } + public boolean isMoving( SourceAndConverter sac ) { if( !isMovingMap.containsKey( sac )) return false; diff --git a/src/main/java/bigwarp/BigWarpExporter.java b/src/main/java/bigwarp/BigWarpExporter.java index 691d2e57..aa0420a8 100644 --- a/src/main/java/bigwarp/BigWarpExporter.java +++ b/src/main/java/bigwarp/BigWarpExporter.java @@ -908,6 +908,7 @@ public static BigWarpExporter getExporter( List movingSourceIndexList = bwData.movingSourceIndexList; // List targetSourceIndexList = bwData.targetSourceIndexList; + //TODO Caleb: Consider a method that just takes a list of all moving sources if ( BigWarpRealExporter.isTypeListFullyConsistent( transformedSources, movingSourceIndexList ) ) { Object baseType = transformedSources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getType(); diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 1e3f081b..746ee520 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -319,25 +319,43 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > public static BigWarpData< ? > createBigWarpData( final Source< ? >[] movingSourceList, final Source< ? >[] fixedSourceList, String[] names ) { BigWarpData data = initData(); - + int nameIdx = 0; int setupId = 0; // moving for ( Source< ? > mvgSource : movingSourceList ) { - add( data, mvgSource, setupId++, 1, true ); + add( data, mvgSource, setupId, 1, true ); + final SourceAndConverter addedSource = ( ( BigWarpData< ? > ) data ).sources.get( data.sources.size() - 1 ); + final SourceInfo info = new SourceInfo( setupId, true, names[ nameIdx++ ] ); + info.setSourceAndConverter( addedSource ); + data.sourceInfos.put( setupId++, info ); } // target for ( Source< ? > fxdSource : fixedSourceList ) { add( data, fxdSource, setupId, 1, false ); + final SourceAndConverter addedSource = ( ( BigWarpData< ? > ) data ).sources.get( data.sources.size() - 1 ); + final SourceInfo info = new SourceInfo( setupId, false, names[ nameIdx++ ] ); + info.setSourceAndConverter( addedSource); + data.sourceInfos.put( setupId++, info); } data.wrapUp(); - if ( names != null ) { return new BigWarpData( - wrapSourcesAsRenamable( data.sources, names ), data.converterSetups, data.cache, - data.movingSourceIndexList, data.targetSourceIndexList ); } + if ( names != null ) + { + final ArrayList wrappedSources = wrapSourcesAsRenamable( data.sources, names ); + final AtomicInteger sourceInfoIdx = new AtomicInteger(); + + final BigWarpData< ? > typedData = data; + typedData.sourceInfos.forEach((id, info) -> { + info.setSourceAndConverter( typedData.sources.get( sourceInfoIdx.getAndIncrement() ) ); + }); + + return new BigWarpData( wrappedSources, data.converterSetups, data.cache ); + + } return data; } diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 148427f4..7854c3f2 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -7,6 +7,7 @@ import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.DisplayMode; import bdv.viewer.Interpolation; +import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bdv.viewer.SynchronizedViewerState; import bdv.viewer.ViewerPanel; @@ -15,7 +16,7 @@ import bdv.viewer.state.ViewerState; import bdv.viewer.state.XmlIoViewerState; import bigwarp.landmarks.LandmarkTableModel; -import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.source.SourceInfo; import bigwarp.transforms.BigWarpTransform; import bigwarp.transforms.io.TransformWriterJson; import com.google.gson.Gson; @@ -29,16 +30,17 @@ import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; +import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.Supplier; +import java.util.stream.Collectors; import mpicbg.spim.data.SpimDataException; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.type.numeric.ARGBType; -import net.imglib2.util.Pair; import org.scijava.listeners.Listeners; import static bdv.viewer.Interpolation.NEARESTNEIGHBOR; @@ -57,7 +59,7 @@ public class BigwarpSettings extends TypeAdapter< BigwarpSettings > private final BigWarpTransform transform; - private final Map< Integer, Pair, List>>> sourceUrls; + private final Map< Integer, SourceInfo> sourceInfos; BigWarpViewerPanel viewerP; @@ -78,10 +80,9 @@ public BigwarpSettings( final SetupAssignments setupAssignments, final Bookmarks bookmarks, final BigWarpAutoSaver autoSaver, - final PlateauSphericalMaskRealRandomAccessible transformMask, final LandmarkTableModel landmarks, final BigWarpTransform transform, - final Map< Integer, Pair, List>>> sourceUrls + final Map< Integer, SourceInfo > sourceInfos ) { @@ -91,10 +92,9 @@ public BigwarpSettings( this.setupAssignments = setupAssignments; this.bookmarks = bookmarks; this.autoSaver = autoSaver; - this.transformMask = transformMask; this.landmarks = landmarks; this.transform = transform; - this.sourceUrls = sourceUrls; + this.sourceInfos = sourceInfos; } public void serialize( String jsonFilename ) throws IOException @@ -111,7 +111,7 @@ public void write( final JsonWriter out, final BigwarpSettings value ) throws IO out.beginObject(); out.name( "Sources" ); - new BigWarpSourcesAdapter( bigWarp.getData() ).write( out, sourceUrls ); + new BigWarpSourcesAdapter( bigWarp, overwriteSources ).write( out, sourceInfos ); out.name( "ViewerP" ); new BigWarpViewerPanelAdapter( viewerP ).write( out, viewerP ); out.name( "ViewerQ" ); @@ -171,46 +171,59 @@ public BigwarpSettings read( final JsonReader in ) throws IOException return this; } - public static class BigWarpSourcesAdapter extends TypeAdapter, List>>>> { + public static class BigWarpSourcesAdapter< T > extends TypeAdapter< Map< Integer, SourceInfo > > + { + + private BigWarp< T > bigwarp; - private final BigWarpData data; + private boolean overwriteExisting; - public BigWarpSourcesAdapter( final BigWarpData data ) + public BigWarpSourcesAdapter( final BigWarp< T > bigwarp, boolean overwriteSources ) { - this.data = data; + + this.bigwarp = bigwarp; + this.overwriteExisting = overwriteSources; } @Override - public void write( final JsonWriter out, final Map< Integer, Pair< Supplier< String >, List< SourceAndConverter< ? > > > > value ) throws IOException + public void write( final JsonWriter out, final Map< Integer, SourceInfo > value ) throws IOException { out.beginObject(); - for ( Map.Entry< Integer, Pair, List>>> entry : value.entrySet() ) + + /* We only want the lowest setupId with the same url*/ + + for ( Map.Entry< Integer, SourceInfo > entry : value.entrySet() ) { - Integer id = entry.getKey(); - final Supplier urlSupplier = entry.getValue().getA(); - /* currently we only care about the first source when a single `add` call creates multiple sources. - * This is because they will deserialzie to multiple sources from one url next time as well. */ - final SourceAndConverter< ? > source = entry.getValue().getB().get( 0 ); + if ( !entry.getValue().isSerializable() ) + continue; + + SourceInfo sourceInfo = entry.getValue(); + int id = sourceInfo.getId(); + URI uriObj; + String uri = sourceInfo.getUri(); + final String name = sourceInfo.getName(); out.name( "" + id ); - out.beginObject(); - - final int sourceIdx = data.sources.indexOf( source ); - final boolean isMoving = data.movingSourceIndexList.contains( sourceIdx ); - - final String url = urlSupplier.get(); - if ( url != null ) + if ( uri == null && name != null && !name.trim().isEmpty() ) + { + uri = "imagej:///" + name; + } + if ( uri != null ) + { + out.name( "uri" ).value( uri ); + } + if ( sourceInfo.getName() != null ) { - out.name( "url" ).value( url ); + out.name( "name" ).value( sourceInfo.getName() ); } - out.name( "isMoving" ).value( isMoving ); + out.name( "isMoving" ).value( sourceInfo.isMoving() ); out.endObject(); } out.endObject(); } @Override - public Map< Integer, Pair< Supplier< String >, List< SourceAndConverter< ? > > > > read( final JsonReader in ) throws IOException + public Map< Integer, SourceInfo > read( final JsonReader in ) throws IOException { in.beginObject(); while ( in.hasNext() ) @@ -218,36 +231,62 @@ public void write( final JsonWriter out, final Map< Integer, Pair< Supplier< Str //TODO Caleb: What to do if `data` alrread has a source for this `id`? int id = Integer.parseInt( in.nextName() ); in.beginObject(); - String url = null; + String uri = null; + String name = null; Boolean isMoving = null; while ( in.hasNext() ) { - switch ( in.nextName() ) + final String key = in.nextName(); + switch ( key ) { - case "url": - url = in.nextString(); + case "uri": + uri = in.nextString(); + break; + case "name": + name = in.nextString(); break; case "isMoving": isMoving = in.nextBoolean(); break; } } - try + /* Only add if we either are told to override (in which case remove previous) or don't have. */ + SourceInfo existingInfo = bigwarp.data.sourceInfos.get( id ); + int targetIdx = -1; + if ( existingInfo != null && overwriteExisting ) { - if (url != null) { - BigWarpInit.add( data, url, id, isMoving ); - } else { - //TODO Caleb: Prompt? Error? - } + targetIdx = bigwarp.data.remove( existingInfo ); + existingInfo = null; } - catch ( URISyntaxException | SpimDataException e ) + if ( existingInfo == null && uri != null ) { - throw new IOException("Error Parsing Source by URI", e ); + + final LinkedHashMap< Source< T >, SourceInfo > sources; + try + { + //TODO Transform + sources = BigWarpInit.createSources( bigwarp.data, uri, id, isMoving ); + } + catch ( URISyntaxException | SpimDataException e ) + { + throw new RuntimeException( e ); + } + BigWarpInit.add( bigwarp.data, sources ); + if ( targetIdx >= 0 ) + { + /* move the source and converterSetup to the correct idx */ + final SourceAndConverter< T > sacToMove = bigwarp.data.sources.remove( bigwarp.data.sources.size() - 1 ); + bigwarp.data.sources.add( targetIdx, sacToMove ); + + final ConverterSetup setupToMove = bigwarp.data.converterSetups.remove( bigwarp.data.converterSetups.size() - 1 ); + bigwarp.data.converterSetups.add( targetIdx, setupToMove ); + } } in.endObject(); } in.endObject(); - return data.urls; + bigwarp.synchronizeSources(); + return bigwarp.data.sourceInfos; } } From 62e3106ead1f9d2e508316d34652413573f49f7e Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:42:43 -0500 Subject: [PATCH 115/282] feat: overwrite existing sources flag for deserialization --- src/main/java/bigwarp/BigWarp.java | 10 +++++++++- src/main/java/bigwarp/BigwarpSettings.java | 9 +++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index c8b7a7fb..2f70e704 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3601,6 +3601,12 @@ private void addInternalSource(int id) { protected void loadSettings( final String jsonOrXmlFilename ) throws IOException, JDOMException + { + loadSettings( jsonOrXmlFilename, false ); + } + + protected void loadSettings( final String jsonOrXmlFilename, boolean overwriteSources ) throws IOException, + JDOMException { if ( jsonOrXmlFilename.endsWith( ".xml" ) ) { @@ -3636,7 +3642,9 @@ protected void loadSettings( final String jsonOrXmlFilename ) throws IOException } else { - getSettings().read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); + final BigwarpSettings settings = getSettings(); + settings.setOverwriteSources( overwriteSources ); + settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); activeSourcesDialogP.update(); activeSourcesDialogQ.update(); } diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 7854c3f2..31b3063f 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -71,7 +71,7 @@ public class BigwarpSettings extends TypeAdapter< BigwarpSettings > BigWarpAutoSaver autoSaver; - final PlateauSphericalMaskRealRandomAccessible transformMask; + boolean overwriteSources = false; public BigwarpSettings( final BigWarp bigWarp, @@ -97,6 +97,11 @@ public BigwarpSettings( this.sourceInfos = sourceInfos; } + public void setOverwriteSources( final boolean overwriteSources ) + { + this.overwriteSources = overwriteSources; + } + public void serialize( String jsonFilename ) throws IOException { try ( final FileWriter fileWriter = new FileWriter( jsonFilename ) ) @@ -140,7 +145,7 @@ public BigwarpSettings read( final JsonReader in ) throws IOException switch ( nextName ) { case "Sources": - new BigWarpSourcesAdapter( bigWarp.data ).read( in ); + new BigWarpSourcesAdapter<>( bigWarp, overwriteSources ).read( in ); break; case "ViewerP": new BigWarpViewerPanelAdapter( viewerP ).read( in ); From da8b2f0479e6b7b6ed4b2a96007769ed68a775b6 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:42:56 -0500 Subject: [PATCH 116/282] feat: setupAssignemnts and converterSetups as objects, not array --- src/main/java/bigwarp/BigwarpSettings.java | 51 +++++++++++++--------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 31b3063f..9d5f1709 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -531,16 +531,18 @@ public void write( final JsonWriter out, final SetupAssignments value ) throws I { out.beginObject(); out.name( "ConverterSetups" ); - out.beginArray(); + out.beginObject(); final List< ConverterSetup > converterSetups = value.getConverterSetups(); final ConverterSetupAdapter converterSetupAdapter = new ConverterSetupAdapter( value ); for ( final ConverterSetup converterSetup : converterSetups ) { + out.name(Integer.toString( converterSetup.getSetupId() )); out.beginObject(); + converterSetupAdapter.setSetupId( converterSetup.getSetupId() ); converterSetupAdapter.write( out, converterSetup ); out.endObject(); } - out.endArray(); + out.endObject(); final List< MinMaxGroup > minMaxGroups = value.getMinMaxGroups(); out.name( "MinMaxGroups" ); new MinMaxGroupsAdapter().write( out, minMaxGroups ); @@ -573,15 +575,33 @@ public SetupAssignments read( final JsonReader in ) throws IOException switch ( name ) { case "ConverterSetups": - in.beginArray(); + final ConverterSetupAdapter converterSetupAdapter = new ConverterSetupAdapter( setupAssignments ); + in.beginObject(); while ( in.hasNext() ) { + final int id = Integer.parseInt( in.nextName() ); + converterSetupAdapter.setSetupId( id ); in.beginObject(); - final ConverterSetupDTO dto = ( ConverterSetupDTO ) new ConverterSetupAdapter( setupAssignments ).read( in ); + final ConverterSetupDTO dto = ( ConverterSetupDTO ) converterSetupAdapter.read( in); converters.add( dto ); + in.endObject(); } - in.endArray(); + in.endObject(); + + final List< ConverterSetup > converterSetups = setupAssignments.getConverterSetups(); + final List originalSetupIdOrder = converterSetups.stream().map( ConverterSetup::getSetupId ).collect( Collectors.toList()); + for ( int idx = 0; idx < converters.size(); idx++ ) + { + final ConverterSetupDTO converterSetupDTO = converters.get( idx ); + final int setupId = converterSetupDTO.getSetupId(); + + final int idxOfConverterSetup = originalSetupIdOrder.indexOf( setupId ); + if (idxOfConverterSetup >= 0 && idx != idxOfConverterSetup) { + converters.remove( idx ); + converters.add( idxOfConverterSetup, converterSetupDTO ); + } + } break; case "MinMaxGroups": minMaxGroups.addAll( new MinMaxGroupsAdapter().read( in ) ); @@ -611,11 +631,11 @@ public static class MinMaxGroupsAdapter extends TypeAdapter< List< MinMaxGroup > @Override public void write( final JsonWriter out, final List< MinMaxGroup > value ) throws IOException { - out.beginArray(); + out.beginObject(); for ( int i = 0; i < value.size(); i++ ) { + out.name( Integer.toString( i )); out.beginObject(); - out.name( "id" ).value( i ); out.name( "fullRangeMin" ).value( value.get( i ).getFullRangeMin() ); out.name( "fullRangeMax" ).value( value.get( i ).getFullRangeMax() ); out.name( "rangeMin" ).value( value.get( i ).getRangeMin() ); @@ -624,7 +644,7 @@ public void write( final JsonWriter out, final List< MinMaxGroup > value ) throw out.name( "currentMax" ).value( value.get( i ).getMaxBoundedValue().getCurrentValue() ); out.endObject(); } - out.endArray(); + out.endObject(); } @Override @@ -632,10 +652,10 @@ public List< MinMaxGroup > read( final JsonReader in ) throws IOException { final HashMap< Integer, MinMaxGroup > groupMap = new HashMap<>(); final ArrayList< MinMaxGroup > groups = new ArrayList<>(); - in.beginArray(); + in.beginObject(); while ( in.hasNext() ) { - int id = 0; + int id = Integer.parseInt( in.nextName() ); double fullRangeMin = 0; double fullRangeMax = 0; double rangeMin = 0; @@ -647,9 +667,6 @@ public List< MinMaxGroup > read( final JsonReader in ) throws IOException { switch ( in.nextName() ) { - case "id": - id = in.nextInt(); - break; case "fullRangeMin": fullRangeMin = in.nextDouble(); break; @@ -683,7 +700,7 @@ public List< MinMaxGroup > read( final JsonReader in ) throws IOException groupMap.put( id, group ); in.endObject(); } - in.endArray(); + in.endObject(); for ( int i = 0; i < groupMap.size(); i++ ) { /* We require that the `id` of the deserialized group matches the index of the returned list. */ @@ -706,7 +723,6 @@ public ConverterSetupAdapter( final SetupAssignments setupAssignments ) public void write( final JsonWriter out, final ConverterSetup value ) throws IOException { final List< MinMaxGroup > minMaxGroups = setupAssignments.getMinMaxGroups(); - out.name( "id" ).value( value.getSetupId() ); out.name( "min" ).value( value.getDisplayRangeMin() ); out.name( "max" ).value( value.getDisplayRangeMax() ); out.name( "color" ).value( value.getColor().get() ); @@ -716,7 +732,6 @@ public void write( final JsonWriter out, final ConverterSetup value ) throws IOE @Override public ConverterSetup read( final JsonReader in ) throws IOException { - int tmpid = 0; double tmpmin = 0; double tmpmax = 0; int tmpcolor = 0; @@ -725,9 +740,6 @@ public ConverterSetup read( final JsonReader in ) throws IOException { switch ( in.nextName() ) { - case "id": - tmpid = in.nextInt(); - break; case "min": tmpmin = in.nextDouble(); break; @@ -743,7 +755,6 @@ public ConverterSetup read( final JsonReader in ) throws IOException } } - final int id = tmpid; final double min = tmpmin; final double max = tmpmax; final int color = tmpcolor; From 7deca4dba2edeabe4987de7151558db9b1f88133 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:43:01 -0500 Subject: [PATCH 117/282] feat: synchronize setupAssignments --- src/main/java/bigwarp/BigWarp.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 2f70e704..7897d713 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -652,6 +652,11 @@ public void synchronizeSources() { viewerP.state().clearSources(); viewerQ.state().clearSources(); + + final ArrayList converterSetupsToRemove = new ArrayList<>(); + setupAssignments.getConverterSetups().forEach( converterSetupsToRemove::add ); + converterSetupsToRemove.forEach( setupAssignments::removeSetup ); + final SynchronizedViewerState pState = viewerP.state(); final SynchronizedViewerState qState = viewerQ.state(); for ( int i = 0; i < data.sources.size(); i++ ) @@ -661,8 +666,11 @@ public void synchronizeSources() qState.addSource( sac ); // update the viewer converter setups too - viewerFrameP.getConverterSetups().put( sac, data.converterSetups.get( i ) ); - viewerFrameQ.getConverterSetups().put( sac, data.converterSetups.get( i ) ); + final ConverterSetup setup = data.converterSetups.get( i ); + + viewerFrameP.getConverterSetups().put( sac, setup ); + viewerFrameQ.getConverterSetups().put( sac, setup ); + setupAssignments.addSetup( setup ); } } From e3c96fab293439a88edc18e98a55397cbd35cf24 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:43:12 -0500 Subject: [PATCH 118/282] refactor!: migrate moving/target flag logic --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 2 +- src/main/java/bdv/ij/ApplyBigwarpPlugin.java | 43 ++++---- .../ij/BigWarpToDeformationFieldPlugIn.java | 16 ++- .../java/bdv/viewer/BigWarpViewerPanel.java | 19 ++-- src/main/java/bigwarp/BigWarp.java | 7 +- src/main/java/bigwarp/BigWarpData.java | 97 ++++++++++++------- src/main/java/bigwarp/BigWarpExporter.java | 3 +- 7 files changed, 112 insertions(+), 75 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 8556493c..0ff833cd 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -112,7 +112,7 @@ public BigWarpViewerFrame( setups.put( source, setup ); } - if ( !isMoving && bw.getData().targetSourceIndexList.size() > 0 ) + if ( !isMoving && bw.getData().numTargetSources() > 0 ) viewer.state().setCurrentSource( bw.getData().getTargetSource( 0 ) ); keybindings = new InputActionBindings(); diff --git a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java index 5268fe61..796854dc 100644 --- a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java +++ b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java @@ -163,21 +163,21 @@ public static double[] getResolution( return res; } - public static String getUnit( final BigWarpData bwData, + public static String getUnit( final BigWarpData bwData, final String resolutionOption ) { String unit = "pix"; - boolean doTargetImagesExist = bwData.targetSourceIndexList != null && bwData.targetSourceIndexList.size() > 0; + boolean doTargetImagesExist = bwData.numTargetSources() > 0; if( resolutionOption.equals( MOVING ) || resolutionOption.equals( MOVING_WARPED ) || !doTargetImagesExist ) { - VoxelDimensions mvgVoxDims = bwData.sources.get( bwData.movingSourceIndexList.get( 0 ) ).getSpimSource().getVoxelDimensions(); + VoxelDimensions mvgVoxDims = bwData.getMovingSource( 0 ).getSpimSource().getVoxelDimensions(); if( mvgVoxDims != null ) unit = mvgVoxDims.unit(); } else { // use target units even if - VoxelDimensions tgtVoxDims = bwData.sources.get( bwData.targetSourceIndexList.get( 0 ) ).getSpimSource().getVoxelDimensions(); + VoxelDimensions tgtVoxDims = bwData.getTargetSource( 0 ).getSpimSource().getVoxelDimensions(); if( tgtVoxDims != null ) unit = tgtVoxDims.unit(); } @@ -194,21 +194,19 @@ public static double[] getResolution( if( resolutionOption.equals( TARGET )) { - if( bwData.targetSourceIndexList.size() <= 0 ) + if( bwData.numTargetSources() <= 0 ) return null; - Source< ? > spimSource = bwData.sources.get( - bwData.targetSourceIndexList.get( 0 )).getSpimSource(); + Source< ? > spimSource = bwData.getTargetSource(0 ).getSpimSource(); return getResolution( spimSource, resolutionOption, resolutionSpec ); } else if( resolutionOption.equals( MOVING )) { - if( bwData.targetSourceIndexList.size() <= 0 ) + if( bwData.numTargetSources() <= 0 ) return null; - Source< ? > spimSource = bwData.sources.get( - bwData.movingSourceIndexList.get( 0 )).getSpimSource(); + Source< ? > spimSource = bwData.getMovingSource( 0 ).getSpimSource(); return getResolution( spimSource, resolutionOption, resolutionSpec ); } else if( resolutionOption.equals( SPECIFIED )) @@ -450,26 +448,26 @@ public static List getPixelInterval( final double[] outputResolution) { if (fieldOfViewOption.equals(TARGET)) { - if (bwData.targetSourceIndexList.size() <= 0) { + if (bwData.numTargetSources() <= 0) { System.err.println("Requested target fov but target image is missing."); return null; } return Stream.of( getPixelInterval( - bwData.sources.get(bwData.targetSourceIndexList.get( 0 )).getSpimSource(), + bwData.getTargetSource( 0 ).getSpimSource(), landmarks, transform, fieldOfViewOption, bboxEst, outputResolution)) .collect(Collectors.toList()); } else if (fieldOfViewOption.equals(MOVING_WARPED)) { return Stream.of( getPixelInterval( - bwData.sources.get(bwData.movingSourceIndexList.get( 0 )).getSpimSource(), + bwData.getMovingSource( 0 ).getSpimSource(), landmarks, transform, fieldOfViewOption, bboxEst, outputResolution)) .collect(Collectors.toList()); } else if (fieldOfViewOption.equals(UNION_TARGET_MOVING)) { return Stream.of( getPixelInterval( - bwData.sources.get(bwData.movingSourceIndexList.get( 0 )).getSpimSource(), + bwData.getMovingSource( 0 ).getSpimSource(), landmarks, transform, fieldOfViewOption, bboxEst, outputResolution)) .collect(Collectors.toList()); } else if (fieldOfViewOption.equals(SPECIFIED_PIXEL)) { @@ -822,17 +820,19 @@ public static List apply( // int numChannels = bwData.movingSourceIndexList.size(); int numChannels = bwData.numMovingSources(); - List movingSourceIndexList = bwData.movingSourceIndexList; List< SourceAndConverter< T >> sourcesxfm = BigWarp.wrapSourcesAsTransformed( - bwData.sources, + bwData.sourceInfos, landmarks.getNumdims(), bwData ); InvertibleRealTransform invXfm = new BigWarpTransform( landmarks, tranformTypeOption ).getTransformation(); for ( int i = 0; i < numChannels; i++ ) { - ((WarpedSource< ? >) (sourcesxfm.get( movingSourceIndexList.get( i )).getSpimSource())).updateTransform( invXfm ); - ((WarpedSource< ? >) (sourcesxfm.get( movingSourceIndexList.get( i )).getSpimSource())).setIsTransformed( true ); + final SourceAndConverter< T > originalMovingSource = bwData.getMovingSource( i ); + final int originalIdx = bwData.sources.indexOf( originalMovingSource ); + + ((WarpedSource< ? >) (sourcesxfm.get( originalIdx).getSpimSource())).updateTransform( invXfm ); + ((WarpedSource< ? >) (sourcesxfm.get( originalIdx).getSpimSource())).setIsTransformed( true ); } ProgressWriter progressWriter = new ProgressWriterIJ(); @@ -983,10 +983,11 @@ public static & NumericType> void runN5Export( pixelRenderToPhysical.concatenate( offsetTransform ); // render and write - final int N = data.movingSourceIndexList.size(); + final int N = data.numMovingSources(); for ( int i = 0; i < N; i++ ) { - final int movingSourceIndex = data.movingSourceIndexList.get( i ); + final SourceAndConverter< S > originalMovingSource = data.getMovingSource( i ); + final int movingSourceIndex = data.sources.indexOf( originalMovingSource ); @SuppressWarnings( "unchecked" ) final RealRandomAccessible< T > raiRaw = ( RealRandomAccessible< T > )sources.get( movingSourceIndex ).getSpimSource().getInterpolatedSource( 0, 0, interp ); @@ -995,7 +996,7 @@ public static & NumericType> void runN5Export( final IntervalView< T > img = Views.interval( Views.raster( rai ), Intervals.zeroMin( outputInterval ) ); - final String srcName = data.sources.get( data.movingSourceIndexList.get( i )).getSpimSource().getName(); + final String srcName = originalMovingSource.getSpimSource().getName(); String destDataset = dataset; if( N > 1 ) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 6f236ba0..55cab0d7 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -114,10 +114,22 @@ public static void main( final String[] args ) new BigWarpToDeformationFieldPlugIn().run( null ); } + + /** + * @deprecated not necessary access thedesired source this way anymore, use {@link #runFromBigWarpInstance(LandmarkTableModel, SourceAndConverter)} + * on the result of {@link bigwarp.BigWarpData#getTargetSource(int)} + */ + @Deprecated public void runFromBigWarpInstance( final LandmarkTableModel landmarkModel, final List> sources, final List targetSourceIndexList ) + { + runFromBigWarpInstance( landmarkModel, sources.get(targetSourceIndexList.get( 0 ))); + } + + public void runFromBigWarpInstance( + final LandmarkTableModel landmarkModel, final SourceAndConverter< T > sourceAndConverter ) { System.out.println( "run from instance." ); ImageJ ij = IJ.getInstance(); @@ -129,7 +141,7 @@ public void runFromBigWarpInstance( if( params == null ) return; - final RandomAccessibleInterval< ? > tgtInterval = sources.get( targetSourceIndexList.get( 0 ) ).getSpimSource().getSource( 0, 0 ); + final RandomAccessibleInterval< ? > tgtInterval = sourceAndConverter.getSpimSource().getSource( 0, 0 ); int ndims = landmarkModel.getNumdims(); // dimensions of the output image plus @@ -153,7 +165,7 @@ public void runFromBigWarpInstance( long[] dims = tgtInterval.dimensionsAsLongArray(); double[] spacing = new double[ 3 ]; - VoxelDimensions voxelDim = sources.get( targetSourceIndexList.get( 0 ) ).getSpimSource().getVoxelDimensions(); + VoxelDimensions voxelDim = sourceAndConverter.getSpimSource().getVoxelDimensions(); voxelDim.dimensions( spacing ); if( params.spacing != null ) diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index 26d5da56..b44da8fc 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -30,6 +30,7 @@ import bdv.viewer.animate.SimilarityTransformAnimator3D; import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import bigwarp.BigWarpData; +import bigwarp.source.SourceInfo; import bigwarp.util.Rotation2DHelpers; import java.awt.Graphics; import java.awt.Graphics2D; @@ -163,15 +164,19 @@ public int updateGrouping() final SynchronizedViewerState state = state(); synchronized ( state ) { - // TODO: work backwards to find out whether movingSourceIndexList - // and targetSourceIndexList are required, or whether a - // List> can be used directly final List< SourceAndConverter< ? > > moving = new ArrayList<>(); - for ( int i : bwData.movingSourceIndexList ) - moving.add( state.getSources().get( i ) ); final List< SourceAndConverter< ? > > target = new ArrayList<>(); - for ( int i : bwData.targetSourceIndexList ) - target.add( state.getSources().get( i ) ); + + int idx = 0; + for ( final SourceInfo sourceInfo : bwData.sourceInfos.values() ) + { + if (sourceInfo.isMoving()) { + moving.add( state.getSources().get( idx ) ); + } else { + target.add( state.getSources().get( idx ) ); + } + idx++; + } state.clearGroups(); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 7897d713..9761a92a 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -197,12 +197,7 @@ public class BigWarp< T > protected BigWarpData< T > data; - protected HashSet< SourceAndConverter< T >> movingSources; - protected final SetupAssignments setupAssignments; - - protected final BrightnessDialog brightnessDialog; - protected final WarpVisFrame warpVisDialog; protected final HelpDialog helpDialog; @@ -1268,7 +1263,7 @@ public void run() public void exportWarpField() { BigWarpToDeformationFieldPlugIn dfieldExporter = new BigWarpToDeformationFieldPlugIn(); - dfieldExporter.runFromBigWarpInstance( landmarkModel, data.sources, data.targetSourceIndexList ); + dfieldExporter.runFromBigWarpInstance( landmarkModel, data.getTargetSource( 0 ) ); } protected void setUpLandmarkMenus() diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 142e1245..adbcb479 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -41,13 +41,6 @@ public class BigWarpData< T > public final List< ConverterSetup > converterSetups; public final CacheControl cache; - - public final List< Integer > movingSourceIndexList; - - public final List< Integer > targetSourceIndexList; - - public final HashMap< SourceAndConverter, Boolean > isMovingMap; - public final HashMap< Integer, ColorSettings > setupSettings; public final HashMap< SourceAndConverter, ColorSettings > sourceColorSettings; @@ -91,10 +84,6 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, IntStream.range( 0, sources.size() ).forEach( i -> this.transforms.add( null )); } - this.movingSourceIndexList = new ArrayList<>(); - this.targetSourceIndexList = new ArrayList<>(); - isMovingMap = new HashMap<>(); - if ( cache == null ) this.cache = new CacheControl.Dummy(); else @@ -129,16 +118,6 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, final List< C sourceColorSettings = new HashMap<>(); } - private void updateIsMovingMap() - { - isMovingMap.clear(); - for( Integer i : movingSourceIndexList ) - isMovingMap.put( sources.get( i ), true ); - - for( Integer i : targetSourceIndexList ) - isMovingMap.put( sources.get( i ), false ); - } - private static ArrayList listOf( int[] x ) { final ArrayList< Integer > out = new ArrayList(); @@ -150,39 +129,87 @@ private static ArrayList listOf( int[] x ) public int numMovingSources() { - return movingSourceIndexList.size(); + final AtomicInteger movingCount = new AtomicInteger(); + sourceInfos.forEach( (id, info) -> { + if (info.isMoving()) movingCount.incrementAndGet(); + } ); + return movingCount.get(); } + @SuppressWarnings( "unchecked" ) public SourceAndConverter< T > getMovingSource( int i ) { - return sources.get( movingSourceIndexList.get( i ) ); + int curIdx = 0; + for ( final Map.Entry< Integer, SourceInfo > idToInfo : sourceInfos.entrySet() ) + { + final SourceInfo info = idToInfo.getValue(); + if (info.isMoving()) { + if (curIdx == i) return ( SourceAndConverter< T > ) info.getSourceAndConverter(); + curIdx++; + } + } + return null; } public int numTargetSources() { - return targetSourceIndexList.size(); + return sourceInfos.size() - numMovingSources(); + } + + public List< Integer > getMovingSourceIndices() { + final ArrayList indices = new ArrayList<>(); + int idx = 0; + for ( final SourceInfo sourceInfo : sourceInfos.values() ) + { + if ( sourceInfo.isMoving()){ + indices.add( idx ); + } + idx++; + } + return indices; } public SourceAndConverter< T > getTargetSource( int i ) { - return sources.get( targetSourceIndexList.get( i ) ); + int curIdx = 0; + for ( final Map.Entry< Integer, SourceInfo > idToInfo : sourceInfos.entrySet() ) + { + final SourceInfo info = idToInfo.getValue(); + if (!info.isMoving()) { + if (curIdx == i) return ( SourceAndConverter< T > ) info.getSourceAndConverter(); + curIdx++; + } + } + return null; } public List getMovingConverterSetups() { final ArrayList out = new ArrayList<>(); - for( int i : movingSourceIndexList ) - out.add( converterSetups.get( i ) ); + final SourceInfo[] infos = sourceInfos.values().toArray(new SourceInfo[]{} ); + for ( int i = 0; i < infos.length; i++ ) + { + final SourceInfo info = infos[ i ]; + if (info.isMoving()) { + out.add( converterSetups.get( i ) ); + } + } return out; } public List getTargetConverterSetups() { final ArrayList out = new ArrayList<>(); - for( int i : targetSourceIndexList ) - out.add( converterSetups.get( i ) ); + final SourceInfo[] infos = sourceInfos.values().toArray(new SourceInfo[]{} ); + for ( int i = 0; i < infos.length; i++ ) + { + final SourceInfo info = infos[ i ]; + if (!info.isMoving()) { + out.add( converterSetups.get( i ) ); + } + } return out; } @@ -203,17 +230,15 @@ public SourceInfo getSourceInfo( SourceAndConverter< ? > sac ) } public boolean isMoving( SourceAndConverter sac ) { - if( !isMovingMap.containsKey( sac )) - return false; - else - return isMovingMap.get( sac ); + return getSourceInfo( sac ).isMoving(); } + /** + * @Deprecated only handled maintaing the moving lists, now a no-op + */ + @Deprecated public void wrapUp() { - Collections.sort( movingSourceIndexList ); - Collections.sort( targetSourceIndexList ); - updateIsMovingMap(); } void addSource( Source src, boolean isMoving ) diff --git a/src/main/java/bigwarp/BigWarpExporter.java b/src/main/java/bigwarp/BigWarpExporter.java index aa0420a8..759b4032 100644 --- a/src/main/java/bigwarp/BigWarpExporter.java +++ b/src/main/java/bigwarp/BigWarpExporter.java @@ -905,8 +905,7 @@ public static BigWarpExporter getExporter( final Interpolation interp, final ProgressWriter progressWriter ) { - List movingSourceIndexList = bwData.movingSourceIndexList; -// List targetSourceIndexList = bwData.targetSourceIndexList; + List movingSourceIndexList = bwData.getMovingSourceIndices(); //TODO Caleb: Consider a method that just takes a list of all moving sources if ( BigWarpRealExporter.isTypeListFullyConsistent( transformedSources, movingSourceIndexList ) ) From 2a43d8c95bf483e364e56331afd1956ed743cd6b Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:43:18 -0500 Subject: [PATCH 119/282] feat: ensure groups align after deserialization --- src/main/java/bigwarp/BigwarpSettings.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 9d5f1709..d5c77726 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -418,23 +418,27 @@ private void writeGroups( final JsonWriter out, final ViewerPanel value ) throws private void readGroups( final JsonReader in ) throws IOException { in.beginArray(); + final SynchronizedViewerState state = panel.state(); + state.setGroupsActive( state.getActiveGroups(), false ); + state.removeGroups( state.getGroups() ); int i = 0; while ( in.hasNext() ) { in.beginObject(); - final SynchronizedViewerState state = panel.state(); - final bdv.viewer.SourceGroup group = state.getGroups().get( i++ ); - + final bdv.viewer.SourceGroup group = new bdv.viewer.SourceGroup(); + state.addGroup( group ); while ( in.hasNext() ) { switch ( in.nextName() ) { case XmlIoViewerState.VIEWERSTATE_GROUP_ACTIVE_TAG: - state.setGroupActive( group, in.nextBoolean() ); + final boolean active = in.nextBoolean(); + state.setGroupActive( group, active ); break; case XmlIoViewerState.VIEWERSTATE_GROUP_NAME_TAG: - state.setGroupName( group, in.nextString() ); + final String name = in.nextString(); + state.setGroupName( group, name ); break; case XmlIoViewerState.VIEWERSTATE_GROUP_SOURCEID_TAG: state.removeSourcesFromGroup( new ArrayList<>( state.getSourcesInGroup( group ) ), group ); From c13957d08eb6730dcf4e2d7cfd79788986dbe9f2 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:43:31 -0500 Subject: [PATCH 120/282] fix: check if mask is null before serialize --- src/main/java/bigwarp/BigWarp.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 9761a92a..29959845 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3527,7 +3527,10 @@ protected void saveSettings( final String xmlFilename ) throws IOException autoSaveNode.addContent( autoSavePeriod ); root.addContent( autoSaveNode ); - root.addContent( transformMask.getRandomAccessible().toXml() ); + if ( transformMask != null ) + { + root.addContent( transformMask.getRandomAccessible().toXml() ); + } final Document doc = new Document( root ); final XMLOutputter xout = new XMLOutputter( Format.getPrettyFormat() ); From 53c1f3c094a58571259405a56b7de395e4c0e79d Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:43:37 -0500 Subject: [PATCH 121/282] fix: don't enforce 2 initial sources --- src/main/java/bigwarp/BigWarp.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 29959845..6821c013 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2539,11 +2539,6 @@ public static void main( final String[] args ) fnP = args[ i++ ]; fnQ = args[ i++ ]; } - else - { - System.err.println( "Must provide at least 2 inputs for moving and target image files" ); - System.exit( 1 ); - } if ( args.length > i ) fnLandmarks = args[ i++ ]; @@ -2588,7 +2583,7 @@ else if ( !fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) bwdata = BigWarpInit.createBigWarpDataFromImagePlusXML( impP, fnQ ); bw = new BigWarp<>( bwdata, new File( fnP ).getName(), progress ); } - else + else if (!fnP.isEmpty() && !fnQ.isEmpty()) { final ImagePlus impP = IJ.openImage( fnP ); final ImagePlus impQ = IJ.openImage( fnQ ); @@ -2596,7 +2591,7 @@ else if ( !fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) if ( !( impP == null || impQ == null ) ) { bwdata = BigWarpInit.createBigWarpDataFromImages( impP, impQ ); - bw = new BigWarp<>( bwdata, new File( fnP ).getName(), progress ); + bw = new BigWarp<>( bwdata, progress ); } else { @@ -2604,8 +2599,11 @@ else if ( !fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) return; } } + else + { + bw = new BigWarp<>( new BigWarpData<>(), progress ); + } - if ( !fnLandmarks.isEmpty() ) bw.loadLandmarks( fnLandmarks ); From d86cd40b51d8ea9ddf56219b7539de0cd2cb911c Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:43:41 -0500 Subject: [PATCH 122/282] fix: grab backing field, instead of copy --- src/main/java/bigwarp/BigwarpSettings.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index d5c77726..80ea210b 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -305,7 +305,18 @@ public static class BigWarpViewerPanelAdapter extends TypeAdapter< BigWarpViewer public BigWarpViewerPanelAdapter( final BigWarpViewerPanel viewerP ) { this.panel = viewerP; - this.state = panel.getState(); + + final Field deprecatedState; + try + { + deprecatedState = ViewerPanel.class.getDeclaredField( "deprecatedState" ); + deprecatedState.setAccessible( true ); + this.state = ( ViewerState ) deprecatedState.get( panel ); + } + catch ( NoSuchFieldException | IllegalAccessException e ) + { + throw new RuntimeException( e ); + } } @Override From fc92fd2f5590fa34f7be83c427790b8325643db7 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:43:44 -0500 Subject: [PATCH 123/282] fix: store id value, don't reference --- src/main/java/bigwarp/BigwarpSettings.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 80ea210b..578d0781 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -729,11 +729,18 @@ public static class ConverterSetupAdapter extends TypeAdapter< ConverterSetup > { private final SetupAssignments setupAssignments; + private int setupId = -1; + public ConverterSetupAdapter( final SetupAssignments setupAssignments ) { this.setupAssignments = setupAssignments; } + public void setSetupId( final int setupId ) + { + this.setupId = setupId; + } + @Override public void write( final JsonWriter out, final ConverterSetup value ) throws IOException { @@ -778,6 +785,8 @@ public ConverterSetup read( final JsonReader in ) throws IOException final ConverterSetup converterSetupDTO = new ConverterSetupDTO() { + private final int id = setupId; + @Override public int getGroupId() { From 5790c7065856da6c8484a021bb51a8a0951756e9 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:43:56 -0500 Subject: [PATCH 124/282] reactor(test): move to BigWarpTestUtils --- src/test/java/bigwarp/SerializationTest.java | 22 ---------------- src/test/java/bigwarp/url/UrlParseTest.java | 27 +++----------------- 2 files changed, 3 insertions(+), 46 deletions(-) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index b3a7ed8c..7a796319 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -361,28 +361,6 @@ private static String prettyPrint( String json ) final JsonElement parse = JsonParser.parseString( json ); final JsonObject asJsonObject = parse.getAsJsonObject(); - return prettyPrint( asJsonObject ); } - private static String prettyPrint (JsonObject json) { - - return new GsonBuilder().setPrettyPrinting().create().toJson( json ); - } - - private static BigWarp< ? > createBigWarp( boolean[] moving ) throws SpimDataException - { - final BigWarpData< Object > data = BigWarpInit.initData(); - FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( - 3, - ( l, v ) -> v.setOne(), - UnsignedByteType::new ); - ImagePlus imp = ImageJFunctions.wrap( Views.interval( fimg, new FinalInterval( 32, 32, 1 ) ), "img" ); - for ( int i = 0; i < moving.length; i++ ) - { - BigWarpInit.add( data, imp, i, 0, moving[ i ] ); - } - data.wrapUp(); - BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); - return new BigWarp<>( data, "bigwarp", opts, null ); - } } diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index 70784820..206e6635 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -26,7 +26,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.scijava.util.FileUtils; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -35,12 +34,11 @@ public class UrlParseTest { + public static final String TIFF_FILE_3D = BigWarpTestUtils.createTemp3DImage( "img3d", "tif" ); - private static final String TIFF_FILE_3D = "src/test/resources/bigwarp/url/img.tif"; + public static final String PNG_FILE_2D = BigWarpTestUtils.createTemp2DImage( "img2d", "png" ); - public static final String PNG_FILE_2D = "src/test/resources/bigwarp/url/img2d.png"; - - public static final String TIFF_STACK_DIR = "src/test/resources/bigwarp/url/imgDir3d/"; + public static final String TIFF_STACK_DIR = BigWarpTestUtils.createTemp3DImageStack( "imgDir3d" ); private Class< N5FSReader > n5Clazz; @@ -55,9 +53,6 @@ public class UrlParseTest @Before public void before() throws IOException { - /* Cleanup, to ensure no old test files persist */ - cleanup(); - n5Clazz = N5FSReader.class; zarrClazz = N5ZarrReader.class; h5Clazz = N5HDF5Reader.class; @@ -78,22 +73,6 @@ public void before() throws IOException final String zarrRoot = new File( "src/test/resources/bigwarp/url/transformTest.zarr" ).getAbsolutePath(); urlToDimensions.put( zarrRoot + "?img", new long[] { 4, 6, 8 } ); urlToDimensions.put( zarrRoot + "?img2", new long[] { 8, 12, 16 } ); - - ImagePlus img3d = NewImage.createByteImage( "img3d", 8, 8, 4, NewImage.FILL_RAMP ); - IJ.save( img3d, TIFF_FILE_3D ); - - ImagePlus img2d = NewImage.createByteImage( "img2d", 8, 8, 1, NewImage.FILL_RAMP ); - IJ.save( img2d, PNG_FILE_2D ); - Files.createDirectory( Paths.get( TIFF_STACK_DIR ) ); - StackWriter.save( img3d , TIFF_STACK_DIR, "format=tif"); - } - - @After - public void cleanup() throws IOException - { - Files.deleteIfExists(Paths.get( TIFF_FILE_3D )); - Files.deleteIfExists(Paths.get( PNG_FILE_2D )); - FileUtils.deleteRecursively( new File(TIFF_STACK_DIR)); } @Test From b9837f81dccb7a511ee0fae5cd80e4c0b95e5e83 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:44:05 -0500 Subject: [PATCH 125/282] feat(test): update tests for source serialization and sourceInfo/moving changes --- src/main/java/bigwarp/SourceInfoDialog.java | 8 +- src/test/java/bigwarp/SerializationTest.java | 121 ++++++++---------- src/test/java/bigwarp/SourceTest.java | 2 +- src/test/java/bigwarp/Sources2Dtests.java | 12 +- .../java/bigwarp/TransformPoints2DTest.java | 2 +- src/test/java/bigwarp/TransformTests.java | 4 +- src/test/java/bigwarp/url/UrlParseTest.java | 53 +++----- 7 files changed, 87 insertions(+), 115 deletions(-) diff --git a/src/main/java/bigwarp/SourceInfoDialog.java b/src/main/java/bigwarp/SourceInfoDialog.java index 4bdd0357..c351482c 100644 --- a/src/main/java/bigwarp/SourceInfoDialog.java +++ b/src/main/java/bigwarp/SourceInfoDialog.java @@ -57,9 +57,9 @@ public SourceInfoDialog( final Frame owner, final BigWarpData< ? > bwData ) final StringBuffer infoString = new StringBuffer(); infoString.append( "MOVING:\n" ); - for ( int i = 0; i < bwData.movingSourceIndexList.size(); i++ ) + for ( int i = 0; i < bwData.numMovingSources(); i++ ) { - SourceAndConverter< ? > src = bwData.sources.get( bwData.movingSourceIndexList.get( i )); + SourceAndConverter< ? > src = bwData.getMovingSource( i); final String name = src.getSpimSource().getName(); if( name.equals( "WarpMagnitudeSource" ) || name.equals( "JacobianDeterminantSource" ) || @@ -72,9 +72,9 @@ public SourceInfoDialog( final Frame owner, final BigWarpData< ? > bwData ) } infoString.append( "\nTARGET:\n" ); - for ( int i = 0; i < bwData.targetSourceIndexList.size(); i++ ) + for ( int i = 0; i < bwData.numTargetSources(); i++ ) { - SourceAndConverter< ? > src = bwData.sources.get( bwData.targetSourceIndexList.get( i )); + SourceAndConverter< ? > src = bwData.getTargetSource( i ); final String name = src.getSpimSource().getName(); if( name.equals( "WarpMagnitudeSource" ) || name.equals( "JacobianDeterminantSource" ) || diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 7a796319..857652bc 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -1,6 +1,5 @@ package bigwarp; -import bdv.gui.BigWarpViewerOptions; import bdv.tools.bookmarks.Bookmarks; import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.MinMaxGroup; @@ -9,30 +8,24 @@ import bdv.viewer.state.XmlIoViewerState; import bigwarp.source.PlateauSphericalMaskSource; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.stream.JsonWriter; -import ij.ImagePlus; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PipedReader; import java.io.PipedWriter; -import java.io.StringWriter; +import java.net.URISyntaxException; import java.nio.file.Files; import java.util.List; import mpicbg.spim.data.SpimDataException; import net.imglib2.FinalInterval; import net.imglib2.RealPoint; -import net.imglib2.img.display.imagej.ImageJFunctions; -import net.imglib2.position.FunctionRandomAccessible; import net.imglib2.realtransform.AffineTransform3D; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.view.Views; import org.custommonkey.xmlunit.XMLAssert; import org.custommonkey.xmlunit.XMLUnit; import org.jdom2.JDOMException; @@ -71,7 +64,7 @@ public void maskTest() center.add( 0.0 ); expected.add( "center", center ); - Assert.assertEquals( expected, actual ); + BigWarpTestUtils.assertJsonDiff( expected, actual ); } @Test @@ -109,11 +102,11 @@ public void bookmarksTest() { translateArray.add( val ); } - bookmarksObj.add("identity", identityArray); - bookmarksObj.add("scale", scaleArray); - bookmarksObj.add("translate", translateArray); + bookmarksObj.add( "identity", identityArray ); + bookmarksObj.add( "scale", scaleArray ); + bookmarksObj.add( "translate", translateArray ); - Assert.assertEquals( expected, actual ); + BigWarpTestUtils.assertJsonDiff( expected, actual ); } @Test @@ -128,13 +121,13 @@ public void autoSaverTest() expected.addProperty( "location", "/tmp" ); saver.stop(); - Assert.assertEquals( expected, actual ); + BigWarpTestUtils.assertJsonDiff( expected, actual ); } @Test - public void setupAssignmentsTest() throws SpimDataException, IOException + public void setupAssignmentsTest() throws SpimDataException, IOException, URISyntaxException { - bw = createBigWarp( new boolean[] { true, false, false, false } ); + bw = BigWarpTestUtils.createBigWarp( true, false, false, false ); final PipedWriter writer = new PipedWriter(); final PipedReader in = new PipedReader( writer, 10000 ); @@ -147,42 +140,41 @@ public void setupAssignmentsTest() throws SpimDataException, IOException final JsonElement actual = JsonParser.parseReader( in ); final JsonObject expected = new JsonObject(); - final JsonArray setups = new JsonArray(); + final JsonObject setups = new JsonObject(); expected.add( "ConverterSetups", setups ); final List< MinMaxGroup > minMaxGroups = bw.setupAssignments.getMinMaxGroups(); for ( final ConverterSetup setup : bw.setupAssignments.getConverterSetups() ) { final JsonObject setupObj = new JsonObject(); - setupObj.addProperty( "id" , setup.getSetupId() ); - setupObj.addProperty( "min" , setup.getDisplayRangeMin() ); - setupObj.addProperty( "max" , setup.getDisplayRangeMax() ); - setupObj.addProperty( "color" , setup.getColor().get() ); - setupObj.addProperty( "groupId" , minMaxGroups.indexOf( bw.setupAssignments.getMinMaxGroup( setup ) ) ); - setups.add( setupObj ); + setupObj.addProperty( "min", setup.getDisplayRangeMin() ); + setupObj.addProperty( "max", setup.getDisplayRangeMax() ); + setupObj.addProperty( "color", setup.getColor().get() ); + setupObj.addProperty( "groupId", minMaxGroups.indexOf( bw.setupAssignments.getMinMaxGroup( setup ) ) ); + setups.add( String.valueOf( setup.getSetupId() ), setupObj ); } - final JsonArray groups = new JsonArray(); + final JsonObject groups = new JsonObject(); expected.add( "MinMaxGroups", groups ); for ( int i = 0; i < minMaxGroups.size(); i++ ) { final MinMaxGroup minMaxGroup = minMaxGroups.get( i ); final JsonObject groupObj = new JsonObject(); - groupObj.addProperty( "id" , i ); - groupObj.addProperty( "fullRangeMin" , minMaxGroup.getFullRangeMin() ); - groupObj.addProperty( "fullRangeMax" , minMaxGroup.getFullRangeMax() ); - groupObj.addProperty( "rangeMin" , minMaxGroup.getRangeMin() ); - groupObj.addProperty( "rangeMax" , minMaxGroup.getRangeMax() ); - groupObj.addProperty( "currentMin" , minMaxGroup.getMinBoundedValue().getCurrentValue() ); - groupObj.addProperty( "currentMax" , minMaxGroup.getMaxBoundedValue().getCurrentValue() ); - groups.add( groupObj ); + groupObj.addProperty( "fullRangeMin", minMaxGroup.getFullRangeMin() ); + groupObj.addProperty( "fullRangeMax", minMaxGroup.getFullRangeMax() ); + groupObj.addProperty( "rangeMin", minMaxGroup.getRangeMin() ); + groupObj.addProperty( "rangeMax", minMaxGroup.getRangeMax() ); + groupObj.addProperty( "currentMin", minMaxGroup.getMinBoundedValue().getCurrentValue() ); + groupObj.addProperty( "currentMax", minMaxGroup.getMaxBoundedValue().getCurrentValue() ); + groups.add( String.valueOf( i ), groupObj ); } - Assert.assertEquals( expected , actual); + + BigWarpTestUtils.assertJsonDiff( expected, actual ); } @Test - public void viewerPanelTest() throws SpimDataException, IOException + public void viewerPanelTest() throws SpimDataException, IOException, URISyntaxException { - bw = createBigWarp( new boolean[] { true, false, false, false } ); + bw = BigWarpTestUtils.createBigWarp( true, false, false, false ); final PipedWriter writer = new PipedWriter(); final PipedReader in = new PipedReader( writer, 10000 ); @@ -199,7 +191,7 @@ public void viewerPanelTest() throws SpimDataException, IOException final JsonArray sources = new JsonArray(); expected.add( XmlIoViewerState.VIEWERSTATE_SOURCES_TAG, sources ); /* All sources are active */ - bw.viewerP.getState().getSources().forEach( source -> sources.add(source.isActive()) ); + bw.viewerP.getState().getSources().forEach( source -> sources.add( source.isActive() ) ); final JsonArray groups = new JsonArray(); expected.add( XmlIoViewerState.VIEWERSTATE_GROUPS_TAG, groups ); @@ -219,27 +211,32 @@ public void viewerPanelTest() throws SpimDataException, IOException } groups.add( sourceGroupObj ); } - expected.addProperty( XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_TAG, XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_GROUP); + expected.addProperty( XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_TAG, XmlIoViewerState.VIEWERSTATE_DISPLAYMODE_VALUE_GROUP ); expected.addProperty( XmlIoViewerState.VIEWERSTATE_INTERPOLATION_TAG, XmlIoViewerState.VIEWERSTATE_INTERPOLATION_VALUE_NEARESTNEIGHBOR ); expected.addProperty( XmlIoViewerState.VIEWERSTATE_CURRENTSOURCE_TAG, value.getState().getCurrentSource() ); expected.addProperty( XmlIoViewerState.VIEWERSTATE_CURRENTGROUP_TAG, value.getState().getCurrentGroup() ); expected.addProperty( XmlIoViewerState.VIEWERSTATE_CURRENTTIMEPOINT_TAG, value.getState().getCurrentTimepoint() ); - Assert.assertEquals( prettyPrint(expected), prettyPrint( actual.getAsJsonObject()) ); + BigWarpTestUtils.assertJsonDiff( expected, actual ); } @Test - public void sourceSerializationTest() throws SpimDataException + public void sourceSerializationTest() throws SpimDataException, URISyntaxException, IOException, JDOMException { - //TODO Caleb: Currently, Bigwarp cannot be loaded without soruces existing. - // When this is possible, this test should be written to create bigwarp with no initial sources, - // and then import some sources from a settings file, and compare the added sources to the expected. - - // bw = createBigWarp( new boolean[0] ); - // bw.loadSettings("src/test/resources/settings/settingsWithSource.json"); + final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( "/tmp/img8270806677315563879.tif" ); + bw.loadSettings("src/test/resources/settings/expected.json"); // Grab the sources // Compare the ids, urls, isMoving status, and isActive - assert(false); + Assert.assertEquals("Wrong Number of Sources", 4, bw.data.sources.size()); + Assert.assertEquals("Wrong Number of Moving Sources", 2, bw.data.numMovingSources()); + Assert.assertEquals("Wrong Number of Target Sources", 2, bw.data.numTargetSources()); + final boolean[] movingById = { true, true, false, false }; + bw.data.sourceInfos.forEach( (id, info) -> { + + Assert.assertEquals("URI Mismatch", "/tmp/img8270806677315563879.tif", info.getUri()); + Assert.assertEquals("Name Mismatch", "img8270806677315563879.tif channel " + (id + 1), info.getName()); + Assert.assertEquals("Moving/Target Mismatch", movingById[id], info.isMoving()); + } ); } /* When creating and closing multiple BigWarp instances, occassionally the comparison test fails. @@ -251,7 +248,7 @@ private void repeatComparison() throws Exception for ( int i = 0; i < 20; i++ ) { System.out.println( i ); - bw = createBigWarp( new boolean[] { true, false, false, false } ); + bw = BigWarpTestUtils.createBigWarp( true, false, false, false ); /* Load the known good*/ final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; @@ -272,9 +269,9 @@ private void repeatComparison() throws Exception } @Test - public void compareKnownXmlComparisonTest() throws SpimDataException, IOException, JDOMException, SAXException + public void compareKnownXmlComparisonTest() throws SpimDataException, IOException, JDOMException, SAXException, URISyntaxException { - BigWarp< ? > bw = createBigWarp( new boolean[] { true, false, false, false } ); + BigWarp< ? > bw = BigWarpTestUtils.createBigWarp( true, false, false, false ); final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; bw.loadSettings( originalXmlSettings ); @@ -290,7 +287,7 @@ public void compareKnownXmlComparisonTest() throws SpimDataException, IOExceptio // bw.closeAll(); // bw = createBigWarp(new boolean[]{true, false, false, false}); - bw.loadSettings( tmpJsonFile.getAbsolutePath() ); + bw.loadSettings( tmpJsonFile.getAbsolutePath(), true ); final File tmpXmlFile = Files.createTempFile( "xml-settings", ".xml" ).toFile(); bw.saveSettings( tmpXmlFile.getAbsolutePath() ); XMLUnit.setIgnoreWhitespace( true ); @@ -300,9 +297,9 @@ public void compareKnownXmlComparisonTest() throws SpimDataException, IOExceptio } @Test - public void jsonLoadSaveComparisonTest() throws SpimDataException, IOException, JDOMException + public void jsonLoadSaveComparisonTest() throws SpimDataException, IOException, JDOMException, URISyntaxException { - bw = createBigWarp( new boolean[] { true, false } ); + bw = BigWarpTestUtils.createBigWarp( "/tmp/img8270806677315563879.tif", true, true, false, false ); final String expectedJsonFile = "src/test/resources/settings/expected_with_dfield.json"; bw.loadSettings( expectedJsonFile ); @@ -320,13 +317,13 @@ public void jsonLoadSaveComparisonTest() throws SpimDataException, IOException, final JsonElement jsonSettingsOut = JsonParser.parseReader( in ); final JsonElement expectedJson = JsonParser.parseReader( new FileReader( expectedJsonFile ) ); - Assert.assertEquals( expectedJson, jsonSettingsOut ); + BigWarpTestUtils.assertJsonDiff( expectedJson, jsonSettingsOut ); } @Test - public void landmarkComparisonTest() throws SpimDataException, IOException, JDOMException + public void landmarkComparisonTest() throws SpimDataException, IOException, JDOMException, URISyntaxException { - bw = createBigWarp( new boolean[] { true, false, false, false } ); + bw = BigWarpTestUtils.createBigWarp( "/tmp/img8270806677315563879.tif", true, true, false, false ); final String xmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; final String csvLandmarks = "src/test/resources/settings/landmarks.csv"; @@ -347,19 +344,7 @@ public void landmarkComparisonTest() throws SpimDataException, IOException, JDOM final JsonElement jsonSettingsOut = JsonParser.parseReader( in ); final JsonElement expectedJson = JsonParser.parseReader( new FileReader( expectedJsonFile ) ); - Assert.assertEquals( expectedJson, jsonSettingsOut ); - - } - - private static String prettyPrint( StringWriter json ) - { - return prettyPrint( json.toString() ); - } - - private static String prettyPrint( String json ) - { - final JsonElement parse = JsonParser.parseString( json ); - final JsonObject asJsonObject = parse.getAsJsonObject(); + BigWarpTestUtils.assertJsonDiff( expectedJson, jsonSettingsOut ); } diff --git a/src/test/java/bigwarp/SourceTest.java b/src/test/java/bigwarp/SourceTest.java index 698ed63d..bd5add62 100644 --- a/src/test/java/bigwarp/SourceTest.java +++ b/src/test/java/bigwarp/SourceTest.java @@ -61,7 +61,7 @@ public static void main( String[] args ) throws IOException, SpimDataException BigWarpData< ? > datasrc = BigWarpInit.createBigWarpData( new Source[] { tsrc }, new Source[] { tsrc }, new String[] { "mvg", "tgt" } ); - BigWarp< ? > bw = new BigWarp<>( datasrc, "bw", BigWarpViewerOptions.options(), new ProgressWriterConsole() ); + BigWarp< ? > bw = new BigWarp<>( datasrc, BigWarpViewerOptions.options(), new ProgressWriterConsole() ); bw.getLandmarkPanel().getTableModel().load( new File( "src/test/resources/mr_landmarks_p2p2p4-111.csv" )); } } diff --git a/src/test/java/bigwarp/Sources2Dtests.java b/src/test/java/bigwarp/Sources2Dtests.java index 16bceb14..d1d417d5 100644 --- a/src/test/java/bigwarp/Sources2Dtests.java +++ b/src/test/java/bigwarp/Sources2Dtests.java @@ -23,7 +23,7 @@ import bdv.util.RandomAccessibleIntervalSource; import bdv.viewer.Source; -import bigwarp.BigWarpData; +import bigwarp.source.SourceInfo; import ij.IJ; import ij.ImagePlus; import mpicbg.spim.data.SpimDataException; @@ -53,10 +53,18 @@ public static & RealType> void run() throws SpimData BigWarpData bwdata = BigWarpInit.initData(); BigWarpInit.add(bwdata, mvg, 0, 0, true); + final SourceInfo mvgInfo = new SourceInfo( 0, true, "mvg", () -> "https://imagej.nih.gov/ij/images/boats.gif" ); + mvgInfo.setSourceAndConverter( bwdata.sources.get( bwdata.sources.size() - 1 ) ); + bwdata.sourceInfos.put( 0, mvgInfo ); + BigWarpInit.add(bwdata, tgt, 1, 0, false); + final SourceInfo tgtInfo = new SourceInfo( 1, true, "tgt", () -> "https://imagej.nih.gov/ij/images/boats.gif" ); + bwdata.sourceInfos.put( 1, tgtInfo ); + tgtInfo.setSourceAndConverter( bwdata.sources.get( bwdata.sources.size() - 1 ) ); + bwdata.wrapUp(); - BigWarp bw = new BigWarp(bwdata, "bw test", null); + BigWarp bw = new BigWarp(bwdata, null); } public static & RealType> Source loadSource( String path, double zOffset ) diff --git a/src/test/java/bigwarp/TransformPoints2DTest.java b/src/test/java/bigwarp/TransformPoints2DTest.java index 6e8ade7c..209b784a 100644 --- a/src/test/java/bigwarp/TransformPoints2DTest.java +++ b/src/test/java/bigwarp/TransformPoints2DTest.java @@ -35,7 +35,7 @@ public static void main(String... args) throws Exception { BigWarpData bwData = BigWarpInit.createBigWarpDataFromImages( impBlobs, impBlobs ); - BigWarp bigWarp = new BigWarp(bwData, "2D points transform", null); + BigWarp bigWarp = new BigWarp(bwData, null); // bigWarp.getLandmarkPanel().getTableModel().load( new File( "src/test/resources/landmarks2d-blobs.csv" )); bigWarp.loadLandmarks( "src/test/resources/landmarks2d-blobs.csv" ); diff --git a/src/test/java/bigwarp/TransformTests.java b/src/test/java/bigwarp/TransformTests.java index 3c6a6a01..e73ead1f 100644 --- a/src/test/java/bigwarp/TransformTests.java +++ b/src/test/java/bigwarp/TransformTests.java @@ -62,7 +62,7 @@ public static void test2d( boolean testTps ) throws SpimDataException BigWarpData data = BigWarpInit.createBigWarpDataFromImages( imp, imp ); @SuppressWarnings({ "unchecked", "rawtypes" }) - BigWarp bw = new BigWarp( data, "bigwarp", opts, null ); + BigWarp bw = new BigWarp( data, opts, null ); LandmarkTableModel ltm = bw.getLandmarkPanel().getTableModel(); @@ -104,7 +104,7 @@ public static void test3d( boolean testTps ) throws SpimDataException BigWarpData data = BigWarpInit.createBigWarpDataFromImages( imp, imp ); @SuppressWarnings({ "unchecked", "rawtypes" }) - BigWarp bw = new BigWarp( data, "bigwarp", opts, null ); + BigWarp bw = new BigWarp( data, opts, null ); LandmarkTableModel ltm = bw.getLandmarkPanel().getTableModel(); diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index 206e6635..4677c9fd 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -1,21 +1,16 @@ package bigwarp.url; -import bdv.tools.transformation.TransformedSource; import bdv.viewer.Source; -import bdv.viewer.SourceAndConverter; -import bigwarp.BigWarp; import bigwarp.BigWarpData; import bigwarp.BigWarpInit; -import ij.IJ; -import ij.ImagePlus; -import ij.gui.NewImage; -import ij.plugin.StackWriter; +import bigwarp.BigWarpTestUtils; +import bigwarp.source.SourceInfo; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; -import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import mpicbg.spim.data.SpimDataException; @@ -23,7 +18,6 @@ import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader; import org.janelia.saalfeldlab.n5.ij.N5Factory; import org.janelia.saalfeldlab.n5.zarr.N5ZarrReader; -import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -92,7 +86,7 @@ public void testFactories() } @Test - public void testUrlSources() + public void testUrlSources() throws SpimDataException, URISyntaxException, IOException { final String bdvXmlUrl = new File( "src/test/resources/mri-stack.xml" ).getAbsolutePath(); @@ -137,7 +131,7 @@ public void testUrlTransforms() } @Test - public void n5FileEquivalencyTest() throws IOException + public void n5FileUrlEquivalencyTest() throws IOException, SpimDataException, URISyntaxException { final String relativePath = "src/test/resources/bigwarp/url/transformTest.n5"; final String absolutePath = Paths.get( relativePath ).toAbsolutePath().toFile().getCanonicalPath(); @@ -165,20 +159,12 @@ public void n5FileEquivalencyTest() throws IOException }; final BigWarpData< Object > data = BigWarpInit.initData(); - try - { - - final AtomicInteger id = new AtomicInteger( 1 ); - for ( String uri : variants) - { - final int setupId = id.getAndIncrement(); - BigWarpInit.add( data, uri, setupId, new Random().nextBoolean() ); - assertEquals( uri, data.urls.get(setupId ).getA().get()); - } - } - catch ( URISyntaxException | IOException | SpimDataException e ) + final AtomicInteger id = new AtomicInteger( 1 ); + for ( String uri : variants ) { - throw new RuntimeException( e ); + final int setupId = id.getAndIncrement(); + BigWarpInit.add( data, BigWarpInit.createSources( data, uri, setupId, new Random().nextBoolean() ) ); + assertEquals( uri, data.sourceInfos.get( setupId ).getUri() ); } } @@ -188,22 +174,15 @@ private Object loadTransformFromUrl( String url ) return null; } - private Source< ? > loadSourceFromUri( String uri ) + private < T > Source< ? > loadSourceFromUri( String uri ) throws SpimDataException, URISyntaxException, IOException { + final BigWarpData< T > data = BigWarpInit.initData(); + final LinkedHashMap< Source< T >, SourceInfo > sources = BigWarpInit.createSources( data, uri, 0, true ); + BigWarpInit.add( data, sources ); + data.wrapUp(); + return (Source) sources.keySet().toArray()[ 0 ]; - final BigWarpData< Object > data = BigWarpInit.initData(); - try - { - final Source< ? > source = BigWarpInit.add( data, uri, 0, true ); - data.wrapUp(); - return source; - } - catch ( URISyntaxException | IOException | SpimDataException e ) - { - throw new RuntimeException( e ); - } } - } From 7633ecb9ce14e0d19d1c794b812e78edacea0618 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Wed, 16 Nov 2022 11:44:08 -0500 Subject: [PATCH 126/282] fix(test): new expected settings files --- .../compareKnownXml.bigwarp.settings.xml | 400 +++++++----------- src/test/resources/settings/expected.json | 178 +++----- .../settings/expected_with_dfield.json | 220 ++++------ 3 files changed, 297 insertions(+), 501 deletions(-) diff --git a/src/test/resources/settings/compareKnownXml.bigwarp.settings.xml b/src/test/resources/settings/compareKnownXml.bigwarp.settings.xml index be8c3996..04e3dceb 100644 --- a/src/test/resources/settings/compareKnownXml.bigwarp.settings.xml +++ b/src/test/resources/settings/compareKnownXml.bigwarp.settings.xml @@ -1,248 +1,156 @@ - - - - - true - - - false - - - true - - - false - - - false - - - false - - - false - - - false - - - - - true - moving images - 0 - 1 - - - true - fixed images - 2 - 3 - - - ss - nlinear - 0 - 0 - 0 - - - - - - - true - - - false - - - true - - - false - - - false - - - false - - - false - - - false - - - - - true - moving images - 0 - 1 - - - true - fixed images - 2 - 3 - - - fs - nearestneighbor - 2 - 1 - 0 - - - - - - 0 - 0.0 - 860.4 - -10027213 - 0 - - - 1 - 0.0 - 255.0 - 0 - 1 - - - 2 - 0.0 - 2000.0 - -39169 - 2 - - - 3 - 0.0 - 433.408 - -1 - 3 - - - 956736363 - 0.0 - 65535.0 - -1 - 4 - - - 1006827158 - 0.0 - 65535.0 - -1 - 5 - - - 1696993146 - 0.0 - 65535.0 - -1 - 6 - - - 33872301 - 0.0 - 65535.0 - -1 - 7 - - - - - 0 - -2.147483648E9 - 2.147483647E9 - 0.0 - 4000.0 - 0.0 - 860.4 - - - 1 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 255.0 - - - 2 - -2.147483648E9 - 2.147483647E9 - 0.0 - 2000.0 - 0.0 - 2000.0 - - - 3 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 255.0 - - - 4 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 5 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 6 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - 7 - -2.147483648E9 - 2.147483647E9 - 0.0 - 65535.0 - 0.0 - 512.0 - - - - - - /tmp/.bigwarp - 180000 - - - plateau-spherical -
0.0 0.0 0.0
- - 64.0 - 100.0 - -
-
+ + + + + false + + + false + + + false + + + false + + + + + true + moving images + + + true + fixed images + + + false + moving images + 0 + 1 + + + false + target images + 2 + 3 + + + sg + nearestneighbor + 0 + 3 + 0 + + + + + + + false + + + false + + + false + + + false + + + + + true + moving images + + + true + fixed images + + + sg + nearestneighbor + 0 + 1 + 0 + + + + + + 0 + 0.0 + 255.0 + -1 + 0 + + + 1 + 0.0 + 65535.0 + -1 + 1 + + + 2 + 0.0 + 255.0 + -1 + 2 + + + 3 + 10.0 + 571.0 + -1 + 3 + + + + + 0 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + 1 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 65535.0 + + + 2 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + 3 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 65535.0 + + + + + + /tmp/.bigwarp + 180000 + + \ No newline at end of file diff --git a/src/test/resources/settings/expected.json b/src/test/resources/settings/expected.json index 5c77a483..5d12674b 100644 --- a/src/test/resources/settings/expected.json +++ b/src/test/resources/settings/expected.json @@ -1,24 +1,28 @@ { "Sources": { - "3": { - "isMoving": false + "0": { + "uri": "/tmp/img8270806677315563879.tif", + "name": "img8270806677315563879.tif channel 1", + "isMoving": true + }, + "1": { + "uri": "/tmp/img8270806677315563879.tif", + "name": "img8270806677315563879.tif channel 2", + "isMoving": true }, "2": { + "uri": "/tmp/img8270806677315563879.tif", + "name": "img8270806677315563879.tif channel 3", "isMoving": false }, - "1": { + "3": { + "uri": "/tmp/img8270806677315563879.tif", + "name": "img8270806677315563879.tif channel 4", "isMoving": false - }, - "0": { - "isMoving": true } }, "ViewerP": { "Sources": [ - true, - false, - true, - false, false, false, false, @@ -28,32 +32,38 @@ { "active": true, "name": "moving images", + "id": [] + }, + { + "active": true, + "name": "fixed images", + "id": [] + }, + { + "active": false, + "name": "moving images", "id": [ 0, 1 ] }, { - "active": true, - "name": "fixed images", + "active": false, + "name": "target images", "id": [ 2, 3 ] } ], - "DisplayMode": "ss", - "Interpolation": "nlinear", + "DisplayMode": "sg", + "Interpolation": "nearestneighbor", "CurrentSource": 0, - "CurrentGroup": 0, + "CurrentGroup": 3, "CurrentTimePoint": 0 }, "ViewerQ": { "Sources": [ - true, - false, - true, - false, false, false, false, @@ -63,115 +73,49 @@ { "active": true, "name": "moving images", - "id": [ - 0, - 1 - ] + "id": [] }, { "active": true, "name": "fixed images", - "id": [ - 2, - 3 - ] + "id": [] } ], - "DisplayMode": "fs", + "DisplayMode": "sg", "Interpolation": "nearestneighbor", - "CurrentSource": 2, + "CurrentSource": 0, "CurrentGroup": 1, "CurrentTimePoint": 0 }, "SetupAssignments": { - "ConverterSetups": [ - { - "id": 0, - "min": 0.0, - "max": 860.4, - "color": -10027213, - "groupId": 0 - }, - { - "id": 1, + "ConverterSetups": { + "0": { "min": 0.0, "max": 255.0, - "color": 0, - "groupId": 1 - }, - { - "id": 2, - "min": 0.0, - "max": 2000.0, - "color": -39169, - "groupId": 2 - }, - { - "id": 3, - "min": 0.0, - "max": 433.408, - "color": -1, - "groupId": 3 - }, - { - "id": 956736363, - "min": 0.0, - "max": 65535.0, "color": -1, - "groupId": 4 + "groupId": 0 }, - { - "id": 1006827158, + "1": { "min": 0.0, "max": 65535.0, "color": -1, - "groupId": 5 + "groupId": 1 }, - { - "id": 1696993146, + "2": { "min": 0.0, - "max": 65535.0, + "max": 255.0, "color": -1, - "groupId": 6 + "groupId": 2 }, - { - "id": 33872301, - "min": 0.0, - "max": 65535.0, + "3": { + "min": 10.0, + "max": 571.0, "color": -1, - "groupId": 7 + "groupId": 3 } - ], - "MinMaxGroups": [ - { - "id": 0, - "fullRangeMin": -2.147483648E9, - "fullRangeMax": 2.147483647E9, - "rangeMin": 0.0, - "rangeMax": 4000.0, - "currentMin": 0.0, - "currentMax": 860.4 - }, - { - "id": 1, - "fullRangeMin": -2.147483648E9, - "fullRangeMax": 2.147483647E9, - "rangeMin": 0.0, - "rangeMax": 65535.0, - "currentMin": 0.0, - "currentMax": 255.0 - }, - { - "id": 2, - "fullRangeMin": -2.147483648E9, - "fullRangeMax": 2.147483647E9, - "rangeMin": 0.0, - "rangeMax": 2000.0, - "currentMin": 0.0, - "currentMax": 2000.0 - }, - { - "id": 3, + }, + "MinMaxGroups": { + "0": { "fullRangeMin": -2.147483648E9, "fullRangeMax": 2.147483647E9, "rangeMin": 0.0, @@ -179,43 +123,31 @@ "currentMin": 0.0, "currentMax": 255.0 }, - { - "id": 4, - "fullRangeMin": -2.147483648E9, - "fullRangeMax": 2.147483647E9, - "rangeMin": 0.0, - "rangeMax": 65535.0, - "currentMin": 0.0, - "currentMax": 512.0 - }, - { - "id": 5, + "1": { "fullRangeMin": -2.147483648E9, "fullRangeMax": 2.147483647E9, "rangeMin": 0.0, "rangeMax": 65535.0, "currentMin": 0.0, - "currentMax": 512.0 + "currentMax": 65535.0 }, - { - "id": 6, + "2": { "fullRangeMin": -2.147483648E9, "fullRangeMax": 2.147483647E9, "rangeMin": 0.0, "rangeMax": 65535.0, "currentMin": 0.0, - "currentMax": 512.0 + "currentMax": 255.0 }, - { - "id": 7, + "3": { "fullRangeMin": -2.147483648E9, "fullRangeMax": 2.147483647E9, "rangeMin": 0.0, "rangeMax": 65535.0, "currentMin": 0.0, - "currentMax": 512.0 + "currentMax": 65535.0 } - ] + } }, "Bookmarks": { "bookmarks": {} diff --git a/src/test/resources/settings/expected_with_dfield.json b/src/test/resources/settings/expected_with_dfield.json index 89b46cb4..2391e17f 100644 --- a/src/test/resources/settings/expected_with_dfield.json +++ b/src/test/resources/settings/expected_with_dfield.json @@ -1,16 +1,28 @@ { "Sources": { + "0": { + "uri": "/tmp/img8270806677315563879.tif", + "name": "img8270806677315563879.tif channel 1", + "isMoving": true + }, "1": { + "uri": "/tmp/img8270806677315563879.tif", + "name": "img8270806677315563879.tif channel 2", + "isMoving": true + }, + "2": { + "uri": "/tmp/img8270806677315563879.tif", + "name": "img8270806677315563879.tif channel 3", "isMoving": false }, - "0": { - "isMoving": true + "3": { + "uri": "/tmp/img8270806677315563879.tif", + "name": "img8270806677315563879.tif channel 4", + "isMoving": false } }, "ViewerP": { "Sources": [ - true, - true, false, false, false, @@ -20,28 +32,38 @@ { "active": true, "name": "moving images", - "id": [ - 0 - ] + "id": [] }, { "active": true, "name": "fixed images", + "id": [] + }, + { + "active": false, + "name": "moving images", "id": [ + 0, 1 ] + }, + { + "active": false, + "name": "target images", + "id": [ + 2, + 3 + ] } ], - "DisplayMode": "ss", + "DisplayMode": "sg", "Interpolation": "nearestneighbor", "CurrentSource": 0, - "CurrentGroup": 0, + "CurrentGroup": 3, "CurrentTimePoint": 0 }, "ViewerQ": { "Sources": [ - true, - true, false, false, false, @@ -51,81 +73,49 @@ { "active": true, "name": "moving images", - "id": [ - 0 - ] + "id": [] }, { "active": true, "name": "fixed images", - "id": [ - 1 - ] + "id": [] } ], - "DisplayMode": "ss", + "DisplayMode": "sg", "Interpolation": "nearestneighbor", - "CurrentSource": 1, + "CurrentSource": 0, "CurrentGroup": 1, "CurrentTimePoint": 0 }, "SetupAssignments": { - "ConverterSetups": [ - { - "id": 0, + "ConverterSetups": { + "0": { "min": 0.0, "max": 255.0, "color": -1, "groupId": 0 }, - { - "id": 1, + "1": { "min": 0.0, - "max": 255.0, + "max": 65535.0, "color": -1, "groupId": 1 }, - { - "id": 956736363, + "2": { "min": 0.0, - "max": 65535.0, + "max": 255.0, "color": -1, "groupId": 2 }, - { - "id": 1006827158, - "min": 0.0, - "max": 65535.0, + "3": { + "min": 10.0, + "max": 571.0, "color": -1, "groupId": 3 - }, - { - "id": 1696993146, - "min": 0.0, - "max": 65535.0, - "color": -1, - "groupId": 4 - }, - { - "id": 33872301, - "min": 0.0, - "max": 65535.0, - "color": -1, - "groupId": 5 } - ], - "MinMaxGroups": [ - { - "id": 0, - "fullRangeMin": -2.147483648E9, - "fullRangeMax": 2.147483647E9, - "rangeMin": 0.0, - "rangeMax": 65535.0, - "currentMin": 0.0, - "currentMax": 255.0 - }, - { - "id": 1, + }, + "MinMaxGroups": { + "0": { "fullRangeMin": -2.147483648E9, "fullRangeMax": 2.147483647E9, "rangeMin": 0.0, @@ -133,115 +123,93 @@ "currentMin": 0.0, "currentMax": 255.0 }, - { - "id": 2, - "fullRangeMin": -2.147483648E9, - "fullRangeMax": 2.147483647E9, - "rangeMin": 0.0, - "rangeMax": 65535.0, - "currentMin": 0.0, - "currentMax": 512.0 - }, - { - "id": 3, + "1": { "fullRangeMin": -2.147483648E9, "fullRangeMax": 2.147483647E9, "rangeMin": 0.0, "rangeMax": 65535.0, "currentMin": 0.0, - "currentMax": 512.0 + "currentMax": 65535.0 }, - { - "id": 4, + "2": { "fullRangeMin": -2.147483648E9, "fullRangeMax": 2.147483647E9, "rangeMin": 0.0, "rangeMax": 65535.0, "currentMin": 0.0, - "currentMax": 512.0 + "currentMax": 255.0 }, - { - "id": 5, + "3": { "fullRangeMin": -2.147483648E9, "fullRangeMax": 2.147483647E9, "rangeMin": 0.0, "rangeMax": 65535.0, "currentMin": 0.0, - "currentMax": 1.0 + "currentMax": 65535.0 } - ] + } }, "Bookmarks": { "bookmarks": {} }, "Transform": { "type": "Thin Plate Spline", - "maskInterpolationType": "LINEAR", + "maskInterpolationType": "NONE", "landmarks": { "type": "BigWarpLandmarks", "numDimensions": 3, "movingPoints": [ [ - 138.5264565425024, - 153.68156638013366, - 130.0 + 193.1527102803737, + 163.57943925233658, + 130.00000000000003 ], [ - 256.96599808978027, - 260.65921680993307, - 130.0 + 132.8910280373831, + 248.17757009345803, + 130.00000000000003 ], [ - 99.04660936007639, - 293.771346704871, - 130.0 + 222.70411214953256, + 272.51401869158883, + 130.00000000000003 ], [ - 185.64756446991402, - 222.45291308500472, - 193.67717287488063 + 182.72280373831765, + 159.52336448598143, + 170.5607476635514 ], [ - 245.0465937080423, - 187.61109998806953, - 85.38357770940299 - ], - [ - 148.2207748912096, - 228.0398521995533, - 85.38357770940299 + 176.92841121495317, + 255.1308411214954, + 170.5607476635514 ] ], "fixedPoints": [ [ - 209.84489016236864, - 199.5291308500477, - 130.0 + 216.01797508417232, + 233.3341910984992, + 126.86263579832789 ], [ - 171.63858643744027, - 283.5829990448901, - 130.0 + 145.77520051769838, + 213.26482693664948, + 126.8626357983279 ], [ - 138.5264565425024, - 200.80267430754532, - 130.0 + 146.49196352347872, + 298.5596246245108, + 126.86263579832789 ], [ - 185.64756446991402, - 222.45291308500472, - 193.67717287488063 + 182.72280373831765, + 159.52336448598143, + 170.5607476635514 ], [ - 269.7014326647564, - 123.11652340019099, - 91.28427889207263 - ], - [ - 138.5264565425024, - 300.13906399235907, - 91.28427889207263 + 176.92841121495317, + 255.1308411214954, + 170.5607476635514 ] ], "active": [ @@ -249,7 +217,6 @@ true, true, true, - true, true ], "names": [ @@ -257,18 +224,7 @@ "Pt-1", "Pt-2", "Pt-3", - "Pt-4", - "Pt-5" - ] - }, - "mask": { - "fallOffShape": "COSINE", - "squaredRadius": 12135.963559594926, - "squaredSigma": 100.0, - "center": [ - 204.1139446036294, - 211.62779369627503, - 91.28427889207263 + "Pt-4" ] } } From cf586e51f1133b460ca8f9fe5bbface08c39bbf0 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 16 Nov 2022 14:01:54 -0500 Subject: [PATCH 127/282] wip init dialog progress --- src/main/java/bdv/gui/BigWarpInitDialog.java | 164 ++++++++++++------- 1 file changed, 109 insertions(+), 55 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 47af4a5c..58540303 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -21,6 +21,8 @@ import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; import org.janelia.saalfeldlab.n5.ij.N5Importer; import org.janelia.saalfeldlab.n5.ij.N5Importer.N5BasePathFun; @@ -46,7 +48,6 @@ import bigwarp.BigWarpData; import bigwarp.BigWarpInit; import ij.IJ; -//import ij.ImageJ; import ij.ImagePlus; import ij.Prefs; import ij.WindowManager; @@ -55,20 +56,19 @@ import net.imagej.ImageJ; import net.imglib2.realtransform.RealTransform; -//@Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp 8" ) -public class BigWarpInitDialog extends JFrame //implements Command +public class BigWarpInitDialog extends JFrame { private static final long serialVersionUID = -2914972130819029899L; private boolean imageJOpen; - private JTextField containerPathText, transformPathText; private String initialPath; + private JTextField projectPathTxt, containerPathText, transformPathText; private JLabel messageLabel; private JButton okBtn, cancelBtn; private JPanel listPanel; private JTable sourceTable; - private JButton browseBtn, addN5Button, addN5TransformButton, browseTransformButton; + private JButton browseProjectButton, browseBtn, addN5Button, addN5TransformButton, browseTransformButton; private BigWarpSourceTableModel sourceTableModel; private JComboBox imagePlusDropdown; private JButton addImageButton, addPathButton, addTransformButton; @@ -80,7 +80,7 @@ public class BigWarpInitDialog extends JFrame //implements Command private Consumer okayCallback; private Consumer cancelCallback; - private Consumer< String > imagePathUpdateCallback, transformPathUpdateCallback; + private Consumer< String > imagePathUpdateCallback, transformPathUpdateCallback, projectPathUpdateCallback; private static final int DEFAULT_OUTER_PAD = 8; private static final int DEFAULT_BUTTON_PAD = 3; @@ -104,7 +104,11 @@ public BigWarpInitDialog( final String title ) initializeImagePlusSources(); - cancelCallback = x -> {}; + cancelCallback = x -> { + setVisible( false ); + dispose(); + }; + okayCallback = x -> { macroRecord( x ); runBigWarp( x ); @@ -123,21 +127,21 @@ public BigWarpInitDialog( final String title ) public static void main( String[] args ) { - ImageJ ij2 = new ImageJ(); - ij2.ui().showUI(); +// ImageJ ij2 = new ImageJ(); +// ij2.ui().showUI(); -// ImageJ ij = new ImageJ(); + ImageJ ij = new ImageJ(); // // IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); // IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); // -//// IJ.openImage( "/home/john/tmp/boats.tif" ).show(); -//// IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); -// -//// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); -//// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); +// IJ.openImage( "/home/john/tmp/boats.tif" ).show(); +// IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); // -// createAndShowGUI(); + IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); + IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); + + createAndShow(); } public static void addTransform( BigWarpData data, SourceRow tableRow ) @@ -213,7 +217,6 @@ public JPanel createContent() final JPanel panel = new JPanel(false); panel.setLayout(new GridBagLayout()); - final GridBagConstraints ctxt = new GridBagConstraints(); ctxt.gridx = 0; ctxt.gridy = 0; @@ -224,10 +227,44 @@ public JPanel createContent() ctxt.anchor = GridBagConstraints.LINE_END; ctxt.fill = GridBagConstraints.NONE; ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); + panel.add( new JLabel("Open BigWarp project:"), ctxt ); + + final GridBagConstraints gbcBar = new GridBagConstraints(); + gbcBar.gridx = 1; + gbcBar.gridy = 0; + gbcBar.gridwidth = 6; + gbcBar.gridheight = 1; + gbcBar.weightx = 1.0; + gbcBar.weighty = 0.0; + gbcBar.fill = GridBagConstraints.HORIZONTAL; + gbcBar.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); + + projectPathTxt = new JTextField(); + projectPathTxt.setPreferredSize( new Dimension( frameSizeX / 3, projectPathTxt.getPreferredSize().height ) ); + panel.add(projectPathTxt, gbcBar); + + // gbc bars below are width 4 + gbcBar.gridwidth = 4; + + final GridBagConstraints cProjBrowse = new GridBagConstraints(); + cProjBrowse.gridx = 7; + cProjBrowse.gridy = 0; + cProjBrowse.gridwidth = 1; + cProjBrowse.weightx = 0.0; + cProjBrowse.fill = GridBagConstraints.HORIZONTAL; + cProjBrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + browseProjectButton = new JButton("Browse"); + browseProjectButton.addActionListener( e -> { browseProjectDialog(); } ); + panel.add(browseProjectButton, cProjBrowse); + + + // Add open imagej image + ctxt.gridy = 1; + panel.add( new JLabel("Add open image:"), ctxt ); final GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 1; - gbc.gridy = 0; + gbc.gridy = 1; gbc.gridwidth = 3; gbc.weightx = 1.0; gbc.weighty = 0.0; @@ -240,45 +277,37 @@ public JPanel createContent() final GridBagConstraints cadd = new GridBagConstraints(); cadd.gridx = 5; - cadd.gridy = 0; + cadd.gridy = 1; cadd.gridwidth = 1; cadd.weightx = 0.0; cadd.fill = GridBagConstraints.NONE; cadd.anchor = GridBagConstraints.LINE_START; cadd.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); - cadd.gridy = 0; + cadd.gridy = 1; addImageButton = new JButton("+"); panel.add( addImageButton, cadd ); addImageButton.addActionListener( e -> { addImagePlus(); }); - final JLabel addFileLabel = new JLabel( "Add file/folder:"); + ctxt.gridy = 2; + final JLabel addFileLabel = new JLabel( "Add image file/folder:"); panel.add(addFileLabel, ctxt); - final GridBagConstraints gbcBar = new GridBagConstraints(); - gbcBar.gridx = 1; - gbcBar.gridy = 1; - gbcBar.gridwidth = 4; - gbcBar.gridheight = 1; - gbcBar.weightx = 1.0; - gbcBar.weighty = 0.0; - gbcBar.fill = GridBagConstraints.HORIZONTAL; - gbcBar.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); - + gbcBar.gridy = 2; containerPathText = new JTextField(); containerPathText.setText( initialPath ); containerPathText.setPreferredSize( new Dimension( frameSizeX / 3, containerPathText.getPreferredSize().height ) ); // containerPathText.addActionListener( e -> openContainer( n5Fun, () -> getN5RootPath(), pathFun ) ); panel.add(containerPathText, gbcBar); - cadd.gridy = 1; + cadd.gridy = 2; addPathButton = new JButton("+"); addPathButton.addActionListener( e -> addPath() ); panel.add(addPathButton, cadd); final GridBagConstraints cbrowse = new GridBagConstraints(); cbrowse.gridx = 6; - cbrowse.gridy = 1; + cbrowse.gridy = 2; cbrowse.gridwidth = 1; cbrowse.weightx = 0.0; cbrowse.fill = GridBagConstraints.HORIZONTAL; @@ -287,15 +316,9 @@ public JPanel createContent() browseBtn.addActionListener( e -> { browseImageDialog(); } ); panel.add(browseBtn, cbrowse); - - // add image / n5 - ctxt.gridy = 1; - panel.add( new JLabel("Add open image:"), ctxt ); - - final GridBagConstraints cn5 = new GridBagConstraints(); cn5.gridx = 7; - cn5.gridy = 1; + cn5.gridy = 2; cn5.gridwidth = 1; cn5.weightx = 0.0; cn5.fill = GridBagConstraints.HORIZONTAL; @@ -308,25 +331,25 @@ public JPanel createContent() }); // add transforms - ctxt.gridy = 2; + ctxt.gridy = 3; panel.add( new JLabel("Add transformation:"), ctxt ); transformPathText = new JTextField(); transformPathText.setPreferredSize( new Dimension( frameSizeX / 3, transformPathText.getPreferredSize().height ) ); - gbcBar.gridy = 2; + gbcBar.gridy = 3; panel.add( transformPathText, gbcBar ); addTransformButton = new JButton( "+" ); addTransformButton.addActionListener( e -> addTransform() ); - cadd.gridy = 2; + cadd.gridy = 3; panel.add( addTransformButton, cadd ); browseTransformButton = new JButton("Browse"); browseTransformButton.addActionListener( e -> { browseTransformDialog(); } ); - cbrowse.gridy = 2; + cbrowse.gridy = 3; panel.add( browseTransformButton, cbrowse ); - cn5.gridy = 2; + cn5.gridy = 3; addN5TransformButton = new JButton( "H5/N5/Zarr" ); panel.add( addN5TransformButton, cn5 ); @@ -337,7 +360,7 @@ public JPanel createContent() // source list final GridBagConstraints clist = new GridBagConstraints(); clist.gridx = 0; - clist.gridy = 3; + clist.gridy = 4; clist.gridwidth = 8; clist.gridheight = 3; clist.weightx = 1.0; @@ -354,7 +377,7 @@ public JPanel createContent() // bottom button section final GridBagConstraints cbot = new GridBagConstraints(); cbot.gridx = 0; - cbot.gridy = 6; + cbot.gridy = 7; cbot.gridwidth = 4; cbot.gridheight = 1; cbot.weightx = 1.0; @@ -441,7 +464,12 @@ protected void addImagePlus() protected void addImagePlus( String title ) { - if ( !imageJOpen ) + addImagePlus( title, true ); + } + + protected void addImagePlus( String title, boolean moving ) + { + if ( IJ.getInstance() == null ) return; final ImagePlus imp = WindowManager.getImage( title ); @@ -450,7 +478,7 @@ protected void addImagePlus( String title ) // an image is not added, and / or updating the dropdown menu periodically if( !title.isEmpty() && imp != null ) { - sourceTableModel.addImagePlus( title ); + sourceTableModel.addImagePlus( title, moving ); repaint(); } } @@ -505,10 +533,16 @@ public void initializeImagePlusSources() { final int N = imagePlusDropdown.getModel().getSize(); if ( N > 0 ) - addImagePlus( ( String ) imagePlusDropdown.getItemAt( 0 ) ); + addImagePlus( ( String ) imagePlusDropdown.getItemAt( 0 ), true ); if ( N > 1 ) - addImagePlus( ( String ) imagePlusDropdown.getItemAt( 1 ) ); + addImagePlus( ( String ) imagePlusDropdown.getItemAt( 1 ), false ); + } + + public void fillTableFromProject() + { + // TODO implement me + System.out.println( "implement me" ); } public static void createAndShow() { @@ -518,7 +552,7 @@ public static void createAndShow() { frame.setVisible(true); } - private String browseDialogGeneral() + private String browseDialogGeneral( final int mode, final FileFilter filefilter ) { final JFileChooser fileChooser = new JFileChooser(); @@ -526,7 +560,12 @@ private String browseDialogGeneral() * Need to allow files so h5 containers can be opened, and directories * so that filesystem n5's and zarrs can be opened. */ - fileChooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES ); + fileChooser.setFileSelectionMode( mode ); + if( filefilter == null ) + { + System.out.println( "file filter"); + fileChooser.setFileFilter( filefilter ); + } if ( lastBrowsePath != null && !lastBrowsePath.isEmpty() ) fileChooser.setCurrentDirectory( new File( lastBrowsePath ) ); @@ -566,9 +605,24 @@ public void setTransformPathUpdateCallback( final Consumer< String > callback ) this.transformPathUpdateCallback = callback; } + public void setProjectPathUpdateCallback( final Consumer< String > callback ) + { + this.projectPathUpdateCallback = callback; + } + + private String browseProjectDialog() + { + final String s = browseDialogGeneral( JFileChooser.FILES_ONLY, new FileNameExtensionFilter( "JSON file", "json" ) ); + projectPathTxt.setText( s ); + if ( projectPathUpdateCallback != null ) + projectPathUpdateCallback.accept( s ); + + return s; + } + private String browseImageDialog() { - final String s = browseDialogGeneral(); + final String s = browseDialogGeneral( JFileChooser.FILES_AND_DIRECTORIES, null ); containerPathText.setText( s ); if ( imagePathUpdateCallback != null ) imagePathUpdateCallback.accept( s ); @@ -578,7 +632,7 @@ private String browseImageDialog() private String browseTransformDialog() { - final String s = browseDialogGeneral(); + final String s = browseDialogGeneral( JFileChooser.FILES_AND_DIRECTORIES, null ); transformPathText.setText( s ); if ( transformPathUpdateCallback != null ) transformPathUpdateCallback.accept( s ); From d700b93a023dd30ccc616e547ebb6cdcc3a7fe4f Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 16 Nov 2022 17:16:30 -0500 Subject: [PATCH 128/282] fix: BigWarpInitDialog works with SourceInfo --- src/main/java/bdv/gui/BigWarpInitDialog.java | 33 +++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 58540303..156dd160 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -8,6 +8,7 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; +import java.util.LinkedHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; @@ -44,9 +45,11 @@ import bdv.gui.sourceList.BigWarpSourceTableModel; import bdv.gui.sourceList.BigWarpSourceTableModel.SourceRow; import bdv.ij.util.ProgressWriterIJ; +import bdv.viewer.Source; import bigwarp.BigWarp; import bigwarp.BigWarpData; import bigwarp.BigWarpInit; +import bigwarp.source.SourceInfo; import ij.IJ; import ij.ImagePlus; import ij.Prefs; @@ -144,21 +147,9 @@ public static void main( String[] args ) createAndShow(); } - public static void addTransform( BigWarpData data, SourceRow tableRow ) + public static void runBigWarp( BigWarpSourceTableModel sourceTable ) { - // TODO combine source and transform addition - String tformName = tableRow.transformName; - if( tformName != null && !tformName.isEmpty() ) - { - // TODO generalize to attributes in n5 - final RealTransform tform = NgffTransformations.openJson( tformName ); - data.transforms.set( data.transforms.size() - 1, tform ); - } - } - - public static void runBigWarp( BigWarpSourceTableModel sourceTable ) - { - final BigWarpData< ? > data = BigWarpInit.initData(); + final BigWarpData< T > data = BigWarpInit.initData(); final int N = sourceTable.getRowCount(); int id = 0; @@ -168,16 +159,20 @@ public static void runBigWarp( BigWarpSourceTableModel sourceTable ) if( tableRow.isImagePlus ) { final ImagePlus imp = WindowManager.getImage( tableRow.srcName ); - id += BigWarpInit.add( data, imp, id, 0, tableRow.moving ); - addTransform( data, tableRow ); +// id += BigWarpInit.add( data, imp, id, 0, tableRow.moving ); +// addTransform( data, tableRow ); + LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, imp, id, 0, tableRow.moving ); + BigWarpInit.add( data, infos, tableRow.getTransform() ); } else { // TODO deal with exceptions, and possibility of multiple sources per uri try { - BigWarpInit.add( data, tableRow.srcName, id, tableRow.moving ); - addTransform( data, tableRow ); +// BigWarpInit.add( data, tableRow.srcName, id, tableRow.moving ); +// addTransform( data, tableRow ); + LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, tableRow.srcName, id, tableRow.moving ); + BigWarpInit.add( data, infos, tableRow.getTransform() ); } catch ( URISyntaxException e ) { @@ -448,7 +443,7 @@ public void n5DialogCallback( DataSelection selection ) { final String n5RootPath = selectionDialog.getN5RootPath(); for( N5Metadata m : selection.metadata ) - sourceTableModel.add( m.getPath() ); + sourceTableModel.add( n5RootPath + "?" + m.getPath() ); repaint(); } From 3cba063bdbbe3965b6654dfd353c00c429708e94 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 16 Nov 2022 17:20:40 -0500 Subject: [PATCH 129/282] feat!: use transforms stored in SourceInfo --- .../sourceList/BigWarpSourceTableModel.java | 15 ++++++++ src/main/java/bigwarp/BigWarpData.java | 34 ++++++++----------- src/main/java/bigwarp/BigWarpInit.java | 4 +-- .../BigWarpTransformedSourcesTest.java | 30 +++++++++------- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index 5fe37891..ffe18c6e 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -13,6 +13,10 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; +import org.janelia.saalfeldlab.n5.imglib2.NgffTransformations; + +import net.imglib2.realtransform.RealTransform; + public class BigWarpSourceTableModel extends AbstractTableModel { private static final long serialVersionUID = 5923947651732788341L; @@ -193,6 +197,17 @@ else if ( c == 2 ) else return null; } + + public RealTransform getTransform() + { + if( transformName != null && !transformName.isEmpty() ) + { + // TODO generalize to attributes in n5 +// final RealTransform tform = NgffTransformations.openJson( transformName ); + return NgffTransformations.openJson( transformName ); + } + return null; + } } protected static class RemoveRowButton extends JButton { diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index adbcb479..27625155 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.IntStream; import bdv.cache.CacheControl; import bdv.gui.BigWarpViewerFrame; @@ -36,8 +35,6 @@ public class BigWarpData< T > public final LinkedHashMap< Integer, SourceInfo > sourceInfos = new LinkedHashMap<>(); - public List transforms; - public final List< ConverterSetup > converterSetups; public final CacheControl cache; @@ -75,14 +72,14 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, this.sources = sources; this.converterSetups = converterSetups; - if( transforms != null ) - this.transforms = transforms; - else - { - // fill the initial transform list with nulls - this.transforms = new ArrayList<>(); - IntStream.range( 0, sources.size() ).forEach( i -> this.transforms.add( null )); - } +// if( transforms != null ) +// this.transforms = transforms; +// else +// { +// // fill the initial transform list with nulls +// this.transforms = new ArrayList<>(); +// IntStream.range( 0, sources.size() ).forEach( i -> this.transforms.add( null )); +// } if ( cache == null ) this.cache = new CacheControl.Dummy(); @@ -276,28 +273,27 @@ void remove( int i ) final int sacId = sourceInfos.entrySet().stream().filter( it -> it.getValue().getSourceAndConverter() == sac ).map( Map.Entry::getKey ).findFirst().get(); final SourceInfo sourceInfo = sourceInfos.remove( sacId ); sources.remove( i ); - transforms.remove( sourceInfo.getTransform() ); setupSettings.remove( sourceInfo.getId() ); sourceColorSettings.remove(sac); converterSetups.remove( i ); } - public void setTransform( int i, RealTransform transform ) - { - transforms.set( i, transform ); - } - public void applyTransformations() { int i = 0; for ( final SourceAndConverter sac : sources ) { - if ( transforms.get( i ) != null ) + final SourceInfo info = getSourceInfo( sac ); + final RealTransform transform = info.getTransform(); + if ( transform != null ) { SourceAndConverter newSac = inheritConverter( - applyFixedTransform( sac.getSpimSource(), transforms.get( i )), + applyFixedTransform( sac.getSpimSource(), transform), sac ); + //final int id = info.getId(); + info.setSourceAndConverter( newSac ); + sourceColorSettings.put( newSac, sourceColorSettings.get( sac )); sources.set( i, newSac ); } diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 746ee520..d7283e9a 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -451,7 +451,7 @@ public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap public static < T > BigWarpData< T > add( BigWarpData bwdata, Source< T > src, int setupId, int numTimepoints, boolean isMoving, RealTransform transform ) { addSourceToListsGenericType( src, setupId, bwdata.converterSetups, bwdata.sources ); - bwdata.transforms.add( transform ); +// bwdata.transforms.add( transform ); return bwdata; } @@ -465,7 +465,7 @@ public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap if ( transform != null ) { info.setTransform( transform ); - bwdata.transforms.add( transform ); +// bwdata.transforms.add( transform ); } bwdata.sourceInfos.put( info.getId(), info ); } ); diff --git a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java index bdbdf476..ad687787 100644 --- a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java +++ b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java @@ -10,6 +10,17 @@ public class BigWarpTransformedSourcesTest { public static void main( String[] args ) throws SpimDataException + { + BigWarpData< ? > data = createData(); + data.applyTransformations(); + + final BigWarp bw = new BigWarp<>( data, new ProgressWriterConsole()); + bw.loadLandmarks( "/home/john/tmp/bw_tformTest_landmarks_simple.csv" ); +// bw.loadLandmarks( "/groups/saalfeld/home/bogovicj/tmp/bw_tformTest_landmarks.csv" ); + + } + + public static BigWarpData createData() { final ImagePlus mr = IJ.openImage("/home/john/tmp/mri-stack.tif"); final ImagePlus t1 = IJ.openImage("/home/john/tmp/t1-head.tif"); @@ -17,26 +28,19 @@ public static void main( String[] args ) throws SpimDataException // final ImagePlus mr = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif"); // final ImagePlus t1 = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/t1-head.tif"); - int id = 0; - final BigWarpData< ? > data = BigWarpInit.initData(); - BigWarpInit.add( data, mr, id++, 0, true ); - BigWarpInit.add( data, t1, id++, 0, false ); - BigWarpInit.add( data, t1, id++, 0, false ); - data.wrapUp(); - AffineTransform3D translation0 = new AffineTransform3D(); translation0.translate( -50, -50, -10 ); - data.setTransform( 0, translation0 ); AffineTransform3D translation = new AffineTransform3D(); translation.translate( -100, -150, -50 ); - data.setTransform( 2, translation ); - data.applyTransformations(); - final BigWarp bw = new BigWarp<>( data, new ProgressWriterConsole()); - bw.loadLandmarks( "/home/john/tmp/bw_tformTest_landmarks_simple.csv" ); -// bw.loadLandmarks( "/groups/saalfeld/home/bogovicj/tmp/bw_tformTest_landmarks.csv" ); + int id = 0; + final BigWarpData< T > data = BigWarpInit.initData(); + BigWarpInit.add( data, BigWarpInit.createSources( data, mr, id++, 0, true ), translation0 ); + BigWarpInit.add( data, BigWarpInit.createSources( data, t1, id++, 0, false )); + BigWarpInit.add( data, BigWarpInit.createSources( data, t1, id++, 0, false ), translation); + return data; } } From f20ef0bb5e10b6e849e6354ab2181ea47cea1562 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 16 Nov 2022 17:20:56 -0500 Subject: [PATCH 130/282] better BigWarpCommand example --- src/main/java/bdv/ij/BigWarpCommand.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/bdv/ij/BigWarpCommand.java b/src/main/java/bdv/ij/BigWarpCommand.java index e35c0d40..55d1347e 100644 --- a/src/main/java/bdv/ij/BigWarpCommand.java +++ b/src/main/java/bdv/ij/BigWarpCommand.java @@ -1,9 +1,12 @@ package bdv.ij; +import java.io.IOException; + import org.scijava.command.Command; import org.scijava.plugin.Plugin; import bdv.gui.BigWarpInitDialog; +import ij.IJ; import net.imagej.ImageJ; @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp Command" ) @@ -15,10 +18,16 @@ public void run() BigWarpInitDialog.createAndShow(); } - public static void main( String[] args ) + public static void main( String[] args ) throws IOException { ImageJ ij2 = new ImageJ(); ij2.ui().showUI(); + + Object im1 = ij2.io().open( "/home/john/tmp/mri-stack.tif" ); + Object im2 = ij2.io().open( "/home/john/tmp/t1-head.tif" ); + + ij2.ui().show( im1 ); + ij2.ui().show( im2 ); } } From f36ffe92f7c9b4106065ca8a8062cd9a2eb244de Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 17 Nov 2022 10:56:22 -0500 Subject: [PATCH 131/282] remove color settings field from BigWarpData --- src/main/java/bigwarp/BigWarp.java | 18 +++--- src/main/java/bigwarp/BigWarpData.java | 62 ++++++------------- src/main/java/bigwarp/BigWarpInit.java | 2 - .../java/bigwarp/loader/ImagePlusLoader.java | 3 +- 4 files changed, 28 insertions(+), 57 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 6821c013..8c6e3a24 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1920,11 +1920,7 @@ public void setGridType( final GridSource.GRID_TYPE method ) @SuppressWarnings( "unchecked" ) public static < T > void wrapMovingSources( final int ndims, final BigWarpData< T > data ) { - final HashMap, ColorSettings> colorSettings = data.sourceColorSettings; -// System.out.println( "before " + colorSettings.keySet().size()); - int i = 0; - for ( final SourceInfo sourceInfo : data.sourceInfos.values() ) { if ( sourceInfo.isMoving() ) @@ -1932,12 +1928,10 @@ public static < T > void wrapMovingSources( final int ndims, final BigWarpData< SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); final int sourceIdx = data.sources.indexOf( sourceInfo.getSourceAndConverter() ); sourceInfo.setSourceAndConverter( newSac ); - colorSettings.put( newSac, sourceInfo.getColorSettings()); data.sources.set( sourceIdx, newSac ); } i++; } -// System.out.println( "after " + colorSettings.keySet().size()); } @SuppressWarnings( "unchecked" ) @@ -1947,9 +1941,6 @@ public static < T > List< SourceAndConverter< T > > wrapSourcesAsTransformed( fi { final List< SourceAndConverter> wrappedSource = new ArrayList<>(); - final HashMap, ColorSettings> colorSettings = data.sourceColorSettings; -// System.out.println( "before " + colorSettings.keySet().size()); - int i = 0; for ( final SourceInfo sourceInfo : sources.values() ) { @@ -1957,7 +1948,6 @@ public static < T > List< SourceAndConverter< T > > wrapSourcesAsTransformed( fi { SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); wrappedSource.add( newSac ); - colorSettings.put( newSac, sourceInfo.getColorSettings() ); } else { @@ -1966,7 +1956,6 @@ public static < T > List< SourceAndConverter< T > > wrapSourcesAsTransformed( fi i++; } -// System.out.println( "after " + colorSettings.keySet().size()); return wrappedSource; } @@ -2588,6 +2577,13 @@ else if (!fnP.isEmpty() && !fnQ.isEmpty()) final ImagePlus impP = IJ.openImage( fnP ); final ImagePlus impQ = IJ.openImage( fnQ ); + + // For testing display and color settings +// impP.setDisplayRange( 10, 200 ); +// impQ.setDisplayRange( 20, 180 ); +// impP.show(); +// impQ.show(); + if ( !( impP == null || impQ == null ) ) { bwdata = BigWarpInit.createBigWarpDataFromImages( impP, impQ ); diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 27625155..468d56d0 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -6,6 +6,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; import bdv.cache.CacheControl; @@ -38,9 +39,6 @@ public class BigWarpData< T > public final List< ConverterSetup > converterSetups; public final CacheControl cache; - public final HashMap< Integer, ColorSettings > setupSettings; - - public final HashMap< SourceAndConverter, ColorSettings > sourceColorSettings; public BigWarpData() { @@ -85,9 +83,6 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, this.cache = new CacheControl.Dummy(); else this.cache = cache; - - setupSettings = new HashMap<>(); - sourceColorSettings = new HashMap<>(); } public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, @@ -110,9 +105,6 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, final List< C this.cache = new CacheControl.Dummy(); else this.cache = cache; - - setupSettings = new HashMap<>(); - sourceColorSettings = new HashMap<>(); } private static ArrayList listOf( int[] x ) @@ -273,8 +265,6 @@ void remove( int i ) final int sacId = sourceInfos.entrySet().stream().filter( it -> it.getValue().getSourceAndConverter() == sac ).map( Map.Entry::getKey ).findFirst().get(); final SourceInfo sourceInfo = sourceInfos.remove( sacId ); sources.remove( i ); - setupSettings.remove( sourceInfo.getId() ); - sourceColorSettings.remove(sac); converterSetups.remove( i ); } @@ -291,10 +281,7 @@ public void applyTransformations() applyFixedTransform( sac.getSpimSource(), transform), sac ); - //final int id = info.getId(); info.setSourceAndConverter( newSac ); - - sourceColorSettings.put( newSac, sourceColorSettings.get( sac )); sources.set( i, newSac ); } i++; @@ -374,38 +361,29 @@ public Source applyFixedTransform( final Source src, final RealTransfo } } - /** - * @deprecated - */ - public void transferChannelSettings( final SetupAssignments setupAssignments, final VisibilityAndGrouping visibility ) - { - for( Integer key : setupSettings.keySet() ) - setupSettings.get( key ).updateSetup( setupAssignments ); - } - public void transferChannelSettings( final BigWarpViewerFrame viewer ) { - SynchronizedViewerState state = viewer.getViewerPanel().state(); - ConverterSetups setups = viewer.getConverterSetups(); - synchronized ( state ) + final SynchronizedViewerState state = viewer.getViewerPanel().state(); + final ConverterSetups setups = viewer.getConverterSetups(); + + // TODO does this need synchronization? + for( Entry< Integer, SourceInfo > infoEntry : sourceInfos.entrySet() ) { - for ( SourceAndConverter< ? > sac : state.getSources() ) + final int id = infoEntry.getKey(); + final SourceInfo info = infoEntry.getValue(); + final SourceAndConverter< ? > sac = info.getSourceAndConverter(); + final ConverterSetup cs = setups.getConverterSetup( sac ); + + if ( info.getColorSettings() == null ) + { + final int timepoint = state.getCurrentTimepoint(); + final Bounds bounds = InitializeViewerState.estimateSourceRange( sac.getSpimSource(), timepoint, 0.001, 0.999 ); + if( cs != null ) + cs.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); + } + else { - if ( sourceColorSettings.containsKey( sac ) ) - { - if ( sourceColorSettings.get( sac ) == null ) - continue; - - sourceColorSettings.get( sac ).updateSetup( setups.getConverterSetup( sac ) ); - } - else - { - final int timepoint = state.getCurrentTimepoint(); - final Bounds bounds = InitializeViewerState.estimateSourceRange( sac.getSpimSource(), timepoint, 0.001, 0.999 ); - ConverterSetup cs = setups.getConverterSetup(sac); - if( cs != null ) - cs.setDisplayRange( bounds.getMinBound(), bounds.getMaxBound() ); - } + info.getColorSettings().updateSetup( cs ); } } } diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index d7283e9a..06cca809 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -401,8 +401,6 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW } return null; } ); - final ImagePlusLoader.ColorSettings colorSettings = bwdata.setupSettings.get( state.getId() ); - state.setColorSettings( colorSettings ); } ); for ( final Map.Entry< Source< T >, SourceInfo > sourceSourceInfoEntry : sourceInfoMap.entrySet() ) diff --git a/src/main/java/bigwarp/loader/ImagePlusLoader.java b/src/main/java/bigwarp/loader/ImagePlusLoader.java index b2d0c43c..00693cc9 100644 --- a/src/main/java/bigwarp/loader/ImagePlusLoader.java +++ b/src/main/java/bigwarp/loader/ImagePlusLoader.java @@ -159,8 +159,7 @@ public void update( final BigWarpData< ? > data ) for( Integer key : settingsMap.keySet() ) { SourceAndConverter sac = data.sources.get( key.intValue() ); - data.setupSettings.put( key, settingsMap.get( key ) ); - data.sourceColorSettings.put( sac, settingsMap.get( key )); + data.getSourceInfo( key ).setColorSettings( settingsMap.get( key ) ); } } From c9a7cd37e911f11318491c7eb9badaa9355375ec Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 09:34:23 -0500 Subject: [PATCH 132/282] feat: don't add channel num if only 1 channel --- src/main/java/bigwarp/loader/ImagePlusLoader.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/loader/ImagePlusLoader.java b/src/main/java/bigwarp/loader/ImagePlusLoader.java index 00693cc9..ffb3c4ec 100644 --- a/src/main/java/bigwarp/loader/ImagePlusLoader.java +++ b/src/main/java/bigwarp/loader/ImagePlusLoader.java @@ -265,7 +265,8 @@ public SpimDataMinimal load( final int setupIdOffset, ImagePlus imp ) for ( int s = 0; s < numSetups; ++s ) { final int id = setupIdOffset + s; - final BasicViewSetup setup = new BasicViewSetup( setupIdOffset + s, String.format( "%s channel %d", imp.getTitle(), id + 1 ), size, voxelSize ); + final String title = numSetups > 1 ? String.format( "%s channel %d", imp.getTitle(), id + 1 ) : imp.getTitle(); + final BasicViewSetup setup = new BasicViewSetup( setupIdOffset + s, title, size, voxelSize ); setup.setAttribute( new Channel( id + 1 ) ); setups.put( id, setup ); From 733dd3219aa92348b998e0bf665f1626f601e143 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 10:01:55 -0500 Subject: [PATCH 133/282] feat(test): method to generate ImagePlus --- src/test/java/bigwarp/BigWarpTestUtils.java | 27 ++++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/test/java/bigwarp/BigWarpTestUtils.java b/src/test/java/bigwarp/BigWarpTestUtils.java index c0f9e97d..25bbc08e 100644 --- a/src/test/java/bigwarp/BigWarpTestUtils.java +++ b/src/test/java/bigwarp/BigWarpTestUtils.java @@ -32,7 +32,6 @@ import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.view.Views; import org.junit.Assert; -import org.scijava.util.FileUtils; public class BigWarpTestUtils { @@ -44,6 +43,7 @@ public static String createTemp3DImage( String title, String format ) try { tmpImgPath = Files.createTempFile( title, "." + format ); + //noinspection ResultOfMethodCallIgnored tmpImgPath.toFile().delete(); } catch ( IOException e ) @@ -62,6 +62,7 @@ public static String createTemp3DImage( Path tmpImgPath ) } catch ( Exception e ) { + //noinspection ResultOfMethodCallIgnored tmpImgPath.toFile().delete(); throw new RuntimeException( e ); } @@ -90,12 +91,14 @@ public static String createTemp2DImage( String title, String format ) try { tmpImg = Files.createTempFile( title, "." + format ); + //noinspection ResultOfMethodCallIgnored tmpImg.toFile().delete(); return create2DImage( tmpImg); } catch ( Exception e ) { if (tmpImg != null) { + //noinspection ResultOfMethodCallIgnored tmpImg.toFile().delete(); } throw new RuntimeException( e ); @@ -107,7 +110,7 @@ public static String createTemp3DImageStack( String title ) final ImagePlus img3d = NewImage.createByteImage( title, 8, 8, 4, NewImage.FILL_RAMP ); - Path tmpStackDir = null; + Path tmpStackDir; try { @@ -117,9 +120,6 @@ public static String createTemp3DImageStack( String title ) } catch ( IOException e ) { - if (tmpStackDir != null) { - FileUtils.deleteRecursively( tmpStackDir.toFile() ); - } throw new RuntimeException( e ); } } @@ -127,6 +127,7 @@ public static String createTemp3DImageStack( String title ) public static void assertJsonDiff( final JsonElement expectedJson, final JsonElement actualJson ) { final Gson gson = new Gson(); + //noinspection UnstableApiUsage Type mapType = new TypeToken< Map< String, Object > >() { }.getType(); @@ -213,12 +214,6 @@ static < T > BigWarp< T > createBigWarp(boolean... moving ) throws SpimDataExcep static < T > BigWarp< T > createBigWarp(String sourcePath, boolean... moving ) throws SpimDataException, URISyntaxException, IOException { final BigWarpData< T > data = BigWarpInit.initData(); - FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( - 3, - ( l, v ) -> v.setOne(), - UnsignedByteType::new ); - ImagePlus imp = ImageJFunctions.wrap( Views.interval( fimg, new FinalInterval( 32, 32, 1 ) ), "img" ); - if (sourcePath != null) { createTemp3DImage( Paths.get(sourcePath) ); } @@ -230,11 +225,19 @@ static < T > BigWarp< T > createBigWarp(String sourcePath, boolean... moving ) t final LinkedHashMap< Source< T >, SourceInfo > sources = BigWarpInit.createSources( data, tmpPath, i, moving[ i ] ); BigWarpInit.add( data, sources ); } - data.wrapUp(); BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); return new BigWarp<>( data, opts, null ); } + static ImagePlus generateImagePlus( final String title ) + { + FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( + 3, + ( l, v ) -> v.setOne(), + UnsignedByteType::new ); + return ImageJFunctions.wrap( Views.interval( fimg, new FinalInterval( 32, 32, 1 ) ), title ); + } + public static void main( String[] args ) throws SpimDataException, URISyntaxException, IOException { createBigWarp( true, true, false, false); From c3b03d6d0cdcab191da284d6c1a42fc3ce14ecb2 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 10:02:49 -0500 Subject: [PATCH 134/282] feat(test): more source deserialization tests --- src/test/java/bigwarp/SerializationTest.java | 93 +++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 857652bc..25a68ff2 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -13,6 +13,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.stream.JsonWriter; +import ij.ImagePlus; import java.io.File; import java.io.FileReader; import java.io.FileWriter; @@ -21,7 +22,10 @@ import java.io.PipedWriter; import java.net.URISyntaxException; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; +import java.util.stream.Collectors; import mpicbg.spim.data.SpimDataException; import net.imglib2.FinalInterval; import net.imglib2.RealPoint; @@ -221,7 +225,7 @@ public void viewerPanelTest() throws SpimDataException, IOException, URISyntaxEx } @Test - public void sourceSerializationTest() throws SpimDataException, URISyntaxException, IOException, JDOMException + public void sourceFromFileTest() throws SpimDataException, URISyntaxException, IOException, JDOMException { final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( "/tmp/img8270806677315563879.tif" ); bw.loadSettings("src/test/resources/settings/expected.json"); @@ -239,6 +243,93 @@ public void sourceSerializationTest() throws SpimDataException, URISyntaxExcepti } ); } + @Test + public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, IOException, JDOMException + { + final ImagePlus img = BigWarpTestUtils.generateImagePlus( "generated image" ); + img.show(); + + final String imagejUri = "imagej://generated image"; + final Path xmlSourceSettings = createNewSettingsWithReplacement( + "src/test/resources/settings/expected.json", + "/tmp/img8270806677315563879.tif", + imagejUri ); + + final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); + bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); + // Grab the sources + // Compare the ids, urls, isMoving status, and isActive + Assert.assertEquals("Wrong Number of Sources", 4, bw.data.sources.size()); + Assert.assertEquals("Wrong Number of Moving Sources", 2, bw.data.numMovingSources()); + Assert.assertEquals("Wrong Number of Target Sources", 2, bw.data.numTargetSources()); + final boolean[] movingById = { true, true, false, false }; + bw.data.sourceInfos.forEach( (id, info) -> { + + Assert.assertEquals("URI Mismatch", imagejUri, info.getUri()); + Assert.assertEquals("Name Mismatch", "generated image", info.getName()); + Assert.assertEquals("Moving/Target Mismatch", movingById[id], info.isMoving()); + } ); + } + + @Test + public void sourceFromXmlTest() throws SpimDataException, URISyntaxException, IOException, JDOMException + { + final String xmlUri = "src/test/resources/mri-stack.xml"; + final Path xmlSourceSettings = createNewSettingsWithReplacement( + "src/test/resources/settings/expected.json", + "/tmp/img8270806677315563879.tif", + xmlUri ); + + final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); + bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); + // Grab the sources + // Compare the ids, urls, isMoving status, and isActive + Assert.assertEquals("Wrong Number of Sources", 4, bw.data.sources.size()); + Assert.assertEquals("Wrong Number of Moving Sources", 2, bw.data.numMovingSources()); + Assert.assertEquals("Wrong Number of Target Sources", 2, bw.data.numTargetSources()); + final boolean[] movingById = { true, true, false, false }; + bw.data.sourceInfos.forEach( (id, info) -> { + + Assert.assertEquals("URI Mismatch", xmlUri, info.getUri()); + Assert.assertEquals("Name Mismatch", "channel 1", info.getName()); + Assert.assertEquals("Moving/Target Mismatch", movingById[id], info.isMoving()); + } ); + } + + @Test + public void sourceFromN5Test() throws SpimDataException, URISyntaxException, IOException, JDOMException + { + final String n5Uri = "src/test/resources/bigwarp/url/transformTest.n5?img"; + final Path xmlSourceSettings = createNewSettingsWithReplacement( + "src/test/resources/settings/expected.json", + "/tmp/img8270806677315563879.tif", + n5Uri ); + + final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); + bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); + // Grab the sources + // Compare the ids, urls, isMoving status, and isActive + Assert.assertEquals("Wrong Number of Sources", 4, bw.data.sources.size()); + Assert.assertEquals("Wrong Number of Moving Sources", 2, bw.data.numMovingSources()); + Assert.assertEquals("Wrong Number of Target Sources", 2, bw.data.numTargetSources()); + final boolean[] movingById = { true, true, false, false }; + bw.data.sourceInfos.forEach( (id, info) -> { + + Assert.assertEquals("URI Mismatch", n5Uri, info.getUri()); + Assert.assertEquals("Name Mismatch", "img", info.getName()); + Assert.assertEquals("Moving/Target Mismatch", movingById[id], info.isMoving()); + } ); + } + + private static Path createNewSettingsWithReplacement( final String baseSettings, final String toReplace, final String replaceWith ) throws IOException + { + /* Load expected.json and replace source path with desired uri */ + final Path settings = Paths.get( baseSettings ); + final List< String > newLines = Files.readAllLines( settings ).stream().map( line -> line.replaceAll( toReplace, replaceWith ) ).collect( Collectors.toList()); + final Path newSettings = Files.createTempFile( "settings", "json" ); + return Files.write( newSettings, newLines ); + } + /* When creating and closing multiple BigWarp instances, occassionally the comparison test fails. * It shouldn't be a problem in practice, since this only occurs during testing, but I think it indicates * there may be a race condidtion somewhere. To duplicate the issue, run this test multiple times, and From 1c907a7c8b7d850a3140eca88903c916bdb016e9 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 11:27:38 -0500 Subject: [PATCH 135/282] refactor: remove unnecessary getOrDefault; Id always new, so don't plan for it existing already. --- src/main/java/bigwarp/BigWarpData.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 468d56d0..0683db5b 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -35,7 +35,6 @@ public class BigWarpData< T > public List< SourceAndConverter< T > > sources; public final LinkedHashMap< Integer, SourceInfo > sourceInfos = new LinkedHashMap<>(); - public final List< ConverterSetup > converterSetups; public final CacheControl cache; @@ -245,11 +244,9 @@ void addSource( Source src, boolean isMoving, RealTransform transform ) id++; } BigWarpInit.add( this, src, id, 0, isMoving, transform ); - final SourceInfo sourceInfo = - sourceInfos.getOrDefault( id, new SourceInfo( id, isMoving, src.getName(), null, transform )); - + final SourceInfo sourceInfo = new SourceInfo( id, isMoving, src.getName(), null, transform ); sourceInfo.setSourceAndConverter( sources.get( sources.size() -1 ) ); - sourceInfos.putIfAbsent( id, sourceInfo); + sourceInfos.put( id, sourceInfo); } int remove( SourceInfo sourceInfo) From 2c262ce4bbb5b4c62719e7ef3a4d6401873e4657 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 11:31:40 -0500 Subject: [PATCH 136/282] feat(test): change channel numbering behavior --- src/test/resources/settings/expected.json | 8 ++++---- src/test/resources/settings/expected_with_dfield.json | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/resources/settings/expected.json b/src/test/resources/settings/expected.json index 5d12674b..4313d54b 100644 --- a/src/test/resources/settings/expected.json +++ b/src/test/resources/settings/expected.json @@ -2,22 +2,22 @@ "Sources": { "0": { "uri": "/tmp/img8270806677315563879.tif", - "name": "img8270806677315563879.tif channel 1", + "name": "img8270806677315563879.tif", "isMoving": true }, "1": { "uri": "/tmp/img8270806677315563879.tif", - "name": "img8270806677315563879.tif channel 2", + "name": "img8270806677315563879.tif", "isMoving": true }, "2": { "uri": "/tmp/img8270806677315563879.tif", - "name": "img8270806677315563879.tif channel 3", + "name": "img8270806677315563879.tif", "isMoving": false }, "3": { "uri": "/tmp/img8270806677315563879.tif", - "name": "img8270806677315563879.tif channel 4", + "name": "img8270806677315563879.tif", "isMoving": false } }, diff --git a/src/test/resources/settings/expected_with_dfield.json b/src/test/resources/settings/expected_with_dfield.json index 2391e17f..6dcb7741 100644 --- a/src/test/resources/settings/expected_with_dfield.json +++ b/src/test/resources/settings/expected_with_dfield.json @@ -2,22 +2,22 @@ "Sources": { "0": { "uri": "/tmp/img8270806677315563879.tif", - "name": "img8270806677315563879.tif channel 1", + "name": "img8270806677315563879.tif", "isMoving": true }, "1": { "uri": "/tmp/img8270806677315563879.tif", - "name": "img8270806677315563879.tif channel 2", + "name": "img8270806677315563879.tif", "isMoving": true }, "2": { "uri": "/tmp/img8270806677315563879.tif", - "name": "img8270806677315563879.tif channel 3", + "name": "img8270806677315563879.tif", "isMoving": false }, "3": { "uri": "/tmp/img8270806677315563879.tif", - "name": "img8270806677315563879.tif channel 4", + "name": "img8270806677315563879.tif", "isMoving": false } }, From 38d3ae55d5e979930f4c391257a578317621e8ca Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 11:32:23 -0500 Subject: [PATCH 137/282] feat: set name by dataset --- src/main/java/bigwarp/BigWarpInit.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 06cca809..0f5f2bac 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -29,12 +29,9 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; import ij.io.FileInfo; import java.util.Objects; -import net.imglib2.util.ValuePair; import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer; import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.N5TreeNode; @@ -509,7 +506,6 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina String encodedUriString = tmpUri.getRawSchemeSpecificPart(); encodedUriString = encodedUriString.replaceAll( "%23", "#" ); URI firstUri = new URI( encodedUriString ); - final int prevSacCount = bwData.sources.size(); final LinkedHashMap< Source< T >, SourceInfo > sourceStateMap = new LinkedHashMap<>(); if ( firstUri.isOpaque() ) { @@ -540,7 +536,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina } final Source< T > source = loadN5Source( n5reader, dataset ); - sourceStateMap.put( source, new SourceInfo( setupId, isMoving ) ); + sourceStateMap.put( source, new SourceInfo( setupId, isMoving, dataset) ); } else { @@ -557,7 +553,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina final String datasetQuery = firstUri.getQuery(); final String dataset = datasetQuery == null ? "/" : datasetQuery; final Source< T > source = loadN5Source( n5reader, dataset ); - sourceStateMap.put( source, new SourceInfo( setupId, isMoving ) ); + sourceStateMap.put( source, new SourceInfo( setupId, isMoving, dataset ) ); } catch ( Exception ignored ) { From adcaebe68bc8137a01c9ed4da9d6a4eab36d3f23 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 11:32:33 -0500 Subject: [PATCH 138/282] fix: get title from uri correctly --- src/main/java/bigwarp/BigWarpInit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 0f5f2bac..52fe5054 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -568,7 +568,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina final ImagePlus ijp; if ( Objects.equals( firstUri.getScheme(), "imagej" ) ) { - final String title = firstUri.getPath(); + final String title = schemeSpecificPartWithoutQuery( firstUri ); IJ.selectWindow( title ); ijp = IJ.getImage(); } From db8bc2295cfc5f98d2b95581193d75302a0830d7 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 11:32:48 -0500 Subject: [PATCH 139/282] feat(test): add serialization tests for n5/xml/imagej --- src/test/java/bigwarp/SerializationTest.java | 68 +++++++++++++++++--- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 25a68ff2..a1089616 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -24,7 +24,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import mpicbg.spim.data.SpimDataException; import net.imglib2.FinalInterval; @@ -238,7 +240,7 @@ public void sourceFromFileTest() throws SpimDataException, URISyntaxException, I bw.data.sourceInfos.forEach( (id, info) -> { Assert.assertEquals("URI Mismatch", "/tmp/img8270806677315563879.tif", info.getUri()); - Assert.assertEquals("Name Mismatch", "img8270806677315563879.tif channel " + (id + 1), info.getName()); + Assert.assertEquals("Name Mismatch", "img8270806677315563879.tif", info.getName()); Assert.assertEquals("Moving/Target Mismatch", movingById[id], info.isMoving()); } ); } @@ -252,8 +254,13 @@ public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, final String imagejUri = "imagej://generated image"; final Path xmlSourceSettings = createNewSettingsWithReplacement( "src/test/resources/settings/expected.json", - "/tmp/img8270806677315563879.tif", - imagejUri ); + new HashMap< String, String >() { + /* Map filled during construction: see: https://stackoverflow.com/questions/6802483/how-to-directly-initialize-a-hashmap-in-a-literal-way */ + { + put( "/tmp/img8270806677315563879.tif", imagejUri); + put( "img8270806677315563879.tif", "generated image" ); + } + }); final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); @@ -269,6 +276,20 @@ public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, Assert.assertEquals("Name Mismatch", "generated image", info.getName()); Assert.assertEquals("Moving/Target Mismatch", movingById[id], info.isMoving()); } ); + + + assertExpectedSettingsToCurrent( xmlSourceSettings, bw ); + } + + private static void assertExpectedSettingsToCurrent( final Path xmlSourceSettings, final BigWarp< Object > bw ) throws IOException + { + /* Save the settings and compare with initial to test the deserialization */ + final Path tempSettings = Files.createTempFile( "deserialization", ".json" ); + tempSettings.toFile().delete(); + bw.saveSettingsJson(tempSettings.toFile().getCanonicalPath()); + final JsonElement expectedJson = JsonParser.parseReader( new FileReader( xmlSourceSettings.toFile() ) ); + final JsonElement actualJson = JsonParser.parseReader( new FileReader( tempSettings.toFile() ) ); + BigWarpTestUtils.assertJsonDiff( expectedJson, actualJson ); } @Test @@ -277,8 +298,13 @@ public void sourceFromXmlTest() throws SpimDataException, URISyntaxException, IO final String xmlUri = "src/test/resources/mri-stack.xml"; final Path xmlSourceSettings = createNewSettingsWithReplacement( "src/test/resources/settings/expected.json", - "/tmp/img8270806677315563879.tif", - xmlUri ); + new HashMap< String, String >() { + /* Map filled during construction: see: https://stackoverflow.com/questions/6802483/how-to-directly-initialize-a-hashmap-in-a-literal-way */ + { + put( "/tmp/img8270806677315563879.tif", xmlUri); + put( "img8270806677315563879.tif", "channel 1" ); + } + }); final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); @@ -294,16 +320,27 @@ public void sourceFromXmlTest() throws SpimDataException, URISyntaxException, IO Assert.assertEquals("Name Mismatch", "channel 1", info.getName()); Assert.assertEquals("Moving/Target Mismatch", movingById[id], info.isMoving()); } ); + + + /* then save the settings, load it, and compare with initial to test the deserialization */ + assertExpectedSettingsToCurrent( xmlSourceSettings, bw ); } @Test public void sourceFromN5Test() throws SpimDataException, URISyntaxException, IOException, JDOMException { final String n5Uri = "src/test/resources/bigwarp/url/transformTest.n5?img"; + + /* Map filled during construction: see: https://stackoverflow.com/questions/6802483/how-to-directly-initialize-a-hashmap-in-a-literal-way */ final Path xmlSourceSettings = createNewSettingsWithReplacement( "src/test/resources/settings/expected.json", - "/tmp/img8270806677315563879.tif", - n5Uri ); + new HashMap< String, String >() { + { + put( "/tmp/img8270806677315563879.tif", n5Uri ); + put( "img8270806677315563879.tif", "img" ); + } + } + ); final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); @@ -319,14 +356,25 @@ public void sourceFromN5Test() throws SpimDataException, URISyntaxException, IOE Assert.assertEquals("Name Mismatch", "img", info.getName()); Assert.assertEquals("Moving/Target Mismatch", movingById[id], info.isMoving()); } ); + + /* then save the settings, load it, and compare with initial to test the deserialization */ + assertExpectedSettingsToCurrent( xmlSourceSettings, bw ); + } - private static Path createNewSettingsWithReplacement( final String baseSettings, final String toReplace, final String replaceWith ) throws IOException + private static Path createNewSettingsWithReplacement( final String baseSettings, final Map replacements ) throws IOException { /* Load expected.json and replace source path with desired uri */ final Path settings = Paths.get( baseSettings ); - final List< String > newLines = Files.readAllLines( settings ).stream().map( line -> line.replaceAll( toReplace, replaceWith ) ).collect( Collectors.toList()); - final Path newSettings = Files.createTempFile( "settings", "json" ); + final List< String > newLines = Files.readAllLines( settings ).stream().map( line -> { + String out = line; + for ( final Map.Entry< String, String > replaceWith : replacements.entrySet() ) + { + out = out.replaceAll( replaceWith.getKey(), replaceWith.getValue() ); + } + return out; + } ).collect( Collectors.toList()); + final Path newSettings = Files.createTempFile( "settings", ".json" ); return Files.write( newSettings, newLines ); } From 208354964326b56e937bac68c07efd1c146c18b5 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 17 Nov 2022 14:05:06 -0500 Subject: [PATCH 140/282] feat: support calling `initialize` multiple times and during deserialziation --- src/main/java/bdv/viewer/BigWarpViewerPanel.java | 10 ++++++++++ src/main/java/bigwarp/BigWarp.java | 16 ++++++++++------ src/main/java/bigwarp/BigwarpSettings.java | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index b44da8fc..3c273f11 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -211,7 +211,17 @@ public boolean isInFixedImageSpace() if( bwData.numMovingSources() < 1 ) return true; else + { + // final Source< ? > spimSource = bwData.getMovingSource( 0 ).getSpimSource(); + // final boolean isTransformed; + // if (spimSource instanceof WarpedSource) { + // isTransformed = ( ( WarpedSource< ? > ) spimSource ).isTransformed(); + // } else { + // isTransformed = false; + // } + // return !isMoving || isTransformed; return !isMoving || ( ( WarpedSource< ? > ) ( ( bwData.getMovingSource( 0 )).getSpimSource() ) ).isTransformed(); + } } public boolean doUpdateOnDrag() diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 8c6e3a24..49ee5f41 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -577,8 +577,13 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final // add landmark mode listener //addKeyEventPostProcessor( new LandmarkModeListener() ); + baselineModelIndex = 0; if( data.sources.size() > 0 ) initialize(); + + createMovingTargetGroups(); + viewerP.state().setCurrentGroup( mvgGrp ); + viewerP.state().setCurrentGroup( tgtGrp ); } public void initialize() @@ -591,9 +596,11 @@ public void initialize() if( data.numTargetSources() > 0 ) data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); - baselineModelIndex = 0; - final ARGBType white = new ARGBType( ARGBType.rgba( 255, 255, 255, 255 )); +//TODO Expose adding these sources via UI + +// final ARGBType white = new ARGBType( ARGBType.rgba( 255, 255, 255, 255 )); +// // warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "Warp magnitude" ); // jacDetSource = addJacobianDeterminantSource( data, "Jacobian determinant" ); // gridSource = addGridSource( data, "GridSource" ); @@ -638,9 +645,6 @@ public void run() InitializeViewerState.initTransform( viewerP ); InitializeViewerState.initTransform( viewerQ ); - createMovingTargetGroups(); - viewerP.state().setCurrentGroup( mvgGrp ); - viewerP.state().setCurrentGroup( tgtGrp ); } public void synchronizeSources() @@ -1923,7 +1927,7 @@ public static < T > void wrapMovingSources( final int ndims, final BigWarpData< int i = 0; for ( final SourceInfo sourceInfo : data.sourceInfos.values() ) { - if ( sourceInfo.isMoving() ) + if ( sourceInfo.isMoving() && !(sourceInfo.getSourceAndConverter().getSpimSource() instanceof WarpedSource)) { SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); final int sourceIdx = data.sources.indexOf( sourceInfo.getSourceAndConverter() ); diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 578d0781..36a0ee6d 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -290,7 +290,7 @@ public Map< Integer, SourceInfo > read( final JsonReader in ) throws IOException in.endObject(); } in.endObject(); - bigwarp.synchronizeSources(); + bigwarp.initialize(); return bigwarp.data.sourceInfos; } } From 9a7925be1800a606c96c5727ecb9c9b4214931db Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 17 Nov 2022 14:23:29 -0500 Subject: [PATCH 141/282] feat: bigwarptransform flag to request 2d transforms not wrapped as 3d --- .../bdv/ij/BigWarpToDeformationFieldPlugIn.java | 2 +- .../java/bigwarp/transforms/BigWarpTransform.java | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index fa0cc5e4..8c180dd0 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -379,7 +379,7 @@ private static RealTransform getTpsAffineToggle( BigWarpTransform bwXfm, boolean new ThinPlateR2LogRSplineKernelTransform( tps.getSourceLandmarks(), null, null, tps.getKnotWeights() ) ); } else - return bwXfm.getTransformation(); + return bwXfm.getTransformation( false ); } /** diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 4b93da12..40416ef6 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -111,10 +111,20 @@ public String getTransformType() public InvertibleRealTransform getTransformation() { - return getTransformation( -1 ); + return getTransformation( -1, true ); } public InvertibleRealTransform getTransformation( final int index ) + { + return getTransformation( index, true ); + } + + public InvertibleRealTransform getTransformation( final boolean force3D ) + { + return getTransformation( -1, force3D ); + } + + public InvertibleRealTransform getTransformation( final int index, final boolean force3D ) { InvertibleRealTransform invXfm = null; if( transformType.equals( TransformTypeSelectDialog.TPS )) @@ -137,7 +147,7 @@ public InvertibleRealTransform getTransformation( final int index ) invXfm = new ModelTransformSolver( getModelType() ).solve(mvgPts, tgtPts); } - if( tableModel.getNumdims() == 2 ) + if( force3D && tableModel.getNumdims() == 2 ) { invXfm = new Wrapped2DTransformAs3D( invXfm ); } From 38591daf647541e495ed7fb5cead835e4c7f1e8d Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 17 Nov 2022 14:43:24 -0500 Subject: [PATCH 142/282] fix: remove NgffTransformations dependencies * and n5-imglib2 SNAPSHOT dependency --- pom.xml | 1 - src/main/java/bdv/gui/BigWarpInitDialog.java | 4 ---- .../gui/sourceList/BigWarpSourceTableModel.java | 15 +++++++-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 9cd8eb68..b0b0ccb2 100644 --- a/pom.xml +++ b/pom.xml @@ -302,7 +302,6 @@ org.janelia.saalfeldlab n5-imglib2 - 5.0.0-SNAPSHOT diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 156dd160..5dc2d4cd 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -28,16 +28,12 @@ import org.janelia.saalfeldlab.n5.ij.N5Importer; import org.janelia.saalfeldlab.n5.ij.N5Importer.N5BasePathFun; import org.janelia.saalfeldlab.n5.ij.N5Importer.N5ViewerReaderFun; -import org.janelia.saalfeldlab.n5.imglib2.NgffTransformations; import org.janelia.saalfeldlab.n5.metadata.N5Metadata; import org.janelia.saalfeldlab.n5.metadata.N5MetadataParser; import org.janelia.saalfeldlab.n5.metadata.canonical.CanonicalDatasetMetadata; import org.janelia.saalfeldlab.n5.ui.DataSelection; import org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog; import org.janelia.saalfeldlab.n5.ui.N5DatasetTreeCellRenderer; -import org.scijava.command.Command; -import org.scijava.plugin.Plugin; -import org.scijava.plugin.SciJavaPlugin; import com.formdev.flatlaf.util.UIScale; diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index ffe18c6e..e497c1ec 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -13,8 +13,6 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; -import org.janelia.saalfeldlab.n5.imglib2.NgffTransformations; - import net.imglib2.realtransform.RealTransform; public class BigWarpSourceTableModel extends AbstractTableModel @@ -200,12 +198,13 @@ else if ( c == 2 ) public RealTransform getTransform() { - if( transformName != null && !transformName.isEmpty() ) - { - // TODO generalize to attributes in n5 -// final RealTransform tform = NgffTransformations.openJson( transformName ); - return NgffTransformations.openJson( transformName ); - } + // TODO depends on in progress dependencies - see dfield-dev branch +// if( transformName != null && !transformName.isEmpty() ) +// { +// // TODO generalize to attributes in n5 +//// final RealTransform tform = NgffTransformations.openJson( transformName ); +// return NgffTransformations.openJson( transformName ); +// } return null; } } From 2fc3f47d669e1cfaded74d98c3be493eddded2ee Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Sun, 20 Nov 2022 15:22:29 -0500 Subject: [PATCH 143/282] feat: add save/load project menu options --- src/main/java/bdv/gui/BigWarpInitDialog.java | 79 +++++++++------- src/main/java/bigwarp/BigWarp.java | 17 +++- src/main/java/bigwarp/BigWarpActions.java | 40 ++++++++ src/main/java/bigwarp/BigWarpInit.java | 96 ++++++++++++++++++-- 4 files changed, 188 insertions(+), 44 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 5dc2d4cd..906bb5df 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -34,6 +34,7 @@ import org.janelia.saalfeldlab.n5.ui.DataSelection; import org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog; import org.janelia.saalfeldlab.n5.ui.N5DatasetTreeCellRenderer; +import org.jdom2.JDOMException; import com.formdev.flatlaf.util.UIScale; @@ -110,7 +111,7 @@ public BigWarpInitDialog( final String title ) okayCallback = x -> { macroRecord( x ); - runBigWarp( x ); + runBigWarp( x, projectPathTxt.getText() ); }; imagePathUpdateCallback = ( p ) -> { @@ -143,58 +144,74 @@ public static void main( String[] args ) createAndShow(); } - public static void runBigWarp( BigWarpSourceTableModel sourceTable ) + public static void runBigWarp( BigWarpSourceTableModel sourceTable, String projectPath ) { final BigWarpData< T > data = BigWarpInit.initData(); final int N = sourceTable.getRowCount(); + final boolean haveProject = projectPath != null && !projectPath.isEmpty(); - int id = 0; - for( int i = 0; i < N; i++ ) + if( !haveProject ) { - SourceRow tableRow = sourceTable.get( i ); - if( tableRow.isImagePlus ) - { - final ImagePlus imp = WindowManager.getImage( tableRow.srcName ); -// id += BigWarpInit.add( data, imp, id, 0, tableRow.moving ); -// addTransform( data, tableRow ); - LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, imp, id, 0, tableRow.moving ); - BigWarpInit.add( data, infos, tableRow.getTransform() ); - } - else + int id = 0; + for( int i = 0; i < N; i++ ) { - // TODO deal with exceptions, and possibility of multiple sources per uri - try + SourceRow tableRow = sourceTable.get( i ); + if( tableRow.isImagePlus ) { -// BigWarpInit.add( data, tableRow.srcName, id, tableRow.moving ); -// addTransform( data, tableRow ); - LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, tableRow.srcName, id, tableRow.moving ); + final ImagePlus imp = WindowManager.getImage( tableRow.srcName ); + // id += BigWarpInit.add( data, imp, id, 0, tableRow.moving ); + // addTransform( data, tableRow ); + LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, imp, id, 0, tableRow.moving ); BigWarpInit.add( data, infos, tableRow.getTransform() ); } - catch ( URISyntaxException e ) - { - e.printStackTrace(); - } - catch ( IOException e ) - { - e.printStackTrace(); - } - catch ( SpimDataException e ) + else { - e.printStackTrace(); + // TODO deal with exceptions, and possibility of multiple sources per uri + try + { + // BigWarpInit.add( data, tableRow.srcName, id, tableRow.moving ); + // addTransform( data, tableRow ); + LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, tableRow.srcName, id, tableRow.moving ); + BigWarpInit.add( data, infos, tableRow.getTransform() ); + } + catch ( URISyntaxException e ) + { + e.printStackTrace(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } + id++; } - id++; } } + BigWarp bw; try { data.applyTransformations(); - new BigWarp<>( data, "BigWarp", new ProgressWriterIJ() ); + bw = new BigWarp<>( data, new ProgressWriterIJ() ); + if( haveProject ) + bw.loadSettings( projectPath ); } catch ( SpimDataException e ) { e.printStackTrace(); } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( JDOMException e ) + { + e.printStackTrace(); + } + } public JPanel createContent() diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 49ee5f41..67188385 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -863,14 +863,21 @@ public void setSpotColor( final Color c ) protected void setUpViewerMenu( final BigWarpViewerFrame vframe ) { // TODO setupviewermenu - final ActionMap actionMap = vframe.getKeybindings().getConcatenatedActionMap(); - final JMenuBar viewerMenuBar = new JMenuBar(); JMenu fileMenu = new JMenu( "File" ); viewerMenuBar.add( fileMenu ); + final JMenuItem loadProject = new JMenuItem( actionMap.get( BigWarpActions.LOAD_PROJECT ) ); + loadProject.setText( "Load project" ); + fileMenu.add( loadProject ); + + final JMenuItem saveProject = new JMenuItem( actionMap.get( BigWarpActions.SAVE_PROJECT ) ); + saveProject.setText( "Save project" ); + fileMenu.add( saveProject ); + + fileMenu.addSeparator(); final JMenuItem openItem = new JMenuItem( actionMap.get( BigWarpActions.LOAD_LANDMARKS ) ); openItem.setText( "Import landmarks" ); fileMenu.add( openItem ); @@ -2557,7 +2564,7 @@ public static void main( final String[] args ) ProgressWriterIJ progress = new ProgressWriterIJ(); - BigWarp bw; + BigWarp bw; BigWarpData bwdata; if ( fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) { @@ -3603,13 +3610,13 @@ private void addInternalSource(int id) { } } - protected void loadSettings( final String jsonOrXmlFilename ) throws IOException, + public void loadSettings( final String jsonOrXmlFilename ) throws IOException, JDOMException { loadSettings( jsonOrXmlFilename, false ); } - protected void loadSettings( final String jsonOrXmlFilename, boolean overwriteSources ) throws IOException, + public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSources ) throws IOException, JDOMException { if ( jsonOrXmlFilename.endsWith( ".xml" ) ) diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 5d8244e5..850b35c1 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -50,6 +50,9 @@ public class BigWarpActions public static final String TOGGLE_LANDMARK_MODE = "landmark mode toggle"; public static final String TRANSFORM_TYPE = "transform type"; + public static final String LOAD_PROJECT = "load project"; + public static final String SAVE_PROJECT = "save project"; + public static final String TOGGLE_POINTS_VISIBLE = "toggle points visible"; public static final String TOGGLE_POINT_NAMES_VISIBLE = "toggle point names visible"; public static final String TOGGLE_MOVING_IMAGE_DISPLAY = "toggle moving image display"; @@ -216,6 +219,9 @@ public static ActionMap createActionMapViewer( final BigWarp< ? > bw ) new SaveSettingsAction( bw ).put( actionMap ); new LoadSettingsAction( bw ).put( actionMap ); + new SaveProjectAction( bw ).put( actionMap ); + new LoadProjectAction( bw ).put( actionMap ); + return actionMap; } @@ -900,6 +906,23 @@ public void actionPerformed( final ActionEvent e ) private static final long serialVersionUID = 1L; } + public static class SaveProjectAction extends AbstractNamedAction + { + private static final long serialVersionUID = -965388576691467002L; + BigWarp< ? > bw; + public SaveProjectAction( final BigWarp< ? > bw ) + { + super( SAVE_PROJECT ); + this.bw = bw; + } + + @Override + public void actionPerformed( final ActionEvent e ) + { + bw.saveSettings(); + } + } + public static class LoadSettingsAction extends AbstractNamedAction { BigWarp< ? > bw; @@ -918,6 +941,23 @@ public void actionPerformed( final ActionEvent e ) private static final long serialVersionUID = 1L; } + public static class LoadProjectAction extends AbstractNamedAction + { + private static final long serialVersionUID = 1793182816804229398L; + BigWarp< ? > bw; + public LoadProjectAction( final BigWarp< ? > bw ) + { + super( LOAD_PROJECT ); + this.bw = bw; + } + + @Override + public void actionPerformed( final ActionEvent e ) + { + bw.loadSettings(); + } + } + public static class WarpToSelectedAction extends AbstractNamedAction { final BigWarp< ? > bw; diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 52fe5054..ab7638d1 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -1123,9 +1123,33 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source * fixed source XML * @return BigWarpData */ - public static BigWarpData< ? > createBigWarpDataFromXML( final String xmlFilenameP, final String xmlFilenameQ ) + public static BigWarpData< T > createBigWarpDataFromXML( final String xmlFilenameP, final String xmlFilenameQ ) { - return createBigWarpData( new XMLLoader( xmlFilenameP ), new XMLLoader( xmlFilenameQ ), null ); +// return createBigWarpData( new XMLLoader( xmlFilenameP ), new XMLLoader( xmlFilenameQ ), null ); + final BigWarpData< T > bwdata = BigWarpInit.initData(); + try + { + int id = 0; + LinkedHashMap< Source< T >, SourceInfo > mvgSrcs; + mvgSrcs = BigWarpInit.createSources( bwdata, xmlFilenameP, id, true ); + id += mvgSrcs.size(); + BigWarpInit.add( bwdata, mvgSrcs ); + BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, xmlFilenameQ, id, false )); + } + catch ( URISyntaxException e ) + { + e.printStackTrace(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } + + return bwdata; } /** @@ -1137,9 +1161,18 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source * fixed source ImagePlus * @return BigWarpData */ - public static BigWarpData< ? > createBigWarpDataFromImages( final ImagePlus impP, final ImagePlus impQ ) + public static BigWarpData< T > createBigWarpDataFromImages( final ImagePlus impP, final ImagePlus impQ ) { - return createBigWarpData( new ImagePlusLoader( impP ), new ImagePlusLoader( impQ ), null ); +// return createBigWarpData( new ImagePlusLoader( impP ), new ImagePlusLoader( impQ ), null ); + + int id = 0; + final BigWarpData< T > bwdata = BigWarpInit.initData(); + LinkedHashMap< Source< T >, SourceInfo > mvgSrcs = BigWarpInit.createSources( bwdata, impP, id, 0, true ); + id += mvgSrcs.size(); + BigWarpInit.add( bwdata, mvgSrcs ); + BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, impQ, id, 0, false )); + + return bwdata; } /** @@ -1195,9 +1228,32 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source * fixed source ImagePlus * @return BigWarpData */ - public static BigWarpData< ? > createBigWarpDataFromXMLImagePlus( final String xmlFilenameP, final ImagePlus impQ ) + public static BigWarpData< T > createBigWarpDataFromXMLImagePlus( final String xmlFilenameP, final ImagePlus impQ ) { - return createBigWarpData( new XMLLoader( xmlFilenameP ), new ImagePlusLoader( impQ ) ); + final BigWarpData< T > bwdata = BigWarpInit.initData(); + try + { + int id = 0; + LinkedHashMap< Source< T >, SourceInfo > mvgSrcs; + mvgSrcs = BigWarpInit.createSources( bwdata, xmlFilenameP, id, true ); + id += mvgSrcs.size(); + BigWarpInit.add( bwdata, mvgSrcs ); + BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, impQ, id, 0, false )); + } + catch ( URISyntaxException e ) + { + e.printStackTrace(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } + + return bwdata; } /** @@ -1224,9 +1280,33 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source * fixed source XML * @return BigWarpData */ - public static BigWarpData< ? > createBigWarpDataFromImagePlusXML( final ImagePlus impP, final String xmlFilenameQ ) + public static BigWarpData< T > createBigWarpDataFromImagePlusXML( final ImagePlus impP, final String xmlFilenameQ ) { - return createBigWarpData( new ImagePlusLoader( impP ), new XMLLoader( xmlFilenameQ ) ); +// return createBigWarpData( new ImagePlusLoader( impP ), new XMLLoader( xmlFilenameQ ) ); + final BigWarpData< T > bwdata = BigWarpInit.initData(); + try + { + int id = 0; + LinkedHashMap< Source< T >, SourceInfo > mvgSrcs; + mvgSrcs = BigWarpInit.createSources( bwdata, impP, id, 0, true ); + id += mvgSrcs.size(); + BigWarpInit.add( bwdata, mvgSrcs ); + BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, xmlFilenameQ, id, false )); + } + catch ( URISyntaxException e ) + { + e.printStackTrace(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } + + return bwdata; } /** From 0161ab77f6d5634fcc93c0628c4a0ee2708b48d8 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 21 Nov 2022 10:52:05 -0500 Subject: [PATCH 144/282] feat: add support to open IJ2 Datasets --- src/main/java/bdv/gui/BigWarpInitDialog.java | 134 +++++-- .../sourceList/BigWarpSourceTableModel.java | 28 +- src/main/java/bdv/ij/BigWarpCommand.java | 13 +- src/main/java/bigwarp/BigWarpInit.java | 337 ++++++++++-------- 4 files changed, 312 insertions(+), 200 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 906bb5df..e2a19426 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.net.URISyntaxException; import java.util.LinkedHashMap; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; @@ -41,6 +42,7 @@ import bdv.gui.sourceList.BigWarpSourceListPanel; import bdv.gui.sourceList.BigWarpSourceTableModel; import bdv.gui.sourceList.BigWarpSourceTableModel.SourceRow; +import bdv.gui.sourceList.BigWarpSourceTableModel.SourceType; import bdv.ij.util.ProgressWriterIJ; import bdv.viewer.Source; import bigwarp.BigWarp; @@ -53,14 +55,15 @@ import ij.WindowManager; import ij.plugin.frame.Recorder; import mpicbg.spim.data.SpimDataException; -import net.imagej.ImageJ; -import net.imglib2.realtransform.RealTransform; +import net.imagej.Dataset; +import net.imagej.DatasetService; public class BigWarpInitDialog extends JFrame { private static final long serialVersionUID = -2914972130819029899L; private boolean imageJOpen; + private DatasetService datasetService; private String initialPath; private JTextField projectPathTxt, containerPathText, transformPathText; @@ -92,8 +95,14 @@ public BigWarpInitDialog() } public BigWarpInitDialog( final String title ) + { + this( title, null ); + } + + public BigWarpInitDialog( final String title, final DatasetService datasetService ) { super( title ); + this.datasetService = datasetService; initialPath = ""; imageJOpen = IJ.getInstance() != null; @@ -111,7 +120,7 @@ public BigWarpInitDialog( final String title ) okayCallback = x -> { macroRecord( x ); - runBigWarp( x, projectPathTxt.getText() ); + runBigWarp( x, projectPathTxt.getText(), datasetService ); }; imagePathUpdateCallback = ( p ) -> { @@ -125,12 +134,12 @@ public BigWarpInitDialog( final String title ) }; } - public static void main( String[] args ) + public static void main( String[] args ) throws IOException { // ImageJ ij2 = new ImageJ(); // ij2.ui().showUI(); - ImageJ ij = new ImageJ(); +// ImageJ ij = new ImageJ(); // // IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); // IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); @@ -138,13 +147,13 @@ public static void main( String[] args ) // IJ.openImage( "/home/john/tmp/boats.tif" ).show(); // IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); // - IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); - IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); +// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); +// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); createAndShow(); } - public static void runBigWarp( BigWarpSourceTableModel sourceTable, String projectPath ) + public static void runBigWarp( BigWarpSourceTableModel sourceTable, String projectPath, DatasetService datasetService ) { final BigWarpData< T > data = BigWarpInit.initData(); final int N = sourceTable.getRowCount(); @@ -155,24 +164,32 @@ public static void runBigWarp( BigWarpSourceTableModel sourceTable, String p int id = 0; for( int i = 0; i < N; i++ ) { + System.out.println( "id : " + id ); SourceRow tableRow = sourceTable.get( i ); - if( tableRow.isImagePlus ) + if( tableRow.type.equals( SourceType.IMAGEPLUS ) ) { final ImagePlus imp = WindowManager.getImage( tableRow.srcName ); - // id += BigWarpInit.add( data, imp, id, 0, tableRow.moving ); - // addTransform( data, tableRow ); LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, imp, id, 0, tableRow.moving ); BigWarpInit.add( data, infos, tableRow.getTransform() ); + id += infos.size(); + } + else if( tableRow.type.equals( SourceType.DATASET )) + { + Dataset dataset = datasetService.getDatasets().stream() + .filter( x -> x.getSource().equals( tableRow.srcName ) ) + .findFirst().get(); + LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, dataset, id, tableRow.moving ); + BigWarpInit.add( data, infos, tableRow.getTransform() ); + id += infos.size(); } else { - // TODO deal with exceptions, and possibility of multiple sources per uri + // TODO deal with exceptions try { - // BigWarpInit.add( data, tableRow.srcName, id, tableRow.moving ); - // addTransform( data, tableRow ); LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, tableRow.srcName, id, tableRow.moving ); BigWarpInit.add( data, infos, tableRow.getTransform() ); + id += infos.size(); } catch ( URISyntaxException e ) { @@ -186,12 +203,11 @@ public static void runBigWarp( BigWarpSourceTableModel sourceTable, String p { e.printStackTrace(); } - id++; } } } - BigWarp bw; + BigWarp bw; try { data.applyTransformations(); @@ -295,7 +311,7 @@ public JPanel createContent() cadd.gridy = 1; addImageButton = new JButton("+"); panel.add( addImageButton, cadd ); - addImageButton.addActionListener( e -> { addImagePlus(); }); + addImageButton.addActionListener( e -> { addImage(); }); ctxt.gridy = 2; final JLabel addFileLabel = new JLabel( "Add image file/folder:"); @@ -461,13 +477,27 @@ public void n5DialogCallback( DataSelection selection ) repaint(); } - protected void addImagePlus() + protected void addImage() { - if ( !imageJOpen ) + if ( !imageJOpen && datasetService == null) return; - final String title = (String)(imagePlusDropdown.getSelectedItem()); - addImagePlus( title ); + if( datasetService != null ) + { + final String title = (String)(imagePlusDropdown.getSelectedItem()); + addDataset( title, false ); + } + else + { + final String title = (String)(imagePlusDropdown.getSelectedItem()); + addImagePlus( title ); + } + this.repaint(); + } + + protected void addDataset( String datasetSource, boolean moving ) + { + sourceTableModel.addDataset( datasetSource, moving ); } protected void addImagePlus( String title ) @@ -514,20 +544,32 @@ protected void addTransform() protected void updateImagePlusDropdown() { - if( !imageJOpen ) + if( !imageJOpen && datasetService == null ) return; - // don't need any open windows if we're using N5 - final int[] ids = WindowManager.getIDList(); + final String[] titles; + if( datasetService != null ) + { + int i = 0; + titles = new String[ datasetService.getDatasets().size() ]; + for( Dataset d : datasetService.getDatasets() ) + titles[i++] = d.getSource(); + } + else + { + // don't need any open windows if we're using N5 + final int[] ids = WindowManager.getIDList(); - // Find any open images - final int N = ids == null ? 0 : ids.length; + // Find any open images + final int N = ids == null ? 0 : ids.length; + + titles = new String[ N ]; + for ( int i = 0; i < N; ++i ) + { + titles[ i ] = ( WindowManager.getImage( ids[ i ] )).getTitle(); + } + } - final String[] titles = new String[ N ]; - for ( int i = 0; i < N; ++i ) - { - titles[ i ] = ( WindowManager.getImage( ids[ i ] )).getTitle(); - } imagePlusDropdown.setModel( new DefaultComboBoxModel<>( titles )); } @@ -541,10 +583,20 @@ public void initializeImagePlusSources() { final int N = imagePlusDropdown.getModel().getSize(); if ( N > 0 ) - addImagePlus( ( String ) imagePlusDropdown.getItemAt( 0 ), true ); + { + if( datasetService == null ) + addImagePlus( ( String ) imagePlusDropdown.getItemAt( 0 ), true ); + else + addDataset( ( String ) imagePlusDropdown.getItemAt( 0 ), false ); + } if ( N > 1 ) - addImagePlus( ( String ) imagePlusDropdown.getItemAt( 1 ), false ); + { + if( datasetService == null ) + addImagePlus( ( String ) imagePlusDropdown.getItemAt( 1 ), true ); + else + addDataset( ( String ) imagePlusDropdown.getItemAt( 1 ), false ); + } } public void fillTableFromProject() @@ -553,12 +605,18 @@ public void fillTableFromProject() System.out.println( "implement me" ); } - public static void createAndShow() { - //Create and set up the window. - BigWarpInitDialog frame = new BigWarpInitDialog("BigWarp"); + public static void createAndShow() + { + createAndShow( null ); + } + + public static void createAndShow( DatasetService datasets ) + { + // Create and set up the window. + BigWarpInitDialog frame = new BigWarpInitDialog( "BigWarp", datasets ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); - frame.setVisible(true); - } + frame.setVisible( true ); + } private String browseDialogGeneral( final int mode, final FileFilter filefilter ) { diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index e497c1ec..919cd92b 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -17,8 +17,10 @@ public class BigWarpSourceTableModel extends AbstractTableModel { + private static final long serialVersionUID = 5923947651732788341L; + public static enum SourceType { IMAGEPLUS, DATASET, URL }; protected final static String[] colNames = new String[] { "Name", "Moving", "Transform", " " }; protected final String[] columnNames; @@ -102,7 +104,7 @@ public void setValueAt(Object value, int row, int col) sources.get( row ).moving = (Boolean)value; } - public void add( String srcName, boolean moving, boolean isImagePlus ) + public void add( String srcName, boolean moving, SourceType type ) { final RemoveRowButton rmButton = new RemoveRowButton( sources.size() ); // rmButton.addActionListener( e -> { @@ -111,7 +113,7 @@ public void add( String srcName, boolean moving, boolean isImagePlus ) // }); rmRowButtons.add( rmButton ); - sources.add( new SourceRow( srcName, moving, "", isImagePlus )); + sources.add( new SourceRow( srcName, moving, "", type )); } public void setTransform( int i, String transform ) @@ -121,7 +123,7 @@ public void setTransform( int i, String transform ) public void add( String srcName, boolean moving ) { - add( srcName, moving, false ); + add( srcName, moving, SourceType.URL ); } public void add( String srcName ) @@ -136,7 +138,17 @@ public void addImagePlus( String srcName ) public void addImagePlus( String srcName, boolean isMoving ) { - add( srcName, isMoving, true ); + add( srcName, isMoving, SourceType.DATASET ); + } + + public void addDataset( String srcName ) + { + addImagePlus( srcName, false ); + } + + public void addDataset( String srcName, boolean isMoving ) + { + add( srcName, isMoving, SourceType.DATASET ); } public boolean remove( int i ) @@ -169,19 +181,19 @@ public static class SourceRow public boolean moving; public String transformName; - public boolean isImagePlus; + public SourceType type; - public SourceRow( String srcName, boolean moving, String transformName, boolean isImagePlus ) + public SourceRow( String srcName, boolean moving, String transformName, SourceType type ) { this.srcName = srcName; this.moving = moving; this.transformName = transformName; - this.isImagePlus = isImagePlus; + this.type = type; } public SourceRow( String srcName, boolean moving, String transformName ) { - this( srcName, moving, transformName, false ); + this( srcName, moving, transformName, SourceType.URL ); } public Object get( int c ) diff --git a/src/main/java/bdv/ij/BigWarpCommand.java b/src/main/java/bdv/ij/BigWarpCommand.java index 55d1347e..156e551f 100644 --- a/src/main/java/bdv/ij/BigWarpCommand.java +++ b/src/main/java/bdv/ij/BigWarpCommand.java @@ -1,23 +1,32 @@ package bdv.ij; import java.io.IOException; +import java.util.List; +import java.util.Map; import org.scijava.command.Command; +import org.scijava.command.CommandService; +import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; import bdv.gui.BigWarpInitDialog; import ij.IJ; +import net.imagej.Dataset; +import net.imagej.DatasetService; import net.imagej.ImageJ; @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp Command" ) public class BigWarpCommand implements Command { + @Parameter + private DatasetService datasets; + @Override public void run() { - BigWarpInitDialog.createAndShow(); + BigWarpInitDialog.createAndShow( datasets ); } - + public static void main( String[] args ) throws IOException { ImageJ ij2 = new ImageJ(); diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index ab7638d1..0d5437b4 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -32,6 +32,7 @@ import ij.io.FileInfo; import java.util.Objects; + import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer; import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.N5TreeNode; @@ -60,6 +61,7 @@ import bdv.tools.brightness.SetupAssignments; import bdv.tools.transformation.TransformedSource; import bdv.util.RandomAccessibleIntervalMipmapSource; +import bdv.util.RandomAccessibleIntervalSource; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bigwarp.loader.ImagePlusLoader; @@ -80,6 +82,9 @@ import mpicbg.spim.data.sequence.Angle; import mpicbg.spim.data.sequence.Channel; import mpicbg.spim.data.sequence.FinalVoxelDimensions; +import net.imagej.Dataset; +import net.imagej.axis.Axes; +import net.imagej.axis.CalibratedAxis; import net.imglib2.RandomAccessibleInterval; import net.imglib2.converter.Converter; import net.imglib2.converter.Converters; @@ -322,7 +327,7 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > for ( Source< ? > mvgSource : movingSourceList ) { add( data, mvgSource, setupId, 1, true ); - final SourceAndConverter addedSource = ( ( BigWarpData< ? > ) data ).sources.get( data.sources.size() - 1 ); + final SourceAndConverter< ? > addedSource = ( ( BigWarpData< ? > ) data ).sources.get( data.sources.size() - 1 ); final SourceInfo info = new SourceInfo( setupId, true, names[ nameIdx++ ] ); info.setSourceAndConverter( addedSource ); data.sourceInfos.put( setupId++, info ); @@ -332,10 +337,10 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > for ( Source< ? > fxdSource : fixedSourceList ) { add( data, fxdSource, setupId, 1, false ); - final SourceAndConverter addedSource = ( ( BigWarpData< ? > ) data ).sources.get( data.sources.size() - 1 ); + final SourceAndConverter< ? > addedSource = ( ( BigWarpData< ? > ) data ).sources.get( data.sources.size() - 1 ); final SourceInfo info = new SourceInfo( setupId, false, names[ nameIdx++ ] ); - info.setSourceAndConverter( addedSource); - data.sourceInfos.put( setupId++, info); + info.setSourceAndConverter( addedSource ); + data.sourceInfos.put( setupId++, info ); } data.wrapUp(); @@ -346,9 +351,9 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > final AtomicInteger sourceInfoIdx = new AtomicInteger(); final BigWarpData< ? > typedData = data; - typedData.sourceInfos.forEach((id, info) -> { + typedData.sourceInfos.forEach( ( id, info ) -> { info.setSourceAndConverter( typedData.sources.get( sourceInfoIdx.getAndIncrement() ) ); - }); + } ); return new BigWarpData( wrappedSources, data.converterSetups, data.cache ); @@ -360,7 +365,10 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > /** * @return * - * @Deprecated Use {@link #createSources(BigWarpData, ImagePlus, int, int, boolean)} instaed, and pass output to {@link #add(BigWarpData, LinkedHashMap, RealTransform)} + * @Deprecated Use + * {@link #createSources(BigWarpData, ImagePlus, int, int, boolean)} + * instaed, and pass output to + * {@link #add(BigWarpData, LinkedHashMap, RealTransform)} */ @SuppressWarnings( { "rawtypes" } ) @Deprecated @@ -385,14 +393,17 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW } sourceInfoMap.forEach( ( sac, state ) -> { - state.setUriSupplier(() -> { + state.setUriSupplier( () -> { final FileInfo originalFileInfo = ip.getOriginalFileInfo(); - if (originalFileInfo != null) { + if ( originalFileInfo != null ) + { final String url = originalFileInfo.url; if ( url != null && !url.isEmpty() ) { return url; - } else { + } + else + { return originalFileInfo.getFilePath(); } } @@ -412,22 +423,26 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW /** * @return * - * @Deprecated Use the output from one of the {{@link #createSources(BigWarpData, String, int, boolean)}} to call {{@link #add(BigWarpData, LinkedHashMap)}} instead + * @Deprecated Use the output from one of the + * {{@link #createSources(BigWarpData, String, int, boolean)}} + * to call {{@link #add(BigWarpData, LinkedHashMap)}} instead */ - @SuppressWarnings( { "rawtypes" } ) @Deprecated public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > src, int setupId, int numTimepoints, boolean isMoving ) { return add( bwdata, src, setupId, numTimepoints, isMoving, null ); } - public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > source, SourceInfo sourceInfo ) { + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > source, SourceInfo sourceInfo ) + { return add( bwdata, source, sourceInfo ); } - public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > source, SourceInfo sourceInfo, RealTransform transform) { + + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > source, SourceInfo sourceInfo, RealTransform transform ) + { final LinkedHashMap< Source< T >, SourceInfo > sourceToInfo = new LinkedHashMap<>(); sourceToInfo.put( source, sourceInfo ); - return add(bwdata, sourceToInfo, transform); + return add( bwdata, sourceToInfo, transform ); } public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap< Source< T >, SourceInfo > sources ) @@ -439,7 +454,11 @@ public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap /** * @return * - * @Deprecated Use the output from one of the {{@link #createSources(BigWarpData, String, int, boolean)}} to call {{@link #add(BigWarpData, LinkedHashMap, RealTransform)}} instead + * @Deprecated Use the output from one of the + * {{@link #createSources(BigWarpData, String, int, boolean)}} + * to call + * {{@link #add(BigWarpData, LinkedHashMap, RealTransform)}} + * instead */ @SuppressWarnings( { "unchecked", "rawtypes" } ) @Deprecated @@ -454,45 +473,100 @@ public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap { sources.forEach( ( source, info ) -> { addSourceToListsGenericType( source, info.getId(), bwdata.converterSetups, bwdata.sources ); - final SourceAndConverter addedSource = bwdata.sources.get( bwdata.sources.size() -1 ); + final SourceAndConverter< T > addedSource = bwdata.sources.get( bwdata.sources.size() - 1 ); info.setSourceAndConverter( addedSource ); if ( transform != null ) { info.setTransform( transform ); -// bwdata.transforms.add( transform ); } bwdata.sourceInfos.put( info.getId(), info ); } ); return bwdata; } + @SuppressWarnings( { "rawtypes" } ) + public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigWarpData bwdata, Dataset data, int baseId, final boolean isMoving ) + { + boolean first = true; + final LinkedHashMap< Source< T >, SourceInfo > sourceInfoMap = new LinkedHashMap<>(); + + AffineTransform3D res = datasetResolution( data ); + final long nc = data.getChannels(); + if ( nc > 1 ) + { + CalibratedAxis[] axes = new CalibratedAxis[ data.numDimensions() ]; + data.axes( axes ); + int channelIdx = -1; + for ( int i = 0; i < data.numDimensions(); i++ ) + { + if ( axes[ i ].type().equals( Axes.CHANNEL ) ) + { + channelIdx = i; + break; + } + } + + for ( int c = 0; c < nc; c++ ) + { + @SuppressWarnings( "unchecked" ) + RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( Views.hyperSlice( data, channelIdx, c ), Util.getTypeFromInterval( data ), res, data.getName() ); + + final SourceInfo info = new SourceInfo( baseId + c, isMoving, data.getName(), () -> data.getSource() ); + info.setSerializable( first ); + if ( first ) + first = false; + + sourceInfoMap.put( source, info ); + } + } + else + { + @SuppressWarnings( "unchecked" ) + RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( data, Util.getTypeFromInterval( data ), res, data.getName() ); + + final SourceInfo info = new SourceInfo( baseId, isMoving, data.getName(), () -> data.getSource() ); + info.setSerializable( true ); + sourceInfoMap.put( source, info ); + } + + return sourceInfoMap; + } + + public static AffineTransform3D datasetResolution( Dataset data ) + { + final AffineTransform3D affine = new AffineTransform3D(); + final CalibratedAxis[] axes = new CalibratedAxis[ data.numDimensions() ]; + data.axes( axes ); + + for ( int d = 0; d < data.numDimensions(); d++ ) + { + if ( axes[ d ].type().equals( Axes.X ) ) + affine.set( axes[ d ].calibratedValue( 1 ), 0, 0 ); + else if ( axes[ d ].type().equals( Axes.Y ) ) + affine.set( axes[ d ].calibratedValue( 1 ), 1, 1 ); + else if ( axes[ d ].type().equals( Axes.Z ) ) + affine.set( axes[ d ].calibratedValue( 1 ), 2, 2 ); + } + return affine; + } + @SuppressWarnings( { "rawtypes" } ) public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigWarpData bwdata, AbstractSpimData< ? > data, int baseId, final boolean isMoving ) { - final List> tmpSources = new ArrayList<>(); - final List tmpConverterSetups = new ArrayList<>(); + final List< SourceAndConverter< ? > > tmpSources = new ArrayList<>(); + final List< ConverterSetup > tmpConverterSetups = new ArrayList<>(); initSetups( data, tmpConverterSetups, tmpSources ); final LinkedHashMap< Source< T >, SourceInfo > sourceInfoMap = new LinkedHashMap<>(); int setupId = baseId; for ( SourceAndConverter sac : tmpSources ) { - final Source source = sac.getSpimSource(); + final Source< T > source = sac.getSpimSource(); sourceInfoMap.put( source, new SourceInfo( setupId++, isMoving, source.getName() ) ); } return sourceInfoMap; - -// int N = bwdata.sources.size(); -// final ArrayList idxList; -// if ( isMoving ) -// idxList = bwdata.movingSourceIndexList; -// else -// idxList = bwdata.targetSourceIndexList; -// -// for( int i = startSize; i < N; i++ ) -// idxList.add( i ); } private static String schemeSpecificPartWithoutQuery( URI uri ) @@ -536,16 +610,13 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina } final Source< T > source = loadN5Source( n5reader, dataset ); - sourceStateMap.put( source, new SourceInfo( setupId, isMoving, dataset) ); + sourceStateMap.put( source, new SourceInfo( setupId, isMoving, dataset ) ); } else { firstUri = new URI( encodedUriString.replaceAll( "%23", "#" ) ); final String firstSchemeSpecificPartMinusQuery = schemeSpecificPartWithoutQuery( firstUri ); - final boolean skipScheme = firstUri.getScheme() == null - || firstUri.getScheme().trim().isEmpty() - || firstUri.getScheme().trim().equalsIgnoreCase( "n5" ) - || firstUri.getScheme().trim().equalsIgnoreCase( "file" ); + final boolean skipScheme = firstUri.getScheme() == null || firstUri.getScheme().trim().isEmpty() || firstUri.getScheme().trim().equalsIgnoreCase( "n5" ) || firstUri.getScheme().trim().equalsIgnoreCase( "file" ); final String firstSchemeAndPath = skipScheme ? firstSchemeSpecificPartMinusQuery : firstUri.getScheme() + "://" + firstSchemeSpecificPartMinusQuery; try { @@ -556,9 +627,9 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina sourceStateMap.put( source, new SourceInfo( setupId, isMoving, dataset ) ); } catch ( Exception ignored ) + {} + if ( sourceStateMap.isEmpty() ) { - } - if ( sourceStateMap.isEmpty() ) { if ( firstSchemeAndPath.trim().toLowerCase().endsWith( ".xml" ) ) { sourceStateMap.putAll( createSources( bwData, isMoving, setupId, firstSchemeAndPath, firstUri.getQuery() ) ); @@ -586,7 +657,10 @@ else if ( new File( uri ).isDirectory() ) } - /* override any already set urls with the uri we used to load this source. */ + /* + * override any already set urls with the uri we used to load this + * source. + */ sourceStateMap.forEach( ( source, state ) -> { state.setUriSupplier( () -> uri ); } ); @@ -602,15 +676,14 @@ else if ( new File( uri ).isDirectory() ) /** * @return * - * @Deprecated Use output froom {@link #createSources(BigWarpData, boolean, int, String, String)} and add with {@link #add(BigWarpData, LinkedHashMap, RealTransform)} instead. + * @Deprecated Use output froom + * {@link #createSources(BigWarpData, boolean, int, String, String)} + * and add with + * {@link #add(BigWarpData, LinkedHashMap, RealTransform)} + * instead. */ @Deprecated - public static < T > SpimData addToData( - final BigWarpData< T > bwdata, - final boolean isMoving, - final int setupId, - final String rootPath, - final String dataset ) + public static < T > SpimData addToData( final BigWarpData< T > bwdata, final boolean isMoving, final int setupId, final String rootPath, final String dataset ) { final AtomicReference< SpimData > returnMovingSpimData = new AtomicReference<>(); final LinkedHashMap< Source< T >, SourceInfo > sources = createSources( bwdata, isMoving, setupId, rootPath, dataset, returnMovingSpimData ); @@ -618,25 +691,14 @@ public static < T > SpimData addToData( return returnMovingSpimData.get(); } - public static < T > Map< Source< T >, SourceInfo > createSources( - final BigWarpData< T > bwdata, - final boolean isMoving, - final int setupId, - final String rootPath, - final String dataset ) + public static < T > Map< Source< T >, SourceInfo > createSources( final BigWarpData< T > bwdata, final boolean isMoving, final int setupId, final String rootPath, final String dataset ) { return createSources( bwdata, isMoving, setupId, rootPath, dataset, null ); } - private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( - final BigWarpData< T > bwdata, - final boolean isMoving, - final int setupId, - final String rootPath, - final String dataset, - final AtomicReference< SpimData > returnMovingSpimData ) + private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( final BigWarpData< T > bwdata, final boolean isMoving, final int setupId, final String rootPath, final String dataset, final AtomicReference< SpimData > returnMovingSpimData ) { - if( rootPath.endsWith( "xml" )) + if ( rootPath.endsWith( "xml" ) ) { SpimData spimData; try @@ -669,7 +731,10 @@ private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( } return sources; } - catch ( SpimDataException e ) { e.printStackTrace(); } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } return null; } else @@ -690,34 +755,26 @@ public static < T > Source< T > loadN5Source( final String n5Root, final String { n5 = new N5Factory().openReader( n5Root ); } - catch ( IOException e ) { + catch ( IOException e ) + { e.printStackTrace(); return null; } return loadN5Source( n5, n5Dataset ); } + public static < T > Source< T > loadN5Source( final N5Reader n5, final String n5Dataset ) { - final N5MetadataParser[] PARSERS = new N5MetadataParser[]{ - new ImagePlusLegacyMetadataParser(), - new N5CosemMetadataParser(), - new N5SingleScaleMetadataParser(), - new CanonicalMetadataParser(), - new N5GenericSingleScaleMetadataParser() + final N5MetadataParser< ? >[] PARSERS = new N5MetadataParser[] { new ImagePlusLegacyMetadataParser(), new N5CosemMetadataParser(), new N5SingleScaleMetadataParser(), new CanonicalMetadataParser(), new N5GenericSingleScaleMetadataParser() }; - final N5MetadataParser[] GROUP_PARSERS = new N5MetadataParser[]{ - new N5CosemMultiScaleMetadata.CosemMultiScaleParser(), - new N5ViewerMultiscaleMetadataParser(), - new CanonicalMetadataParser(), + final N5MetadataParser< ? >[] GROUP_PARSERS = new N5MetadataParser[] { new N5CosemMultiScaleMetadata.CosemMultiScaleParser(), new N5ViewerMultiscaleMetadataParser(), new CanonicalMetadataParser(), }; N5Metadata meta = null; try { - final N5DatasetDiscoverer discoverer = new N5DatasetDiscoverer( n5, - N5DatasetDiscoverer.fromParsers(PARSERS), - N5DatasetDiscoverer.fromParsers(GROUP_PARSERS) ); + final N5DatasetDiscoverer discoverer = new N5DatasetDiscoverer( n5, N5DatasetDiscoverer.fromParsers( PARSERS ), N5DatasetDiscoverer.fromParsers( GROUP_PARSERS ) ); final N5TreeNode node = discoverer.discoverAndParseRecursive( n5Dataset ); meta = node.getMetadata(); @@ -725,9 +782,9 @@ public static < T > Source< T > loadN5Source( final N5Reader n5, final String n5 catch ( IOException e ) {} - if( meta instanceof MultiscaleMetadata ) + if ( meta instanceof MultiscaleMetadata ) { - return openAsSourceMulti( n5, (MultiscaleMetadata)meta, true ); + return openAsSourceMulti( n5, ( MultiscaleMetadata< ? > ) meta, true ); } else { @@ -742,33 +799,28 @@ public static < T, M extends N5Metadata > Source< T > openAsSource( final N5Read final RandomAccessibleInterval image; try { - if( isVolatile ) - imageRaw = to3d( N5Utils.openVolatile( n5, meta.getPath() )); + if ( isVolatile ) + imageRaw = to3d( N5Utils.openVolatile( n5, meta.getPath() ) ); else - imageRaw = to3d( N5Utils.open( n5, meta.getPath() )); + imageRaw = to3d( N5Utils.open( n5, meta.getPath() ) ); - if( meta instanceof N5ImagePlusMetadata - && ((N5ImagePlusMetadata)meta).getType() == ImagePlus.COLOR_RGB - && Util.getTypeFromInterval( imageRaw ) instanceof UnsignedIntType ) + if ( meta instanceof N5ImagePlusMetadata && ( ( N5ImagePlusMetadata ) meta ).getType() == ImagePlus.COLOR_RGB && Util.getTypeFromInterval( imageRaw ) instanceof UnsignedIntType ) { image = toColor( imageRaw ); } else image = imageRaw; - if( meta instanceof SpatialMetadata ) + if ( meta instanceof SpatialMetadata ) { - final String unit = ((SpatialMetadata)meta).unit(); - final AffineTransform3D srcXfm = ((SpatialMetadata)meta).spatialTransform3d(); - final FinalVoxelDimensions voxelDims = new FinalVoxelDimensions( unit, - new double[]{ srcXfm.get( 0, 0 ), srcXfm.get( 1, 1 ), srcXfm.get( 2, 2 ) }); + final String unit = ( ( SpatialMetadata ) meta ).unit(); + final AffineTransform3D srcXfm = ( ( SpatialMetadata ) meta ).spatialTransform3d(); + final FinalVoxelDimensions voxelDims = new FinalVoxelDimensions( unit, new double[] { srcXfm.get( 0, 0 ), srcXfm.get( 1, 1 ), srcXfm.get( 2, 2 ) } ); - return new BwRandomAccessibleIntervalSource( image, (NumericType ) Util.getTypeFromInterval( image ), - srcXfm, meta.getPath(), voxelDims ); + return new BwRandomAccessibleIntervalSource( image, ( NumericType ) Util.getTypeFromInterval( image ), srcXfm, meta.getPath(), voxelDims ); } else - return new BwRandomAccessibleIntervalSource( image, ( NumericType ) Util.getTypeFromInterval( image ), - new AffineTransform3D(), meta.getPath() ); + return new BwRandomAccessibleIntervalSource( image, ( NumericType ) Util.getTypeFromInterval( image ), new AffineTransform3D(), meta.getPath() ); } catch ( IOException e ) { @@ -778,23 +830,23 @@ public static < T, M extends N5Metadata > Source< T > openAsSource( final N5Read return null; } - public static < T > Source< T > openAsSourceMulti( final N5Reader n5, final MultiscaleMetadata multiMeta, final boolean isVolatile ) + public static < T > Source< T > openAsSourceMulti( final N5Reader n5, final MultiscaleMetadata< ? > multiMeta, final boolean isVolatile ) { final String[] paths = multiMeta.getPaths(); final AffineTransform3D[] transforms = multiMeta.spatialTransforms3d(); - final String unit = multiMeta.units()[0]; + final String unit = multiMeta.units()[ 0 ]; @SuppressWarnings( "rawtypes" ) - final RandomAccessibleInterval[] images = new RandomAccessibleInterval[paths.length]; + final RandomAccessibleInterval[] images = new RandomAccessibleInterval[ paths.length ]; final double[][] mipmapScales = new double[ images.length ][ 3 ]; for ( int s = 0; s < images.length; ++s ) { try { - if( isVolatile ) - images[ s ] = to3d( N5Utils.openVolatile( n5, paths[s] )); + if ( isVolatile ) + images[ s ] = to3d( N5Utils.openVolatile( n5, paths[ s ] ) ); else - images[ s ] = to3d( N5Utils.open( n5, paths[s] )); + images[ s ] = to3d( N5Utils.open( n5, paths[ s ] ) ); } catch ( IOException e ) { @@ -807,37 +859,29 @@ public static < T > Source< T > openAsSourceMulti( final N5Reader n5, final Mult } @SuppressWarnings( { "unchecked", "rawtypes" } ) - final RandomAccessibleIntervalMipmapSource source = new RandomAccessibleIntervalMipmapSource( - images, - (NumericType ) Util.getTypeFromInterval(images[0]), - mipmapScales, - new mpicbg.spim.data.sequence.FinalVoxelDimensions( unit, mipmapScales[0]), - new AffineTransform3D(), - multiMeta.getPaths()[0] + "_group" ); + final RandomAccessibleIntervalMipmapSource source = new RandomAccessibleIntervalMipmapSource( images, ( NumericType ) Util.getTypeFromInterval( images[ 0 ] ), mipmapScales, new mpicbg.spim.data.sequence.FinalVoxelDimensions( unit, mipmapScales[ 0 ] ), new AffineTransform3D(), multiMeta.getPaths()[ 0 ] + "_group" ); return source; } - private static RandomAccessibleInterval to3d( RandomAccessibleInterval img ) + private static RandomAccessibleInterval< ? > to3d( RandomAccessibleInterval< ? > img ) { - if( img.numDimensions() == 2 ) + if ( img.numDimensions() == 2 ) return Views.addDimension( img, 0, 0 ); else return img; } - private static RandomAccessibleInterval toColor( RandomAccessibleInterval img ) + private static RandomAccessibleInterval< ARGBType > toColor( RandomAccessibleInterval< UnsignedIntType > img ) { - return Converters.convertRAI( img, - new Converter() - { - @Override - public void convert( UnsignedIntType input, ARGBType output ) - { - output.set( input.getInt() ); - } - }, - new ARGBType() ); + return Converters.convertRAI( img, new Converter< UnsignedIntType, ARGBType >() + { + @Override + public void convert( UnsignedIntType input, ARGBType output ) + { + output.set( input.getInt() ); + } + }, new ARGBType() ); } @SuppressWarnings( { "rawtypes", "unchecked" } ) @@ -867,11 +911,7 @@ public static < T > BigWarpData< T > initData() * be added. */ @SuppressWarnings( { "rawtypes", "unchecked" } ) - private static < T > void addSourceToListsGenericType( - final Source< T > source, - final int setupId, - final List< ConverterSetup > converterSetups, - final List< SourceAndConverter< T > > sources ) + private static < T > void addSourceToListsGenericType( final Source< T > source, final int setupId, final List< ConverterSetup > converterSetups, final List< SourceAndConverter< T > > sources ) { final T type = source.getType(); if ( type instanceof RealType || type instanceof ARGBType || type instanceof VolatileARGBType ) @@ -897,15 +937,10 @@ private static < T > void addSourceToListsGenericType( * list of {@link SourceAndConverter}s to which the source should * be added. */ - private static < T extends NumericType< T > > void addSourceToListsNumericType( - final Source< T > source, - final int setupId, - final List< ConverterSetup > converterSetups, - final List< SourceAndConverter< T > > sources ) + private static < T extends NumericType< T > > void addSourceToListsNumericType( final Source< T > source, final int setupId, final List< ConverterSetup > converterSetups, final List< SourceAndConverter< T > > sources ) { final T type = source.getType(); - final SourceAndConverter< T > soc = BigDataViewer.wrapWithTransformedSource( - new SourceAndConverter<>( source, BigDataViewer.createConverterToARGB( type ) ) ); + final SourceAndConverter< T > soc = BigDataViewer.wrapWithTransformedSource( new SourceAndConverter<>( source, BigDataViewer.createConverterToARGB( type ) ) ); converterSetups.add( BigDataViewer.createConverterSetup( soc, setupId ) ); sources.add( soc ); } @@ -1012,7 +1047,6 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source // List movingSourceIndices = IntStream.range( 0, numMovingSources ).collect( Collectors.toList()); // List targetSourceIndices = IntStream.range( numMovingSources, numTargetSources + numMovingSources ) // .collect( Collectors.toList()); - /* Load the second source */ BigWarpInit.initSetups( spimDataQ, converterSetups, sources ); @@ -1025,8 +1059,7 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source return createBigWarpData( loaderP, loaderQ, null ); } - public static BigWarpData< ? > createBigWarpData( final ImagePlusLoader loaderP, final ImagePlusLoader loaderQ, - final String[] names ) + public static BigWarpData< ? > createBigWarpData( final ImagePlusLoader loaderP, final ImagePlusLoader loaderQ, final String[] names ) { /* Load the first source */ final AbstractSpimData< ? >[] spimDataP = loaderP.loadAll( 0 ); @@ -1075,29 +1108,29 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source { /* Load the moving sources */ final AbstractSpimData< ? >[] spimDataP; - if( loaderP instanceof ImagePlusLoader ) + if ( loaderP instanceof ImagePlusLoader ) spimDataP = loaderP.load(); - else + else spimDataP = loaderP.load(); /* Load the fixed sources */ final AbstractSpimData< ? >[] spimDataQ; - if( loaderQ instanceof ImagePlusLoader ) - spimDataQ = ((ImagePlusLoader)loaderQ).loadAll( spimDataP.length ); + if ( loaderQ instanceof ImagePlusLoader ) + spimDataQ = ( ( ImagePlusLoader ) loaderQ ).loadAll( spimDataP.length ); else spimDataQ = loaderQ.load(); int N = loaderP.numSources() + loaderQ.numSources(); String[] names; - if( namesIn == null || namesIn.length != N ) + if ( namesIn == null || namesIn.length != N ) { names = new String[ N ]; int j = 0; - for( int i = 0; i < loaderP.numSources(); i++ ) + for ( int i = 0; i < loaderP.numSources(); i++ ) names[ j++ ] = loaderP.name( i ); - for( int i = 0; i < loaderQ.numSources(); i++ ) + for ( int i = 0; i < loaderQ.numSources(); i++ ) names[ j++ ] = loaderQ.name( i ); } else @@ -1105,11 +1138,11 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source BigWarpData< ? > data = createBigWarpData( spimDataP, spimDataQ, names ); - if( loaderP instanceof ImagePlusLoader ) - ((ImagePlusLoader)loaderP).update( data ); + if ( loaderP instanceof ImagePlusLoader ) + ( ( ImagePlusLoader ) loaderP ).update( data ); - if( loaderQ instanceof ImagePlusLoader ) - ((ImagePlusLoader)loaderQ).update( data ); + if ( loaderQ instanceof ImagePlusLoader ) + ( ( ImagePlusLoader ) loaderQ ).update( data ); return data; } @@ -1123,7 +1156,7 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source * fixed source XML * @return BigWarpData */ - public static BigWarpData< T > createBigWarpDataFromXML( final String xmlFilenameP, final String xmlFilenameQ ) + public static < T > BigWarpData< T > createBigWarpDataFromXML( final String xmlFilenameP, final String xmlFilenameQ ) { // return createBigWarpData( new XMLLoader( xmlFilenameP ), new XMLLoader( xmlFilenameQ ), null ); final BigWarpData< T > bwdata = BigWarpInit.initData(); @@ -1134,7 +1167,7 @@ public static BigWarpData< T > createBigWarpDataFromXML( final String xmlFil mvgSrcs = BigWarpInit.createSources( bwdata, xmlFilenameP, id, true ); id += mvgSrcs.size(); BigWarpInit.add( bwdata, mvgSrcs ); - BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, xmlFilenameQ, id, false )); + BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, xmlFilenameQ, id, false ) ); } catch ( URISyntaxException e ) { @@ -1161,7 +1194,7 @@ public static BigWarpData< T > createBigWarpDataFromXML( final String xmlFil * fixed source ImagePlus * @return BigWarpData */ - public static BigWarpData< T > createBigWarpDataFromImages( final ImagePlus impP, final ImagePlus impQ ) + public static < T > BigWarpData< T > createBigWarpDataFromImages( final ImagePlus impP, final ImagePlus impQ ) { // return createBigWarpData( new ImagePlusLoader( impP ), new ImagePlusLoader( impQ ), null ); @@ -1170,7 +1203,7 @@ public static BigWarpData< T > createBigWarpDataFromImages( final ImagePlus LinkedHashMap< Source< T >, SourceInfo > mvgSrcs = BigWarpInit.createSources( bwdata, impP, id, 0, true ); id += mvgSrcs.size(); BigWarpInit.add( bwdata, mvgSrcs ); - BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, impQ, id, 0, false )); + BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, impQ, id, 0, false ) ); return bwdata; } @@ -1228,7 +1261,7 @@ public static BigWarpData< T > createBigWarpDataFromImages( final ImagePlus * fixed source ImagePlus * @return BigWarpData */ - public static BigWarpData< T > createBigWarpDataFromXMLImagePlus( final String xmlFilenameP, final ImagePlus impQ ) + public static < T > BigWarpData< T > createBigWarpDataFromXMLImagePlus( final String xmlFilenameP, final ImagePlus impQ ) { final BigWarpData< T > bwdata = BigWarpInit.initData(); try @@ -1238,7 +1271,7 @@ public static BigWarpData< T > createBigWarpDataFromXMLImagePlus( final Stri mvgSrcs = BigWarpInit.createSources( bwdata, xmlFilenameP, id, true ); id += mvgSrcs.size(); BigWarpInit.add( bwdata, mvgSrcs ); - BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, impQ, id, 0, false )); + BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, impQ, id, 0, false ) ); } catch ( URISyntaxException e ) { @@ -1280,7 +1313,7 @@ public static BigWarpData< T > createBigWarpDataFromXMLImagePlus( final Stri * fixed source XML * @return BigWarpData */ - public static BigWarpData< T > createBigWarpDataFromImagePlusXML( final ImagePlus impP, final String xmlFilenameQ ) + public static < T > BigWarpData< T > createBigWarpDataFromImagePlusXML( final ImagePlus impP, final String xmlFilenameQ ) { // return createBigWarpData( new ImagePlusLoader( impP ), new XMLLoader( xmlFilenameQ ) ); final BigWarpData< T > bwdata = BigWarpInit.initData(); @@ -1291,7 +1324,7 @@ public static BigWarpData< T > createBigWarpDataFromImagePlusXML( final Imag mvgSrcs = BigWarpInit.createSources( bwdata, impP, id, 0, true ); id += mvgSrcs.size(); BigWarpInit.add( bwdata, mvgSrcs ); - BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, xmlFilenameQ, id, false )); + BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, xmlFilenameQ, id, false ) ); } catch ( URISyntaxException e ) { From f0563b220b59abf0d69c16ce4f8d9fb19f582607 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 21 Nov 2022 10:52:19 -0500 Subject: [PATCH 145/282] chore: stop using deprecated constructor --- src/main/java/bigwarp/BigWarp.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 67188385..3dddf02b 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2569,26 +2569,25 @@ public static void main( final String[] args ) if ( fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) { bwdata = BigWarpInit.createBigWarpDataFromXML( fnP, fnQ ); - bw = new BigWarp<>( bwdata, new File( fnP ).getName(), progress ); + bw = new BigWarp<>( bwdata, progress ); } else if ( fnP.endsWith( "xml" ) && !fnQ.endsWith( "xml" ) ) { final ImagePlus impQ = IJ.openImage( fnQ ); bwdata = BigWarpInit.createBigWarpDataFromXMLImagePlus( fnP, impQ ); - bw = new BigWarp<>( bwdata, new File( fnP ).getName(), progress ); + bw = new BigWarp<>( bwdata, progress ); } else if ( !fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) { final ImagePlus impP = IJ.openImage( fnP ); bwdata = BigWarpInit.createBigWarpDataFromImagePlusXML( impP, fnQ ); - bw = new BigWarp<>( bwdata, new File( fnP ).getName(), progress ); + bw = new BigWarp<>( bwdata, progress ); } else if (!fnP.isEmpty() && !fnQ.isEmpty()) { final ImagePlus impP = IJ.openImage( fnP ); final ImagePlus impQ = IJ.openImage( fnQ ); - // For testing display and color settings // impP.setDisplayRange( 10, 200 ); // impQ.setDisplayRange( 20, 180 ); From f2c5eaabd1527b8c8d938f749ba6e2dc872ec337 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 21 Nov 2022 13:32:58 -0500 Subject: [PATCH 146/282] fix: allow undo / redo in landmark mode * and a little clean up --- src/main/java/bigwarp/BigWarpActions.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index ad2851f0..94f8bec5 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -751,12 +751,6 @@ public UndoRedoAction( final String name, BigWarp< ? > bw ) @Override public void actionPerformed( ActionEvent e ) { - if( bw.isInLandmarkMode() ) - { - bw.message.showMessage( "Undo/Redo not allowed in landmark mode" ); - return; - } - // I would love for this check to work instead of using a try-catch // bug it doesn't seem to be consistent // if( isRedo && manager.canRedo() ){ @@ -795,8 +789,6 @@ public void actionPerformed( ActionEvent e ) { bw.message.showMessage("Can't undo"); } - //System.err.println( " Undo / redo error, or nothing to do " ); - //ex.printStackTrace(); } } } @@ -1581,16 +1573,5 @@ public void actionPerformed(ActionEvent e) bw.getViewerFrameQ().getViewerPanel().getMaskOverlay().toggleVisible(); } } - -// public synchronized void discoverCommandDescriptions() -// { -// final CommandDescriptionsBuilder builder = new CommandDescriptionsBuilder(); -// final Context context = new Context( PluginService.class ); -// context.inject( builder ); -// builder.discoverProviders( KeyConfigScopes.BIGDATAVIEWER ); -// builder.discoverProviders( "bw" ); -// context.dispose(); -// setCommandDescriptions( builder.build() ); -// } } From b396576bf1ec66b5069818b54b9d6fd746168d6b Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Sat, 26 Nov 2022 13:46:39 -0500 Subject: [PATCH 147/282] fix: actions viewer plane alignment and landmark activation --- .../java/bdv/viewer/LandmarkPointMenu.java | 30 ++++----- src/main/java/bigwarp/BigWarp.java | 19 ++++-- src/main/java/bigwarp/BigWarpActions.java | 63 ++++++++++++++----- .../bigwarp/ui/keymap/NavigationKeys.java | 10 +++ 4 files changed, 89 insertions(+), 33 deletions(-) diff --git a/src/main/java/bdv/viewer/LandmarkPointMenu.java b/src/main/java/bdv/viewer/LandmarkPointMenu.java index 5dd83d2c..49965081 100644 --- a/src/main/java/bdv/viewer/LandmarkPointMenu.java +++ b/src/main/java/bdv/viewer/LandmarkPointMenu.java @@ -44,16 +44,16 @@ public class LandmarkPointMenu extends JPopupMenu public static final boolean MOVING = true; public static final boolean FIXED = false; - public static final String CLEAR_MOVING = "table clear moving"; - public static final String CLEAR_FIXED = "table clear fixed"; - public static final String CLEAR_SELECTED_MOVING = "table clear selected moving"; - public static final String CLEAR_SELECTED_FIXED = "table clear selected fixed"; - - public static final String DELETE = "table delete"; - public static final String DELETE_SELECTED = "table delete selected "; - - public static final String ACTIVATE_SELECTED = "table activate selected"; - public static final String DEACTIVATE_SELECTED = "table deactivate selected "; +// public static final String CLEAR_MOVING = "table clear moving"; +// public static final String CLEAR_FIXED = "table clear fixed"; +// public static final String CLEAR_SELECTED_MOVING = "table clear selected moving"; +// public static final String CLEAR_SELECTED_FIXED = "table clear selected fixed"; +// +// public static final String DELETE = "table delete"; +// public static final String DELETE_SELECTED = "table delete selected "; +// +// public static final String ACTIVATE_SELECTED = "table activate selected"; +// public static final String DEACTIVATE_SELECTED = "table deactivate selected "; private static final long serialVersionUID = -3676180390835767585L; @@ -92,12 +92,12 @@ public LandmarkPointMenu( BigWarpLandmarkPanel landmarkPanel ) { this.landmarkPanel = landmarkPanel; - deleteSelectedHandler = new DeleteSelectedHandler( DELETE_SELECTED ); - activateSelectedHandler = new ActivateSelectedHandler( ACTIVATE_SELECTED ); - deactivateSelectedHandler = new DeactivateSelectedHandler( DEACTIVATE_SELECTED ); + deleteSelectedHandler = new DeleteSelectedHandler( BigWarpActions.DELETE_SELECTED ); + activateSelectedHandler = new ActivateSelectedHandler( BigWarpActions.ACTIVATE_SELECTED ); + deactivateSelectedHandler = new DeactivateSelectedHandler( BigWarpActions.DEACTIVATE_SELECTED ); - clearSelectedMoving = new ClearSelectedHandler( CLEAR_SELECTED_MOVING, MOVING ); - clearSelectedFixed = new ClearSelectedHandler( CLEAR_SELECTED_FIXED, FIXED ); + clearSelectedMoving = new ClearSelectedHandler( BigWarpActions.CLEAR_SELECTED_MOVING, MOVING ); + clearSelectedFixed = new ClearSelectedHandler( BigWarpActions.CLEAR_SELECTED_FIXED, FIXED ); addAboveHandler = new AddToSelection( BigWarpActions.LANDMARK_SELECT_ABOVE, true, false ); addAllAboveHandler = new AddToSelection( BigWarpActions.LANDMARK_SELECT_ALL_ABOVE, true, true ); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 6a1b06f6..d9cac41d 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -115,6 +115,7 @@ import bdv.ui.keymap.Keymap; import bdv.ui.keymap.KeymapSettingsPage; import bdv.util.Bounds; +import bdv.viewer.AbstractViewerPanel.AlignPlane; import bdv.viewer.BigWarpDragOverlay; import bdv.viewer.BigWarpLandmarkFrame; import bdv.viewer.BigWarpOverlay; @@ -125,6 +126,7 @@ import bdv.viewer.Interpolation; import bdv.viewer.LandmarkPointMenu; import bdv.viewer.MultiBoxOverlay2d; +import bdv.viewer.NavigationActions; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bdv.viewer.TransformListener; @@ -606,21 +608,18 @@ public boolean accept( final File f ) final Actions navigationActions = new Actions( inputTriggerConfig, "navigation" ); navigationActions.install( getViewerFrameP().getKeybindings(), "navigation" ); NavigationKeys.install( navigationActions, getViewerFrameP().getViewerPanel(), options.values.is2D() ); - navigationActions.install( getViewerFrameQ().getKeybindings(), "navigation" ); NavigationKeys.install( navigationActions, getViewerFrameQ().getViewerPanel(), options.values.is2D() ); final BigWarpActions bwActions = new BigWarpActions( inputTriggerConfig, "bigwarp" ); BigWarpActions.installViewerActions( bwActions, getViewerFrameP(), this ); BigWarpActions.installViewerActions( bwActions, getViewerFrameQ(), this ); - final BigWarpActions tableActions = new BigWarpActions( inputTriggerConfig, "bw-table" ); BigWarpActions.installTableActions( tableActions, getLandmarkFrame().getKeybindings(), this ); - UnmappedNavigationActions.install( tableActions, options.values.is2D() ); +// UnmappedNavigationActions.install( tableActions, options.values.is2D() ); keymap.updateListeners().add( () -> { - navigationActions.updateKeyConfig( keymap.getConfig() ); bwActions.updateKeyConfig( keymap.getConfig() ); tableActions.updateKeyConfig( keymap.getConfig() ); @@ -1629,6 +1628,18 @@ private void printViewerTransforms() System.out.println( " dotxy = " + BigWarpUtils.dotXy( xfm )); } + protected void alignActive( final AlignPlane plane ) + { + if ( viewerFrameP.isActive() ) + { + viewerFrameP.getViewerPanel().align( plane ); + } + else if ( viewerFrameQ.isActive() ) + { + viewerFrameQ.getViewerPanel().align( plane ); + } + } + /** * Changes the view transformation of 'panelToChange' to match that of 'panelToMatch' * @param panelToChange the viewer panel whose transform will change diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 94f8bec5..80d9217b 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -44,6 +44,7 @@ import bdv.util.Prefs; import bdv.viewer.LandmarkPointMenu; import bdv.viewer.SourceAndConverter; +import bdv.viewer.AbstractViewerPanel.AlignPlane; import bigwarp.BigWarp.BigWarpData; import bigwarp.landmarks.LandmarkGridGenerator; import bigwarp.source.GridSource; @@ -208,8 +209,8 @@ public class BigWarpActions extends Actions public static final String LANDMARK_DEACTIVATE_SELECTED = "deactivate selected landmarks"; public static final String[] LANDMARK_DEACTIVATE_SELECTED_KEYS = new String[]{ "BACK_SPACE" }; - public static final String LANDMARK_ACTIVATE_SELECTED = "activate selected landmarks"; public static final String[] LANDMARK_ACTIVATE_SELECTED_KEYS = new String[]{ "ctrl BACK_SPACE" }; + public static final String LANDMARK_ACTIVATE_SELECTED = "activate selected landmarks"; public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; @@ -230,24 +231,23 @@ public class BigWarpActions extends Actions public static final String EXPORT_AFFINE = "export affine"; public static final String[] EXPORT_AFFINE_KEYS = new String[] { "ctrl A" }; - public static final String CLEAR_MOVING = "table clear moving"; - public static final String[] CLEAR_MOVING_KEYS = new String[] { NOT_MAPPED }; + public static final String[] CLEAR_MOVING_KEYS = new String[] { "BACK_SPACE" }; public static final String CLEAR_FIXED = "table clear fixed"; - public static final String[] CLEAR_FIXED_KEYS = new String[] { NOT_MAPPED }; + public static final String[] CLEAR_FIXED_KEYS = new String[] { "ctrl BACK_SPACE" }; public static final String CLEAR_SELECTED_MOVING = "table clear selected moving"; - public static final String[] CLEAR_SELECTED_MOVING_KEYS = new String[] { NOT_MAPPED }; + public static final String[] CLEAR_SELECTED_MOVING_KEYS = new String[] { "ctrl BACK_SPACE" }; public static final String CLEAR_SELECTED_FIXED = "table clear selected fixed"; - public static final String[] CLEAR_SELECTED_FIXED_KEYS = new String[] { NOT_MAPPED }; + public static final String[] CLEAR_SELECTED_FIXED_KEYS = new String[] { "ctrl BACK_SPACE" }; public static final String DELETE = "table delete"; public static final String[] DELETE_KEYS = new String[] { NOT_MAPPED }; public static final String DELETE_SELECTED = "table delete selected "; - public static final String[] DELETE_SELECTED_KEYS = new String[] { NOT_MAPPED }; + public static final String[] DELETE_SELECTED_KEYS = new String[] { "DELETE" }; public static final String ACTIVATE_SELECTED = "table activate selected"; public static final String[] ACTIVATE_SELECTED_KEYS = new String[] { NOT_MAPPED }; @@ -255,10 +255,18 @@ public class BigWarpActions extends Actions public static final String DEACTIVATE_SELECTED = "table deactivate selected "; public static final String[] DEACTIVATE_SELECTED_KEYS = new String[]{ NOT_MAPPED }; - public static final String DEBUG = "debug"; public static final String GARBAGE_COLLECTION = "garbage collection"; + public static final String XYPLANE = "xyPlane"; + public static final String[] XYPLANE_KEYS = new String[] { "shift Z" }; + + public static final String YZPLANE = "yzPlane"; + public static final String[] YZPLANE_KEYS = new String[] { "shift X" }; + + public static final String XZPLANE = "xzPlane"; + public static final String[] XZPLANE_KEYS = new String[] { "shift Y", "shift A" }; + public BigWarpActions( final KeyStrokeAdder.Factory keyConfig, String name ) { this( keyConfig, "bigwarp", name ); @@ -331,6 +339,17 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) descriptions.add( TOGGLE_POINTS_VISIBLE, TOGGLE_POINTS_VISIBLE_KEYS, "Toggle visibility of landmarks." ); descriptions.add( TOGGLE_POINT_NAMES_VISIBLE, TOGGLE_POINT_NAMES_VISIBLE_KEYS , "Toggle visibility of landmark names." ); + descriptions.add( TOGGLE_BOX_AND_TEXT_OVERLAY_VISIBLE, TOGGLE_BOX_AND_TEXT_OVERLAY_VISIBLE_KEYS, "Toggle visibility of bounding box and source information." ); + descriptions.add( TOGGLE_POINTS_VISIBLE, TOGGLE_POINTS_VISIBLE_KEYS, "Toggle visibility of landmark points." ); + descriptions.add( TOGGLE_POINT_NAMES_VISIBLE, TOGGLE_POINT_NAMES_VISIBLE_KEYS, "Toggle visibility of landmark point names." ); + + descriptions.add( LANDMARK_ACTIVATE_SELECTED, LANDMARK_ACTIVATE_SELECTED_KEYS, "Activate selected landmarks." ); + descriptions.add( LANDMARK_DEACTIVATE_SELECTED, LANDMARK_DEACTIVATE_SELECTED_KEYS, "Deactivate selected landmarks." ); + + // alignment + descriptions.add( XYPLANE, XYPLANE_KEYS, "xy plane" ); + descriptions.add( XZPLANE, XZPLANE_KEYS, "xz plane" ); + descriptions.add( YZPLANE, YZPLANE_KEYS, "yz plane" ); } } @@ -374,6 +393,9 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) descriptions.add( UNDO, UNDO_KEYS, "Undo the last landmark change." ); descriptions.add( REDO, REDO_KEYS, "Redo the last landmark change." ); + + descriptions.add( TOGGLE_POINTS_VISIBLE, TOGGLE_POINTS_VISIBLE_KEYS, "Toggle visibility of landmark points." ); + descriptions.add( TOGGLE_POINT_NAMES_VISIBLE, TOGGLE_POINT_NAMES_VISIBLE_KEYS, "Toggle visibility of landmark point names." ); } } @@ -390,6 +412,9 @@ public static void installViewerActions( actions.runnableAction( bw::toggleInLandmarkMode, TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS); actions.runnableAction( bw::toggleMovingImageDisplay, TOGGLE_MOVING_IMAGE_DISPLAY, TOGGLE_MOVING_IMAGE_DISPLAY_KEYS ); + actions.namedAction( new TogglePointsVisibleAction( TOGGLE_POINTS_VISIBLE, bw ), TOGGLE_POINTS_VISIBLE_KEYS); + actions.namedAction( new TogglePointNameVisibleAction( TOGGLE_POINT_NAMES_VISIBLE, bw ), TOGGLE_POINT_NAMES_VISIBLE_KEYS); + // navigation actions.runnableAction( bw::resetView, RESET_VIEWER, RESET_VIEWER_KEYS); actions.runnableAction( bw::matchOtherViewerPanelToActive, ALIGN_OTHER_TO_ACTIVE, ALIGN_OTHER_TO_ACTIVE_KEYS ); @@ -441,6 +466,13 @@ public static void installViewerActions( actions.namedAction( new UndoRedoAction( UNDO, bw ), UNDO_KEYS ); actions.namedAction( new UndoRedoAction( REDO, bw ), REDO_KEYS ); + actions.namedAction( new ToggleBoxAndTexOverlayVisibility( TOGGLE_BOX_AND_TEXT_OVERLAY_VISIBLE, bw ), TOGGLE_BOX_AND_TEXT_OVERLAY_VISIBLE_KEYS); + actions.namedAction( new TogglePointsVisibleAction( TOGGLE_POINTS_VISIBLE, bw ), TOGGLE_POINTS_VISIBLE_KEYS ); + actions.namedAction( new TogglePointNameVisibleAction( TOGGLE_POINT_NAMES_VISIBLE, bw ), TOGGLE_POINT_NAMES_VISIBLE_KEYS); + + actions.runnableAction( () -> bw.alignActive( AlignPlane.XY ), XYPLANE, XYPLANE_KEYS ); + actions.runnableAction( () -> bw.alignActive( AlignPlane.XZ ), XZPLANE, XZPLANE_KEYS ); + actions.runnableAction( () -> bw.alignActive( AlignPlane.ZY ), YZPLANE, YZPLANE_KEYS ); } public static void installTableActions( @@ -504,6 +536,10 @@ public static void installTableActions( actions.namedAction( new UndoRedoAction( UNDO, bw ), UNDO_KEYS ); actions.namedAction( new UndoRedoAction( REDO, bw ), REDO_KEYS ); + + actions.namedAction( new ToggleBoxAndTexOverlayVisibility( TOGGLE_BOX_AND_TEXT_OVERLAY_VISIBLE, bw ), NOT_MAPPED ); + actions.namedAction( new TogglePointsVisibleAction( TOGGLE_POINTS_VISIBLE, bw ), TOGGLE_POINTS_VISIBLE_KEYS ); + actions.namedAction( new TogglePointNameVisibleAction( TOGGLE_POINT_NAMES_VISIBLE, bw ), TOGGLE_POINT_NAMES_VISIBLE_KEYS); } /** @@ -537,7 +573,7 @@ public static void installLandmarkPanelActionBindings( { inputActionBindings.addActionMap( "bw", createActionMap( bw ) ); inputActionBindings.addInputMap( "bw", createInputMap( keyProperties ) ); - + TableCellEditor celled = landmarkTable.getCellEditor( 0, 1 ); Component c = celled.getTableCellEditorComponent(landmarkTable, Boolean.TRUE, true, 0, 1 ); @@ -619,6 +655,7 @@ public static ActionMap createActionMapViewer( final BigWarp< ? > bw ) public static InputMap createInputMap( final KeyStrokeAdder.Factory keyProperties ) { + System.out.println( "create input map" ); final InputMap inputMap = new InputMap(); final KeyStrokeAdder map = keyProperties.keyStrokeAdder( inputMap ); @@ -647,9 +684,9 @@ public static InputMap createInputMap( final KeyStrokeAdder.Factory keyPropertie // map.put( SAVE_WARPED, "control alt shift E" ); map.put( SAVE_WARPED_XML, "control shift E" ); - map.put( LandmarkPointMenu.CLEAR_SELECTED_MOVING, "BACK_SPACE" ); - map.put( LandmarkPointMenu.CLEAR_SELECTED_FIXED, "control BACK_SPACE" ); - map.put( LandmarkPointMenu.DELETE_SELECTED, "DELETE" ); + map.put( CLEAR_SELECTED_MOVING, "BACK_SPACE" ); + map.put( CLEAR_SELECTED_FIXED, "control BACK_SPACE" ); + map.put( DELETE_SELECTED, "DELETE" ); map.put( String.format( SELECT_TABLE_ROWS, -1 ), "shift ESCAPE" ); @@ -811,7 +848,6 @@ public LandmarkModeAction( final String name, final BigWarp< ? > bw, final boole @Override public void actionPerformed( ActionEvent e ) { -// System.out.println( "LM MODE : " + isOn ); bw.setInLandmarkMode( isOn ); } } @@ -831,7 +867,6 @@ public ToggleLandmarkModeAction( final String name, final BigWarp< ? > bw ) @Override public void actionPerformed( ActionEvent e ) { -// System.out.println( "TOGGLE LM MODE" ); bw.setInLandmarkMode( !bw.inLandmarkMode ); } } diff --git a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java index 3a8e387c..a022d32e 100644 --- a/src/main/java/bigwarp/ui/keymap/NavigationKeys.java +++ b/src/main/java/bigwarp/ui/keymap/NavigationKeys.java @@ -6,8 +6,10 @@ import org.scijava.ui.behaviour.KeyStrokeAdder.Factory; import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider; import org.scijava.ui.behaviour.io.gui.CommandDescriptions; +import org.scijava.ui.behaviour.util.Actions; import bdv.TransformEventHandler3D; +import bdv.viewer.AbstractViewerPanel; import bdv.viewer.NavigationActions; import bigwarp.BigWarpActions; @@ -118,5 +120,13 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) } } + public static void install( final Actions actions, final AbstractViewerPanel viewer, final boolean is2D ) + { + installModeActions( actions, viewer.state() ); + installSourceActions( actions, viewer.state() ); + installTimeActions( actions, viewer.state() ); + // align plane actions need to be moved to bigwarp actions due to tricky two-viewer issue + } + } From 4623f278bb911027dc9e884562e249115e357113 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 29 Nov 2022 09:40:01 -0500 Subject: [PATCH 148/282] fix: synchronization issue during drags * transform solver always copies landmark arrays * minor edits to warped source and bigwarp --- src/main/java/bdv/img/WarpedSource.java | 14 +++- src/main/java/bigwarp/BigWarp.java | 16 ++-- src/main/java/bigwarp/BigWarpData.java | 75 ++++++++++++------- .../transforms/AbstractTransformSolver.java | 37 +++++---- 4 files changed, 91 insertions(+), 51 deletions(-) diff --git a/src/main/java/bdv/img/WarpedSource.java b/src/main/java/bdv/img/WarpedSource.java index 1bf4d86c..cc4900f0 100644 --- a/src/main/java/bdv/img/WarpedSource.java +++ b/src/main/java/bdv/img/WarpedSource.java @@ -84,6 +84,7 @@ public WarpedSource( final Source< T > source, final String name, this.name = name; this.isTransformed = false; this.boundingBoxCullingSupplier = doBoundingBoxCulling; + bboxEst = new BoundingBoxEstimation( BoundingBoxEstimation.Method.FACES, 5 ); this.xfm = null; @@ -145,7 +146,16 @@ public RandomAccessibleInterval< T > getSource( final int t, final int level ) private Interval estimateBoundingInterval( final int t, final int level ) { - return bboxEst.estimatePixelInterval( xfm, source.getSource( t, level ) ); + if( xfm == null ) + { + return source.getSource( t, level ); + } + else + { + // getSource can be called by multiple threads, so need ensure application of + // the transform is thread safe here by copying + return bboxEst.estimatePixelInterval( xfm.copy(), source.getSource( t, level ) ); + } } @Override @@ -184,7 +194,7 @@ public RealRandomAccessible< T > getInterpolatedSource( final int t, final int l if( xfm == null ) return srcRaTransformed; else - return new RealTransformRealRandomAccessible< T, RealTransform >( srcRaTransformed, xfm.copy() ); + return new RealTransformRealRandomAccessible< T, RealTransform >( srcRaTransformed, xfm); } else { diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 3dddf02b..5f51f50d 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -490,6 +490,7 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final solverThread.start(); bboxOptions = new BoundingBoxEstimation( BoundingBoxEstimation.Method.FACES, 5 ); +// bboxOptions = new BoundingBoxEstimation( BoundingBoxEstimation.Method.CORNERS, 5 ); dragOverlayP = new BigWarpDragOverlay( this, viewerP, solverThread ); dragOverlayQ = new BigWarpDragOverlay( this, viewerQ, solverThread ); @@ -588,8 +589,6 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final public void initialize() { - // TODO JOHN CHECK THIS!! -// data.sources = wrapSourcesAsTransformed( data.sources, ndims, data ); wrapMovingSources( ndims, data ); // starting view @@ -1934,7 +1933,8 @@ public static < T > void wrapMovingSources( final int ndims, final BigWarpData< int i = 0; for ( final SourceInfo sourceInfo : data.sourceInfos.values() ) { - if ( sourceInfo.isMoving() && !(sourceInfo.getSourceAndConverter().getSpimSource() instanceof WarpedSource)) +// if ( sourceInfo.isMoving() && !(sourceInfo.getSourceAndConverter().getSpimSource() instanceof WarpedSource)) + if ( sourceInfo.isMoving() ) { SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); final int sourceIdx = data.sources.indexOf( sourceInfo.getSourceAndConverter() ); @@ -2331,7 +2331,6 @@ else if ( viewerFrameQ.isActive() ) private void setTransformationMovingSourceOnly( final InvertibleRealTransform transform ) { this.currentTransform = transform; - data.sourceInfos.values().forEach( sourceInfo -> { if ( sourceInfo.isMoving() ) { @@ -2340,8 +2339,10 @@ private void setTransformationMovingSourceOnly( final InvertibleRealTransform tr // InverseRealTransform xfm = new InverseRealTransform( new TpsTransformWrapper( 3, transform )); // the updateTransform method creates a copy of the transform - ( ( WarpedSource< ? > ) sourceInfo.getSourceAndConverter().getSpimSource() ).updateTransform( transform ); - if ( data.sources.get( 0 ).asVolatile() != null ) + final SourceAndConverter< ? > sac = sourceInfo.getSourceAndConverter(); + final WarpedSource< ? > wsrc = ( WarpedSource< ? > ) sac.getSpimSource(); + wsrc.updateTransform( transform ); + if ( sac.asVolatile() != null ) ( ( WarpedSource< ? > ) sourceInfo.getSourceAndConverter().asVolatile().getSpimSource() ).updateTransform( transform ); } } ); @@ -3238,7 +3239,8 @@ public void run() else { // update the transform and warped point - bw.setTransformationMovingSourceOnly( invXfm ); +// bw.setTransformationMovingSourceOnly( invXfm ); + bw.data.updateEditableTransformation( invXfm ); } // update fixed point - but don't allow undo/redo diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 0683db5b..482a35a9 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -2,7 +2,6 @@ import bigwarp.source.SourceInfo; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -22,7 +21,6 @@ import bdv.viewer.SourceAndConverter; import bdv.viewer.SynchronizedViewerState; import bdv.viewer.VisibilityAndGrouping; -import bigwarp.loader.ImagePlusLoader.ColorSettings; import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.InvertibleRealTransform; @@ -69,15 +67,6 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, this.sources = sources; this.converterSetups = converterSetups; -// if( transforms != null ) -// this.transforms = transforms; -// else -// { -// // fill the initial transform list with nulls -// this.transforms = new ArrayList<>(); -// IntStream.range( 0, sources.size() ).forEach( i -> this.transforms.add( null )); -// } - if ( cache == null ) this.cache = new CacheControl.Dummy(); else @@ -299,6 +288,17 @@ public static < T > SourceAndConverter< T > inheritConverter( final Source sr } } + /** + * Returns a source that applies the given {@link RealTransform} to the given {@link Source}. + *

+ * The returned source will be a new instance than unless the transform + * is a instance of {@link AffineGet} and source is an instance of {@link TransformedSource}. + * + * @param the type + * @param src the original source + * @param transform the transformation + * @return the transformed source + */ public Source applyFixedTransform( final Source src, final RealTransform transform ) { RealTransform tform = transform; @@ -313,16 +313,6 @@ public Source applyFixedTransform( final Source src, final RealTransfo if( transform instanceof AffineGet ) { // can use TransformedSource - TransformedSource tsrc; - - /* - * UNSURE WHAT TO DO IN THIS CASE - */ -// if( (src instanceof WarpedSource )) -// { -// Source< ? > wsrc = ( ( WarpedSource< ? > ) src ).getWrappedSource(); -// } - final AffineTransform3D affine3d; if( transform instanceof AffineTransform3D ) affine3d = ( AffineTransform3D ) transform; @@ -332,6 +322,8 @@ public Source applyFixedTransform( final Source src, final RealTransfo affine3d.preConcatenate( ( AffineGet ) transform ); } + // could perhaps try to be clever if its a warped source (?), maybe later + TransformedSource tsrc; if ( src instanceof TransformedSource ) { tsrc = ( TransformedSource ) ( src ); @@ -346,18 +338,47 @@ public Source applyFixedTransform( final Source src, final RealTransfo else { // need to use WarpedSource - WarpedSource wsrc; - if( !(src instanceof WarpedSource )) - wsrc = new WarpedSource( src, src.getName() ); - else - wsrc = (WarpedSource)src; - + final WarpedSource wsrc = new WarpedSource( src, src.getName() ); wsrc.updateTransform( tform ); wsrc.setIsTransformed( true ); return ( Source< T > ) wsrc; } } + /** + * Updates the moving sources' transformation with the transform currently + * being edited by BigWarp. + * + * @param transform the transformation + */ + public void updateEditableTransformation( RealTransform transform ) + { + for ( final SourceInfo sourceInfo : sourceInfos.values() ) + { + // could be extra careful and ensure the source is a WarpedSource, but hopefully not necessary + if ( sourceInfo.isMoving() ) + { + final SourceAndConverter< ? > sac = sourceInfo.getSourceAndConverter(); + final WarpedSource< ? > wsrc = ( WarpedSource< ? > ) sac.getSpimSource(); + wsrc.updateTransform( transform ); + if ( sac.asVolatile() != null ) + ( ( WarpedSource< ? > ) sourceInfo.getSourceAndConverter().asVolatile().getSpimSource() ).updateTransform( transform ); + + wsrc.updateTransform( transform ); + + /* + * There was a time when I had a single WarpedSource manage a RealTransformSequence + * instead of a WarpedSource wrapping a different WarpedSource as I'm doing now. + * + * But I decided against having a single source because warped sources can toggle their transforms. + * That toggling makes sense for the editable transform, but the fixex should be "on" + * always, and therefore be handled by either a TransformedSource or a different + * WarpedSource instance. + */ + } + } + } + public void transferChannelSettings( final BigWarpViewerFrame viewer ) { final SynchronizedViewerState state = viewer.getViewerPanel().state(); diff --git a/src/main/java/bigwarp/transforms/AbstractTransformSolver.java b/src/main/java/bigwarp/transforms/AbstractTransformSolver.java index 8a0c81d5..8a37996b 100644 --- a/src/main/java/bigwarp/transforms/AbstractTransformSolver.java +++ b/src/main/java/bigwarp/transforms/AbstractTransformSolver.java @@ -26,8 +26,8 @@ public abstract class AbstractTransformSolver implements TransformSolver { - protected double[][] mvgPts; - protected double[][] tgtPts; +// protected double[][] mvgPts; +// protected double[][] tgtPts; public T solve( final LandmarkTableModel landmarkTable ) { @@ -36,22 +36,29 @@ public T solve( final LandmarkTableModel landmarkTable ) public T solve( final LandmarkTableModel landmarkTable, final int indexChanged ) { - synchronized( landmarkTable ) - { int numActive = landmarkTable.numActive(); int ndims = landmarkTable.getNumdims(); + double[][] mvgPts = new double[ ndims ][ numActive ]; + double[][] tgtPts = new double[ ndims ][ numActive ]; + landmarkTable.copyLandmarks( mvgPts, tgtPts ); - if( mvgPts == null || mvgPts[0].length != numActive ) - { - mvgPts = new double[ ndims ][ numActive ]; - tgtPts = new double[ ndims ][ numActive ]; - landmarkTable.copyLandmarks( mvgPts, tgtPts ); - } - else if( indexChanged >= 0 ) - { - landmarkTable.copyLandmarks( indexChanged, mvgPts, tgtPts ); - } - } + /* + * The optimization below causes problems because the landmark arrays are used directly by transformations, + * and they are modified below. + */ +// synchronized( landmarkTable ) +// { +// mvgPts; +// double[][] tgtPts; +// if( mvgPts == null || mvgPts[0].length != numActive ) +// { +// landmarkTable.copyLandmarks( mvgPts, tgtPts ); +// } +// else if( indexChanged >= 0 ) +// { +// landmarkTable.copyLandmarks( indexChanged, mvgPts, tgtPts ); +// } +// } return solve( mvgPts, tgtPts ); } From 9f53e5f556292bd922c7cee511140471a9dea889 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 29 Nov 2022 09:40:23 -0500 Subject: [PATCH 149/282] feat: (wip) toward macro recordability --- src/main/java/bdv/gui/BigWarpInitDialog.java | 89 ++++++++++++++------ 1 file changed, 62 insertions(+), 27 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index e2a19426..4b6f5d29 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -9,7 +9,6 @@ import java.io.IOException; import java.net.URISyntaxException; import java.util.LinkedHashMap; -import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; @@ -62,6 +61,8 @@ public class BigWarpInitDialog extends JFrame { private static final long serialVersionUID = -2914972130819029899L; + public static String listSeparator = ","; + private boolean imageJOpen; private DatasetService datasetService; @@ -89,6 +90,12 @@ public class BigWarpInitDialog extends JFrame private static final int DEFAULT_BUTTON_PAD = 3; private static final int DEFAULT_MID_PAD = 5; + private String imageList; + + private String movingList; + + private String transformList; + public BigWarpInitDialog() { // this( "BigWarp" ); @@ -119,7 +126,7 @@ public BigWarpInitDialog( final String title, final DatasetService datasetServic }; okayCallback = x -> { - macroRecord( x ); + macroRecord(); runBigWarp( x, projectPathTxt.getText(), datasetService ); }; @@ -605,17 +612,18 @@ public void fillTableFromProject() System.out.println( "implement me" ); } - public static void createAndShow() + public static BigWarpInitDialog createAndShow() { - createAndShow( null ); + return createAndShow( null ); } - public static void createAndShow( DatasetService datasets ) + public static BigWarpInitDialog createAndShow( DatasetService datasets ) { // Create and set up the window. BigWarpInitDialog frame = new BigWarpInitDialog( "BigWarp", datasets ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setVisible( true ); + return frame; } private String browseDialogGeneral( final int mode, final FileFilter filefilter ) @@ -706,39 +714,66 @@ private String browseTransformDialog() return s; } - public String macroRecord( BigWarpSourceTableModel sourceTable ) + public void setParameters( String images, String moving, String transforms ) { + this.imageList = images; + this.movingList = moving; + this.transformList = transforms; + } + + public void updateTableFromParameters() + { + for( int i = 0; i < sourceTableModel.getRowCount(); i++ ) + sourceTableModel.remove( i ); + + final String[] imageParams = imageList.split( listSeparator ); + final String[] movingParams = movingList.split( listSeparator ); + final String[] transformParams = transformList.split( listSeparator ); + + final int N = imageParams.length; + if( movingParams.length != N || transformParams.length != N ) + { + System.err.println("Parameter arrays must have identical lengths"); + return; + } + + for( int i = 0; i < N; i++ ) + { + sourceTableModel.add( imageParams[ i ], movingParams[ i ].trim().equals( "true" ) ); + sourceTableModel.setTransform( i, transformParams[ i ] ); + } + } + + public void updateParametersFromTable() { // make source list - StringBuffer sourceList = new StringBuffer(); - StringBuffer movingList = new StringBuffer(); - StringBuffer transformList = new StringBuffer(); + final StringBuffer imageList = new StringBuffer(); + final StringBuffer movingList = new StringBuffer(); + final StringBuffer transformList = new StringBuffer(); final int N = sourceTable.getRowCount(); for( int i = 0; i < N; i++ ) { - sourceList.append( sourceTable.get( i ).srcName ); - movingList.append( sourceTable.get( i ).moving ); - transformList.append( sourceTable.get( i ).transformName ); + imageList.append( sourceTableModel.get( i ).srcName ); + movingList.append( sourceTableModel.get( i ).moving ); + transformList.append( sourceTableModel.get( i ).transformName ); if( i < N -1 ) { - sourceList.append( "," ); - movingList.append( "," ); - transformList.append( "," ); + imageList.append( listSeparator ); + movingList.append( listSeparator ); + transformList.append( listSeparator ); } } + + this.imageList = imageList.toString(); + this.movingList = movingList.toString(); + this.transformList = transformList.toString(); + } -// if ( imageJOpen && Recorder.record ) -// { -// Recorder.resetCommandOptions(); -// -//// Recorder.recordOption(n5PathKey, n5RootAndDataset); -//// -//// if (virtual) -//// Recorder.recordOption(virtualKey); -// -// return Recorder.getCommandOptions(); -// } - return ""; + public String macroRecord() + { + updateParametersFromTable(); + return String.format( "images=[%s], moving=[%s], transformations=[%s]", + imageList.toString(), movingList.toString(), transformList.toString() ); } } From d57203f9083a927a3fd9971f80a762881fbdee2e Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 29 Nov 2022 13:58:44 -0500 Subject: [PATCH 150/282] feat: more wip work toward macro recording --- src/main/java/bdv/gui/BigWarpInitDialog.java | 142 +++++++++++++++++-- src/main/java/bdv/ij/BigWarpCommand.java | 56 ++++++-- src/main/java/bigwarp/util/BigWarpUtils.java | 41 ++++++ 3 files changed, 215 insertions(+), 24 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 4b6f5d29..b432c45c 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -8,7 +8,10 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; @@ -48,6 +51,7 @@ import bigwarp.BigWarpData; import bigwarp.BigWarpInit; import bigwarp.source.SourceInfo; +import bigwarp.util.BigWarpUtils; import ij.IJ; import ij.ImagePlus; import ij.Prefs; @@ -90,6 +94,13 @@ public class BigWarpInitDialog extends JFrame private static final int DEFAULT_BUTTON_PAD = 3; private static final int DEFAULT_MID_PAD = 5; + private static final String commandName = "BigWarp"; + private static final String imagesKey = "images"; + private static final String movingKey = "moving"; + private static final String transformsKey = "transforms"; + + private String projectPath; + private String imageList; private String movingList; @@ -127,7 +138,7 @@ public BigWarpInitDialog( final String title, final DatasetService datasetServic okayCallback = x -> { macroRecord(); - runBigWarp( x, projectPathTxt.getText(), datasetService ); + runBigWarp( projectPathTxt.getText(), x, datasetService ); }; imagePathUpdateCallback = ( p ) -> { @@ -160,15 +171,83 @@ public static void main( String[] args ) throws IOException createAndShow(); } - public static void runBigWarp( BigWarpSourceTableModel sourceTable, String projectPath, DatasetService datasetService ) + public static void runBigWarp( String projectPath, String[] images, String[] moving, String[] transforms ) { final BigWarpData< T > data = BigWarpInit.initData(); - final int N = sourceTable.getRowCount(); final boolean haveProject = projectPath != null && !projectPath.isEmpty(); if( !haveProject ) { int id = 0; + final int N = images.length; + for( int i = 0; i < N; i++ ) + { + // TODO deal with exceptions? + try + { + LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, images[ i ], id, moving[ i ].equals( "true" ) ); +// BigWarpInit.add( data, infos, transforms[ i ] ); + + // TODO fix transforms + BigWarpInit.add( data, infos ); + + id += infos.size(); + } + catch ( URISyntaxException e ) + { + e.printStackTrace(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } + } + } + + BigWarp bw; + try + { + data.applyTransformations(); + bw = new BigWarp<>( data, new ProgressWriterIJ() ); + if( haveProject ) + bw.loadSettings( projectPath ); + } + catch ( SpimDataException e ) + { + e.printStackTrace(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( JDOMException e ) + { + e.printStackTrace(); + } + + } + + public void runBigWarp() + { + if (Recorder.record) + { + System.out.println( "record" ); + Recorder.setCommand(commandName); + macroRecord(); + Recorder.saveCommand(); + } + + final BigWarpData< T > data = BigWarpInit.initData(); + final boolean haveProject = projectPath != null && !projectPath.isEmpty(); + + if( !haveProject ) + { + int id = 0; + final int N = sourceTable.getRowCount(); for( int i = 0; i < N; i++ ) { System.out.println( "id : " + id ); @@ -714,7 +793,8 @@ private String browseTransformDialog() return s; } - public void setParameters( String images, String moving, String transforms ) { + public void setParameters( String projectPath, String images, String moving, String transforms ) { + this.projectPath = projectPath; this.imageList = images; this.movingList = moving; this.transformList = transforms; @@ -725,9 +805,9 @@ public void updateTableFromParameters() for( int i = 0; i < sourceTableModel.getRowCount(); i++ ) sourceTableModel.remove( i ); - final String[] imageParams = imageList.split( listSeparator ); - final String[] movingParams = movingList.split( listSeparator ); - final String[] transformParams = transformList.split( listSeparator ); + final String[] imageParams = imageList.split( listSeparator, -1 ); + final String[] movingParams = movingList.split( listSeparator, -1 ); + final String[] transformParams = transformList.split( listSeparator, -1 ); final int N = imageParams.length; if( movingParams.length != N || transformParams.length != N ) @@ -772,8 +852,52 @@ public void updateParametersFromTable() public String macroRecord() { updateParametersFromTable(); - return String.format( "images=[%s], moving=[%s], transformations=[%s]", - imageList.toString(), movingList.toString(), transformList.toString() ); +// return String.format( "images=[%s], moving=[%s], transformations=[%s]", +// imageList.toString(), movingList.toString(), transformList.toString() ); + + Recorder.resetCommandOptions(); + Recorder.recordOption(imagesKey, imageList.toString()); + Recorder.recordOption(movingKey, movingList.toString()); + + if( transformList != null ) + Recorder.recordOption(transformsKey, transformList.toString()); + + return Recorder.getCommandOptions(); + } + + public static void runMacro( String args ) + { + final HashMap< String, String > keyVals = BigWarpUtils.parseMacroArguments( args ); + final Set< String > keys = keyVals.keySet(); + + if( keys.contains("project")) + { + runBigWarp( keyVals.get( "project" ), null, null, null ); + } + else + { + if( !keys.contains( "images" ) || !keys.contains( "moving" )) + { + System.out.println( "images and moving keys required" ); + return; + } + + final String[] images = keyVals.get( "images" ).split( ",", -1 ); + final String[] moving = keyVals.get( "moving" ).split( ",", -1 ); + +// final Boolean[] moving = Arrays.stream( keyVals.get( "moving" ).split( ",", -1 ) ).map( x -> { +// return x.equals( "true" ); +// } ).toArray( Boolean[]::new ); + +// final String transforms; +// if( keys.contains( "transforms" ) ) +// transforms = keyVals.get( "transforms" ); +// else +// transforms = ""; + + // TOD fix transforms + runBigWarp( null, images, moving, null ); + } } } diff --git a/src/main/java/bdv/ij/BigWarpCommand.java b/src/main/java/bdv/ij/BigWarpCommand.java index 156e551f..1e86be0c 100644 --- a/src/main/java/bdv/ij/BigWarpCommand.java +++ b/src/main/java/bdv/ij/BigWarpCommand.java @@ -1,42 +1,68 @@ package bdv.ij; import java.io.IOException; -import java.util.List; -import java.util.Map; import org.scijava.command.Command; -import org.scijava.command.CommandService; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; import bdv.gui.BigWarpInitDialog; -import ij.IJ; -import net.imagej.Dataset; +import ij.Macro; +import ij.plugin.PlugIn; import net.imagej.DatasetService; -import net.imagej.ImageJ; @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp Command" ) -public class BigWarpCommand implements Command +public class BigWarpCommand implements Command, PlugIn { + @Parameter private DatasetService datasets; + + @Override + public void run( String args ) + { + System.out.println( "BigWarpCommand" ); + + final String macroOptions = Macro.getOptions(); + String options = args; + if ( options == null || options.isEmpty() ) + options = macroOptions; + + System.out.println( "macro options : " + macroOptions ); + final boolean isMacro = (options != null && !options.isEmpty()); + + if ( isMacro ) + BigWarpInitDialog.runMacro( macroOptions ); + else + BigWarpInitDialog.createAndShow( datasets ); + } @Override public void run() { - BigWarpInitDialog.createAndShow( datasets ); + run(null); } - public static void main( String[] args ) throws IOException + public static void main( String[] a ) throws IOException { - ImageJ ij2 = new ImageJ(); - ij2.ui().showUI(); +// ImageJ ij2 = new ImageJ(); +// ij2.ui().showUI(); +// +//// Object im1 = ij2.io().open( "/home/john/tmp/mri-stack.tif" ); +//// Object im2 = ij2.io().open( "/home/john/tmp/t1-head.tif" ); +// +// Object im1 = ij2.io().open( "/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif" ); +// Object im2 = ij2.io().open( "/groups/saalfeld/home/bogovicj/tmp/t1-head.tif" ); +// +// ij2.ui().show( im1 ); +// ij2.ui().show( im2 ); - Object im1 = ij2.io().open( "/home/john/tmp/mri-stack.tif" ); - Object im2 = ij2.io().open( "/home/john/tmp/t1-head.tif" ); - ij2.ui().show( im1 ); - ij2.ui().show( im2 ); +// String args = "images=[a, b, c], isMoving=[true, true, false], transforms=[,,]"; +// +// String imagesList = null; +// String isMovingList = null; +// String transformsList = null; } } diff --git a/src/main/java/bigwarp/util/BigWarpUtils.java b/src/main/java/bigwarp/util/BigWarpUtils.java index 0a98a964..fe15a580 100644 --- a/src/main/java/bigwarp/util/BigWarpUtils.java +++ b/src/main/java/bigwarp/util/BigWarpUtils.java @@ -22,6 +22,7 @@ package bigwarp.util; import java.awt.Dimension; +import java.util.HashMap; import bdv.util.Affine3DHelpers; import bdv.viewer.Source; @@ -226,6 +227,46 @@ public static void normalize( double[] x ) x[ i ] /= magSqr; } + public static HashMap parseMacroArguments( String input ) + { + return parseMacroArguments( input, "=", "[", "]" ); + } + + public static HashMap parseMacroArguments( String input, String keyDelim, String startDelim, String endDelim ) + { + final HashMap output = new HashMap<>(); + + String arguments = input.trim(); + boolean done = false; + while( !done ) + { + int i = arguments.indexOf( keyDelim ); + final String key = arguments.substring( 0, i ); + output.put( key, parse( arguments, startDelim, endDelim )); + + i = arguments.indexOf( endDelim ); + if( i < 0 || i +1 > arguments.length() ) + done = true; + + arguments = arguments.substring( i + 1 ).trim(); + if( arguments.length() == 0 ) + done = true; + else + arguments = arguments.substring( 1 ).trim(); // remove comma + } + + return output; + } + + public static String parse( String arg, String start, String end ) + { + final int startIdx = arg.indexOf( start ) + 1; + final int endIdx = arg.indexOf( end ); + if ( startIdx < 0 || endIdx < 0 ) + return null; + + return arg.substring( startIdx, endIdx ); + } // /** // * Computes the angle of rotation between the two input quaternions, From d730e9f42599ffeb05823312a4ce06d167518790 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 29 Nov 2022 17:12:28 -0500 Subject: [PATCH 151/282] feat: working macro recording --- src/main/java/bdv/gui/BigWarpInitDialog.java | 84 ++++++++++++------- .../sourceList/BigWarpSourceTableModel.java | 2 +- src/main/java/bdv/ij/BigWarpCommand.java | 20 +++-- 3 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index b432c45c..3236987b 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -8,7 +8,6 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; -import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Set; @@ -53,7 +52,9 @@ import bigwarp.source.SourceInfo; import bigwarp.util.BigWarpUtils; import ij.IJ; +import ij.ImageJ; import ij.ImagePlus; +import ij.Macro; import ij.Prefs; import ij.WindowManager; import ij.plugin.frame.Recorder; @@ -95,6 +96,7 @@ public class BigWarpInitDialog extends JFrame private static final int DEFAULT_MID_PAD = 5; private static final String commandName = "BigWarp"; + private static final String projectKey = "project"; private static final String imagesKey = "images"; private static final String movingKey = "moving"; private static final String transformsKey = "transforms"; @@ -138,7 +140,7 @@ public BigWarpInitDialog( final String title, final DatasetService datasetServic okayCallback = x -> { macroRecord(); - runBigWarp( projectPathTxt.getText(), x, datasetService ); + runBigWarp(); }; imagePathUpdateCallback = ( p ) -> { @@ -168,7 +170,13 @@ public static void main( String[] args ) throws IOException // IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); // IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); - createAndShow(); + new ImageJ(); + IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); + String macroOptions = "images=imagej://mri-stack.tif,imagej://mri-stack.tif moving=true,false transforms=,"; + runMacro( macroOptions ); + +// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); +// createAndShow(); } public static void runBigWarp( String projectPath, String[] images, String[] moving, String[] transforms ) @@ -235,7 +243,6 @@ public void runBigWarp() { if (Recorder.record) { - System.out.println( "record" ); Recorder.setCommand(commandName); macroRecord(); Recorder.saveCommand(); @@ -250,8 +257,7 @@ public void runBigWarp() final int N = sourceTable.getRowCount(); for( int i = 0; i < N; i++ ) { - System.out.println( "id : " + id ); - SourceRow tableRow = sourceTable.get( i ); + SourceRow tableRow = sourceTableModel.get( i ); if( tableRow.type.equals( SourceType.IMAGEPLUS ) ) { final ImagePlus imp = WindowManager.getImage( tableRow.srcName ); @@ -716,7 +722,6 @@ private String browseDialogGeneral( final int mode, final FileFilter filefilter fileChooser.setFileSelectionMode( mode ); if( filefilter == null ) { - System.out.println( "file filter"); fileChooser.setFileFilter( filefilter ); } @@ -867,37 +872,60 @@ public String macroRecord() public static void runMacro( String args ) { - final HashMap< String, String > keyVals = BigWarpUtils.parseMacroArguments( args ); - final Set< String > keys = keyVals.keySet(); + String project = Macro.getValue( args, projectKey, "" ); - if( keys.contains("project")) + String[] images = Macro.getValue( args, imagesKey, "" ).split( ",", -1 ); + String[] moving = Macro.getValue( args, movingKey, "" ).split( ",", -1 ); + String[] transforms = Macro.getValue( args, transformsKey, "" ).split( ",", -1 ); + + if( !project.isEmpty()) { - runBigWarp( keyVals.get( "project" ), null, null, null ); + runBigWarp( project, null, null, null ); } else { - if( !keys.contains( "images" ) || !keys.contains( "moving" )) + if( images.length == 0 || moving.length == 0 ) { - System.out.println( "images and moving keys required" ); + System.err.println( "images and moving keys required" ); return; } - - final String[] images = keyVals.get( "images" ).split( ",", -1 ); - final String[] moving = keyVals.get( "moving" ).split( ",", -1 ); - -// final Boolean[] moving = Arrays.stream( keyVals.get( "moving" ).split( ",", -1 ) ).map( x -> { -// return x.equals( "true" ); -// } ).toArray( Boolean[]::new ); - -// final String transforms; -// if( keys.contains( "transforms" ) ) -// transforms = keyVals.get( "transforms" ); -// else -// transforms = ""; - - // TOD fix transforms + // TODO fix transforms runBigWarp( null, images, moving, null ); } + +// System.out.println( "BigWarpInitDialog runMacro"); +// System.out.println( args ); +// final HashMap< String, String > keyVals = BigWarpUtils.parseMacroArguments( args ); +// final Set< String > keys = keyVals.keySet(); + +// if( keys.contains("project")) +// { +// runBigWarp( keyVals.get( "project" ), null, null, null ); +// } +// else +// { +// if( !keys.contains( "images" ) || !keys.contains( "moving" )) +// { +// System.out.println( "images and moving keys required" ); +// return; +// } +// +// final String[] images = keyVals.get( "images" ).split( ",", -1 ); +// final String[] moving = keyVals.get( "moving" ).split( ",", -1 ); +// +//// final Boolean[] moving = Arrays.stream( keyVals.get( "moving" ).split( ",", -1 ) ).map( x -> { +//// return x.equals( "true" ); +//// } ).toArray( Boolean[]::new ); +// +//// final String transforms; +//// if( keys.contains( "transforms" ) ) +//// transforms = keyVals.get( "transforms" ); +//// else +//// transforms = ""; +// +// // TOD fix transforms +// runBigWarp( null, images, moving, null ); +// } } } diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index 919cd92b..a754ad0d 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -138,7 +138,7 @@ public void addImagePlus( String srcName ) public void addImagePlus( String srcName, boolean isMoving ) { - add( srcName, isMoving, SourceType.DATASET ); + add( srcName, isMoving, SourceType.IMAGEPLUS ); } public void addDataset( String srcName ) diff --git a/src/main/java/bdv/ij/BigWarpCommand.java b/src/main/java/bdv/ij/BigWarpCommand.java index 1e86be0c..ffa57c09 100644 --- a/src/main/java/bdv/ij/BigWarpCommand.java +++ b/src/main/java/bdv/ij/BigWarpCommand.java @@ -9,32 +9,24 @@ import bdv.gui.BigWarpInitDialog; import ij.Macro; import ij.plugin.PlugIn; -import net.imagej.DatasetService; @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp Command" ) public class BigWarpCommand implements Command, PlugIn { - @Parameter - private DatasetService datasets; - @Override public void run( String args ) { - System.out.println( "BigWarpCommand" ); - final String macroOptions = Macro.getOptions(); String options = args; if ( options == null || options.isEmpty() ) options = macroOptions; - System.out.println( "macro options : " + macroOptions ); final boolean isMacro = (options != null && !options.isEmpty()); - if ( isMacro ) BigWarpInitDialog.runMacro( macroOptions ); else - BigWarpInitDialog.createAndShow( datasets ); + BigWarpInitDialog.createAndShow( null ); } @Override @@ -45,6 +37,16 @@ public void run() public static void main( String[] a ) throws IOException { +// String options = "images=mri-stack.tif,mri-stack.tif moving=true,false transforms=,"; +// +// String images = Macro.getValue(options, "images", ""); +// String moving = Macro.getValue(options, "moving", ""); +// String transforms = Macro.getValue(options, "transforms", ""); +// +// System.out.println( images ); +// System.out.println( moving ); +// System.out.println( transforms ); + // ImageJ ij2 = new ImageJ(); // ij2.ui().showUI(); // From ef85e360035cd77f16c30652a931d02dfd444f91 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 30 Nov 2022 10:27:52 -0500 Subject: [PATCH 152/282] fix: attempt to prevent initial useless recorded command --- src/main/java/bdv/gui/BigWarpInitDialog.java | 13 +++++++++++++ src/main/java/bdv/ij/BigWarpCommand.java | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 3236987b..f904e5df 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -109,6 +109,8 @@ public class BigWarpInitDialog extends JFrame private String transformList; + private boolean initialRecorderState; + public BigWarpInitDialog() { // this( "BigWarp" ); @@ -136,11 +138,14 @@ public BigWarpInitDialog( final String title, final DatasetService datasetServic cancelCallback = x -> { setVisible( false ); dispose(); + Recorder.record = initialRecorderState; }; okayCallback = x -> { macroRecord(); runBigWarp(); + Recorder.record = initialRecorderState; + setVisible( false ); }; imagePathUpdateCallback = ( p ) -> { @@ -154,6 +159,11 @@ public BigWarpInitDialog( final String title, final DatasetService datasetServic }; } + public void setInitialRecorderState( boolean initialRecorderState ) + { + this.initialRecorderState = initialRecorderState; + } + public static void main( String[] args ) throws IOException { // ImageJ ij2 = new ImageJ(); @@ -856,6 +866,9 @@ public void updateParametersFromTable() public String macroRecord() { + if( !Recorder.record ) + return ""; + updateParametersFromTable(); // return String.format( "images=[%s], moving=[%s], transformations=[%s]", // imageList.toString(), movingList.toString(), transformList.toString() ); diff --git a/src/main/java/bdv/ij/BigWarpCommand.java b/src/main/java/bdv/ij/BigWarpCommand.java index ffa57c09..4d45afbc 100644 --- a/src/main/java/bdv/ij/BigWarpCommand.java +++ b/src/main/java/bdv/ij/BigWarpCommand.java @@ -9,14 +9,23 @@ import bdv.gui.BigWarpInitDialog; import ij.Macro; import ij.plugin.PlugIn; +import ij.plugin.frame.Recorder; @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp Command" ) public class BigWarpCommand implements Command, PlugIn { + private boolean initialRecorderState; + + public BigWarpCommand() + { + initialRecorderState = Recorder.record; + Recorder.record = false; + } @Override public void run( String args ) { + Recorder.record = initialRecorderState; final String macroOptions = Macro.getOptions(); String options = args; if ( options == null || options.isEmpty() ) @@ -26,7 +35,11 @@ public void run( String args ) if ( isMacro ) BigWarpInitDialog.runMacro( macroOptions ); else - BigWarpInitDialog.createAndShow( null ); + { + final BigWarpInitDialog dialog = BigWarpInitDialog.createAndShow( null ); + // dialog sets recorder to its initial state on cancel or execution + dialog.setInitialRecorderState( initialRecorderState ); + } } @Override From 09cc00889e5c9395c3ee29a6203eeecbbed09d2e Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 30 Nov 2022 10:31:29 -0500 Subject: [PATCH 153/282] fix: make BigWarpInitDialog string fields editable in the table --- .../java/bdv/gui/BigWarpLandmarkPanel.java | 9 +++--- .../sourceList/BigWarpSourceListPanel.java | 31 ++++++++++--------- .../sourceList/BigWarpSourceTableModel.java | 9 ++++-- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpLandmarkPanel.java b/src/main/java/bdv/gui/BigWarpLandmarkPanel.java index 961af7f1..1750004f 100644 --- a/src/main/java/bdv/gui/BigWarpLandmarkPanel.java +++ b/src/main/java/bdv/gui/BigWarpLandmarkPanel.java @@ -37,6 +37,7 @@ import javax.swing.KeyStroke; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; +import javax.swing.table.AbstractTableModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -153,11 +154,11 @@ public JTable getJTable() * while editing cells. This prevents hotkeys from being activated. * */ - public class JTableChecking extends JTable + public static class JTableChecking extends JTable { private static final long serialVersionUID = 1437406384583869710L; - public JTableChecking( LandmarkTableModel tableModel ) + public JTableChecking( AbstractTableModel tableModel ) { super( tableModel ); } @@ -175,7 +176,7 @@ protected boolean processKeyBinding( } } - public class TextFieldCell extends JTextField + public static class TextFieldCell extends JTextField { private static final long serialVersionUID = -4327183047476876882L; @@ -211,7 +212,7 @@ public void focusLost( FocusEvent e ) } } - public class TextFieldCellEditor extends DefaultCellEditor + public static class TextFieldCellEditor extends DefaultCellEditor { private static final long serialVersionUID = 9185738725311357320L; diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java index 3d5923e9..97b7bc11 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceListPanel.java @@ -32,6 +32,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import bdv.gui.BigWarpLandmarkPanel.JTableChecking; +import bdv.gui.BigWarpLandmarkPanel.TextFieldCell; +import bdv.gui.BigWarpLandmarkPanel.TextFieldCellEditor; import bdv.gui.sourceList.BigWarpSourceTableModel.ButtonEditor; import bdv.gui.sourceList.BigWarpSourceTableModel.ButtonRenderer; @@ -41,23 +44,16 @@ public class BigWarpSourceListPanel extends JPanel protected BigWarpSourceTableModel tableModel; - protected JTable table; + protected JTableChecking table; public final Logger logger = LoggerFactory.getLogger( BigWarpSourceListPanel.class ); public BigWarpSourceListPanel( BigWarpSourceTableModel tableModel ) { super( new GridLayout( 1, 0 ) ); - setTableModel( tableModel ); - table = new JTable( tableModel ); - table.setPreferredScrollableViewportSize( new Dimension( 500, 70 ) ); - table.setFillsViewportHeight( true ); - - table.getColumn( " " ).setCellRenderer( new ButtonRenderer() ); - table.getColumn( " " ).setCellEditor( new ButtonEditor( new JCheckBox(), tableModel ) ); - table.getColumn( " " ).setPreferredWidth( 24 ); - table.getColumn( " " ).setWidth( 24 ); + // set table model re-generates the table + setTableModel( tableModel ); final JScrollPane scrollPane = new JScrollPane( table ); add( scrollPane ); @@ -70,11 +66,18 @@ public BigWarpSourceTableModel getTableModel() public void genJTable() { - table = new JTable( getTableModel() ); - - table.setPreferredScrollableViewportSize( new Dimension( 400, 800 ) ); + table = new JTableChecking( tableModel ); + table.setPreferredScrollableViewportSize( new Dimension( 500, 70 ) ); table.setFillsViewportHeight( true ); table.setShowVerticalLines( false ); + + table.setDefaultEditor( String.class, + new TextFieldCellEditor( new TextFieldCell(table), String.class )); + + table.getColumn( " " ).setCellRenderer( new ButtonRenderer() ); + table.getColumn( " " ).setCellEditor( new ButtonEditor( new JCheckBox(), tableModel ) ); + table.getColumn( " " ).setPreferredWidth( 24 ); + table.getColumn( " " ).setWidth( 24 ); } public void setTableModel( BigWarpSourceTableModel tableModel ) @@ -87,6 +90,6 @@ public JTable getJTable() { return table; } - + } diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index a754ad0d..45f8ca0d 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -27,7 +27,9 @@ public static enum SourceType { IMAGEPLUS, DATASET, URL }; protected final ArrayList sources; protected final ArrayList rmRowButtons; + protected static int imageColIdx = 0; protected static int movingColIdx = 1; + protected static int transformColIdx = 2; protected static int removeColIdx = 3; private Component container; @@ -94,7 +96,6 @@ else if ( col == 3 ) public boolean isCellEditable( int row, int col ) { return true; -// return ( col == movingColIdx ) || ( col == removeColIdx ); } @Override @@ -102,6 +103,10 @@ public void setValueAt(Object value, int row, int col) { if( col == movingColIdx ) sources.get( row ).moving = (Boolean)value; + if( col == imageColIdx ) + sources.get( row ).srcName = (String)value; + if( col == transformColIdx ) + sources.get( row ).transformName = (String)value; } public void add( String srcName, boolean moving, SourceType type ) @@ -155,7 +160,7 @@ public boolean remove( int i ) { if( i >= sources.size() ) { - System.out.println( "NOT REMOVED - SHOULD NEVER BE CALLED" ); + //System.out.println( "NOT REMOVED - SHOULD NEVER BE CALLED" ); return false; } From 4a6b664588fd0d731ea77da562af493445604308 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 30 Nov 2022 10:32:36 -0500 Subject: [PATCH 154/282] fix: add imagej scheme for image names --- src/main/java/bdv/gui/BigWarpInitDialog.java | 27 ++++++++------------ 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index f904e5df..1b5b2008 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -8,9 +8,7 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; -import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; @@ -50,7 +48,6 @@ import bigwarp.BigWarpData; import bigwarp.BigWarpInit; import bigwarp.source.SourceInfo; -import bigwarp.util.BigWarpUtils; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; @@ -101,19 +98,17 @@ public class BigWarpInitDialog extends JFrame private static final String movingKey = "moving"; private static final String transformsKey = "transforms"; - private String projectPath; + public static final String ImageJPrefix = "imagej://"; + private String projectPath; private String imageList; - private String movingList; - private String transformList; private boolean initialRecorderState; public BigWarpInitDialog() { -// this( "BigWarp" ); } public BigWarpInitDialog( final String title ) @@ -181,12 +176,12 @@ public static void main( String[] args ) throws IOException // IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); new ImageJ(); - IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); - String macroOptions = "images=imagej://mri-stack.tif,imagej://mri-stack.tif moving=true,false transforms=,"; - runMacro( macroOptions ); +// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); +// String macroOptions = "images=imagej://mri-stack.tif,imagej://mri-stack.tif moving=true,false transforms=,"; +// runMacro( macroOptions ); -// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); -// createAndShow(); + IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); + createAndShow(); } public static void runBigWarp( String projectPath, String[] images, String[] moving, String[] transforms ) @@ -270,7 +265,8 @@ public void runBigWarp() SourceRow tableRow = sourceTableModel.get( i ); if( tableRow.type.equals( SourceType.IMAGEPLUS ) ) { - final ImagePlus imp = WindowManager.getImage( tableRow.srcName ); + // strip off prefix if present + final ImagePlus imp = WindowManager.getImage( tableRow.srcName.replaceAll( "^"+ImageJPrefix, "" ) ); LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, imp, id, 0, tableRow.moving ); BigWarpInit.add( data, infos, tableRow.getTransform() ); id += infos.size(); @@ -338,8 +334,7 @@ public JPanel createContent() final int BUTTON_PAD = DEFAULT_BUTTON_PAD; final int MID_PAD = DEFAULT_MID_PAD; - final int frameSizeX = getSize().width; - + final int frameSizeX = UIScale.scale( 600 ); final JPanel panel = new JPanel(false); panel.setLayout(new GridBagLayout()); @@ -618,7 +613,7 @@ protected void addImagePlus( String title, boolean moving ) // an image is not added, and / or updating the dropdown menu periodically if( !title.isEmpty() && imp != null ) { - sourceTableModel.addImagePlus( title, moving ); + sourceTableModel.addImagePlus( ImageJPrefix + title, moving ); repaint(); } } From c80cbde6bc53dbc2e9ac1c9a22fd78a4e79e1c05 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 30 Nov 2022 10:37:32 -0500 Subject: [PATCH 155/282] feat: toward improving settings loading on empty bigwarp * add new method for creating landmark frame * landmark frame, ndims no longer final * viewer transform event handlers still incorrect see #158 --- src/main/java/bigwarp/BigWarp.java | 68 ++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 5f51f50d..8b95c8d3 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -24,9 +24,11 @@ import java.awt.Color; import java.awt.Component; import java.awt.Cursor; +import java.awt.Dimension; import java.awt.FileDialog; import java.awt.KeyEventPostProcessor; import java.awt.KeyboardFocusManager; +import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; @@ -236,7 +238,7 @@ public class BigWarp< T > protected final LandmarkPointMenu landmarkPopupMenu; - protected final BigWarpLandmarkFrame landmarkFrame; + protected BigWarpLandmarkFrame landmarkFrame; protected final BigWarpViewerSettings viewerSettings; @@ -340,8 +342,7 @@ public class BigWarp< T > private CopyOnWriteArrayList< TransformListener< InvertibleRealTransform > > transformListeners = new CopyOnWriteArrayList<>( ); - final int ndims; - + int ndims; @Deprecated public BigWarp( final BigWarpData< T > data, final String windowTitle, final ProgressWriter progressWriter ) throws SpimDataException @@ -382,19 +383,10 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final * Set up LandmarkTableModel, holds the data and interfaces with the * LandmarkPanel */ - landmarkModel = new LandmarkTableModel( ndims ); - landmarkModellistener = new LandmarkTableListener(); - landmarkModel.addTableModelListener( landmarkModellistener ); - addTransformListener( landmarkModel ); - /* Set up landmark panel */ - landmarkPanel = new BigWarpLandmarkPanel( landmarkModel ); - landmarkPanel.setOpaque( true ); - landmarkTable = landmarkPanel.getJTable(); - landmarkTable.setDefaultRenderer( Object.class, new WarningTableCellRenderer() ); - addDefaultTableMouseListener(); - landmarkFrame = new BigWarpLandmarkFrame( "Landmarks", landmarkPanel, this ); + /* Set up landmark panel */ + setupLandmarkFrame(); baseXfmList = new AbstractModel< ? >[ 3 ]; setupWarpMagBaselineOptions( baseXfmList, ndims ); @@ -646,6 +638,48 @@ public void run() } + protected void setupLandmarkFrame() + { + Point loc = null; + Dimension sz = null; + if ( landmarkFrame != null ) + { + loc = landmarkFrame.getLocation(); + sz = landmarkFrame.getSize(); + + landmarkModel = null; + landmarkFrame.setVisible( false ); + landmarkFrame.dispose(); + landmarkFrame = null; + landmarkPanel = null; + + } + + landmarkModel = new LandmarkTableModel( ndims ); + landmarkModellistener = new LandmarkTableListener(); + landmarkModel.addTableModelListener( landmarkModellistener ); + addTransformListener( landmarkModel ); + + /* Set up landmark panel */ + landmarkPanel = new BigWarpLandmarkPanel( landmarkModel ); + landmarkPanel.setOpaque( true ); + landmarkTable = landmarkPanel.getJTable(); + landmarkTable.setDefaultRenderer( Object.class, new WarningTableCellRenderer() ); + addDefaultTableMouseListener(); + landmarkFrame = new BigWarpLandmarkFrame( "Landmarks", landmarkPanel, this ); + + if ( loc != null ) + landmarkFrame.setLocation( loc ); + + if ( sz != null ) + landmarkFrame.setSize( sz ); + + landmarkFrame.pack(); + landmarkFrame.setVisible( true ); + + setUpLandmarkMenus(); + } + public void synchronizeSources() { viewerP.state().clearSources(); @@ -3659,6 +3693,12 @@ public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSourc settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); activeSourcesDialogP.update(); activeSourcesDialogQ.update(); + + //ndims = detec data.sources + ndims = detectNumDims( data.sources ); + setupLandmarkFrame(); + viewerP.setNumDim( ndims ); + viewerQ.setNumDim( ndims ); } viewerFrameP.repaint(); From 3004763bbb872ea9863caf1ef6a4142961b289a7 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 30 Nov 2022 16:21:02 -0500 Subject: [PATCH 156/282] feat: working transform loading from url --- pom.xml | 7 + src/main/java/bdv/gui/BigWarpInitDialog.java | 18 +- .../sourceList/BigWarpSourceTableModel.java | 26 +- .../transforms/NgffTransformations.java | 344 ++++++++++++++++++ 4 files changed, 376 insertions(+), 19 deletions(-) create mode 100644 src/main/java/bigwarp/transforms/NgffTransformations.java diff --git a/pom.xml b/pom.xml index b0b0ccb2..3e0b1a09 100644 --- a/pom.xml +++ b/pom.xml @@ -215,6 +215,7 @@ org.janelia.saalfeldlab n5 + 2.5.2-SNAPSHOT org.janelia.saalfeldlab @@ -302,6 +303,7 @@ org.janelia.saalfeldlab n5-imglib2 + 5.0.0-SNAPSHOT @@ -315,5 +317,10 @@ xmlunit 1.5 + + ome + ome-ngff-java + 0.0.0-SNAPSHOT + diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 1b5b2008..420c568d 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -48,6 +48,7 @@ import bigwarp.BigWarpData; import bigwarp.BigWarpInit; import bigwarp.source.SourceInfo; +import bigwarp.transforms.NgffTransformations; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; @@ -58,6 +59,7 @@ import mpicbg.spim.data.SpimDataException; import net.imagej.Dataset; import net.imagej.DatasetService; +import net.imglib2.realtransform.RealTransform; public class BigWarpInitDialog extends JFrame { @@ -198,11 +200,17 @@ public static void runBigWarp( String projectPath, String[] images, String[] // TODO deal with exceptions? try { - LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, images[ i ], id, moving[ i ].equals( "true" ) ); -// BigWarpInit.add( data, infos, transforms[ i ] ); + final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, images[ i ], id, moving[ i ].equals( "true" ) ); - // TODO fix transforms - BigWarpInit.add( data, infos ); + final String transformUrl = transforms[ i ]; + RealTransform transform = null; + if( transformUrl!= null && !transformUrl.isEmpty() ) + transform = NgffTransformations.open( transformUrl ); + + if( transform != null ) + BigWarpInit.add( data, infos, transform ); + else + BigWarpInit.add( data, infos ); id += infos.size(); } @@ -845,7 +853,7 @@ public void updateParametersFromTable() { imageList.append( sourceTableModel.get( i ).srcName ); movingList.append( sourceTableModel.get( i ).moving ); - transformList.append( sourceTableModel.get( i ).transformName ); + transformList.append( sourceTableModel.get( i ).transformUrl ); if( i < N -1 ) { imageList.append( listSeparator ); diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index 45f8ca0d..0a2e393b 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -13,6 +13,7 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; +import bigwarp.transforms.NgffTransformations; import net.imglib2.realtransform.RealTransform; public class BigWarpSourceTableModel extends AbstractTableModel @@ -106,7 +107,7 @@ public void setValueAt(Object value, int row, int col) if( col == imageColIdx ) sources.get( row ).srcName = (String)value; if( col == transformColIdx ) - sources.get( row ).transformName = (String)value; + sources.get( row ).transformUrl = (String)value; } public void add( String srcName, boolean moving, SourceType type ) @@ -123,7 +124,7 @@ public void add( String srcName, boolean moving, SourceType type ) public void setTransform( int i, String transform ) { - sources.get( i ).transformName = transform; + sources.get( i ).transformUrl = transform; } public void add( String srcName, boolean moving ) @@ -184,15 +185,15 @@ public static class SourceRow { public String srcName; public boolean moving; - public String transformName; + public String transformUrl; public SourceType type; - public SourceRow( String srcName, boolean moving, String transformName, SourceType type ) + public SourceRow( String srcName, boolean moving, String transformUrl, SourceType type ) { this.srcName = srcName; this.moving = moving; - this.transformName = transformName; + this.transformUrl = transformUrl; this.type = type; } @@ -208,21 +209,18 @@ public Object get( int c ) else if( c == 1 ) return moving; else if ( c == 2 ) - return transformName; + return transformUrl; else return null; } public RealTransform getTransform() { - // TODO depends on in progress dependencies - see dfield-dev branch -// if( transformName != null && !transformName.isEmpty() ) -// { -// // TODO generalize to attributes in n5 -//// final RealTransform tform = NgffTransformations.openJson( transformName ); -// return NgffTransformations.openJson( transformName ); -// } - return null; + RealTransform transform = null; + if( transformUrl!= null && !transformUrl.isEmpty() ) + transform = NgffTransformations.open( transformUrl ); + + return transform; } } diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java new file mode 100644 index 00000000..7be24e80 --- /dev/null +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -0,0 +1,344 @@ +package bigwarp.transforms; + +import java.io.FileWriter; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Optional; + +import org.janelia.saalfeldlab.n5.DatasetAttributes; +import org.janelia.saalfeldlab.n5.N5FSReader; +import org.janelia.saalfeldlab.n5.N5Reader; +import org.janelia.saalfeldlab.n5.N5URL; +import org.janelia.saalfeldlab.n5.ij.N5Factory; +import org.janelia.saalfeldlab.n5.metadata.graph.TransformGraph; +import org.janelia.saalfeldlab.n5.metadata.graph.TransformPath; +import org.janelia.saalfeldlab.n5.metadata.omengff.NgffCoordinateTransformation; +import org.janelia.saalfeldlab.n5.metadata.omengff.NgffCoordinateTransformationAdapter; +import org.janelia.saalfeldlab.n5.metadata.omengff.NgffTranslationTransformation; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.stream.JsonWriter; + +import net.imglib2.img.array.ArrayImg; +import net.imglib2.img.array.ArrayImgs; +import net.imglib2.img.basictypeaccess.array.IntArray; +import net.imglib2.realtransform.AffineGet; +import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.RealTransform; +import net.imglib2.realtransform.RealTransformSequence; +import net.imglib2.realtransform.TransformUtils; +import net.imglib2.type.numeric.RealType; +import net.imglib2.type.numeric.integer.IntType; +import net.imglib2.util.Intervals; +import net.imglib2.util.Pair; +import net.imglib2.util.ValuePair; +import net.imglib2.view.IntervalView; +import ome.ngff.axes.Axis; +import ome.ngff.axes.CoordinateSystem; +import ome.ngff.transformations.CoordinateTransformation; +import ome.ngff.transformations.CoordinateTransformationAdapter; + +public class NgffTransformations +{ + + public static void main( String[] args ) throws Exception + { + // full +// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5?/#/coordinateTransformations[0]"; + + // no dataset +// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5#/coordinateTransformations[0]"; + + // no dataset no attribute + final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; + + final N5URL url = new N5URL( bijPath ); + System.out.println( url.getDataset()); + System.out.println( url.getAttribute()); + + Pair< NgffCoordinateTransformation< ? >, N5Reader > bijN5 = openTransformN5( bijPath ); + System.out.println( bijN5.getA() ); + InvertibleRealTransform bij = openInvertible( bijPath ); + System.out.println( bij ); + + +// final String path = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; +// final N5URL url = new N5URL( path ); +// System.out.println( url.getAttribute() ); +// System.out.println( url.getDataset()); + + +// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5?/#/coordinateTransformations[0]"; +// final N5URL url = new N5URL( bijPath ); +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( url.getLocation() ); +// final CoordinateTransformation ct = n5.getAttribute( url.getDataset(), url.getAttribute(), CoordinateTransformation.class ); +// System.out.println( ct ); +// +// final NgffCoordinateTransformation< ? > nct = NgffCoordinateTransformation.create( ct ); +// RealTransform tform = nct.getTransform( n5 ); +// System.out.println( tform ); + + + + +// final String basePath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; +// final String csPath = "?dfield#coordinateSystems/[0]"; +// final String namePath = "?dfield#coordinateSystems/[0]/name"; +// final String dimPath = "?dfield#/dimensions"; +// +// final N5URL baseUrl = new N5URL( basePath ); +// final N5URL nameUrl = baseUrl.getRelative( namePath ); +// final N5URL csUrl = baseUrl.getRelative( csPath ); +// final N5URL dimUrl = baseUrl.getRelative( dimPath ); +// +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( baseUrl.getLocation() ); +// final String name = n5.getAttribute( nameUrl.getDataset(), nameUrl.getAttribute(), String.class ); +// final CoordinateSystem cs = n5.getAttribute( csUrl.getDataset(), csUrl.getAttribute(), CoordinateSystem.class ); +// final long[] dims = n5.getAttribute( dimUrl.getDataset(), dimUrl.getAttribute(), long[].class ); +// +// System.out.println( name ); +// System.out.println( cs ); +// System.out.println( cs.getAxes()[0].getName() ); +// System.out.println( Arrays.toString( dims ) ); + + + + +//// final String path = "/home/john/projects/ngff/dfieldTest/dfield.n5"; +// final String path = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; +// +// final String dataset = "/"; +//// final String dataset = "coordinateTransformations"; +//// final String dataset = "/dfield"; +// +// final N5FSReader n5 = new N5FSReader( path, gsonBuilder() ); +// +//// RealTransform dfieldTform = open( n5, dataset ); +//// System.out.println( dfieldTform ); +// +//// RealTransform dfieldTform = open( n5, dataset ); +//// System.out.println( dfieldTform ); +// +// TransformGraph g = openGraph( n5, dataset ); +// g.printSummary(); +// RealTransform fwdXfm = g.path( "jrc18F", "fcwb" ).get().totalTransform( n5, g ); +// RealTransform invXfm = g.path( "fcwb", "jrc18F" ).get().totalTransform( n5, g ); +// System.out.println( fwdXfm ); +// System.out.println( invXfm ); + + +// ArrayImg< IntType, IntArray > img = ArrayImgs.ints( 2, 3, 4, 5 ); +// +// int[] p = vectorAxisLastNgff( n5, dataset ); +// System.out.println( Arrays.toString( p )); +// System.out.println( "" ); +// +// IntervalView< IntType > imgP = N5DisplacementField.permute( img, p ); +// System.out.println( Intervals.toString( imgP )); + + +// try +// { +//// AffineGet p2p = N5DisplacementField.openPixelToPhysicalNgff( n5, "transform", true ); +//// System.out.println( p2p ); +// +//// int[] indexes = new int[] {1, 2, 3 }; +//// AffineGet sp2p = TransformUtils.subAffine( p2p, indexes ); +//// System.out.println( sp2p ); +// } +// catch ( Exception e ) +// { +// e.printStackTrace(); +// } + + } + + public static TransformGraph openGraph( N5Reader n5 ) + { + return openGraph( n5, "/" ); + } + + public static TransformGraph openGraph( N5Reader n5, String dataset ) + { + return new TransformGraph( n5, dataset ); + } + + public static RealTransform open( N5Reader n5, String dataset ) + { + // TODO error handling + return openGraph( n5, dataset ).getTransforms().get( 0 ).getTransform( n5 ); + } + + public static RealTransform open( N5Reader n5, String dataset, String name ) + { + // TODO error handling + return openGraph( n5, dataset ).getTransform( name ).get().getTransform( n5 ); + } + + public static < T extends RealTransform> T open( N5Reader n5, String dataset, String input, String output ) + { + // TODO error handling + TransformGraph g = openGraph( n5, dataset ); + return (T)g.path( input, output ).get().totalTransform( n5, g ); + } + + public static RealTransform open( final String url ) + { + Pair< NgffCoordinateTransformation< ? >, N5Reader > pair = openTransformN5( url ); + return pair.getA().getTransform( pair.getB() ); + } + + public static InvertibleRealTransform openInvertible( final String url ) + { + Pair< NgffCoordinateTransformation< ? >, N5Reader > pair = openTransformN5( url ); + return pair.getA().getInvertibleTransform( pair.getB() ); + } + + public static Pair,N5Reader> openTransformN5( final String url ) + { + try + { + final N5URL n5url = new N5URL( url ); + final String loc = n5url.getLocation(); + if( loc.endsWith( ".json" )) + { + return new ValuePair<>( openJson( url ), null); + } + else + { + final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( loc ); + final String dataset = n5url.getDataset() != null ? n5url.getDataset() : "/"; + final String attribute = n5url.getAttribute() != null ? n5url.getAttribute() : "coordinateTransformations/[0]"; + + final CoordinateTransformation ct = n5.getAttribute( dataset, attribute, CoordinateTransformation.class ); + final NgffCoordinateTransformation< ? > nct = NgffCoordinateTransformation.create( ct ); + return new ValuePair<>( nct, n5 ); + } + } + catch ( URISyntaxException | IOException e ) + { + e.printStackTrace(); + return null; + } + } + + public static NgffCoordinateTransformation openJson( final String url ) + { + final Path path = Paths.get( url ); + String string; + try + { + string = new String(Files.readAllBytes(path)); + } + catch ( IOException e ) + { + return null; + } + + final Gson gson = gsonBuilder().create(); + final JsonElement elem = gson.fromJson( string, JsonElement.class ); +// System.out.println( elem ); + +// final CoordinateTransformation ct = gson.fromJson( elem.getAsJsonArray().get( 0 ), CoordinateTransformation.class ); + final CoordinateTransformation ct = gson.fromJson( elem, CoordinateTransformation.class ); +// System.out.println( ct ); + + NgffCoordinateTransformation< ? > nct = NgffCoordinateTransformation.create( ct ); + return nct; +// final RealTransform tform = nct.getTransform( null ); +// System.out.println( tform ); +// +// return tform; + } + + public static void save( String jsonFile, NgffCoordinateTransformation transform ) + { + final GsonBuilder gb = new GsonBuilder(); + gb.registerTypeAdapter(CoordinateTransformation.class, new CoordinateTransformationAdapter() ); + final Gson gson = gb.create(); + try( FileWriter writer = new FileWriter( jsonFile )) + { + gson.toJson( transform, writer ); + writer.close(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + } + + /** + * returns null if no permutation needed + * + * @param cs + * @return a permutation if needed + * @throws Exception + */ + public static final int[] vectorAxisLastNgff( CoordinateSystem cs ) throws Exception { + + final Axis[] axes = cs.getAxes(); + final int n = axes.length; + + if ( axes[ n - 1 ].getType().equals( Axis.DISPLACEMENT_TYPE )) + return null; + else + { + int vecDim = -1; +// for( int i = 0; i < n; i++ ) +// { +// vecDim = i; +// break; +// } +// +// if( vecDim < 0 ) +// return null; + + final int[] permutation = new int[ n ]; + + int k = 0; + for( int i = 0; i < n; i++ ) + { + if ( axes[ i ].getType().equals( Axis.DISPLACEMENT_TYPE )) + vecDim = i; + else + permutation[i] = k++; + } + + // did not find a matching axis + if( vecDim < 0 ) + return null; + + permutation[vecDim] = n-1; + return permutation; + } + } + + /** + * @throws Exception the exception + */ + public static final int[] vectorAxisLastNgff( + final N5Reader n5, String dataset ) throws Exception { + + // TODO move to somewhere more central + TransformGraph g = openGraph( n5, dataset ); + + // TODO need to be smarter about which coordinate system to get + CoordinateSystem cs = g.getCoordinateSystems().iterator().next(); + return vectorAxisLastNgff( cs ); + } + + public static GsonBuilder gsonBuilder() + { + final GsonBuilder gb = new GsonBuilder(); + gb.registerTypeAdapter(CoordinateTransformation.class, new CoordinateTransformationAdapter() ); + return gb; + } + +} From 8ecd8da70ae2dd379fed0ed639a3cd9450718fef Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 30 Nov 2022 17:54:30 -0500 Subject: [PATCH 157/282] feat: add static method to load landmarks --- .../bigwarp/landmarks/LandmarkTableModel.java | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java index 8f521cb4..759ae70b 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java +++ b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java @@ -1214,6 +1214,29 @@ else if( f.getCanonicalPath().endsWith("json")) fromJson( f ); } + public static LandmarkTableModel loadFromCsv( File f, boolean invert ) throws IOException + { + CSVReader reader = new CSVReader( new FileReader( f.getAbsolutePath() ) ); + List< String[] > rows = null; + try + { + rows = reader.readAll(); + reader.close(); + } + catch ( CsvException e ) {} + + LandmarkTableModel ltm = null; + if ( rows.get( 0 ).length == 6 ) + ltm = new LandmarkTableModel( 2 ); + else if ( rows.get( 0 ).length == 8 ) + ltm = new LandmarkTableModel( 3 ); + + if( ltm != null ) + ltm.loadCsvHelper( invert, rows ); + + return ltm; + } + /** * Loads this table from a file * @param f the file @@ -1221,18 +1244,30 @@ else if( f.getCanonicalPath().endsWith("json")) * @throws IOException an exception */ public void loadCsv( File f, boolean invert ) throws IOException + { + CSVReader reader = new CSVReader( new FileReader( f.getAbsolutePath() )); + List< String[] > rows = null; + try + { + rows = reader.readAll(); + reader.close(); + } + catch( CsvException e ){} + + loadCsvHelper( invert, rows ); + } + + /** + * Loads this table from a file + * @param f the file + * @param invert invert the moving and target point sets + * @throws IOException an exception + */ + protected void loadCsvHelper( boolean invert, final List rows ) throws IOException { synchronized(this) { clear(); - CSVReader reader = new CSVReader( new FileReader( f.getAbsolutePath() )); - List< String[] > rows = null; - try - { - rows = reader.readAll(); - reader.close(); - } - catch( CsvException e ){} if( rows == null || rows.size() < 1 ) { System.err.println("Error reading csv"); From 0174ebab9f09d2c709ee60efbe2d6b5b753846eb Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 30 Nov 2022 17:54:55 -0500 Subject: [PATCH 158/282] feat: more methods for imglib2 transforms from mpicbg models --- .../bigwarp/transforms/BigWarpTransform.java | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index dbe5ded9..a8f4e726 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -46,11 +46,14 @@ import mpicbg.models.TranslationModel2D; import mpicbg.models.TranslationModel3D; import net.imglib2.RealRandomAccessible; +import net.imglib2.realtransform.AffineGet; +import net.imglib2.realtransform.AffineTransform2D; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.InverseRealTransform; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.MaskedSimilarityTransform.Interpolators; import net.imglib2.realtransform.ThinplateSplineTransform; +import net.imglib2.realtransform.Translation2D; import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.RealType; @@ -334,7 +337,7 @@ else if( ndims == 3 ) } } } - + public ThinPlateR2LogRSplineKernelTransform getTpsBase() { ThinplateSplineTransform tps = getTps(); @@ -525,6 +528,24 @@ public static AffineTransform3D affine3d( AbstractAffineModel2D model2d, AffineT return out; } + public static AffineTransform2D affine2d( AbstractAffineModel2D model2d, AffineTransform2D out ) + { + double[][] mtx = new double[2][3]; + model2d.toMatrix( mtx ); + + double[] affine = new double[ 6 ]; + affine[ 0 ] = mtx[ 0 ][ 0 ]; + affine[ 1 ] = mtx[ 0 ][ 1 ]; + affine[ 2 ] = mtx[ 0 ][ 2 ]; + + affine[ 4 ] = mtx[ 1 ][ 0 ]; + affine[ 5 ] = mtx[ 1 ][ 1 ]; + affine[ 6 ] = mtx[ 1 ][ 2 ]; + + out.set( affine ); + return out; + } + public static AffineTransform3D affine3d( AbstractAffineModel3D model3d, AffineTransform3D out ) { double[][] mtx = new double[3][4]; @@ -594,4 +615,32 @@ public static AffineTransform3D affine3d( ThinPlateR2LogRSplineKernelTransform t return out; } + public AffineGet toImglib2( Model< ? > model ) + { + if ( tableModel.getNumdims() == 2 ) + return toImglib2( ( AbstractAffineModel2D ) model ); + else + return toImglib2( ( AbstractAffineModel3D ) model ); + } + + public AffineGet toImglib2( AbstractAffineModel2D model ) + { + if( model instanceof TranslationModel2D ) + { + final TranslationModel2D t = (TranslationModel2D)model; + return new Translation2D( t.getTranslation() ); + } + else + { + // affine, rigid, and similarity + // TODO split out rigid? + AffineTransform2D out = new AffineTransform2D(); + return affine2d( model, out ); + } + } + + public AffineGet toImglib2( AbstractAffineModel3D model ) + { + return affine3d( model, new AffineTransform3D() ); + } } From 9d9d218c52499456279b2d61d778ada0e32e861e Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 30 Nov 2022 17:56:03 -0500 Subject: [PATCH 159/282] feat: prelim plugin for exporting linear transformations --- .../bdv/ij/BigWarpTransformExportPlugin.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/main/java/bdv/ij/BigWarpTransformExportPlugin.java diff --git a/src/main/java/bdv/ij/BigWarpTransformExportPlugin.java b/src/main/java/bdv/ij/BigWarpTransformExportPlugin.java new file mode 100644 index 00000000..45b6ca57 --- /dev/null +++ b/src/main/java/bdv/ij/BigWarpTransformExportPlugin.java @@ -0,0 +1,102 @@ +package bdv.ij; + +import java.io.File; +import java.io.IOException; + +import org.janelia.saalfeldlab.n5.imglib2.NgffTransformations; + +import bigwarp.BigWarp; +import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.transforms.BigWarpTransform; +import bigwarp.transforms.WrappedCoordinateTransform; +import fiji.util.gui.GenericDialogPlus; +import ij.ImageJ; +import ij.plugin.PlugIn; +import mpicbg.models.Model; +import net.imglib2.realtransform.AffineGet; + +public class BigWarpTransformExportPlugin implements PlugIn +{ + private boolean promptLandmarks = true; + + private BigWarpTransform bwTransform; + + public static void main( final String[] args ) + { + new ImageJ(); + new BigWarpTransformExportPlugin().run( null ); + } + + public void runFromBigWarpInstance( final BigWarp< ? > bw ) + { + promptLandmarks = false; + bwTransform = bw.getBwTransform(); + run( null ); + } + + @Override + public void run( final String arg ) + { + // TODO deal with macro recordability + + final GenericDialogPlus gd = new GenericDialogPlus( "Export BigWarp Transformation" ); + gd.addMessage( "Transformation export:" ); + if ( promptLandmarks ) + { + gd.addFileField( "landmarks_file", "" ); + } + + gd.addChoice( "Transform type", + new String[] { + BigWarpTransform.AFFINE, + BigWarpTransform.SIMILARITY, + BigWarpTransform.ROTATION, + BigWarpTransform.TRANSLATION }, + BigWarpTransform.AFFINE ); + + gd.addFileField( "Output json file or n5", "" ); + gd.addStringField( "N5 dataset", "" ); + gd.addStringField( "N5 attribute name", "" ); + + gd.showDialog(); + if ( gd.wasCanceled() ) + return; + + String landmarksPath = null; + if ( promptLandmarks ) + { + landmarksPath = gd.getNextString(); + } + + final String transformTypeOption = gd.getNextChoice(); + final String fileOrN5Root = gd.getNextString(); + final String n5Dataset = gd.getNextString(); + final String n5Attr = gd.getNextString(); + + if ( bwTransform == null ) + { + try + { + final LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File( landmarksPath ), false ); + bwTransform = new BigWarpTransform( ltm, transformTypeOption ); + } + catch ( IOException e ) + { + e.printStackTrace(); + return; + } + } + + String url = fileOrN5Root; + if ( !n5Dataset.isEmpty() ) + url = url + "?" + n5Dataset; + + if ( !n5Attr.isEmpty() ) + url = url + "#" + n5Attr; + + final WrappedCoordinateTransform wct = ( WrappedCoordinateTransform ) bwTransform.getTransformation( false ); + final AffineGet affine = bwTransform.toImglib2( ( Model< ? > ) wct.getTransform() ); + NgffTransformations.save( url, NgffTransformations.createAffine( affine ) ); + } + +} From c263dbafd41e21e9d108995d22b0ea77d014d756 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 1 Dec 2022 09:34:14 -0500 Subject: [PATCH 160/282] feat(test): add main for duplicating #158 --- src/test/java/bigwarp/SerializationTest.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index a1089616..07e522c8 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -40,6 +40,8 @@ import org.junit.Test; import org.xml.sax.SAXException; +import static bigwarp.BigWarpTestUtils.createTemp3DImage; + public class SerializationTest { @@ -136,7 +138,7 @@ public void setupAssignmentsTest() throws SpimDataException, IOException, URISyn bw = BigWarpTestUtils.createBigWarp( true, false, false, false ); final PipedWriter writer = new PipedWriter(); - final PipedReader in = new PipedReader( writer, 10000 ); + final PipedReader in = new PipedReader( writer, 1000 ); final JsonWriter out = new JsonWriter( writer ); new BigwarpSettings.SetupAssignmentsAdapter( bw.setupAssignments ).write( out, bw.setupAssignments ); @@ -487,4 +489,13 @@ public void landmarkComparisonTest() throws SpimDataException, IOException, JDOM } + public static void main( String[] args ) throws SpimDataException, URISyntaxException, IOException, JDOMException, InterruptedException + { + BigWarp bw = BigWarpTestUtils.createBigWarp("/tmp/img8270806677315563879.tif", true, true, false, false); + bw.saveSettingsJson( "/tmp/3d-settings.json" ); + bw.closeAll(); + Thread.sleep( 1000 ); + bw = BigWarpTestUtils.createBigWarp(); + bw.loadSettings("/tmp/3d-settings.json"); + } } From 33b699b5e491a24b76771b592810600398252275 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Sat, 3 Dec 2022 14:26:46 -0500 Subject: [PATCH 161/282] chore: imglib-realtransform-4.0.1 --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3e0b1a09..53b1f6dd 100644 --- a/pom.xml +++ b/pom.xml @@ -111,12 +111,11 @@ **/resources/*.xml 6.0.0 - 4.0.0 + 4.0.1 1.48 1.4.1 3.0.3 - 4.0.0 2.5.1 3.2.1 From 54e073b46801ea04ca1bd396231451c3a17dd252 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Sat, 3 Dec 2022 14:30:38 -0500 Subject: [PATCH 162/282] feat: implement export of flattened dfield --- .../ij/BigWarpToDeformationFieldPlugIn.java | 219 +++++++++++++----- src/main/java/bigwarp/BigWarp.java | 2 +- .../transforms/NgffTransformations.java | 49 +++- 3 files changed, 209 insertions(+), 61 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 5403be64..7d98772c 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -42,12 +43,17 @@ import org.janelia.saalfeldlab.n5.ij.N5Exporter; import org.janelia.saalfeldlab.n5.ij.N5Factory; import org.janelia.saalfeldlab.n5.imglib2.N5DisplacementField; +import org.janelia.saalfeldlab.n5.metadata.omengff.NgffAffineTransformation; +import org.janelia.saalfeldlab.n5.metadata.omengff.NgffDisplacementsTransformation; +import org.janelia.saalfeldlab.n5.metadata.omengff.NgffSequenceTransformation; -import bdv.gui.TransformTypeSelectDialog; import bdv.viewer.SourceAndConverter; +import bigwarp.BigWarpData; import bigwarp.BigWarpExporter; import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.source.SourceInfo; import bigwarp.transforms.BigWarpTransform; +import bigwarp.transforms.NgffTransformations; import fiji.util.gui.GenericDialogPlus; import ij.IJ; import ij.ImageJ; @@ -73,9 +79,9 @@ import net.imglib2.realtransform.AffineTransform2D; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.DisplacementFieldTransform; +import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.RealTransform; -import net.imglib2.realtransform.Scale2D; -import net.imglib2.realtransform.Scale3D; +import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.ThinplateSplineTransform; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.DoubleType; @@ -84,6 +90,7 @@ import net.imglib2.view.Views; import net.imglib2.view.composite.CompositeIntervalView; import net.imglib2.view.composite.GenericComposite; +import ome.ngff.transformations.CoordinateTransformation; /** * ImageJ plugin to convert the thin plate spline to a deformation field. @@ -101,6 +108,9 @@ public class BigWarpToDeformationFieldPlugIn implements PlugIn N5Exporter.XZ_COMPRESSION, N5Exporter.BLOSC_COMPRESSION }; + public static final String flattenOption = "Flat"; + public static final String sequenceOption = "Sequence"; + public static void main( final String[] args ) { new ImageJ(); @@ -121,22 +131,22 @@ public static void main( final String[] args ) */ @Deprecated public void runFromBigWarpInstance( + final BigWarpData data, final LandmarkTableModel landmarkModel, final List> sources, final List targetSourceIndexList ) { - runFromBigWarpInstance( landmarkModel, sources.get(targetSourceIndexList.get( 0 ))); + runFromBigWarpInstance( data, landmarkModel, data.getTargetSource( 0 ) ); } public void runFromBigWarpInstance( - final LandmarkTableModel landmarkModel, final SourceAndConverter< T > sourceAndConverter ) + final BigWarpData data, final LandmarkTableModel landmarkModel, final SourceAndConverter< T > sourceAndConverter ) { System.out.println( "run from instance." ); ImageJ ij = IJ.getInstance(); if ( ij == null ) return; - final DeformationFieldExportParameters params = DeformationFieldExportParameters.fromDialog( false, false ); if( params == null ) return; @@ -144,45 +154,35 @@ public void runFromBigWarpInstance( final RandomAccessibleInterval< ? > tgtInterval = sourceAndConverter.getSpimSource().getSource( 0, 0 ); int ndims = landmarkModel.getNumdims(); - // dimensions of the output image plus -// long[] dims; -// if ( ndims <= 2 ) -// { -// dims = new long[ 3 ]; -// dims[ 0 ] = tgtInterval.dimension( 0 ); -// dims[ 1 ] = tgtInterval.dimension( 1 ); -// dims[ 2 ] = 2; -// } -// else -// { -// dims = new long[ 4 ]; -// dims[ 0 ] = tgtInterval.dimension( 0 ); -// dims[ 1 ] = tgtInterval.dimension( 1 ); -// dims[ 2 ] = 3; -// dims[ 3 ] = tgtInterval.dimension( 2 ); -// } - long[] dims = tgtInterval.dimensionsAsLongArray(); double[] spacing = new double[ 3 ]; + double[] offset = new double[ 3 ]; + String unit = "pix"; VoxelDimensions voxelDim = sourceAndConverter.getSpimSource().getVoxelDimensions(); voxelDim.dimensions( spacing ); if( params.spacing != null ) spacing = params.spacing; + if( params.offset != null ) + offset = params.offset; + + if( params.unit != null ) + unit = params.unit; + if( params.size != null ) dims = params.size; if( params.n5Base.isEmpty() ) { - toImagePlus( landmarkModel, params.ignoreAffine, params.virtual, dims, spacing, params.nThreads ); + toImagePlus( data, landmarkModel, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); } else { try { - writeN5( params.n5Base, params.n5Dataset, landmarkModel, dims, spacing, params.blockSize, params.compression, params.nThreads, params.ignoreAffine ); + writeN5( params.n5Base, params.n5Dataset, landmarkModel, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); } catch ( IOException e ) { @@ -214,13 +214,13 @@ public void run( final String arg ) if( params.n5Base.isEmpty() ) { - toImagePlus( ltm, params.ignoreAffine, params.virtual, params.size, params.spacing, params.nThreads ); + toImagePlus( null, ltm, params.ignoreAffine, params.flatten(), params.virtual, params.size, params.spacing, params.nThreads ); } else { try { - writeN5( params.n5Base, params.n5Dataset, ltm, params.size, params.spacing, params.blockSize, params.compression, params.nThreads, params.ignoreAffine ); + writeN5( params.n5Base, params.n5Dataset, ltm, null, params.size, params.spacing, params.offset, params.unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); } catch ( IOException e ) { @@ -229,15 +229,17 @@ public void run( final String arg ) } } public static ImagePlus toImagePlus( + final BigWarpData data, final LandmarkTableModel ltm, final boolean ignoreAffine, + final boolean flatten, final boolean virtual, final long[] dims, final double[] spacing, final int nThreads ) { final double[] offset = new double[ spacing.length ]; - return toImagePlus( ltm, ignoreAffine, virtual, dims, spacing, offset, nThreads ); + return toImagePlus( data, ltm, ignoreAffine, flatten, virtual, dims, spacing, offset, nThreads ); } /** @@ -253,20 +255,22 @@ public static ImagePlus toImagePlus( * @return an image holding the displacement field */ public static ImagePlus toImagePlus( + final BigWarpData data, final LandmarkTableModel ltm, final boolean ignoreAffine, + final boolean flatten, final boolean virtual, final long[] dims, final double[] spacing, final double[] offset, final int nThreads ) { - final BigWarpTransform bwXfm = new BigWarpTransform( ltm, TransformTypeSelectDialog.TPS ); - final RealTransform tps = getTpsAffineToggle( bwXfm, ignoreAffine ); - - int nd = dims.length; + final BigWarpTransform bwXfm = new BigWarpTransform( ltm, BigWarpTransform.TPS ); + final RealTransform startingTransform = getTransformation( data, bwXfm, flatten ); + + int nd = ltm.getNumdims(); long[] ipDims = null; - if ( nd == 2) + if ( nd == 2 ) { ipDims = new long[ 4 ]; ipDims[ 0 ] = dims[ 0 ]; @@ -285,7 +289,7 @@ else if ( nd == 3 ) else return null; - final RandomAccessibleInterval< DoubleType > dfieldVirt = DisplacementFieldTransform.createDisplacementField( tps, new FinalInterval( dims ), spacing, offset ); + final RandomAccessibleInterval< DoubleType > dfieldVirt = DisplacementFieldTransform.createDisplacementField( startingTransform, new FinalInterval( dims ), spacing, offset ); ImagePlus dfieldIp; if( virtual ) @@ -328,47 +332,91 @@ else if ( nd == 3 ) return dfieldIp; } + protected static RealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concat ) + { + InvertibleRealTransform tps = transform.getTransformation( false ); + if( data == null || !concat ) + return tps; + + RealTransform preTransform = null; + for( Entry< Integer, SourceInfo > entry : data.sourceInfos.entrySet()) + { + if( entry.getValue().getTransform() != null ) + { + preTransform = entry.getValue().getTransform(); + break; + } + } + + final RealTransform startingTransform; + if(preTransform != null ) + { + System.out.println( "flattening with transform");; + final RealTransformSequence seq = new RealTransformSequence(); + seq.add( tps ); + seq.add( preTransform ); + startingTransform = seq; + } + else + startingTransform = tps; + + return startingTransform; + } + public static void writeN5( final String n5BasePath, final LandmarkTableModel ltm, + final BigWarpData data, final long[] dims, final double[] spacing, + final double[] offset, + final String unit, final int[] spatialBlockSize, final Compression compression, - final int nThreads ) throws IOException + final int nThreads, + final boolean flatten ) throws IOException { - writeN5( n5BasePath, "dfield", ltm, dims, spacing, spatialBlockSize, compression, nThreads ); + writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, flatten ); } public static void writeN5( final String n5BasePath, final String n5Dataset, final LandmarkTableModel ltm, + final BigWarpData data, final long[] dims, final double[] spacing, + final double[] offset, + final String unit, final int[] spatialBlockSize, final Compression compression, - final int nThreads ) throws IOException + final int nThreads, + final boolean flatten ) throws IOException { - writeN5( n5BasePath, n5Dataset, ltm, dims, spacing, spatialBlockSize, compression, nThreads, false ); + writeN5( n5BasePath, n5Dataset, ltm, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, false, flatten ); } public static void writeN5( final String n5BasePath, final String n5Dataset, final LandmarkTableModel ltm, + final BigWarpData data, final long[] dims, final double[] spacing, + final double[] offset, + final String unit, final int[] spatialBlockSize, final Compression compression, final int nThreads, - final boolean splitAffine ) throws IOException + final boolean splitAffine, + final boolean flatten ) throws IOException { final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; - final BigWarpTransform bwXfm = new BigWarpTransform( ltm, TransformTypeSelectDialog.TPS ); - final RealTransform tpsTotal = getTpsAffineToggle( bwXfm, splitAffine ); + final BigWarpTransform bwXfm = new BigWarpTransform( ltm, BigWarpTransform.TPS ); +// final RealTransform tpsTotal = bwXfm.getTransformation( false ); + final RealTransform totalTransform = getTransformation( data, bwXfm, flatten ); AffineGet affine = null; if ( splitAffine ) @@ -388,15 +436,39 @@ public static void writeN5( } } - RandomAccessibleInterval< DoubleType > dfield = DisplacementFieldTransform.createDisplacementField( - tpsTotal, new FinalInterval( dims ), spacing ); - int[] blockSize = new int[ spatialBlockSize.length + 1 ]; blockSize[ 0 ] = spatialBlockSize.length; System.arraycopy( spatialBlockSize, 0, blockSize, 1, spatialBlockSize.length ); final N5Writer n5 = new N5Factory().openWriter( n5BasePath ); - N5DisplacementField.save( n5, dataset, affine, dfield, spacing, blockSize, compression ); +// N5DisplacementField.save( n5, dataset, affine, dfield, spacing, blockSize, compression ); + + final RandomAccessibleInterval< DoubleType > dfield; + if( affine != null ) + { + // the affine part + NgffAffineTransformation ngffAffine = new NgffAffineTransformation( affine.getRowPackedCopy() ); + + // displacement field (with the affine removed) + RealTransformSequence totalNoAffine = new RealTransformSequence(); + totalNoAffine.add( totalTransform ); + totalNoAffine.add( affine.inverse() ); + dfield = DisplacementFieldTransform.createDisplacementField( totalNoAffine, new FinalInterval( dims ), spacing ); + NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, "in", "out", spacing, offset, unit, blockSize, compression, nThreads ); + + // the total transform + NgffSequenceTransformation totalTform = new NgffSequenceTransformation( "in", "out", + new CoordinateTransformation[]{ dfieldTform, ngffAffine }); + + N5DisplacementField.addCoordinateTransformations( n5, "/", totalTform ); + } + else + { + dfield = DisplacementFieldTransform.createDisplacementField( totalTransform, new FinalInterval( dims ), spacing ); + NgffDisplacementsTransformation ngffTform = NgffTransformations.save( n5, dataset, dfield, "in", "out", spacing, offset, unit, blockSize, compression, nThreads ); + N5DisplacementField.addCoordinateTransformations( n5, "/", ngffTform ); + } + n5.close(); } @@ -486,18 +558,16 @@ public static long[] dimensionsFromImagePlus( final ImagePlus ref_imp ) long[] dims; if( ref_imp.getNSlices() < 2 ) { - dims = new long[ 3 ]; + dims = new long[ 2 ]; dims[ 0 ] = ref_imp.getWidth(); dims[ 1 ] = ref_imp.getHeight(); - dims[ 2 ] = 2; } else { - dims = new long[ 4 ]; + dims = new long[ 3 ]; dims[ 0 ] = ref_imp.getWidth(); dims[ 1 ] = ref_imp.getHeight(); - dims[ 2 ] = 3; - dims[ 3 ] = ref_imp.getNSlices(); + dims[ 2 ] = ref_imp.getNSlices(); } return dims; } @@ -743,11 +813,14 @@ private static class DeformationFieldExportParameters { public final String landmarkPath; public final boolean ignoreAffine; + public final String option; public final boolean virtual; public final int nThreads; public final long[] size; public final double[] spacing; + public final double[] offset; + public final String unit; public final String n5Base; public final String n5Dataset; @@ -757,10 +830,13 @@ private static class DeformationFieldExportParameters public DeformationFieldExportParameters( final String landmarkPath, final boolean ignoreAffine, + final String option, final boolean virtual, final int nThreads, final long[] size, final double[] spacing, + final double[] offset, + final String unit, final String n5Base, final String n5Dataset, final int[] blockSize, @@ -768,11 +844,14 @@ public DeformationFieldExportParameters( { this.landmarkPath = landmarkPath; this.ignoreAffine = ignoreAffine; + this.option = option; this.virtual = virtual; this.nThreads = nThreads; this.size = size; this.spacing = spacing; + this.offset = offset; + this.unit = unit; this.n5Base = n5Base; this.n5Dataset = n5Dataset; @@ -780,6 +859,11 @@ public DeformationFieldExportParameters( this.compression = compression; } + public boolean flatten() + { + return option.equals( flattenOption ); + } + public static DeformationFieldExportParameters fromDialog( final boolean promptLandmarks, final boolean promptReference ) @@ -791,7 +875,11 @@ public static DeformationFieldExportParameters fromDialog( gd.addFileField( "landmarks_image_file", "" ); } - gd.addCheckbox( "Ignore affine part", false ); + gd.addCheckbox( "Split affine part", false ); + + final String[] choices = new String[] { flattenOption, sequenceOption }; + gd.addChoice( "type", choices, flattenOption ); + gd.addCheckbox( "virtual", false ); gd.addNumericField( "threads", 1, 0 ); gd.addMessage( "Size and spacing" ); @@ -811,10 +899,12 @@ public static DeformationFieldExportParameters fromDialog( } gd.addStringField( "output size", ""); gd.addStringField( "output spacing", ""); + gd.addStringField( "output offset", ""); + gd.addStringField( "output unit", "pixel"); gd.addMessage( "Leave n5 path empty to export as ImagePlus" ); gd.addDirectoryOrFileField( "n5 root path", "" ); - gd.addStringField( "n5 dataset", ""); + gd.addStringField( "n5 dataset", N5DisplacementField.FORWARD_ATTR ); gd.addStringField( "n5 block size", "32,32,32"); gd.addChoice( "n5 compression", compressionOptions, N5Exporter.GZIP_COMPRESSION ); gd.showDialog(); @@ -827,6 +917,7 @@ public static DeformationFieldExportParameters fromDialog( landmarkPath = gd.getNextString(); final boolean ignoreAffine = gd.getNextBoolean(); + final String option = gd.getNextChoice(); final boolean virtual = gd.getNextBoolean(); final int nThreads = ( int ) gd.getNextNumber(); @@ -840,6 +931,8 @@ public static DeformationFieldExportParameters fromDialog( final String sizeString = gd.getNextString(); final String spacingString = gd.getNextString(); + final String offsetString = gd.getNextString(); + final String unitString = gd.getNextString(); final String n5Base = gd.getNextString(); final String n5Dataset = gd.getNextString(); @@ -852,6 +945,8 @@ public static DeformationFieldExportParameters fromDialog( final long[] size; final double[] spacing; + final double[] offset; + String unit = "pixel"; if( ref_imp == null ) { if( !sizeString.isEmpty()) @@ -863,6 +958,14 @@ public static DeformationFieldExportParameters fromDialog( spacing = Arrays.stream( spacingString.split( "," ) ).mapToDouble( Double::parseDouble ).toArray(); else spacing = null; + + if( !offsetString.isEmpty() ) + offset = Arrays.stream( offsetString.split( "," ) ).mapToDouble( Double::parseDouble ).toArray(); + else + offset = null; + + if( !unitString.isEmpty() ) + unit = unitString; } else { @@ -872,11 +975,18 @@ public static DeformationFieldExportParameters fromDialog( // account for physical units of reference image spacing = new double[ nd ]; + offset = new double[ nd ]; spacing[ 0 ] = ref_imp.getCalibration().pixelWidth; spacing[ 1 ] = ref_imp.getCalibration().pixelHeight; + offset[ 0 ] = ref_imp.getCalibration().xOrigin; + offset[ 1 ] = ref_imp.getCalibration().yOrigin; + if ( nd > 2 ) + { spacing[ 2 ] = ref_imp.getCalibration().pixelDepth; + offset[ 2 ] = ref_imp.getCalibration().zOrigin; + } size = BigWarpToDeformationFieldPlugIn.dimensionsFromImagePlus( ref_imp ); } @@ -884,10 +994,13 @@ public static DeformationFieldExportParameters fromDialog( return new DeformationFieldExportParameters( landmarkPath, ignoreAffine, + option, virtual, nThreads, size, spacing, + offset, + unit, n5Base, n5Dataset, blockSize, diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 8b95c8d3..d7af2b92 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1307,7 +1307,7 @@ public void run() public void exportWarpField() { BigWarpToDeformationFieldPlugIn dfieldExporter = new BigWarpToDeformationFieldPlugIn(); - dfieldExporter.runFromBigWarpInstance( landmarkModel, data.getTargetSource( 0 ) ); + dfieldExporter.runFromBigWarpInstance( data, landmarkModel, data.getTargetSource( 0 ) ); } protected void setUpLandmarkMenus() diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index 7be24e80..bda4b1c5 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -9,16 +9,23 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.Optional; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.DatasetAttributes; import org.janelia.saalfeldlab.n5.N5FSReader; import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.N5URL; +import org.janelia.saalfeldlab.n5.N5Writer; import org.janelia.saalfeldlab.n5.ij.N5Factory; +import org.janelia.saalfeldlab.n5.imglib2.N5DisplacementField; import org.janelia.saalfeldlab.n5.metadata.graph.TransformGraph; import org.janelia.saalfeldlab.n5.metadata.graph.TransformPath; import org.janelia.saalfeldlab.n5.metadata.omengff.NgffCoordinateTransformation; import org.janelia.saalfeldlab.n5.metadata.omengff.NgffCoordinateTransformationAdapter; +import org.janelia.saalfeldlab.n5.metadata.omengff.NgffDisplacementsTransformation; import org.janelia.saalfeldlab.n5.metadata.omengff.NgffTranslationTransformation; import com.google.gson.Gson; @@ -26,6 +33,7 @@ import com.google.gson.JsonElement; import com.google.gson.stream.JsonWriter; +import net.imglib2.RandomAccessibleInterval; import net.imglib2.img.array.ArrayImg; import net.imglib2.img.array.ArrayImgs; import net.imglib2.img.basictypeaccess.array.IntArray; @@ -34,6 +42,7 @@ import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.TransformUtils; +import net.imglib2.type.NativeType; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.integer.IntType; import net.imglib2.util.Intervals; @@ -60,8 +69,8 @@ public static void main( String[] args ) throws Exception final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; final N5URL url = new N5URL( bijPath ); - System.out.println( url.getDataset()); - System.out.println( url.getAttribute()); + System.out.println( url.getGroupPath()); + System.out.println( url.getAttributePath()); Pair< NgffCoordinateTransformation< ? >, N5Reader > bijN5 = openTransformN5( bijPath ); System.out.println( bijN5.getA() ); @@ -206,7 +215,7 @@ public static Pair,N5Reader> openTransformN5( fi try { final N5URL n5url = new N5URL( url ); - final String loc = n5url.getLocation(); + final String loc = n5url.getContainerPath(); if( loc.endsWith( ".json" )) { return new ValuePair<>( openJson( url ), null); @@ -214,8 +223,8 @@ public static Pair,N5Reader> openTransformN5( fi else { final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( loc ); - final String dataset = n5url.getDataset() != null ? n5url.getDataset() : "/"; - final String attribute = n5url.getAttribute() != null ? n5url.getAttribute() : "coordinateTransformations/[0]"; + final String dataset = n5url.getGroupPath() != null ? n5url.getGroupPath() : "/"; + final String attribute = n5url.getAttributePath() != null ? n5url.getAttributePath() : "coordinateTransformations/[0]"; final CoordinateTransformation ct = n5.getAttribute( dataset, attribute, CoordinateTransformation.class ); final NgffCoordinateTransformation< ? > nct = NgffCoordinateTransformation.create( ct ); @@ -228,7 +237,7 @@ public static Pair,N5Reader> openTransformN5( fi return null; } } - + public static NgffCoordinateTransformation openJson( final String url ) { final Path path = Paths.get( url ); @@ -257,7 +266,7 @@ public static NgffCoordinateTransformation openJson( final String url ) // // return tform; } - + public static void save( String jsonFile, NgffCoordinateTransformation transform ) { final GsonBuilder gb = new GsonBuilder(); @@ -274,6 +283,32 @@ public static void save( String jsonFile, NgffCoordinateTransformation transf } } + public static < T extends NativeType< T > & RealType< T > > NgffDisplacementsTransformation save( + final N5Writer n5, + final String dataset, + final RandomAccessibleInterval< T > dfield, + final String inName, + final String outName, + final double[] spacing, + final double[] offset, + final String unit, + final int[] blockSize, + final Compression compression, + int nThreads ) throws IOException + { + final String[] axisNames = ( spacing.length == 2 ) ? new String[] { "x", "y" } : new String[] { "x", "y", "z"}; + final CoordinateSystem inputCoordinates = new CoordinateSystem( inName, Axis.space( unit, axisNames ) ); + final CoordinateSystem outputCoordinates = new CoordinateSystem( outName, Axis.space( unit, axisNames ) ); + + final ThreadPoolExecutor threadPool = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue() ); + N5DisplacementField.saveDisplacementFieldNgff( n5, dataset, "/", inputCoordinates, outputCoordinates, + dfield, spacing, offset, blockSize, compression, threadPool ); + + final NgffDisplacementsTransformation ngffDfield = new NgffDisplacementsTransformation( dataset, "linear" ); + return ngffDfield; +// N5DisplacementField.addCoordinateTransformations( n5, "/", ngffDfield ); + } + /** * returns null if no permutation needed * From a29d4bdfd80f801f5cf72689e5e6cb546edb0280 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 5 Dec 2022 15:20:06 -0500 Subject: [PATCH 163/282] feat: add FieldOfViewPanel ui element --- src/main/java/bdv/gui/FieldOfViewPanel.java | 228 ++++++++++++++ .../bdv/gui/ImprovedFormattedTextField.java | 277 ++++++++++++++++++ 2 files changed, 505 insertions(+) create mode 100644 src/main/java/bdv/gui/FieldOfViewPanel.java create mode 100644 src/main/java/bdv/gui/ImprovedFormattedTextField.java diff --git a/src/main/java/bdv/gui/FieldOfViewPanel.java b/src/main/java/bdv/gui/FieldOfViewPanel.java new file mode 100644 index 00000000..fe478767 --- /dev/null +++ b/src/main/java/bdv/gui/FieldOfViewPanel.java @@ -0,0 +1,228 @@ +package bdv.gui; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.text.DecimalFormat; +import java.text.NumberFormat; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +public class FieldOfViewPanel extends JPanel +{ + private static final long serialVersionUID = 1719652204751351335L; + + private static final int DEFAULT_OUTER_PAD = 8; + private static final int DEFAULT_BUTTON_PAD = 3; + private static final int DEFAULT_MID_PAD = 5; + + private String unit; + private int ndims; + private int textFieldWidth; + + private double[] initMin; + private double[] initSpacing; + private long[] initPixsize; + + private double[] min; + private double[] spacing; + private double[] size; + private long[] pixSize; + + private ImprovedFormattedTextField[] minFields; + private ImprovedFormattedTextField[] sizeFields; + private ImprovedFormattedTextField[] spacingFields; + private ImprovedFormattedTextField[] pixelFields; + + public FieldOfViewPanel( final int ndims, final String unit, final int textFieldWidth, final double[] initMin, final double[] initSpacing, final long[] initPixsize ) + { + super(); + + // only support 2 or 3 dimensional fields of view + // defending for ndims > 3 but not ndims < 2 + this.ndims = ndims > 3 ? 3 : ndims; + this.unit = unit; + this.textFieldWidth = textFieldWidth; + + this.initMin = initMin; + this.initSpacing = initSpacing; + this.initPixsize = initPixsize; + + this.min = new double[ ndims ]; + System.arraycopy( initMin, 0, min, 0, ndims ); + + this.spacing = new double[ ndims ]; + System.arraycopy( initSpacing, 0, spacing, 0, ndims ); + + this.pixSize = new long[ ndims ]; + System.arraycopy( initPixsize, 0, pixSize, 0, ndims ); + + this.size = new double[ ndims ]; + for ( int i = 0; i < ndims; i++ ) + size[ i ] = spacing[ i ] * pixSize[ i ]; + + create(); + } + + public double[] getMin() + { + return min; + } + + public double[] getSpacing() + { + return spacing; + } + + public double[] getPhysicalSize() + { + return size; + } + + public long[] getPixelSize() + { + return pixSize; + } + + public void create() + { + setLayout(new GridBagLayout()); + + final GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 1; + gbc.gridheight = 1; + gbc.weightx = 0.0; + gbc.weighty = 0.0; + gbc.anchor = GridBagConstraints.CENTER; + gbc.fill = GridBagConstraints.NONE; + gbc.insets = new Insets( DEFAULT_OUTER_PAD, DEFAULT_OUTER_PAD, DEFAULT_MID_PAD, DEFAULT_BUTTON_PAD ); + + JLabel minLabel = new JLabel( "min" ); + JLabel sizeLabel = new JLabel( String.format( "size (%s)", unit ) ); + JLabel spacingLabel = new JLabel( "spacing" ); + JLabel pixelLabel = new JLabel( "size (pixels)" ); + + gbc.gridx = 1; + add( minLabel, gbc ); + gbc.gridx = 2; + add( sizeLabel, gbc ); + gbc.gridx = 3; + add( spacingLabel, gbc ); + gbc.gridx = 4; + add( pixelLabel, gbc ); + + final JLabel yLabel = new JLabel("y"); + + gbc.gridx = 0; + gbc.gridy = 1; + + final JLabel xLabel = new JLabel("x"); + add( xLabel, gbc ); + + gbc.gridy = 2; + add( yLabel, gbc ); + + if( ndims >= 3 ) + { + gbc.gridy = 3; + JLabel zLabel = new JLabel("z"); + add( zLabel, gbc ); + } + + minFields = new ImprovedFormattedTextField[ ndims ]; + sizeFields = new ImprovedFormattedTextField[ ndims ]; + spacingFields = new ImprovedFormattedTextField[ ndims ]; + pixelFields = new ImprovedFormattedTextField[ ndims ]; + gbc.fill = GridBagConstraints.HORIZONTAL; + + final Dimension textFieldSize = new Dimension( textFieldWidth, 20 ); + final DecimalFormat decimalFormat = new DecimalFormat(); + decimalFormat.setMaximumFractionDigits( 8 ); + + // add fields + for( int i = 0; i < ndims; i++ ) + { + final int idx = i; + gbc.gridy = i + 1; + + gbc.gridx = 1; + minFields[ i ] = new ImprovedFormattedTextField( decimalFormat ); + minFields[ i ].setPreferredSize( textFieldSize ); + minFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); + minFields[ i ].setValue( new Double( initMin[i]) ); + add( minFields[ i ], gbc ); + + gbc.gridx = 2; + sizeFields[ i ] = new ImprovedFormattedTextField( decimalFormat ); + sizeFields[ i ].setPreferredSize( textFieldSize ); + sizeFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); + sizeFields[ i ].setValue( new Double( initSpacing[ i ] * initPixsize[ i ] ) ); + sizeFields[ i ].addActionListener( a -> + { + size[ idx ] = Double.parseDouble( sizeFields[ idx ].getText() ); + updatePixelsFromSize( idx ); + }); + add( sizeFields[ i ], gbc ); + + gbc.gridx = 3; + spacingFields[ i ] = new ImprovedFormattedTextField( decimalFormat ); + spacingFields[ i ].setPreferredSize( textFieldSize ); + spacingFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); + spacingFields[ i ].setValue( new Double( initSpacing[ i ] ) ); + spacingFields[ i ].addActionListener( a -> + { + spacing[ idx ] = Double.parseDouble( spacingFields[ idx ].getText() ); + updatePixelsFromSpacing( idx ); + }); + + add( spacingFields[ i ], gbc ); + + gbc.gridx = 4; + pixelFields[ i ] = new ImprovedFormattedTextField( NumberFormat.getIntegerInstance() ); + pixelFields[ i ].setPreferredSize( textFieldSize ); + pixelFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); + pixelFields[ i ].setValue( new Long( initPixsize[ i ] ) ); + pixelFields[ i ].addActionListener( a -> + { + pixSize[ idx ] = Long.parseLong( pixelFields[ idx ].getText() ); + updateSpacingFromPixels( idx ); + }); + add( pixelFields[ i ], gbc ); + } + } + + protected void updatePixelsFromSize( int i ) + { + pixSize[ i ] = (long)Math.ceil( size[ i ] / spacing[ i ] ); + pixelFields[ i ].setValue( new Double( pixSize[ i ] )); + } + + protected void updatePixelsFromSpacing( int i ) + { + pixSize[ i ] = (long)Math.floor( size[ i ] / spacing[ i ] ); + pixelFields[ i ].setValue( new Long( pixSize[ i ] )); + } + + protected void updateSpacingFromPixels( int i ) + { + spacing[ i ] = size[ i ] / pixSize[ i ]; + spacingFields[ i ].setValue( new Double( spacing[ i ] )); + } + + public static void main( String[] args ) + { + final JFrame frame = new JFrame( "fov" ); + final FieldOfViewPanel panel = new FieldOfViewPanel( 3, "mm", 150, new double[] { 0, 0, 0 }, new double[] { 1, 1, 1 }, new long[] { 300, 200, 100 } ); + + frame.add( panel ); + frame.pack(); + frame.setVisible( true ); + } + +} diff --git a/src/main/java/bdv/gui/ImprovedFormattedTextField.java b/src/main/java/bdv/gui/ImprovedFormattedTextField.java new file mode 100644 index 00000000..29226ad0 --- /dev/null +++ b/src/main/java/bdv/gui/ImprovedFormattedTextField.java @@ -0,0 +1,277 @@ +package bdv.gui; + +import javax.swing.JFormattedTextField; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.Color; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.text.Format; +import java.text.ParseException; +import java.text.AttributedCharacterIterator; +import java.text.FieldPosition; +import java.text.ParsePosition; + +/** + *

+ * Extension of {@code JFormattedTextField} which solves some of the usability + * issues + *

+ * + *

+ * from + * https://stackoverflow.com/questions/1313390/is-there-any-way-to-accept-only-numeric-values-in-a-jtextfield?answertab=scoredesc#tab-top + *

+ */ +public class ImprovedFormattedTextField extends JFormattedTextField +{ + private static final Color ERROR_BACKGROUND_COLOR = new Color( 255, 215, 215 ); + + private static final Color ERROR_FOREGROUND_COLOR = null; + + private Color fBackground, fForeground; + + /** + * Create a new {@code ImprovedFormattedTextField} instance which will use + * {@code aFormat} for the validation of the user input. + * + * @param aFormat + * The format. May not be {@code null} + */ + public ImprovedFormattedTextField( Format aFormat ) + { + // use a ParseAllFormat as we do not want to accept user input which is + // partially valid + super( new ParseAllFormat( aFormat ) ); + setFocusLostBehavior( JFormattedTextField.COMMIT_OR_REVERT ); + updateBackgroundOnEachUpdate(); + // improve the caret behavior + // see also + // http://tips4java.wordpress.com/2010/02/21/formatted-text-field-tips/ + addFocusListener( new MousePositionCorrectorListener() ); + } + + /** + * Create a new {@code ImprovedFormattedTextField} instance which will use + * {@code aFormat} for the validation of the user input. The field will be + * initialized with {@code aValue}. + * + * @param aFormat + * The format. May not be {@code null} + * @param aValue + * The initial value + */ + public ImprovedFormattedTextField( Format aFormat, Object aValue ) + { + this( aFormat ); + setValue( aValue ); + } + + private void updateBackgroundOnEachUpdate() + { + getDocument().addDocumentListener( new DocumentListener() + { + @Override + public void insertUpdate( DocumentEvent e ) + { + updateBackground(); + } + + @Override + public void removeUpdate( DocumentEvent e ) + { + updateBackground(); + } + + @Override + public void changedUpdate( DocumentEvent e ) + { + updateBackground(); + } + } ); + } + + /** + * Update the background color depending on the valid state of the current + * input. This provides visual feedback to the user + */ + private void updateBackground() + { + boolean valid = validContent(); + if ( ERROR_BACKGROUND_COLOR != null ) + { + setBackground( valid ? fBackground : ERROR_BACKGROUND_COLOR ); + } + if ( ERROR_FOREGROUND_COLOR != null ) + { + setForeground( valid ? fForeground : ERROR_FOREGROUND_COLOR ); + } + } + + @Override + public void updateUI() + { + super.updateUI(); + fBackground = getBackground(); + fForeground = getForeground(); + } + + private boolean validContent() + { + AbstractFormatter formatter = getFormatter(); + if ( formatter != null ) + { + try + { + formatter.stringToValue( getText() ); + return true; + } + catch ( ParseException e ) + { + return false; + } + } + return true; + } + + @Override + public void setValue( Object value ) + { + boolean validValue = true; + // before setting the value, parse it by using the format + try + { + AbstractFormatter formatter = getFormatter(); + if ( formatter != null ) + { + formatter.valueToString( value ); + } + } + catch ( ParseException e ) + { + validValue = false; + updateBackground(); + } + // only set the value when valid + if ( validValue ) + { + int old_caret_position = getCaretPosition(); + super.setValue( value ); + setCaretPosition( Math.min( old_caret_position, getText().length() ) ); + } + } + + @Override + protected boolean processKeyBinding( KeyStroke ks, KeyEvent e, int condition, boolean pressed ) + { + // do not let the formatted text field consume the enters. This allows + // to trigger an OK button by + // pressing enter from within the formatted text field + if ( validContent() ) + { + return super.processKeyBinding( ks, e, condition, pressed ) && ks != KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ); + } + else + { + return super.processKeyBinding( ks, e, condition, pressed ); + } + } + + private static class MousePositionCorrectorListener extends FocusAdapter + { + @Override + public void focusGained( FocusEvent e ) + { + /* + * After a formatted text field gains focus, it replaces its text + * with its current value, formatted appropriately of course. It + * does this after any focus listeners are notified. We want to make + * sure that the caret is placed in the correct position rather than + * the dumb default that is before the 1st character ! + */ + final JTextField field = ( JTextField ) e.getSource(); + final int dot = field.getCaret().getDot(); + final int mark = field.getCaret().getMark(); + if ( field.isEnabled() && field.isEditable() ) + { + SwingUtilities.invokeLater( new Runnable() + { + @Override + public void run() + { + // Only set the caret if the textfield hasn't got a + // selection on it + if ( dot == mark ) + { + field.getCaret().setDot( dot ); + } + } + } ); + } + } + } + + /** + *

+ * Decorator for a {@link Format Format} which only accepts values which can + * be completely parsed by the delegate format. If the value can only be + * partially parsed, the decorator will refuse to parse the value. + *

+ */ + public static class ParseAllFormat extends Format + { + private final Format fDelegate; + + /** + * Decorate aDelegate to make sure if parser everything or + * nothing + * + * @param aDelegate + * The delegate format + */ + public ParseAllFormat( Format aDelegate ) + { + fDelegate = aDelegate; + } + + @Override + public StringBuffer format( Object obj, StringBuffer toAppendTo, FieldPosition pos ) + { + return fDelegate.format( obj, toAppendTo, pos ); + } + + @Override + public AttributedCharacterIterator formatToCharacterIterator( Object obj ) + { + return fDelegate.formatToCharacterIterator( obj ); + } + + @Override + public Object parseObject( String source, ParsePosition pos ) + { + int initialIndex = pos.getIndex(); + Object result = fDelegate.parseObject( source, pos ); + if ( result != null && pos.getIndex() < source.length() ) + { + int errorIndex = pos.getIndex(); + pos.setIndex( initialIndex ); + pos.setErrorIndex( errorIndex ); + return null; + } + return result; + } + + @Override + public Object parseObject( String source ) throws ParseException + { + // no need to delegate the call, super will call the parseObject( + // source, pos ) method + return super.parseObject( source ); + } + } + +} From 71edcbedf0eede1fcb79d2fd91fe9f4e344cdd8d Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 6 Dec 2022 16:18:34 -0500 Subject: [PATCH 164/282] feat: new dialog for displacement field export mostly functional --- src/main/java/bdv/gui/BigWarpInitDialog.java | 11 +- .../bdv/gui/ExportDisplacementFieldFrame.java | 513 ++++++++++++++++++ src/main/java/bdv/gui/FieldOfViewPanel.java | 230 +++++++- .../ij/BigWarpToDeformationFieldPlugIn.java | 79 ++- 4 files changed, 801 insertions(+), 32 deletions(-) create mode 100644 src/main/java/bdv/gui/ExportDisplacementFieldFrame.java diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 420c568d..a128f780 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -83,16 +83,16 @@ public class BigWarpInitDialog extends JFrame private DatasetSelectorDialog selectionDialog; private String lastOpenedContainer = ""; - private String lastBrowsePath = ""; + private String lastBrowsePath = null; private ExecutorService exec; private Consumer okayCallback; private Consumer cancelCallback; private Consumer< String > imagePathUpdateCallback, transformPathUpdateCallback, projectPathUpdateCallback; - private static final int DEFAULT_OUTER_PAD = 8; - private static final int DEFAULT_BUTTON_PAD = 3; - private static final int DEFAULT_MID_PAD = 5; + public static final int DEFAULT_OUTER_PAD = 8; + public static final int DEFAULT_BUTTON_PAD = 3; + public static final int DEFAULT_MID_PAD = 5; private static final String commandName = "BigWarp"; private static final String projectKey = "project"; @@ -182,7 +182,8 @@ public static void main( String[] args ) throws IOException // String macroOptions = "images=imagej://mri-stack.tif,imagej://mri-stack.tif moving=true,false transforms=,"; // runMacro( macroOptions ); - IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); +// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); + IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); createAndShow(); } diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java new file mode 100644 index 00000000..eac376c6 --- /dev/null +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -0,0 +1,513 @@ +package bdv.gui; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.function.Consumer; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; + +import com.formdev.flatlaf.FlatDarculaLaf; +import com.formdev.flatlaf.util.UIScale; + +import bdv.ij.BigWarpToDeformationFieldPlugIn; +import bdv.ij.BigWarpToDeformationFieldPlugIn.DeformationFieldExportParameters; +import bdv.viewer.Source; +import bigwarp.BigWarp; +import bigwarp.BigWarpData; +import bigwarp.BigWarpInit; +import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.transforms.BigWarpTransform; +import ij.IJ; +import ij.ImageJ; +import ij.plugin.frame.Recorder; +import mpicbg.spim.data.SpimDataException; + +public class ExportDisplacementFieldFrame extends JFrame +{ + private static final long serialVersionUID = -6179153725489981013L; + + private String lastBrowsePath = null; + private String initialPath = null; + + // no need at the moment for these callbacks to consume parameters, but will leave it this way + private Consumer okayCallback; + private Consumer cancelCallback; + + private BigWarpData< ? > data; + private BigWarpTransform bwTransform; + private LandmarkTableModel ltm; + + private boolean imageJOpen; + private boolean initialRecorderState; + + private JTextField landmarkPathTxt; + private JButton browseLandmarksButton; + private JTextField n5RootTxt; + private JButton browseN5Button; + private JTextField n5DatasetTxt; + private JTextField n5BlockSizeTxt; + private JComboBox< String > n5CompressionDropdown; + private JCheckBox splitAffineCheckBox; + private JCheckBox virtualCheckBox; + private JComboBox< String > typeComboBox; + private JSpinner nThreadsField; + private JButton okBtn; + private JButton cancelBtn; + private FieldOfViewPanel fovPanel; + + public ExportDisplacementFieldFrame( BigWarp bw ) + { + this( bw.getData(), bw.getBwTransform(), bw.getLandmarkPanel().getTableModel()); + } + + public ExportDisplacementFieldFrame( BigWarpData data, BigWarpTransform bwTransform, LandmarkTableModel ltm ) + { + super( "Export displacement field" ); + initialPath = ""; + imageJOpen = IJ.getInstance() != null; + + this.data = data; + this.bwTransform = bwTransform; + this.ltm = ltm; + + cancelCallback = x -> { + dispose(); + setVisible( false ); + Recorder.record = initialRecorderState; + }; + + okayCallback = x -> { + macroRecord(); + run(); + Recorder.record = initialRecorderState; + dispose(); + setVisible( false ); + }; + } + + public static void main( String[] args ) throws URISyntaxException, IOException, SpimDataException, UnsupportedLookAndFeelException + { + UIManager.setLookAndFeel(new FlatDarculaLaf()); + +// LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/mri-stack-mm-landmarks.csv"), false ); +// BigWarpTransform bwTransform = new BigWarpTransform( ltm, BigWarpTransform.TPS ); +// try +// { +// BigWarpData data = makeData(); +//// ExportDisplacementFieldFrame.createAndShow( data, bwTransform, ltm ); +// ExportDisplacementFieldFrame.createAndShow( null, null, null ); +// } +// catch ( URISyntaxException | IOException | SpimDataException e ) +// { +// e.printStackTrace(); +// } + + ImageJ ij = new ImageJ(); + IJ.openImage("/home/john/tmp/mri-stack_mm.tif").show(); + + ExportDisplacementFieldFrame.createAndShow( null, null, null ); + } + + public static < T > BigWarpData< T > makeData() throws URISyntaxException, IOException, SpimDataException + { + int id = 0; + final BigWarpData< T > data = BigWarpInit.initData(); + BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack.tif", id++, true )); + BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack.tif", id++, false )); + return data; + } + + public static void createAndShow() + { + createAndShow( null ); + } + + public static void createAndShow( final BigWarp< ? > bw ) + { + ExportDisplacementFieldFrame frame = new ExportDisplacementFieldFrame( bw ); + if ( bw == null ) + frame = new ExportDisplacementFieldFrame( null, null, null ); + else + frame = new ExportDisplacementFieldFrame( bw ); + + frame.createContent(); + frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + frame.pack(); + frame.setVisible( true ); + } + + public static void createAndShow( BigWarpData< ? > data, BigWarpTransform bwTransform, LandmarkTableModel ltm ) + { + ExportDisplacementFieldFrame frame = new ExportDisplacementFieldFrame( data, bwTransform, ltm ); + frame.createContent(); + frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + frame.pack(); + frame.setVisible( true ); + } + + public void createContent() + { + final int frameSizeX = UIScale.scale( 600 ); + + final JPanel panel = basicPanel(); + + final JPanel n5Panel = n5OptionsPanel( frameSizeX ); + n5Panel.setBorder( BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), + BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "N5 options" ), + BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); + + // field of view panel + String unit = "pixel"; + if( data != null ) + { + final Source< ? > src = data.getMovingSource( 0 ).getSpimSource(); + unit = src.getVoxelDimensions().unit(); + } + + fovPanel = new FieldOfViewPanel( data, ltm, bwTransform, unit, 150, + new double[] { 0, 0, 0 }, + new double[] { 1, 1, 1 }, + new long[] { 300, 200, 100 } + ); + + fovPanel.setBorder( BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), + BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "Field of view" ), + BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); + + final JPanel contentPanel = new JPanel(); + contentPanel.setLayout( new GridBagLayout() ); + + final GridBagConstraints cGbc = new GridBagConstraints(); + cGbc.gridx = 0; + cGbc.gridwidth = 4; + cGbc.fill = GridBagConstraints.HORIZONTAL; + + cGbc.gridy = 0; + contentPanel.add( panel, cGbc ); + cGbc.gridy = 1; + contentPanel.add( n5Panel, cGbc ); + cGbc.gridy = 2; + contentPanel.add( fovPanel, cGbc ); + + // bottom button section + final GridBagConstraints cbot = new GridBagConstraints(); + cbot.gridx = 0; + cbot.gridy = 3; + cbot.gridwidth = 1; + cbot.gridheight = 1; + cbot.weightx = 1.0; + cbot.weighty = 0.0; + cbot.fill = GridBagConstraints.NONE; + + okBtn = new JButton( "OK" ); + okBtn.setPreferredSize( new Dimension( okBtn.getPreferredSize().width, okBtn.getPreferredSize().height ) ); + okBtn.addActionListener( e -> okayCallback.accept( getParams() ) ); + cbot.gridx = 2; + cbot.gridwidth = 1; + cbot.insets = new Insets( 20, ( int ) ( frameSizeX * 0.8 ), 20, 2 ); + cbot.anchor = GridBagConstraints.LINE_END; + contentPanel.add( okBtn, cbot ); + + cancelBtn = new JButton( "Cancel" ); + cancelBtn.setPreferredSize( new Dimension( cancelBtn.getPreferredSize().width, cancelBtn.getPreferredSize().height ) ); + cancelBtn.addActionListener( e -> cancelCallback.accept( null ) ); + cbot.gridx = 3; + cbot.anchor = GridBagConstraints.LINE_START; + cbot.ipadx = 0; + cbot.insets = new Insets( 2, 2, 2, 2 ); + contentPanel.add( cancelBtn, cbot ); + + final Container content = getContentPane(); + content.add( contentPanel ); + } + + public JPanel basicPanel() + { + final int OUTER_PAD = BigWarpInitDialog.DEFAULT_OUTER_PAD; + final int BUTTON_PAD = BigWarpInitDialog.DEFAULT_BUTTON_PAD; + final int MID_PAD = BigWarpInitDialog.DEFAULT_MID_PAD; + + final int szX = UIScale.scale( 600 ); + + final JPanel panel = new JPanel( false ); + panel.setLayout( new GridBagLayout() ); + + final GridBagConstraints ctxt = new GridBagConstraints(); + ctxt.gridx = 0; + ctxt.gridy = 0; + ctxt.gridwidth = 1; + ctxt.gridheight = 1; + ctxt.weightx = 0.0; + ctxt.weighty = 0.0; + ctxt.anchor = GridBagConstraints.LINE_END; + ctxt.fill = GridBagConstraints.NONE; + ctxt.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); + panel.add( new JLabel( "Landmarks:" ), ctxt ); + + final GridBagConstraints gbcBar = new GridBagConstraints(); + gbcBar.gridx = 1; + gbcBar.gridy = 0; + gbcBar.gridwidth = 6; + gbcBar.gridheight = 1; + gbcBar.weightx = 1.0; + gbcBar.weighty = 0.0; + gbcBar.fill = GridBagConstraints.HORIZONTAL; + gbcBar.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); + + landmarkPathTxt = new JTextField(); + landmarkPathTxt.setPreferredSize( new Dimension( szX / 3, landmarkPathTxt.getPreferredSize().height ) ); + panel.add( landmarkPathTxt, gbcBar ); + + final GridBagConstraints cProjBrowse = new GridBagConstraints(); + cProjBrowse.gridx = 7; + cProjBrowse.gridy = 0; + cProjBrowse.gridwidth = 1; + cProjBrowse.weightx = 0.0; + cProjBrowse.fill = GridBagConstraints.HORIZONTAL; + cProjBrowse.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); + browseLandmarksButton = new JButton( "Browse" ); + browseLandmarksButton.addActionListener( e -> { + browseLandmarksDialog(); + } ); + panel.add( browseLandmarksButton, cProjBrowse ); + + ctxt.gridy = 1; + ctxt.anchor = GridBagConstraints.LINE_END; + panel.add( new JLabel( "Split affine:" ), ctxt ); + + final GridBagConstraints gbcCheck = new GridBagConstraints(); + gbcCheck.gridx = 1; + gbcCheck.gridy = 1; + gbcCheck.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); + gbcCheck.anchor = GridBagConstraints.LINE_START; + splitAffineCheckBox = new JCheckBox(); + panel.add( splitAffineCheckBox, gbcCheck ); + + ctxt.gridx = 2; + ctxt.anchor = GridBagConstraints.LINE_END; + ctxt.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); + ctxt.weightx = 0.1; + panel.add( new JLabel( "Virtual:" ), ctxt ); + + gbcCheck.gridx = 3; + gbcCheck.weightx = 0.1; + virtualCheckBox = new JCheckBox(); + panel.add( virtualCheckBox, gbcCheck ); + + ctxt.gridx = 4; + ctxt.anchor = GridBagConstraints.LINE_END; + panel.add( new JLabel( "Type:" ), ctxt ); + + gbcCheck.gridx = 5; + typeComboBox = new JComboBox< String >( new String[] { + BigWarpToDeformationFieldPlugIn.flattenOption, + BigWarpToDeformationFieldPlugIn.sequenceOption } ); + panel.add( typeComboBox, gbcCheck ); + + ctxt.gridx = 6; + ctxt.anchor = GridBagConstraints.LINE_END; + panel.add( new JLabel( "Threads:" ), ctxt ); + + gbcCheck.gridx = 7; + nThreadsField = new JSpinner( new SpinnerNumberModel( 1, 1, 9999, 1 ) ); + panel.add( nThreadsField, gbcCheck ); + return panel; + } + + public JPanel n5OptionsPanel( final int frameSizeX ) + { + final int OUTER_PAD = BigWarpInitDialog.DEFAULT_OUTER_PAD; + final int BUTTON_PAD = BigWarpInitDialog.DEFAULT_BUTTON_PAD; + final int MID_PAD = BigWarpInitDialog.DEFAULT_MID_PAD; + + JPanel panel = new JPanel(); + panel.setLayout( new GridBagLayout() ); + + final GridBagConstraints ctxt = new GridBagConstraints(); + ctxt.gridx = 0; + ctxt.gridy = 0; + ctxt.gridwidth = 1; + ctxt.gridheight = 1; + ctxt.weightx = 0.0; + ctxt.weighty = 0.0; + ctxt.anchor = GridBagConstraints.LINE_END; + ctxt.fill = GridBagConstraints.NONE; + ctxt.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); + panel.add( new JLabel( "Root folder:" ), ctxt ); + + final GridBagConstraints gbcBar = new GridBagConstraints(); + gbcBar.gridx = 1; + gbcBar.gridy = 0; + gbcBar.gridwidth = 6; + gbcBar.gridheight = 1; + gbcBar.weightx = 1.0; + gbcBar.weighty = 0.0; + gbcBar.fill = GridBagConstraints.HORIZONTAL; + gbcBar.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); + + n5RootTxt = new JTextField(); + n5RootTxt.setPreferredSize( new Dimension( frameSizeX / 3, landmarkPathTxt.getPreferredSize().height ) ); + panel.add( n5RootTxt, gbcBar ); + + final GridBagConstraints cProjBrowse = new GridBagConstraints(); + cProjBrowse.gridx = 7; + cProjBrowse.gridy = 0; + cProjBrowse.gridwidth = 1; + cProjBrowse.weightx = 0.0; + cProjBrowse.fill = GridBagConstraints.HORIZONTAL; + cProjBrowse.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); + browseN5Button = new JButton( "Browse" ); + browseN5Button.addActionListener( e -> { + browseN5Root(); + } ); + panel.add( browseN5Button, cProjBrowse ); + + ctxt.gridy = 1; + panel.add( new JLabel( "Dataset:" ), ctxt ); + + gbcBar.gridy = 1; + n5DatasetTxt = new JTextField(); + n5DatasetTxt.setPreferredSize( new Dimension( frameSizeX / 3, landmarkPathTxt.getPreferredSize().height ) ); + n5DatasetTxt.setText( "dfield" ); + panel.add( n5DatasetTxt, gbcBar ); + + ctxt.gridy = 2; + panel.add( new JLabel( "Block size:" ), ctxt ); + + gbcBar.gridy = 2; + n5BlockSizeTxt = new JTextField(); + n5BlockSizeTxt.setPreferredSize( new Dimension( frameSizeX / 3, landmarkPathTxt.getPreferredSize().height ) ); + n5BlockSizeTxt.setText( "64" ); + panel.add( n5BlockSizeTxt, gbcBar ); + + ctxt.gridy = 3; + panel.add( new JLabel( "Compression" ), ctxt ); + + gbcBar.gridy = 3; + gbcBar.fill = GridBagConstraints.NONE; + gbcBar.anchor = GridBagConstraints.LINE_START; + n5CompressionDropdown = new JComboBox< String >( BigWarpToDeformationFieldPlugIn.compressionOptions ); + panel.add( n5CompressionDropdown, gbcBar ); + + return panel; + } + + private String browseLandmarksDialog() + { + final String s = browseDialogGeneral( JFileChooser.FILES_ONLY, new FileNameExtensionFilter( "csv file", "csv" ) ); + landmarkPathTxt.setText( s ); + + return s; + } + + private String browseN5Root() + { + final String s = browseDialogGeneral( JFileChooser.FILES_AND_DIRECTORIES, null ); + n5RootTxt.setText( s ); + return s; + } + + private String browseDialogGeneral( final int mode, final FileFilter filefilter ) + { + + final JFileChooser fileChooser = new JFileChooser(); + /* + * Need to allow files so h5 containers can be opened, and directories + * so that filesystem n5's and zarrs can be opened. + */ + fileChooser.setFileSelectionMode( mode ); + if( filefilter == null ) + { + fileChooser.setFileFilter( filefilter ); + } + + if ( lastBrowsePath != null && !lastBrowsePath.isEmpty() ) + fileChooser.setCurrentDirectory( new File( lastBrowsePath ) ); + else if ( initialPath != null && !initialPath.isEmpty() ) + fileChooser.setCurrentDirectory( new File( initialPath ) ); + else if ( imageJOpen ) + { + File f = null; + + final String currDir = IJ.getDirectory( "current" ); + final String homeDir = IJ.getDirectory( "home" ); + if ( currDir != null ) + f = new File( currDir ); + else if ( homeDir != null ) + f = new File( homeDir ); + + fileChooser.setCurrentDirectory( f ); + } + + final int ret = fileChooser.showOpenDialog( this ); + if ( ret != JFileChooser.APPROVE_OPTION ) + return null; + + final String path = fileChooser.getSelectedFile().getAbsolutePath(); + lastBrowsePath = path; + + return path; + } + + public DeformationFieldExportParameters getParams() + { + final String n5BlockSizeString = n5BlockSizeTxt.getText(); + final int[] blockSize = n5BlockSizeString.isEmpty() ? null : + Arrays.stream( n5BlockSizeString.split( "," ) ).mapToInt( Integer::parseInt ).toArray(); + + return new DeformationFieldExportParameters( + landmarkPathTxt.getText(), + splitAffineCheckBox.isSelected(), + (String)typeComboBox.getSelectedItem(), + virtualCheckBox.isSelected(), + (Integer)nThreadsField.getValue(), + fovPanel.getPixelSize(), + fovPanel.getSpacing(), + fovPanel.getMin(), + n5RootTxt.getText(), + n5DatasetTxt.getText(), + blockSize, + BigWarpToDeformationFieldPlugIn.getCompression( (String)n5CompressionDropdown.getSelectedItem() ) ); + } + + public void run() + { + BigWarpToDeformationFieldPlugIn.runFromParameters( getParams(), data, ltm ); + } + + public void macroRecord() + { + // TODO implement + } + + +} diff --git a/src/main/java/bdv/gui/FieldOfViewPanel.java b/src/main/java/bdv/gui/FieldOfViewPanel.java index fe478767..a0a3fab7 100644 --- a/src/main/java/bdv/gui/FieldOfViewPanel.java +++ b/src/main/java/bdv/gui/FieldOfViewPanel.java @@ -4,14 +4,34 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; import java.text.DecimalFormat; import java.text.NumberFormat; +import java.util.Arrays; +import java.util.List; +import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; +import com.formdev.flatlaf.util.UIScale; + +import bdv.ij.ApplyBigwarpPlugin; +import bigwarp.BigWarpData; +import bigwarp.BigWarpInit; +import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.transforms.BigWarpTransform; +import ij.IJ; +import ij.ImagePlus; +import ij.WindowManager; +import mpicbg.spim.data.SpimDataException; +import net.imglib2.Interval; +import net.imglib2.realtransform.BoundingBoxEstimation; + public class FieldOfViewPanel extends JPanel { private static final long serialVersionUID = 1719652204751351335L; @@ -20,6 +40,10 @@ public class FieldOfViewPanel extends JPanel private static final int DEFAULT_BUTTON_PAD = 3; private static final int DEFAULT_MID_PAD = 5; + private BigWarpData data; + private LandmarkTableModel ltm; + private BigWarpTransform bwTransform; + private String unit; private int ndims; private int textFieldWidth; @@ -33,18 +57,29 @@ public class FieldOfViewPanel extends JPanel private double[] size; private long[] pixSize; + private JComboBox referenceComboBox; + private ImprovedFormattedTextField[] minFields; private ImprovedFormattedTextField[] sizeFields; private ImprovedFormattedTextField[] spacingFields; private ImprovedFormattedTextField[] pixelFields; - public FieldOfViewPanel( final int ndims, final String unit, final int textFieldWidth, final double[] initMin, final double[] initSpacing, final long[] initPixsize ) + public FieldOfViewPanel( final LandmarkTableModel ltm, final BigWarpTransform bwTransform, final String unit, final int textFieldWidth, + final double[] initMin, final double[] initSpacing, final long[] initPixsize ) + { + this( null, ltm, bwTransform, unit, textFieldWidth, initMin, initSpacing, initPixsize ); + } + + public FieldOfViewPanel( final BigWarpData data, final LandmarkTableModel ltm, final BigWarpTransform bwTransform, final String unit, final int textFieldWidth, + final double[] initMin, final double[] initSpacing, final long[] initPixsize ) { super(); - // only support 2 or 3 dimensional fields of view - // defending for ndims > 3 but not ndims < 2 - this.ndims = ndims > 3 ? 3 : ndims; + this.data = data; + this.ltm = ltm; + this.bwTransform = bwTransform; + + this.ndims = ltm != null ? ltm.getNumdims() : 3; this.unit = unit; this.textFieldWidth = textFieldWidth; @@ -73,11 +108,31 @@ public double[] getMin() return min; } + public void setMin( final double[] newMin ) + { + final int N = newMin.length > min.length ? min.length : newMin.length; + for ( int i = 0; i < N; i++ ) + { + minFields[ i ].setValue( new Double( newMin[ i ] ) ); + min[ i ] = newMin[ i ]; + } + } + public double[] getSpacing() { return spacing; } + public void setSpacing( final double[] newSpacing ) + { + final int N = newSpacing.length > spacing.length ? spacing.length : newSpacing.length; + for ( int i = 0; i < N; i++ ) + { + spacingFields[ i ].setValue( new Double( newSpacing[ i ] ) ); + spacing[ i ] = newSpacing[ i ]; + } + } + public double[] getPhysicalSize() { return size; @@ -88,6 +143,16 @@ public long[] getPixelSize() return pixSize; } + public void setPixelSize( final long[] newSize ) + { + final int N = newSize.length > pixSize.length ? pixSize.length : newSize.length; + for ( int i = 0; i < N; i++ ) + { + pixelFields[ i ].setValue( new Long( newSize[ i ])); + pixSize[ i ] = newSize[ i ]; + } + } + public void create() { setLayout(new GridBagLayout()); @@ -103,6 +168,53 @@ public void create() gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets( DEFAULT_OUTER_PAD, DEFAULT_OUTER_PAD, DEFAULT_MID_PAD, DEFAULT_BUTTON_PAD ); + int j = 1; + if( data != null ) + { + add( new JLabel( "reference:" ), gbc ); + + final String[] fovOpts = new String[]{ + ApplyBigwarpPlugin.SPECIFIED, + ApplyBigwarpPlugin.TARGET, + ApplyBigwarpPlugin.MOVING_WARPED, + ApplyBigwarpPlugin.LANDMARK_POINTS }; + referenceComboBox = new JComboBox<>( fovOpts ); + referenceComboBox.addActionListener( e -> { + updateFieldsFromReference(); + }); + + gbc.gridx = 1; + add( referenceComboBox, gbc ); + + j = 2; + gbc.gridy = 1; + } + else if( IJ.getInstance() != null ) + { + add( new JLabel( "reference:" ), gbc ); + + String[] impTitles = getImagePlusTitles(); + int numImp = 0; + if( impTitles != null ) + numImp = impTitles.length; + + final String[] fovOpts = new String[ numImp + 1 ]; + fovOpts[ 0 ] = ApplyBigwarpPlugin.SPECIFIED; + for( int i = 0; i < numImp; i++ ) + fovOpts[ i + 1 ] = impTitles[ i ]; + + referenceComboBox = new JComboBox<>( fovOpts ); + referenceComboBox.addActionListener( e -> { + updateFieldsFromImageJReference(); + }); + + gbc.gridx = 1; + add( referenceComboBox, gbc ); + + j = 2; + gbc.gridy = 1; + } + JLabel minLabel = new JLabel( "min" ); JLabel sizeLabel = new JLabel( String.format( "size (%s)", unit ) ); JLabel spacingLabel = new JLabel( "spacing" ); @@ -120,17 +232,18 @@ public void create() final JLabel yLabel = new JLabel("y"); gbc.gridx = 0; - gbc.gridy = 1; + gbc.gridy++; + gbc.anchor = GridBagConstraints.LINE_END; final JLabel xLabel = new JLabel("x"); add( xLabel, gbc ); - gbc.gridy = 2; + gbc.gridy++; add( yLabel, gbc ); if( ndims >= 3 ) { - gbc.gridy = 3; + gbc.gridy++; JLabel zLabel = new JLabel("z"); add( zLabel, gbc ); } @@ -141,7 +254,9 @@ public void create() pixelFields = new ImprovedFormattedTextField[ ndims ]; gbc.fill = GridBagConstraints.HORIZONTAL; - final Dimension textFieldSize = new Dimension( textFieldWidth, 20 ); + final int textWidthScaled = UIScale.scale( textFieldWidth ); + final int textHeight = UIScale.scale( 20 ); + final Dimension textFieldSize = new Dimension( textWidthScaled, textHeight ); final DecimalFormat decimalFormat = new DecimalFormat(); decimalFormat.setMaximumFractionDigits( 8 ); @@ -149,8 +264,8 @@ public void create() for( int i = 0; i < ndims; i++ ) { final int idx = i; - gbc.gridy = i + 1; - + gbc.gridy = i + j; + gbc.gridx = 1; minFields[ i ] = new ImprovedFormattedTextField( decimalFormat ); minFields[ i ].setPreferredSize( textFieldSize ); @@ -199,26 +314,107 @@ public void create() protected void updatePixelsFromSize( int i ) { - pixSize[ i ] = (long)Math.ceil( size[ i ] / spacing[ i ] ); - pixelFields[ i ].setValue( new Double( pixSize[ i ] )); + pixSize[ i ] = ( long ) Math.ceil( size[ i ] / spacing[ i ] ); + pixelFields[ i ].setValue( new Double( pixSize[ i ] ) ); } protected void updatePixelsFromSpacing( int i ) { - pixSize[ i ] = (long)Math.floor( size[ i ] / spacing[ i ] ); - pixelFields[ i ].setValue( new Long( pixSize[ i ] )); + pixSize[ i ] = ( long ) Math.floor( size[ i ] / spacing[ i ] ); + pixelFields[ i ].setValue( new Long( pixSize[ i ] ) ); } protected void updateSpacingFromPixels( int i ) { spacing[ i ] = size[ i ] / pixSize[ i ]; - spacingFields[ i ].setValue( new Double( spacing[ i ] )); + spacingFields[ i ].setValue( new Double( spacing[ i ] ) ); + } + + protected void updateSize( int i ) + { + size[ i ] = spacing[ i ] * pixSize[ i ]; + sizeFields[ i ].setValue( new Double( size[ i ] ) ); + } + + protected void updateFieldsFromReference() + { + if ( data == null || bwTransform == null ) + return; + + final String referenceOption = ( String ) referenceComboBox.getSelectedItem(); + if ( referenceOption.equals( ApplyBigwarpPlugin.SPECIFIED ) ) + return; + + final double[] res = ApplyBigwarpPlugin.getResolution( data, referenceOption, null ); + if ( res != null ) + setSpacing( res ); + + final List< Interval > itvl = ApplyBigwarpPlugin.getPixelInterval( data, ltm, bwTransform.getTransformation( false ), + referenceOption, "", new BoundingBoxEstimation(), null, null, getSpacing() ); + + final double[] offset = ApplyBigwarpPlugin.getPixelOffset( referenceOption, null, res, itvl.get( 0 ) ); + + setPixelSize( itvl.get( 0 ).dimensionsAsLongArray() ); + setMin( offset ); + + for ( int i = 0; i < size.length; i++ ) + updateSize( i ); } - public static void main( String[] args ) + protected String[] getImagePlusTitles() + { + if( IJ.getInstance() != null ) + { + return WindowManager.getImageTitles(); + } + else + return null; + } + + protected void updateFieldsFromImageJReference() + { + final String referenceOption = (String)referenceComboBox.getSelectedItem(); + if( referenceOption.equals( ApplyBigwarpPlugin.SPECIFIED )) + return; + + if( IJ.getInstance() != null ) + { + final ImagePlus refImp = WindowManager.getImage( (String)referenceComboBox.getSelectedItem() ); + setSpacing( new double[] { + refImp.getCalibration().pixelWidth, + refImp.getCalibration().pixelHeight, + refImp.getCalibration().pixelDepth, + }); + + setMin( new double[] { + refImp.getCalibration().xOrigin, + refImp.getCalibration().yOrigin, + refImp.getCalibration().zOrigin, + }); + + setPixelSize( new long[] { + refImp.getWidth(), + refImp.getHeight(), + refImp.getNSlices() + }); + } + } + + public static void main( String[] args ) throws IOException, URISyntaxException, SpimDataException { final JFrame frame = new JFrame( "fov" ); - final FieldOfViewPanel panel = new FieldOfViewPanel( 3, "mm", 150, new double[] { 0, 0, 0 }, new double[] { 1, 1, 1 }, new long[] { 300, 200, 100 } ); + BigWarpData data = new BigWarpData(); + + int id = 0; + BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack_mm.tif", id++, true ) ); + BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack_mm.tif", id++, false ) ); + +// LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/mri-stack-landmarks.csv"), false ); + LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/mri-stack-mm-landmarks.csv"), false ); + BigWarpTransform bwTransform = new BigWarpTransform( ltm, BigWarpTransform.TPS ); + + final FieldOfViewPanel panel = new FieldOfViewPanel( data, ltm, bwTransform, "mm", 150, + new double[] { 0, 0, 0 }, new double[] { 1, 1, 1 }, new long[] { 300, 200, 100 } ); frame.add( panel ); frame.pack(); diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 7d98772c..26e476c1 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -21,6 +21,7 @@ */ package bdv.ij; +import java.awt.GridBagLayout; import java.io.File; import java.io.IOException; import java.util.Arrays; @@ -33,6 +34,9 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; +import javax.swing.JFrame; +import javax.swing.JPanel; + import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.GzipCompression; import org.janelia.saalfeldlab.n5.Lz4Compression; @@ -47,6 +51,10 @@ import org.janelia.saalfeldlab.n5.metadata.omengff.NgffDisplacementsTransformation; import org.janelia.saalfeldlab.n5.metadata.omengff.NgffSequenceTransformation; +import com.formdev.flatlaf.util.UIScale; + +import bdv.gui.BigWarpInitDialog; +import bdv.gui.ExportDisplacementFieldFrame; import bdv.viewer.SourceAndConverter; import bigwarp.BigWarpData; import bigwarp.BigWarpExporter; @@ -168,9 +176,6 @@ public void runFromBigWarpInstance( if( params.offset != null ) offset = params.offset; - if( params.unit != null ) - unit = params.unit; - if( params.size != null ) dims = params.size; @@ -190,6 +195,56 @@ public void runFromBigWarpInstance( } } } + + public static void runFromParameters( final DeformationFieldExportParameters params, final BigWarpData data, final LandmarkTableModel landmarkModel ) + { + String unit = "pixel"; + LandmarkTableModel ltm; + if( landmarkModel == null ) + { + // load + try + { + ltm = LandmarkTableModel.loadFromCsv( new File( params.landmarkPath ), false ); + } + catch ( IOException e ) + { + e.printStackTrace(); + return; + } + } + else + ltm = landmarkModel; + + int ndims = ltm.getNumdims(); + double[] spacing = new double[ ndims ]; + double[] offset = new double[ ndims ]; + long[] dims = new long[ ndims ]; + if ( params.spacing != null ) + spacing = params.spacing; + + if ( params.offset != null ) + offset = params.offset; + + if ( params.size != null ) + dims = params.size; + + if ( params.n5Base.isEmpty() ) + { + toImagePlus( data, ltm, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); + } + else + { + try + { + writeN5( params.n5Base, params.n5Dataset, ltm, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + } + } @Override public void run( final String arg ) @@ -200,6 +255,7 @@ public void run( final String arg ) DeformationFieldExportParameters params = DeformationFieldExportParameters.fromDialog( true, true ); int nd = params.size.length; + String unit = "pixel"; // load LandmarkTableModel ltm = new LandmarkTableModel( nd ); try @@ -220,7 +276,7 @@ public void run( final String arg ) { try { - writeN5( params.n5Base, params.n5Dataset, ltm, null, params.size, params.spacing, params.offset, params.unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); + writeN5( params.n5Base, params.n5Dataset, ltm, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); } catch ( IOException e ) { @@ -786,7 +842,7 @@ public Boolean call() } } - private static Compression getCompression( final String compressionArg ) + public static Compression getCompression( final String compressionArg ) { switch (compressionArg) { case N5Exporter.GZIP_COMPRESSION: @@ -809,7 +865,7 @@ private static Compression getCompression( final String compressionArg ) * and can prompt the user for these parameters. * */ - private static class DeformationFieldExportParameters + public static class DeformationFieldExportParameters { public final String landmarkPath; public final boolean ignoreAffine; @@ -820,7 +876,6 @@ private static class DeformationFieldExportParameters public final long[] size; public final double[] spacing; public final double[] offset; - public final String unit; public final String n5Base; public final String n5Dataset; @@ -836,7 +891,6 @@ public DeformationFieldExportParameters( final long[] size, final double[] spacing, final double[] offset, - final String unit, final String n5Base, final String n5Dataset, final int[] blockSize, @@ -851,7 +905,6 @@ public DeformationFieldExportParameters( this.size = size; this.spacing = spacing; this.offset = offset; - this.unit = unit; this.n5Base = n5Base; this.n5Dataset = n5Dataset; @@ -1000,12 +1053,18 @@ public static DeformationFieldExportParameters fromDialog( size, spacing, offset, - unit, n5Base, n5Dataset, blockSize, compression ); } + + public JFrame makeDialog() + { + ExportDisplacementFieldFrame frame = new ExportDisplacementFieldFrame( null ); + return frame; + } + } } From b9d9276dd8b46c3ab059c6b50870bb555a649962 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 7 Dec 2022 11:27:57 -0500 Subject: [PATCH 165/282] feat: functional deformation field plugin * working macro recording * add unit field ot fov panel --- .../bdv/gui/ExportDisplacementFieldFrame.java | 175 +++++++++++------- src/main/java/bdv/gui/FieldOfViewPanel.java | 82 +++++--- .../ij/BigWarpToDeformationFieldPlugIn.java | 77 ++++++-- src/main/java/bigwarp/BigWarp.java | 2 +- .../bigwarp/transforms/BigWarpTransform.java | 9 +- 5 files changed, 237 insertions(+), 108 deletions(-) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index eac376c6..ee24b461 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -6,10 +6,9 @@ import java.awt.GridBagLayout; import java.awt.Insets; import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.Arrays; import java.util.function.Consumer; +import java.util.stream.Collectors; import javax.swing.BorderFactory; import javax.swing.JButton; @@ -22,12 +21,9 @@ import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; -import com.formdev.flatlaf.FlatDarculaLaf; import com.formdev.flatlaf.util.UIScale; import bdv.ij.BigWarpToDeformationFieldPlugIn; @@ -35,18 +31,32 @@ import bdv.viewer.Source; import bigwarp.BigWarp; import bigwarp.BigWarpData; -import bigwarp.BigWarpInit; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.transforms.BigWarpTransform; import ij.IJ; -import ij.ImageJ; +import ij.Macro; import ij.plugin.frame.Recorder; -import mpicbg.spim.data.SpimDataException; public class ExportDisplacementFieldFrame extends JFrame { private static final long serialVersionUID = -6179153725489981013L; + // macro recording + public static final String commandName = "Big Warp to Displacement field"; + protected static final String landmarksKey = "landmarks"; + protected static final String splitAffineKey = "split_affine"; + protected static final String typeKey = "type"; + protected static final String virtualKey = "virtual"; + protected static final String threadsKey = "threads"; + protected static final String sizeKey = "pixel_size"; + protected static final String spacingKey = "pixel_spacing"; + protected static final String minKey = "min"; + protected static final String unitKey = "unit"; + protected static final String n5RootKey = "n5_root"; + protected static final String n5DatasetKey = "n5_dataset"; + protected static final String n5BlockSizeKey = "n5_block_size"; + protected static final String n5CompressionKey = "n5_compression"; + private String lastBrowsePath = null; private String initialPath = null; @@ -86,7 +96,7 @@ public ExportDisplacementFieldFrame( BigWarpData data, BigWarpTransform bwTra super( "Export displacement field" ); initialPath = ""; imageJOpen = IJ.getInstance() != null; - + this.data = data; this.bwTransform = bwTransform; this.ltm = ltm; @@ -106,41 +116,9 @@ public ExportDisplacementFieldFrame( BigWarpData data, BigWarpTransform bwTra }; } - public static void main( String[] args ) throws URISyntaxException, IOException, SpimDataException, UnsupportedLookAndFeelException - { - UIManager.setLookAndFeel(new FlatDarculaLaf()); - -// LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/mri-stack-mm-landmarks.csv"), false ); -// BigWarpTransform bwTransform = new BigWarpTransform( ltm, BigWarpTransform.TPS ); -// try -// { -// BigWarpData data = makeData(); -//// ExportDisplacementFieldFrame.createAndShow( data, bwTransform, ltm ); -// ExportDisplacementFieldFrame.createAndShow( null, null, null ); -// } -// catch ( URISyntaxException | IOException | SpimDataException e ) -// { -// e.printStackTrace(); -// } - - ImageJ ij = new ImageJ(); - IJ.openImage("/home/john/tmp/mri-stack_mm.tif").show(); - - ExportDisplacementFieldFrame.createAndShow( null, null, null ); - } - - public static < T > BigWarpData< T > makeData() throws URISyntaxException, IOException, SpimDataException - { - int id = 0; - final BigWarpData< T > data = BigWarpInit.initData(); - BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack.tif", id++, true )); - BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack.tif", id++, false )); - return data; - } - public static void createAndShow() { - createAndShow( null ); + createAndShow( null, null, null ); } public static void createAndShow( final BigWarp< ? > bw ) @@ -189,10 +167,10 @@ public void createContent() unit = src.getVoxelDimensions().unit(); } - fovPanel = new FieldOfViewPanel( data, ltm, bwTransform, unit, 150, - new double[] { 0, 0, 0 }, - new double[] { 1, 1, 1 }, - new long[] { 300, 200, 100 } + fovPanel = new FieldOfViewPanel( data, ltm, bwTransform, unit, 150, + new double[] { 0, 0, 0 }, + new double[] { 1, 1, 1 }, + new long[] { 256, 256, 128 } ); fovPanel.setBorder( BorderFactory.createCompoundBorder( @@ -248,6 +226,11 @@ public void createContent() final Container content = getContentPane(); content.add( contentPanel ); + + if( data != null ) + fovPanel.updateFieldsFromReference(); + else + fovPanel.updateFieldsFromImageJReference(); } public JPanel basicPanel() @@ -271,7 +254,6 @@ public JPanel basicPanel() ctxt.anchor = GridBagConstraints.LINE_END; ctxt.fill = GridBagConstraints.NONE; ctxt.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); - panel.add( new JLabel( "Landmarks:" ), ctxt ); final GridBagConstraints gbcBar = new GridBagConstraints(); gbcBar.gridx = 1; @@ -283,10 +265,6 @@ public JPanel basicPanel() gbcBar.fill = GridBagConstraints.HORIZONTAL; gbcBar.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); - landmarkPathTxt = new JTextField(); - landmarkPathTxt.setPreferredSize( new Dimension( szX / 3, landmarkPathTxt.getPreferredSize().height ) ); - panel.add( landmarkPathTxt, gbcBar ); - final GridBagConstraints cProjBrowse = new GridBagConstraints(); cProjBrowse.gridx = 7; cProjBrowse.gridy = 0; @@ -294,11 +272,22 @@ public JPanel basicPanel() cProjBrowse.weightx = 0.0; cProjBrowse.fill = GridBagConstraints.HORIZONTAL; cProjBrowse.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); - browseLandmarksButton = new JButton( "Browse" ); - browseLandmarksButton.addActionListener( e -> { - browseLandmarksDialog(); - } ); - panel.add( browseLandmarksButton, cProjBrowse ); + + // Don't ask for landmarks if running from a bigwarp instance + if( bwTransform == null ) + { + panel.add( new JLabel( "Landmarks:" ), ctxt ); + + landmarkPathTxt = new JTextField(); + landmarkPathTxt.setPreferredSize( new Dimension( szX / 3, landmarkPathTxt.getPreferredSize().height ) ); + panel.add( landmarkPathTxt, gbcBar ); + + browseLandmarksButton = new JButton( "Browse" ); + browseLandmarksButton.addActionListener( e -> { + browseLandmarksDialog(); + } ); + panel.add( browseLandmarksButton, cProjBrowse ); + } ctxt.gridy = 1; ctxt.anchor = GridBagConstraints.LINE_END; @@ -375,7 +364,7 @@ public JPanel n5OptionsPanel( final int frameSizeX ) gbcBar.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); n5RootTxt = new JTextField(); - n5RootTxt.setPreferredSize( new Dimension( frameSizeX / 3, landmarkPathTxt.getPreferredSize().height ) ); + n5RootTxt.setPreferredSize( new Dimension( frameSizeX / 3, n5RootTxt.getPreferredSize().height ) ); panel.add( n5RootTxt, gbcBar ); final GridBagConstraints cProjBrowse = new GridBagConstraints(); @@ -396,7 +385,7 @@ public JPanel n5OptionsPanel( final int frameSizeX ) gbcBar.gridy = 1; n5DatasetTxt = new JTextField(); - n5DatasetTxt.setPreferredSize( new Dimension( frameSizeX / 3, landmarkPathTxt.getPreferredSize().height ) ); + n5DatasetTxt.setPreferredSize( new Dimension( frameSizeX / 3, n5DatasetTxt.getPreferredSize().height ) ); n5DatasetTxt.setText( "dfield" ); panel.add( n5DatasetTxt, gbcBar ); @@ -405,7 +394,7 @@ public JPanel n5OptionsPanel( final int frameSizeX ) gbcBar.gridy = 2; n5BlockSizeTxt = new JTextField(); - n5BlockSizeTxt.setPreferredSize( new Dimension( frameSizeX / 3, landmarkPathTxt.getPreferredSize().height ) ); + n5BlockSizeTxt.setPreferredSize( new Dimension( frameSizeX / 3, n5BlockSizeTxt.getPreferredSize().height ) ); n5BlockSizeTxt.setText( "64" ); panel.add( n5BlockSizeTxt, gbcBar ); @@ -485,7 +474,7 @@ public DeformationFieldExportParameters getParams() Arrays.stream( n5BlockSizeString.split( "," ) ).mapToInt( Integer::parseInt ).toArray(); return new DeformationFieldExportParameters( - landmarkPathTxt.getText(), + landmarkPathTxt == null ? "" : landmarkPathTxt.getText(), splitAffineCheckBox.isSelected(), (String)typeComboBox.getSelectedItem(), virtualCheckBox.isSelected(), @@ -493,6 +482,7 @@ public DeformationFieldExportParameters getParams() fovPanel.getPixelSize(), fovPanel.getSpacing(), fovPanel.getMin(), + fovPanel.getUnit(), n5RootTxt.getText(), n5DatasetTxt.getText(), blockSize, @@ -504,10 +494,69 @@ public void run() BigWarpToDeformationFieldPlugIn.runFromParameters( getParams(), data, ltm ); } - public void macroRecord() + public String macroRecord() { - // TODO implement + if( !Recorder.record ) + return ""; + + Recorder.setCommand( commandName ); + final String szString = Arrays.stream( fovPanel.getPixelSize() ).mapToObj( Long::toString ).collect( Collectors.joining( "," ) ); + final String spacingString = Arrays.stream( fovPanel.getSpacing() ).mapToObj( Double::toString ).collect( Collectors.joining( "," ) ); + final String minString = Arrays.stream( fovPanel.getMin() ).mapToObj( Double::toString ).collect( Collectors.joining( "," ) ); + + Recorder.resetCommandOptions(); + Recorder.recordOption( landmarksKey, landmarkPathTxt.getText().trim() ); + Recorder.recordOption( splitAffineKey ); + Recorder.recordOption( virtualKey ); + Recorder.recordOption( typeKey, ( String ) typeComboBox.getSelectedItem() ); + Recorder.recordOption( threadsKey, Integer.toString( ( Integer ) nThreadsField.getValue() ) ); + Recorder.recordOption( sizeKey, szString ); + Recorder.recordOption( spacingKey, spacingString ); + Recorder.recordOption( minKey, minString ); + Recorder.recordOption( unitKey, fovPanel.getUnit() ); + + if( !n5RootTxt.getText().isEmpty() ) + { + Recorder.recordOption( n5RootKey, n5RootTxt.getText().trim() ); + Recorder.recordOption( n5DatasetKey, n5DatasetTxt.getText().trim() ); + Recorder.recordOption( n5BlockSizeKey, n5BlockSizeTxt.getText().trim() ); + Recorder.recordOption( n5CompressionKey, ( String ) n5CompressionDropdown.getSelectedItem() ); + } + + Recorder.saveCommand(); + return Recorder.getCommandOptions(); } + public static void runMacro( String args ) + { + final String landmarks = Macro.getValue( args, landmarksKey, "" ); + final String type = Macro.getValue( args, typeKey, "" ); + final boolean splitAffine = args.contains(" " + splitAffineKey ); + final boolean openAsVirtual = args.contains(" " + virtualKey); + final int threads = Integer.valueOf( Macro.getValue( args, threadsKey, "1" )); + + final double[] min = Arrays.stream( Macro.getValue( args, minKey, "" ).split( "," ) ).mapToDouble( Double::valueOf ).toArray(); + final double[] spacing = Arrays.stream( Macro.getValue( args, spacingKey, "" ).split( "," ) ).mapToDouble( Double::valueOf ).toArray(); + final long[] pixSize = Arrays.stream( Macro.getValue( args, sizeKey, "" ).split( "," ) ).mapToLong( Long::valueOf ).toArray(); + final String unit = Macro.getValue( args, typeKey, "pixel" ); + + final String n5Root = Macro.getValue( args, n5RootKey, "" ); + final String n5Dataset = Macro.getValue( args, n5DatasetKey, "" ); + final String n5BlockSizeString = Macro.getValue( args, n5BlockSizeKey, "" ); + final String n5Compression = Macro.getValue( args, n5CompressionKey, "" ); + + final int[] blockSize = n5BlockSizeString.isEmpty() ? null : + Arrays.stream( n5BlockSizeString.split( "," ) ).mapToInt( Integer::parseInt ).toArray(); + + DeformationFieldExportParameters params = new DeformationFieldExportParameters( + landmarks, splitAffine, type, openAsVirtual, threads, + pixSize, spacing, min, unit, + n5Root, + n5Dataset, + blockSize, + BigWarpToDeformationFieldPlugIn.getCompression( n5Compression ) ); + + BigWarpToDeformationFieldPlugIn.runFromParameters( params, null, null ); + } -} +} \ No newline at end of file diff --git a/src/main/java/bdv/gui/FieldOfViewPanel.java b/src/main/java/bdv/gui/FieldOfViewPanel.java index a0a3fab7..ce9e5f1c 100644 --- a/src/main/java/bdv/gui/FieldOfViewPanel.java +++ b/src/main/java/bdv/gui/FieldOfViewPanel.java @@ -9,7 +9,6 @@ import java.net.URISyntaxException; import java.text.DecimalFormat; import java.text.NumberFormat; -import java.util.Arrays; import java.util.List; import javax.swing.JComboBox; @@ -58,6 +57,7 @@ public class FieldOfViewPanel extends JPanel private long[] pixSize; private JComboBox referenceComboBox; + private JTextField unitField; private ImprovedFormattedTextField[] minFields; private ImprovedFormattedTextField[] sizeFields; @@ -153,6 +153,16 @@ public void setPixelSize( final long[] newSize ) } } + public String getUnit() + { + return unitField.getText(); + } + + public void setUnit( String unit ) + { + unitField.setText( unit ); + } + public void create() { setLayout(new GridBagLayout()); @@ -179,6 +189,7 @@ public void create() ApplyBigwarpPlugin.MOVING_WARPED, ApplyBigwarpPlugin.LANDMARK_POINTS }; referenceComboBox = new JComboBox<>( fovOpts ); + referenceComboBox.setSelectedItem( ApplyBigwarpPlugin.MOVING_WARPED ); referenceComboBox.addActionListener( e -> { updateFieldsFromReference(); }); @@ -187,7 +198,6 @@ public void create() add( referenceComboBox, gbc ); j = 2; - gbc.gridy = 1; } else if( IJ.getInstance() != null ) { @@ -204,6 +214,9 @@ else if( IJ.getInstance() != null ) fovOpts[ i + 1 ] = impTitles[ i ]; referenceComboBox = new JComboBox<>( fovOpts ); + if( impTitles.length > 0 ) + referenceComboBox.setSelectedIndex( 1 ); + referenceComboBox.addActionListener( e -> { updateFieldsFromImageJReference(); }); @@ -212,14 +225,26 @@ else if( IJ.getInstance() != null ) add( referenceComboBox, gbc ); j = 2; - gbc.gridy = 1; } - JLabel minLabel = new JLabel( "min" ); - JLabel sizeLabel = new JLabel( String.format( "size (%s)", unit ) ); - JLabel spacingLabel = new JLabel( "spacing" ); - JLabel pixelLabel = new JLabel( "size (pixels)" ); + final JLabel unitLabel = new JLabel( "units:" ); + gbc.gridx = 2; + gbc.anchor = GridBagConstraints.LINE_END; + add( unitLabel, gbc ); + gbc.gridx = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.anchor = GridBagConstraints.CENTER; + unitField = new JTextField("pixel"); + add( unitField, gbc ); + + + final JLabel minLabel = new JLabel( "min" ); + final JLabel sizeLabel = new JLabel( String.format( "size (%s)", unit ) ); + final JLabel spacingLabel = new JLabel( "spacing" ); + final JLabel pixelLabel = new JLabel( "size (pixels)" ); + + gbc.gridy++; gbc.gridx = 1; add( minLabel, gbc ); gbc.gridx = 2; @@ -356,6 +381,7 @@ protected void updateFieldsFromReference() setPixelSize( itvl.get( 0 ).dimensionsAsLongArray() ); setMin( offset ); + setUnit( ApplyBigwarpPlugin.getUnit( data, referenceOption )); for ( int i = 0; i < size.length; i++ ) updateSize( i ); @@ -397,28 +423,30 @@ protected void updateFieldsFromImageJReference() refImp.getHeight(), refImp.getNSlices() }); + + setUnit( refImp.getCalibration().getUnit() ); } } - public static void main( String[] args ) throws IOException, URISyntaxException, SpimDataException - { - final JFrame frame = new JFrame( "fov" ); - BigWarpData data = new BigWarpData(); - - int id = 0; - BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack_mm.tif", id++, true ) ); - BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack_mm.tif", id++, false ) ); - -// LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/mri-stack-landmarks.csv"), false ); - LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/mri-stack-mm-landmarks.csv"), false ); - BigWarpTransform bwTransform = new BigWarpTransform( ltm, BigWarpTransform.TPS ); - - final FieldOfViewPanel panel = new FieldOfViewPanel( data, ltm, bwTransform, "mm", 150, - new double[] { 0, 0, 0 }, new double[] { 1, 1, 1 }, new long[] { 300, 200, 100 } ); - - frame.add( panel ); - frame.pack(); - frame.setVisible( true ); - } +// public static void main( String[] args ) throws IOException, URISyntaxException, SpimDataException +// { +// final JFrame frame = new JFrame( "fov" ); +// BigWarpData data = new BigWarpData(); +// +// int id = 0; +// BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack_mm.tif", id++, true ) ); +// BigWarpInit.add( data, BigWarpInit.createSources( data, "/home/john/tmp/mri-stack_mm.tif", id++, false ) ); +// +//// LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/mri-stack-landmarks.csv"), false ); +// LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/mri-stack-mm-landmarks.csv"), false ); +// BigWarpTransform bwTransform = new BigWarpTransform( ltm, BigWarpTransform.TPS ); +// +// final FieldOfViewPanel panel = new FieldOfViewPanel( data, ltm, bwTransform, "mm", 150, +// new double[] { 0, 0, 0 }, new double[] { 1, 1, 1 }, new long[] { 300, 200, 100 } ); +// +// frame.add( panel ); +// frame.pack(); +// frame.setVisible( true ); +// } } diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 26e476c1..15c9b3da 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -21,7 +21,6 @@ */ package bdv.ij; -import java.awt.GridBagLayout; import java.io.File; import java.io.IOException; import java.util.Arrays; @@ -35,7 +34,6 @@ import java.util.concurrent.Future; import javax.swing.JFrame; -import javax.swing.JPanel; import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.GzipCompression; @@ -53,9 +51,9 @@ import com.formdev.flatlaf.util.UIScale; -import bdv.gui.BigWarpInitDialog; import bdv.gui.ExportDisplacementFieldFrame; import bdv.viewer.SourceAndConverter; +import bigwarp.BigWarp; import bigwarp.BigWarpData; import bigwarp.BigWarpExporter; import bigwarp.landmarks.LandmarkTableModel; @@ -66,8 +64,10 @@ import ij.IJ; import ij.ImageJ; import ij.ImagePlus; +import ij.Macro; import ij.WindowManager; import ij.plugin.PlugIn; +import ij.plugin.frame.Recorder; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import mpicbg.spim.data.sequence.VoxelDimensions; import net.imglib2.Cursor; @@ -122,32 +122,44 @@ public class BigWarpToDeformationFieldPlugIn implements PlugIn public static void main( final String[] args ) { new ImageJ(); + + new Recorder(); + Recorder.record = true; + // IJ.run("Boats (356K)"); // ImagePlus imp = IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif" ); - ImagePlus imp = IJ.openImage( "/home/john/tmp/mri-stack.tif" ); - -// WindowManager.getActiveWindow(); +// ImagePlus imp = IJ.openImage( "/home/john/tmp/mri-stack.tif" ); + ImagePlus imp = IJ.openImage( "/home/john/tmp/mri-stack_mm.tif" ); imp.show(); new BigWarpToDeformationFieldPlugIn().run( null ); } + public void runFromBigWarpInstance( final BigWarp bw ) + { + System.out.println( "run from instance." ); + ImageJ ij = IJ.getInstance(); + if ( ij == null ) + return; + + ExportDisplacementFieldFrame.createAndShow( bw ); + } /** * @deprecated not necessary access thedesired source this way anymore, use {@link #runFromBigWarpInstance(LandmarkTableModel, SourceAndConverter)} * on the result of {@link bigwarp.BigWarpData#getTargetSource(int)} */ @Deprecated - public void runFromBigWarpInstance( + public void runFromBigWarpInstanceOld( final BigWarpData data, final LandmarkTableModel landmarkModel, final List> sources, final List targetSourceIndexList ) { - runFromBigWarpInstance( data, landmarkModel, data.getTargetSource( 0 ) ); + runFromBigWarpInstanceOld( data, landmarkModel, data.getTargetSource( 0 ) ); } - public void runFromBigWarpInstance( + public void runFromBigWarpInstanceOld( final BigWarpData data, final LandmarkTableModel landmarkModel, final SourceAndConverter< T > sourceAndConverter ) { System.out.println( "run from instance." ); @@ -246,8 +258,25 @@ public static void runFromParameters( final DeformationFieldExportParameters par } } - @Override - public void run( final String arg ) + public void run( final String args ) + { + if ( IJ.versionLessThan( "1.40" ) ) + return; + + final String macroOptions = Macro.getOptions(); + String options = args; + if( options == null || options.isEmpty()) + options = macroOptions; + + final boolean isMacro = (options != null && !options.isEmpty()); + + if( isMacro ) + ExportDisplacementFieldFrame.runMacro( macroOptions ); + else + ExportDisplacementFieldFrame.createAndShow(); + } + + public void runBackup( final String arg ) { if ( IJ.versionLessThan( "1.40" ) ) return; @@ -461,7 +490,7 @@ public static void writeN5( final double[] spacing, final double[] offset, final String unit, - final int[] spatialBlockSize, + final int[] spatialBlockSizeArg, final Compression compression, final int nThreads, final boolean splitAffine, @@ -492,6 +521,7 @@ public static void writeN5( } } + int[] spatialBlockSize = fillBlockSize( spatialBlockSizeArg, ltm.getNumdims() ); int[] blockSize = new int[ spatialBlockSize.length + 1 ]; blockSize[ 0 ] = spatialBlockSize.length; System.arraycopy( spatialBlockSize, 0, blockSize, 1, spatialBlockSize.length ); @@ -528,6 +558,25 @@ public static void writeN5( n5.close(); } + private static int[] fillBlockSize(int[] blockSize, int N) + { + if( blockSize.length >= N ) + return blockSize; + else + { + final int[] out = new int[ N ]; + int j = blockSize.length - 1; + for ( int i = 0; i < N; i++ ) + { + if ( i < blockSize.length ) + out[ i ] = blockSize[ i ]; + else + out[ i ] = blockSize[ j ]; + } + return out; + } + } + private static RealTransform getTpsAffineToggle( BigWarpTransform bwXfm, boolean splitAffine ) { if ( splitAffine ) @@ -876,6 +925,7 @@ public static class DeformationFieldExportParameters public final long[] size; public final double[] spacing; public final double[] offset; + public final String unit; public final String n5Base; public final String n5Dataset; @@ -891,6 +941,7 @@ public DeformationFieldExportParameters( final long[] size, final double[] spacing, final double[] offset, + final String unit, final String n5Base, final String n5Dataset, final int[] blockSize, @@ -905,6 +956,7 @@ public DeformationFieldExportParameters( this.size = size; this.spacing = spacing; this.offset = offset; + this.unit = unit; this.n5Base = n5Base; this.n5Dataset = n5Dataset; @@ -1053,6 +1105,7 @@ public static DeformationFieldExportParameters fromDialog( size, spacing, offset, + unit, n5Base, n5Dataset, blockSize, diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index d7af2b92..2383480d 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1307,7 +1307,7 @@ public void run() public void exportWarpField() { BigWarpToDeformationFieldPlugIn dfieldExporter = new BigWarpToDeformationFieldPlugIn(); - dfieldExporter.runFromBigWarpInstance( data, landmarkModel, data.getTargetSource( 0 ) ); + dfieldExporter.runFromBigWarpInstance( this ); } protected void setUpLandmarkMenus() diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index a8f4e726..797a860d 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -21,7 +21,6 @@ */ package bigwarp.transforms; -import java.lang.reflect.Field; import java.util.Arrays; import bdv.gui.TransformTypeSelectDialog; @@ -618,12 +617,12 @@ public static AffineTransform3D affine3d( ThinPlateR2LogRSplineKernelTransform t public AffineGet toImglib2( Model< ? > model ) { if ( tableModel.getNumdims() == 2 ) - return toImglib2( ( AbstractAffineModel2D ) model ); + return toAffine2D( ( AbstractAffineModel2D ) model ); else - return toImglib2( ( AbstractAffineModel3D ) model ); + return toAffine3D( ( AbstractAffineModel3D ) model ); } - public AffineGet toImglib2( AbstractAffineModel2D model ) + public AffineGet toAffine2D( AbstractAffineModel2D model ) { if( model instanceof TranslationModel2D ) { @@ -639,7 +638,7 @@ public AffineGet toImglib2( AbstractAffineModel2D model ) } } - public AffineGet toImglib2( AbstractAffineModel3D model ) + public AffineGet toAffine3D( AbstractAffineModel3D model ) { return affine3d( model, new AffineTransform3D() ); } From 593674109e711970a3ac562c5c8165d792732291 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 7 Dec 2022 16:17:40 -0500 Subject: [PATCH 166/282] fix: add transform mask source, and setup when toggled. --- src/main/java/bigwarp/BigWarp.java | 24 ++++++++++++++++++----- src/main/java/bigwarp/BigWarpActions.java | 1 - 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 2383480d..23c5ec56 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -501,7 +501,6 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final // dialogs have to be constructed before action maps are made warpVisDialog = new WarpVisFrame( viewerFrameQ, this ); - warpVisDialog.maskOptionsPanel.setMask( transformMask ); WarpNavigationActions.installActionBindings( getViewerFrameP().getKeybindings(), viewerFrameP, keyProperties, ( ndims == 2 ) ); BigWarpActions.installActionBindings( getViewerFrameP().getKeybindings(), this, keyProperties ); @@ -1934,6 +1933,11 @@ public void toggleMaskOverlayVisibility() public void setMaskOverlayVisibility( final boolean visible ) { + if( transformMask == null) + { + addTransformMaskSource( data, ndims, "Transform mask" ); + } + getViewerFrameQ().getViewerPanel().getMaskOverlay().setVisible( visible ); } @@ -2046,10 +2050,13 @@ private static < T > SourceAndConverter< FloatType > addGridSource( final BigWar @SuppressWarnings( { "unchecked", "rawtypes" } ) private SourceAndConverter< DoubleType > addTransformMaskSource( final BigWarpData< T > data, final int ndims, final String name ) { - // TODO think about whether its worth it to pass a type parameter. - // or should we just stick with Floats? -// FinalInterval itvl = new FinalInterval( data.sources.get( data.targetSourceIndices[0] ).getSpimSource().getSource( 0, 0 )); - FinalInterval itvl = new FinalInterval( data.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 )); + // think about whether its worth it to pass a type parameter. or should we just stick with Floats? + + final BoundingBoxEstimation bbe = new BoundingBoxEstimation(); + final AffineTransform3D affine = new AffineTransform3D(); + data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, affine ); + final Interval itvl = bbe.estimatePixelInterval( affine, data.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ) ); + transformMask = PlateauSphericalMaskSource.build( new RealPoint( ndims ), itvl ); final RealARGBColorConverter< DoubleType > converter = RealARGBColorConverter.create( new DoubleType(), 0, 1 ); @@ -2057,6 +2064,13 @@ private SourceAndConverter< DoubleType > addTransformMaskSource( final BigWarpDa final SourceAndConverter< DoubleType > soc = new SourceAndConverter( transformMask, converter, null ); data.converterSetups.add( BigDataViewer.createConverterSetup( soc, TRANSFORM_MASK_SOURCE_ID ) ); data.sources.add( ( SourceAndConverter ) soc ); + + // connect to UI + warpVisDialog.maskOptionsPanel.setMask( transformMask ); + addMaskMouseListener(); + bwTransform.setLambda( transformMask.getRandomAccessible() ); + synchronizeSources(); + return soc; } diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 850b35c1..409f3814 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -1218,7 +1218,6 @@ public MaskSizeEdit( final BigWarp< ? > bw ) @Override public void actionPerformed(ActionEvent e) { - bw.maskSourceMouseListenerP.toggleActive(); bw.maskSourceMouseListenerQ.toggleActive(); } } From 6ea15774bbde65b01ea90ecc605bc5bb3540f62d Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 7 Dec 2022 16:17:59 -0500 Subject: [PATCH 167/282] fix: better intervals for warp vis sources --- src/main/java/bigwarp/source/GridSource.java | 6 +++++- .../java/bigwarp/source/JacobianDeterminantSource.java | 9 ++++++++- src/main/java/bigwarp/source/WarpMagnitudeSource.java | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/bigwarp/source/GridSource.java b/src/main/java/bigwarp/source/GridSource.java index ced14706..02e6f9a7 100644 --- a/src/main/java/bigwarp/source/GridSource.java +++ b/src/main/java/bigwarp/source/GridSource.java @@ -30,6 +30,7 @@ import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealRandomAccessible; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.BoundingBoxEstimation; import net.imglib2.realtransform.RealTransform; import net.imglib2.type.numeric.RealType; import net.imglib2.view.Views; @@ -78,7 +79,10 @@ private static Interval getInterval( BigWarpData data ) { // return new FinalInterval( data.sources.get( data.targetSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 )); // return new FinalInterval( data.sources.get( data.movingSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 )); - return new FinalInterval( data.getMovingSource( 0 ).getSpimSource().getSource( 0, 0 )); + BoundingBoxEstimation bbe = new BoundingBoxEstimation(); + AffineTransform3D affine = new AffineTransform3D(); + data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, affine ); + return bbe.estimatePixelInterval( affine, data.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ) ); } public void setGridSpacing( double spacing ) diff --git a/src/main/java/bigwarp/source/JacobianDeterminantSource.java b/src/main/java/bigwarp/source/JacobianDeterminantSource.java index 51e9d851..e2b3fdaa 100644 --- a/src/main/java/bigwarp/source/JacobianDeterminantSource.java +++ b/src/main/java/bigwarp/source/JacobianDeterminantSource.java @@ -35,6 +35,7 @@ import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.BoundingBoxEstimation; import net.imglib2.realtransform.inverse.DifferentiableRealTransform; import net.imglib2.type.numeric.RealType; import net.imglib2.view.Views; @@ -62,7 +63,13 @@ public JacobianDeterminantSource( String name, BigWarpData data, T t ) //RandomAccessibleInterval fixedsrc = sourceData.sources.get( 1 ).getSpimSource().getSource( 0, 0 ); // interval = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 ); - interval = sourceData.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ); +// interval = sourceData.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ); + + final BoundingBoxEstimation bbe = new BoundingBoxEstimation(); + final AffineTransform3D affine = new AffineTransform3D(); + data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, affine ); + interval = bbe.estimatePixelInterval( affine, data.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ) ); + // VoxelDimensions srcVoxDims = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getVoxelDimensions(); VoxelDimensions srcVoxDims = sourceData.getTargetSource( 0 ).getSpimSource().getVoxelDimensions(); diff --git a/src/main/java/bigwarp/source/WarpMagnitudeSource.java b/src/main/java/bigwarp/source/WarpMagnitudeSource.java index 92102b58..f21fefd9 100644 --- a/src/main/java/bigwarp/source/WarpMagnitudeSource.java +++ b/src/main/java/bigwarp/source/WarpMagnitudeSource.java @@ -35,6 +35,7 @@ import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.BoundingBoxEstimation; import net.imglib2.realtransform.RealTransform; import net.imglib2.type.numeric.RealType; import net.imglib2.view.Views; @@ -61,7 +62,13 @@ public WarpMagnitudeSource( String name, BigWarpData data, T t ) sourceData = data; // interval = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getSource( 0, 0 ); - interval = sourceData.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ); +// interval = sourceData.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ); + + final BoundingBoxEstimation bbe = new BoundingBoxEstimation(); + final AffineTransform3D affine = new AffineTransform3D(); + data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, affine ); + interval = bbe.estimatePixelInterval( affine, data.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ) ); + // VoxelDimensions srcVoxDims = sourceData.sources.get( sourceData.targetSourceIndices[ 0 ] ).getSpimSource().getVoxelDimensions(); final VoxelDimensions srcVoxDims = sourceData.getTargetSource( 0 ).getSpimSource().getVoxelDimensions(); From b7688261dbdde9b662a3313ad1266e40a6cf16c1 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 7 Dec 2022 17:06:38 -0500 Subject: [PATCH 168/282] fix: dfield export from bw instance when using mask --- .../bdv/gui/ExportDisplacementFieldFrame.java | 4 +- .../ij/BigWarpToDeformationFieldPlugIn.java | 49 ++++++++++++------- src/main/java/bigwarp/BigWarp.java | 4 +- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index ee24b461..7a08acd4 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -491,7 +491,7 @@ public DeformationFieldExportParameters getParams() public void run() { - BigWarpToDeformationFieldPlugIn.runFromParameters( getParams(), data, ltm ); + BigWarpToDeformationFieldPlugIn.runFromParameters( getParams(), data, ltm, bwTransform ); } public String macroRecord() @@ -556,7 +556,7 @@ public static void runMacro( String args ) blockSize, BigWarpToDeformationFieldPlugIn.getCompression( n5Compression ) ); - BigWarpToDeformationFieldPlugIn.runFromParameters( params, null, null ); + BigWarpToDeformationFieldPlugIn.runFromParameters( params, null, null, null ); } } \ No newline at end of file diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 15c9b3da..d1053040 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -137,11 +137,11 @@ public static void main( final String[] args ) public void runFromBigWarpInstance( final BigWarp bw ) { - System.out.println( "run from instance." ); - ImageJ ij = IJ.getInstance(); - if ( ij == null ) - return; - +// System.out.println( "run from instance." ); +// ImageJ ij = IJ.getInstance(); +// if ( ij == null ) +// return; +// ExportDisplacementFieldFrame.createAndShow( bw ); } @@ -193,13 +193,13 @@ public void runFromBigWarpInstanceOld( if( params.n5Base.isEmpty() ) { - toImagePlus( data, landmarkModel, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); + toImagePlus( data, landmarkModel, null, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); } else { try { - writeN5( params.n5Base, params.n5Dataset, landmarkModel, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); + writeN5( params.n5Base, params.n5Dataset, landmarkModel, null, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); } catch ( IOException e ) { @@ -208,7 +208,7 @@ public void runFromBigWarpInstanceOld( } } - public static void runFromParameters( final DeformationFieldExportParameters params, final BigWarpData data, final LandmarkTableModel landmarkModel ) + public static void runFromParameters( final DeformationFieldExportParameters params, final BigWarpData data, final LandmarkTableModel landmarkModel, final BigWarpTransform bwTransform ) { String unit = "pixel"; LandmarkTableModel ltm; @@ -243,13 +243,13 @@ public static void runFromParameters( final DeformationFieldExportParameters par if ( params.n5Base.isEmpty() ) { - toImagePlus( data, ltm, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); + toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); } else { try { - writeN5( params.n5Base, params.n5Dataset, ltm, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); + writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); } catch ( IOException e ) { @@ -299,13 +299,13 @@ public void runBackup( final String arg ) if( params.n5Base.isEmpty() ) { - toImagePlus( null, ltm, params.ignoreAffine, params.flatten(), params.virtual, params.size, params.spacing, params.nThreads ); + toImagePlus( null, ltm, null, params.ignoreAffine, params.flatten(), params.virtual, params.size, params.spacing, params.nThreads ); } else { try { - writeN5( params.n5Base, params.n5Dataset, ltm, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); + writeN5( params.n5Base, params.n5Dataset, ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); } catch ( IOException e ) { @@ -316,6 +316,7 @@ public void runBackup( final String arg ) public static ImagePlus toImagePlus( final BigWarpData data, final LandmarkTableModel ltm, + final BigWarpTransform bwTransform, final boolean ignoreAffine, final boolean flatten, final boolean virtual, @@ -324,7 +325,7 @@ public static ImagePlus toImagePlus( final int nThreads ) { final double[] offset = new double[ spacing.length ]; - return toImagePlus( data, ltm, ignoreAffine, flatten, virtual, dims, spacing, offset, nThreads ); + return toImagePlus( data, ltm, bwTransform, ignoreAffine, flatten, virtual, dims, spacing, offset, nThreads ); } /** @@ -342,6 +343,7 @@ public static ImagePlus toImagePlus( public static ImagePlus toImagePlus( final BigWarpData data, final LandmarkTableModel ltm, + final BigWarpTransform bwTransform, final boolean ignoreAffine, final boolean flatten, final boolean virtual, @@ -350,7 +352,12 @@ public static ImagePlus toImagePlus( final double[] offset, final int nThreads ) { - final BigWarpTransform bwXfm = new BigWarpTransform( ltm, BigWarpTransform.TPS ); + BigWarpTransform bwXfm; + if( bwTransform == null ) + bwXfm = new BigWarpTransform( ltm, BigWarpTransform.TPS ); + else + bwXfm = bwTransform; + final RealTransform startingTransform = getTransformation( data, bwXfm, flatten ); int nd = ltm.getNumdims(); @@ -451,6 +458,7 @@ protected static RealTransform getTransformation( final BigWarpData data, fin public static void writeN5( final String n5BasePath, final LandmarkTableModel ltm, + final BigWarpTransform bwTransform, final BigWarpData data, final long[] dims, final double[] spacing, @@ -461,13 +469,14 @@ public static void writeN5( final int nThreads, final boolean flatten ) throws IOException { - writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, flatten ); + writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, flatten ); } public static void writeN5( final String n5BasePath, final String n5Dataset, final LandmarkTableModel ltm, + final BigWarpTransform bwTransform, final BigWarpData data, final long[] dims, final double[] spacing, @@ -478,13 +487,14 @@ public static void writeN5( final int nThreads, final boolean flatten ) throws IOException { - writeN5( n5BasePath, n5Dataset, ltm, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, false, flatten ); + writeN5( n5BasePath, n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, false, flatten ); } public static void writeN5( final String n5BasePath, final String n5Dataset, final LandmarkTableModel ltm, + final BigWarpTransform bwTransform, final BigWarpData data, final long[] dims, final double[] spacing, @@ -499,7 +509,12 @@ public static void writeN5( final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; - final BigWarpTransform bwXfm = new BigWarpTransform( ltm, BigWarpTransform.TPS ); + final BigWarpTransform bwXfm; + if( bwTransform == null ) + bwXfm = new BigWarpTransform( ltm, BigWarpTransform.TPS ); + else + bwXfm = bwTransform; + // final RealTransform tpsTotal = bwXfm.getTransformation( false ); final RealTransform totalTransform = getTransformation( data, bwXfm, flatten ); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 23c5ec56..899d6261 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -92,6 +92,7 @@ import bdv.gui.BigWarpViewerFrame; import bdv.gui.BigWarpViewerOptions; import bdv.gui.BigwarpLandmarkSelectionPanel; +import bdv.gui.ExportDisplacementFieldFrame; import bdv.gui.LandmarkKeyboardProcessor; import bdv.gui.MaskedSourceEditorMouseListener; import bdv.gui.TransformTypeSelectDialog; @@ -1305,8 +1306,7 @@ public void run() public void exportWarpField() { - BigWarpToDeformationFieldPlugIn dfieldExporter = new BigWarpToDeformationFieldPlugIn(); - dfieldExporter.runFromBigWarpInstance( this ); + ExportDisplacementFieldFrame.createAndShow( this ); } protected void setUpLandmarkMenus() From fcc5cdcdc86895eb938b5943d531791251e31cb0 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 7 Dec 2022 17:50:39 -0500 Subject: [PATCH 169/282] fix: isMoving setting for initial ImagePlus --- src/main/java/bdv/gui/BigWarpInitDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index a128f780..27d1afa5 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -693,13 +693,13 @@ public void initializeImagePlusSources() if( datasetService == null ) addImagePlus( ( String ) imagePlusDropdown.getItemAt( 0 ), true ); else - addDataset( ( String ) imagePlusDropdown.getItemAt( 0 ), false ); + addDataset( ( String ) imagePlusDropdown.getItemAt( 0 ), true ); } if ( N > 1 ) { if( datasetService == null ) - addImagePlus( ( String ) imagePlusDropdown.getItemAt( 1 ), true ); + addImagePlus( ( String ) imagePlusDropdown.getItemAt( 1 ), false ); else addDataset( ( String ) imagePlusDropdown.getItemAt( 1 ), false ); } From 916d856285e5caa3d1eb932e8c6dc580c3ab11e5 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 8 Dec 2022 10:18:24 -0500 Subject: [PATCH 170/282] fix: initial viewer grouping and transform * adjust initial window sizes * rm logback config --- .../java/bdv/viewer/BigWarpViewerPanel.java | 9 +- src/main/java/bigwarp/BigWarp.java | 89 ++++++++++--------- src/main/resources/logback.xml | 10 --- 3 files changed, 54 insertions(+), 54 deletions(-) delete mode 100644 src/main/resources/logback.xml diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index 3c273f11..aacc46fc 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -102,7 +102,7 @@ public BigWarpViewerPanel( final BigWarpData bwData, final BigWarpViewerSettings } } ); - updateGrouping(); + //updateGrouping(); } @Override @@ -154,13 +154,14 @@ public void setHoveredIndex( int index ) /** * Makes the first group contain all the moving images and the second group * contain all the fixed images - * + *

+ * Deprecated. use {@link BigWarp#createMovingTargetGroup()} + * * @return the number sources in the moving group */ + @Deprecated public int updateGrouping() { - // TODO consider deprecating in favor of Bigwarp.createMovingTargetGroups - final SynchronizedViewerState state = state(); synchronized ( state ) { diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 899d6261..0becdae2 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -184,9 +184,9 @@ public class BigWarp< T > { - protected static final int DEFAULT_WIDTH = 600; + protected static final int DEFAULT_WIDTH = 400; - protected static final int DEFAULT_HEIGHT = 400; + protected static final int DEFAULT_HEIGHT = 300; public static final int GRID_SOURCE_ID = 1696993146; @@ -227,9 +227,9 @@ public class BigWarp< T > protected final BigWarpViewerPanel viewerQ; - protected final AffineTransform3D initialViewP; + protected AffineTransform3D initialViewP; - protected final AffineTransform3D initialViewQ; + protected AffineTransform3D initialViewQ; private JMenuItem toggleAlwaysWarpMenuP; @@ -399,14 +399,17 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final final InputTriggerConfig keyProperties = BigDataViewer.getInputTriggerConfig( options ); options = options.inputTriggerConfig( keyProperties ); + final int width = UIScale.scale( DEFAULT_WIDTH ); + final int height = UIScale.scale( DEFAULT_HEIGHT ); + // Viewer frame for the moving image - viewerFrameP = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, data.converterSetups, viewerSettings, + viewerFrameP = new BigWarpViewerFrame( this, width, height, data.converterSetups, viewerSettings, data.cache, options, "Bigwarp moving image", true ); viewerP = getViewerFrameP().getViewerPanel(); // Viewer frame for the fixed image - viewerFrameQ = new BigWarpViewerFrame( this, DEFAULT_WIDTH, DEFAULT_HEIGHT, data.converterSetups, viewerSettings, + viewerFrameQ = new BigWarpViewerFrame( this, width, height, data.converterSetups, viewerSettings, data.cache, options, "Bigwarp fixed image", false ); viewerQ = getViewerFrameQ().getViewerPanel(); @@ -483,7 +486,6 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final solverThread.start(); bboxOptions = new BoundingBoxEstimation( BoundingBoxEstimation.Method.FACES, 5 ); -// bboxOptions = new BoundingBoxEstimation( BoundingBoxEstimation.Method.CORNERS, 5 ); dragOverlayP = new BigWarpDragOverlay( this, viewerP, solverThread ); dragOverlayQ = new BigWarpDragOverlay( this, viewerQ, solverThread ); @@ -521,10 +523,10 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final /* Set the locations of frames */ viewerFrameP.setLocation( 0, 0 ); - viewerFrameP.setSize( DEFAULT_WIDTH, DEFAULT_HEIGHT ); - viewerFrameQ.setLocation( DEFAULT_WIDTH, 0 ); - viewerFrameQ.setSize( DEFAULT_WIDTH, DEFAULT_HEIGHT ); - landmarkFrame.setLocation( 2 * DEFAULT_WIDTH, 0 ); + viewerFrameP.setSize( width, height ); + viewerFrameQ.setLocation( width, 0 ); + viewerFrameQ.setSize( width, height ); + landmarkFrame.setLocation( 2 * width, 0 ); landmarkClickListenerP = new MouseLandmarkListener( this.viewerP ); landmarkClickListenerQ = new MouseLandmarkListener( this.viewerQ ); @@ -534,12 +536,6 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final inLandmarkMode = false; setupKeyListener(); - // save the initial viewer transforms - initialViewP = new AffineTransform3D(); - initialViewQ = new AffineTransform3D(); - viewerP.state().getViewerTransform( initialViewP ); - viewerQ.state().getViewerTransform( initialViewQ ); - viewerFrameP.setVisible( true ); viewerFrameQ.setVisible( true ); @@ -571,12 +567,9 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final //addKeyEventPostProcessor( new LandmarkModeListener() ); baselineModelIndex = 0; + if( data.sources.size() > 0 ) initialize(); - - createMovingTargetGroups(); - viewerP.state().setCurrentGroup( mvgGrp ); - viewerP.state().setCurrentGroup( tgtGrp ); } public void initialize() @@ -587,7 +580,6 @@ public void initialize() if( data.numTargetSources() > 0 ) data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, fixedViewXfm ); - //TODO Expose adding these sources via UI // final ARGBType white = new ARGBType( ARGBType.rgba( 255, 255, 255, 255 )); @@ -616,26 +608,45 @@ public void initialize() // viewerQ.state().setSourceActive( jacDetSource, false ); // data.sourceColorSettings.put( jacDetSource, new ImagePlusLoader.ColorSettings( -1, 0.0, 1.0, white )); - synchronizeSources(); + updateSourceBoundingBoxEstimators(); - SwingUtilities.invokeLater( new Runnable() - { - @Override - public void run() - { - data.transferChannelSettings( viewerFrameP ); - data.transferChannelSettings( viewerFrameQ ); + createMovingTargetGroups(); + viewerP.state().setCurrentGroup( mvgGrp ); + viewerP.state().setCurrentGroup( tgtGrp ); + + // set initial transforms so data are visible + SwingUtilities.invokeLater( () -> { + data.transferChannelSettings( viewerFrameP ); + data.transferChannelSettings( viewerFrameQ ); + // show moving sources in the moving viewer + if( data.numMovingSources() == 1 ) + viewerP.state().setCurrentSource( data.getMovingSource( 0 ) ); + else + { + viewerP.state().setDisplayMode( DisplayMode.GROUP ); + viewerP.state().setCurrentGroup( mvgGrp ); } - } ); - updateSourceBoundingBoxEstimators(); + // show fixed sources in the fixed viewer + if( data.numTargetSources() == 1 ) + viewerQ.state().setCurrentSource( data.getTargetSource( 0 ) ); + else + { + viewerQ.state().setDisplayMode( DisplayMode.GROUP ); + viewerQ.state().setCurrentGroup( tgtGrp ); + } - // set initial transforms so data are visible - InitializeViewerState.initTransform( viewerP ); - InitializeViewerState.initTransform( viewerQ ); + InitializeViewerState.initTransform( viewerP ); + InitializeViewerState.initTransform( viewerQ ); + // save the initial viewer transforms + initialViewP = new AffineTransform3D(); + initialViewQ = new AffineTransform3D(); + viewerP.state().getViewerTransform( initialViewP ); + viewerQ.state().getViewerTransform( initialViewQ ); + } ); } protected void setupLandmarkFrame() @@ -719,16 +730,14 @@ public void createMovingTargetGroups() tgtGrp = new SourceGroup(); final SynchronizedViewerState pState = viewerP.state(); - final SynchronizedViewerState qState = viewerP.state(); - pState.addGroup( mvgGrp ); pState.addGroup( tgtGrp ); + pState.setGroupName( mvgGrp, "moving images" ); + pState.setGroupName( tgtGrp, "target images" ); + final SynchronizedViewerState qState = viewerQ.state(); qState.addGroup( mvgGrp ); qState.addGroup( tgtGrp ); - - pState.setGroupName( mvgGrp, "moving images" ); - pState.setGroupName( tgtGrp, "target images" ); qState.setGroupName( mvgGrp, "moving images" ); qState.setGroupName( tgtGrp, "target images" ); diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml deleted file mode 100644 index 3c259b6d..00000000 --- a/src/main/resources/logback.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - From efc44c1651f2fbda3b425464c07c7d01f2a9ff6a Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 8 Dec 2022 10:28:32 -0500 Subject: [PATCH 171/282] fix: BigWarpInitDialog uses thread count from ImageJ * adjust frame size * defer transform null check to BigWarpInit --- src/main/java/bdv/gui/BigWarpInitDialog.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 27d1afa5..8118b8f0 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -192,13 +192,16 @@ public static void runBigWarp( String projectPath, String[] images, String[] final BigWarpData< T > data = BigWarpInit.initData(); final boolean haveProject = projectPath != null && !projectPath.isEmpty(); + final int nThreads = IJ.getInstance() != null ? Prefs.getThreads() : 1; + BigWarpViewerOptions bwOpts = ( BigWarpViewerOptions ) BigWarpViewerOptions.options().numRenderingThreads( nThreads ); + if( !haveProject ) { int id = 0; final int N = images.length; for( int i = 0; i < N; i++ ) { - // TODO deal with exceptions? + // TODO better messages for exceptions? try { final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, images[ i ], id, moving[ i ].equals( "true" ) ); @@ -208,10 +211,8 @@ public static void runBigWarp( String projectPath, String[] images, String[] if( transformUrl!= null && !transformUrl.isEmpty() ) transform = NgffTransformations.open( transformUrl ); - if( transform != null ) - BigWarpInit.add( data, infos, transform ); - else - BigWarpInit.add( data, infos ); + // add performs a null check on transform + BigWarpInit.add( data, infos, transform ); id += infos.size(); } @@ -234,7 +235,7 @@ public static void runBigWarp( String projectPath, String[] images, String[] try { data.applyTransformations(); - bw = new BigWarp<>( data, new ProgressWriterIJ() ); + bw = new BigWarp<>( data, bwOpts, new ProgressWriterIJ() ); if( haveProject ) bw.loadSettings( projectPath ); } @@ -345,6 +346,7 @@ public JPanel createContent() final int frameSizeX = UIScale.scale( 600 ); final JPanel panel = new JPanel(false); + panel.setPreferredSize( new Dimension( frameSizeX, UIScale.scale( 335 ) )); // ~ 16:9 panel.setLayout(new GridBagLayout()); final GridBagConstraints ctxt = new GridBagConstraints(); From 6fa7611b99a64b987448536c60d8ea0f4d7db3cd Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 8 Dec 2022 14:32:08 -0500 Subject: [PATCH 172/282] fix: depend on n5-imglib2-5.0.0 (ngff) * flatlaf fixes --- pom.xml | 2 +- src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java | 2 -- src/main/java/bigwarp/BigWarp.java | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 53b1f6dd..f9a41a8d 100644 --- a/pom.xml +++ b/pom.xml @@ -120,7 +120,7 @@ 2.5.1 3.2.1 1.4.1 - + 5.0.0-SNAPSHOT sign,deploy-to-scijava diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index d1053040..7f9956f4 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -49,8 +49,6 @@ import org.janelia.saalfeldlab.n5.metadata.omengff.NgffDisplacementsTransformation; import org.janelia.saalfeldlab.n5.metadata.omengff.NgffSequenceTransformation; -import com.formdev.flatlaf.util.UIScale; - import bdv.gui.ExportDisplacementFieldFrame; import bdv.viewer.SourceAndConverter; import bigwarp.BigWarp; diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 0becdae2..43eee8f8 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -82,6 +82,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.formdev.flatlaf.util.UIScale; import com.google.gson.stream.JsonReader; import bdv.BigDataViewer; From 2be9c93dd0241b3829a88ed42f7f1f26f6e7ff80 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 19 Dec 2022 15:35:18 -0500 Subject: [PATCH 173/282] feat: loading / saving projects suggest better file names * bw, add loadProject, saveProject methods --- src/main/java/bigwarp/BigWarp.java | 39 ++++++++++++++++++----- src/main/java/bigwarp/BigWarpActions.java | 5 +-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 43eee8f8..8b2f6fc6 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3533,17 +3533,30 @@ else if( filename.endsWith( "json" )) protected void saveSettings() { - final JFileChooser fileChooser = new JFileChooser( getLastDirectory() ); File proposedSettingsFile = new File( "bigwarp.settings.xml" ); + saveSettingsOrProject( proposedSettingsFile ); + } + + protected void saveProject() + { + System.out.println( "save project" ); + File proposedSettingsFile = new File( "bigwarp-project.json" ); + saveSettingsOrProject( proposedSettingsFile ); + } + + protected void saveSettingsOrProject( final File proposedFile ) + { + final JFileChooser fileChooser = new JFileChooser( getLastDirectory() ); - fileChooser.setSelectedFile( proposedSettingsFile ); + File settingsFile; + fileChooser.setSelectedFile( proposedFile ); final int returnVal = fileChooser.showSaveDialog( null ); if ( returnVal == JFileChooser.APPROVE_OPTION ) { - proposedSettingsFile = fileChooser.getSelectedFile(); + settingsFile = fileChooser.getSelectedFile(); try { - final String canonicalPath = proposedSettingsFile.getCanonicalPath(); + final String canonicalPath = settingsFile.getCanonicalPath(); if ( canonicalPath.endsWith( ".xml" ) ) { saveSettings( canonicalPath ); @@ -3623,18 +3636,28 @@ public BigwarpSettings getSettings() } protected void loadSettings() + { + loadSettingsOrProject( new File( "bigwarp.settings.xml" ) ); + } + + protected void loadProject() + { + loadSettingsOrProject( new File( "bigwarp-project.json" ) ); + } + + protected void loadSettingsOrProject( final File f ) { final JFileChooser fileChooser = new JFileChooser( getLastDirectory() ); - File proposedSettingsFile = new File( "bigwarp.settings.xml" ); - fileChooser.setSelectedFile( proposedSettingsFile ); + File settingsFile; + fileChooser.setSelectedFile( f ); final int returnVal = fileChooser.showOpenDialog( null ); if ( returnVal == JFileChooser.APPROVE_OPTION ) { - proposedSettingsFile = fileChooser.getSelectedFile(); + settingsFile = fileChooser.getSelectedFile(); try { - loadSettings( proposedSettingsFile.getCanonicalPath() ); + loadSettings( settingsFile.getCanonicalPath(), true ); } catch ( final Exception e ) { e.printStackTrace(); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 409f3814..3de65651 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -919,7 +919,8 @@ public SaveProjectAction( final BigWarp< ? > bw ) @Override public void actionPerformed( final ActionEvent e ) { - bw.saveSettings(); + System.out.println("action save project"); + bw.saveProject(); } } @@ -954,7 +955,7 @@ public LoadProjectAction( final BigWarp< ? > bw ) @Override public void actionPerformed( final ActionEvent e ) { - bw.loadSettings(); + bw.loadProject(); } } From ea6cb9a2aa55467fa0939067a236a7a30b995774 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 19 Dec 2022 15:48:02 -0500 Subject: [PATCH 174/282] fix: project loading * note difficulty in changing dimensionality --- src/main/java/bigwarp/BigWarp.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 8b2f6fc6..c788a998 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3741,11 +3741,16 @@ public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSourc activeSourcesDialogP.update(); activeSourcesDialogQ.update(); - //ndims = detec data.sources - ndims = detectNumDims( data.sources ); - setupLandmarkFrame(); - viewerP.setNumDim( ndims ); - viewerQ.setNumDim( ndims ); + /** + * TODO John: + * The below were an attempt to change the dimensionality of bigwarp upon loading of settings. + * Unfortunately, the transform handlers for bdv are final, so best we can do is start a new bigwarp + * if the dimensionality changes. + */ +// ndims = detectNumDims( data.sources ); +// setupLandmarkFrame(); +// viewerP.setNumDim( ndims ); +// viewerQ.setNumDim( ndims ); } viewerFrameP.repaint(); From c520c3e0bb6f7256a7f3061ee07bc692fe5ba910 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 20 Dec 2022 15:54:33 -0500 Subject: [PATCH 175/282] feat: set colorSettings from SourceInfo --- src/main/java/bigwarp/loader/ImagePlusLoader.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/bigwarp/loader/ImagePlusLoader.java b/src/main/java/bigwarp/loader/ImagePlusLoader.java index ffb3c4ec..bd54fc73 100644 --- a/src/main/java/bigwarp/loader/ImagePlusLoader.java +++ b/src/main/java/bigwarp/loader/ImagePlusLoader.java @@ -37,6 +37,7 @@ */ package bigwarp.loader; +import bigwarp.source.SourceInfo; import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -163,6 +164,11 @@ public void update( final BigWarpData< ? > data ) } } + public void update( final SourceInfo sourceInfo ) + { + sourceInfo.setColorSettings( settingsMap.get( sourceInfo.getId() ) ); + } + @SuppressWarnings( "unchecked" ) @Override public SpimDataMinimal[] load() From ec4260ac292e697b44d585ba5196851456de6abd Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 20 Dec 2022 15:54:53 -0500 Subject: [PATCH 176/282] fix: properly set colorSettings for ImagePlus sources --- src/main/java/bigwarp/BigWarpInit.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 0d5437b4..926fe343 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -393,6 +393,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW } sourceInfoMap.forEach( ( sac, state ) -> { + loader.update( state ); state.setUriSupplier( () -> { final FileInfo originalFileInfo = ip.getOriginalFileInfo(); if ( originalFileInfo != null ) From d6d43dd287d87b3f8d5fa131f208530119fb5239 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 20 Dec 2022 15:55:41 -0500 Subject: [PATCH 177/282] fix: avoid race condition when loading converter setup settings --- src/main/java/bigwarp/BigWarp.java | 12 ++---------- src/main/java/bigwarp/BigWarpData.java | 1 - 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 8b95c8d3..2851f1be 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -619,16 +619,8 @@ public void initialize() synchronizeSources(); - SwingUtilities.invokeLater( new Runnable() - { - @Override - public void run() - { - data.transferChannelSettings( viewerFrameP ); - data.transferChannelSettings( viewerFrameQ ); - - } - } ); + data.transferChannelSettings( viewerFrameP ); + data.transferChannelSettings( viewerFrameQ ); updateSourceBoundingBoxEstimators(); diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 482a35a9..ef46543a 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -384,7 +384,6 @@ public void transferChannelSettings( final BigWarpViewerFrame viewer ) final SynchronizedViewerState state = viewer.getViewerPanel().state(); final ConverterSetups setups = viewer.getConverterSetups(); - // TODO does this need synchronization? for( Entry< Integer, SourceInfo > infoEntry : sourceInfos.entrySet() ) { final int id = infoEntry.getKey(); From 0b2ad3be01264a20f52c03bc5448961a427ae10d Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 20 Dec 2022 15:56:14 -0500 Subject: [PATCH 178/282] feat(test): repeat now supported --- src/test/java/bigwarp/BigWarpTestUtils.java | 1 + src/test/java/bigwarp/SerializationTest.java | 39 ++++++++++++-------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/test/java/bigwarp/BigWarpTestUtils.java b/src/test/java/bigwarp/BigWarpTestUtils.java index 25bbc08e..e8adf5fe 100644 --- a/src/test/java/bigwarp/BigWarpTestUtils.java +++ b/src/test/java/bigwarp/BigWarpTestUtils.java @@ -71,6 +71,7 @@ public static String createTemp3DImage( Path tmpImgPath ) private static String create3DImage( final Path tmpImgPath ) throws IOException { ImagePlus img3d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 4, NewImage.FILL_RAMP ); + img3d.setDisplayRange( 5, 15 ); IJ.save( img3d, tmpImgPath.toFile().getCanonicalPath() ); tmpImgPath.toFile().deleteOnExit(); return tmpImgPath.toString(); diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 07e522c8..c9310979 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -6,6 +6,7 @@ import bdv.viewer.BigWarpViewerPanel; import bdv.viewer.state.SourceGroup; import bdv.viewer.state.XmlIoViewerState; +import bigwarp.loader.ImagePlusLoader; import bigwarp.source.PlateauSphericalMaskSource; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -251,6 +252,7 @@ public void sourceFromFileTest() throws SpimDataException, URISyntaxException, I public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, IOException, JDOMException { final ImagePlus img = BigWarpTestUtils.generateImagePlus( "generated image" ); + img.setDisplayRange( 5, 15 ); img.show(); final String imagejUri = "imagej://generated image"; @@ -380,19 +382,16 @@ private static Path createNewSettingsWithReplacement( final String baseSettings, return Files.write( newSettings, newLines ); } - /* When creating and closing multiple BigWarp instances, occassionally the comparison test fails. - * It shouldn't be a problem in practice, since this only occurs during testing, but I think it indicates - * there may be a race condidtion somewhere. To duplicate the issue, run this test multiple times, and - * it should eventually fail. It is not consistent. */ - private void repeatComparison() throws Exception + @Test + public void repeatComparison() throws Exception { - for ( int i = 0; i < 20; i++ ) + for ( int i = 0; i < 40; i++ ) { System.out.println( i ); - bw = BigWarpTestUtils.createBigWarp( true, false, false, false ); + bw = BigWarpTestUtils.createBigWarp( true ); /* Load the known good*/ - final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; + final String originalXmlSettings = "src/test/resources/settings/repeatFail.settings.xml"; bw.loadSettings( originalXmlSettings ); /* save it back out*/ @@ -489,13 +488,23 @@ public void landmarkComparisonTest() throws SpimDataException, IOException, JDOM } - public static void main( String[] args ) throws SpimDataException, URISyntaxException, IOException, JDOMException, InterruptedException + public static void main( String[] args ) throws SpimDataException, URISyntaxException, IOException, JDOMException, InterruptedException { - BigWarp bw = BigWarpTestUtils.createBigWarp("/tmp/img8270806677315563879.tif", true, true, false, false); - bw.saveSettingsJson( "/tmp/3d-settings.json" ); - bw.closeAll(); - Thread.sleep( 1000 ); - bw = BigWarpTestUtils.createBigWarp(); - bw.loadSettings("/tmp/3d-settings.json"); + + final ImagePlus img = BigWarpTestUtils.generateImagePlus( "generated image" ); + img.setDisplayRange( 5, 15 ); + img.show(); + + final BigWarpData< T > data = BigWarpInit.initData(); + BigWarpInit.add(data, BigWarpInit.createSources( data, img, 123, 0, true )); + + new BigWarp<>(data, null); + + // BigWarp bw = BigWarpTestUtils.createBigWarp("/tmp/img8270806677315563879.tif", true, true, false, false); + // bw.saveSettingsJson( "/tmp/3d-settings.json" ); + // bw.closeAll(); + // Thread.sleep( 1000 ); + // bw = BigWarpTestUtils.createBigWarp(); + // bw.loadSettings("/tmp/3d-settings.json"); } } From 398b8d45812fe23be02ab4962125a6d534b471b0 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 20 Dec 2022 16:05:07 -0500 Subject: [PATCH 179/282] fix(test): add necessary test file --- .../settings/repeatFail.settings.xml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/test/resources/settings/repeatFail.settings.xml diff --git a/src/test/resources/settings/repeatFail.settings.xml b/src/test/resources/settings/repeatFail.settings.xml new file mode 100644 index 00000000..900f5cf9 --- /dev/null +++ b/src/test/resources/settings/repeatFail.settings.xml @@ -0,0 +1,71 @@ + + + + + + + false + + + + + false + moving images + 0 + + + sg + nearestneighbor + 0 + 0 + 0 + + + + + + + false + + + + + true + moving images + + + sg + nearestneighbor + 0 + 0 + 0 + + + + + + 0 + 0.0 + 65535.0 + -1 + 0 + + + + + 0 + -2.147483648E9 + 2.147483647E9 + 0.0 + 65535.0 + 0.0 + 255.0 + + + + + + /tmp/.bigwarp + 180000 + + \ No newline at end of file From 50cff50660df9662f891fafec669ec3e3eed39a0 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 20 Dec 2022 16:27:03 -0500 Subject: [PATCH 180/282] fix: intermittent deadlock on startup --- src/main/java/bigwarp/BigWarp.java | 37 ++++++++++++++---------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 2851f1be..0067a047 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -313,9 +313,9 @@ public class BigWarp< T > protected int baselineModelIndex; // file selection - final JFrame fileFrame; + protected JFrame fileFrame; - final FileDialog fileDialog; + protected FileDialog fileDialog; protected File lastDirectory; @@ -384,7 +384,6 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final * LandmarkPanel */ - /* Set up landmark panel */ setupLandmarkFrame(); @@ -540,26 +539,13 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final viewerP.state().getViewerTransform( initialViewP ); viewerQ.state().getViewerTransform( initialViewQ ); - viewerFrameP.setVisible( true ); - viewerFrameQ.setVisible( true ); - - landmarkFrame.pack(); - landmarkFrame.setVisible( true ); - checkBoxInputMaps(); - // file selection - fileFrame = new JFrame( "Select File" ); - fileDialog = new FileDialog( fileFrame ); - if ( ij == null || (IJ.getDirectory( "current" ) == null) ) lastDirectory = new File( System.getProperty( "user.home" )); else lastDirectory = new File( IJ.getDirectory( "current" )); - // default to linear interpolation - fileFrame.setVisible( false ); - // add focus listener //new BigwarpFocusListener( this ); @@ -577,6 +563,16 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final createMovingTargetGroups(); viewerP.state().setCurrentGroup( mvgGrp ); viewerP.state().setCurrentGroup( tgtGrp ); + + SwingUtilities.invokeLater( () -> { + viewerFrameP.setVisible( true ); + viewerFrameQ.setVisible( true ); + landmarkFrame.setVisible( true ); + + fileFrame = new JFrame( "Select File" ); + fileDialog = new FileDialog( fileFrame ); + fileFrame.setVisible( false ); + }); } public void initialize() @@ -666,10 +662,10 @@ protected void setupLandmarkFrame() if ( sz != null ) landmarkFrame.setSize( sz ); - landmarkFrame.pack(); - landmarkFrame.setVisible( true ); - - setUpLandmarkMenus(); + SwingUtilities.invokeLater( () -> { + setUpLandmarkMenus(); + landmarkFrame.pack(); + }); } public void synchronizeSources() @@ -2683,6 +2679,7 @@ public void checkBoxInputMaps() // Make it enter instead // This is super ugly ... why does it have to be this way. + final TableCellEditor celled = landmarkTable.getCellEditor( 0, 1 ); final Component c = celled.getTableCellEditorComponent( landmarkTable, Boolean.TRUE, true, 0, 1 ); From e7e07bafa7133056c43fdef94b81933406f3098e Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 20 Dec 2022 16:38:54 -0500 Subject: [PATCH 181/282] fix: don't override landmarks after loading settings --- src/main/java/bigwarp/BigWarp.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 0067a047..c5277082 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3682,12 +3682,6 @@ public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSourc settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); activeSourcesDialogP.update(); activeSourcesDialogQ.update(); - - //ndims = detec data.sources - ndims = detectNumDims( data.sources ); - setupLandmarkFrame(); - viewerP.setNumDim( ndims ); - viewerQ.setNumDim( ndims ); } viewerFrameP.repaint(); From 7c172f036ee9820ff2e745936ffefb5e24f123d3 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 20 Dec 2022 16:39:32 -0500 Subject: [PATCH 182/282] fix: don't set displayRange randomly --- src/test/java/bigwarp/BigWarpTestUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/bigwarp/BigWarpTestUtils.java b/src/test/java/bigwarp/BigWarpTestUtils.java index e8adf5fe..25bbc08e 100644 --- a/src/test/java/bigwarp/BigWarpTestUtils.java +++ b/src/test/java/bigwarp/BigWarpTestUtils.java @@ -71,7 +71,6 @@ public static String createTemp3DImage( Path tmpImgPath ) private static String create3DImage( final Path tmpImgPath ) throws IOException { ImagePlus img3d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 4, NewImage.FILL_RAMP ); - img3d.setDisplayRange( 5, 15 ); IJ.save( img3d, tmpImgPath.toFile().getCanonicalPath() ); tmpImgPath.toFile().deleteOnExit(); return tmpImgPath.toString(); From be148f26b5e1252acaddd8e252e2ca7d11668502 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 20 Dec 2022 16:39:44 -0500 Subject: [PATCH 183/282] refactor: rename and remove println --- src/test/java/bigwarp/SerializationTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index c9310979..6f551aad 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -285,13 +285,13 @@ public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, assertExpectedSettingsToCurrent( xmlSourceSettings, bw ); } - private static void assertExpectedSettingsToCurrent( final Path xmlSourceSettings, final BigWarp< Object > bw ) throws IOException + private static void assertExpectedSettingsToCurrent( final Path expectedSettings, final BigWarp< Object > bw ) throws IOException { /* Save the settings and compare with initial to test the deserialization */ final Path tempSettings = Files.createTempFile( "deserialization", ".json" ); tempSettings.toFile().delete(); bw.saveSettingsJson(tempSettings.toFile().getCanonicalPath()); - final JsonElement expectedJson = JsonParser.parseReader( new FileReader( xmlSourceSettings.toFile() ) ); + final JsonElement expectedJson = JsonParser.parseReader( new FileReader( expectedSettings.toFile() ) ); final JsonElement actualJson = JsonParser.parseReader( new FileReader( tempSettings.toFile() ) ); BigWarpTestUtils.assertJsonDiff( expectedJson, actualJson ); } @@ -387,7 +387,6 @@ public void repeatComparison() throws Exception { for ( int i = 0; i < 40; i++ ) { - System.out.println( i ); bw = BigWarpTestUtils.createBigWarp( true ); /* Load the known good*/ From 5338a1dd406c4ae9fbe7b0ca3e4585e044c7e60a Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 20 Dec 2022 17:36:21 -0500 Subject: [PATCH 184/282] fix: init dialog loads images fromn project when present --- src/main/java/bdv/gui/BigWarpInitDialog.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 8118b8f0..e13adc32 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -146,12 +146,10 @@ public BigWarpInitDialog( final String title, final DatasetService datasetServic }; imagePathUpdateCallback = ( p ) -> { - System.out.println( "add image: " + p ); addPath(); }; transformPathUpdateCallback = ( p ) -> { - System.out.println( "add transform: " + p ); addTransform(); }; } @@ -184,6 +182,7 @@ public static void main( String[] args ) throws IOException // IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); + createAndShow(); } @@ -237,7 +236,9 @@ public static void runBigWarp( String projectPath, String[] images, String[] data.applyTransformations(); bw = new BigWarp<>( data, bwOpts, new ProgressWriterIJ() ); if( haveProject ) - bw.loadSettings( projectPath ); + { + bw.loadSettings( projectPath, true ); + } } catch ( SpimDataException e ) { @@ -321,7 +322,7 @@ else if( tableRow.type.equals( SourceType.DATASET )) data.applyTransformations(); bw = new BigWarp<>( data, new ProgressWriterIJ() ); if( haveProject ) - bw.loadSettings( projectPath ); + bw.loadSettings( projectPath, true ); } catch ( SpimDataException e ) { From fedbb11bff0dc8df5a58d322ca6569fa0934d1d9 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 21 Dec 2022 13:40:49 -0500 Subject: [PATCH 185/282] fix: add mask source correctly, display overlay initially * some cleanup --- src/main/java/bdv/gui/MaskOptionsPanel.java | 62 +++++++++---------- .../overlay/BigWarpMaskSphereOverlay.java | 2 +- src/main/java/bigwarp/BigWarp.java | 53 ++++++++++++---- src/main/java/bigwarp/BigWarpActions.java | 1 - src/main/java/bigwarp/WarpVisFrame.java | 1 + ...teauSphericalMaskRealRandomAccessible.java | 2 +- .../bigwarp/transforms/BigWarpTransform.java | 1 + 7 files changed, 75 insertions(+), 47 deletions(-) diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index 8d728790..bf7b8105 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -14,8 +14,6 @@ import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; public class MaskOptionsPanel extends JPanel { @@ -29,7 +27,7 @@ public class MaskOptionsPanel extends JPanel + "If your transformation has lots of rotation, try selecting \"ROTATION\" or \"SIMILARITY\"."; public static final String[] maskTypes = new String[] { - "NONE", + BigWarpTransform.NO_MASK_INTERP, BigWarpTransform.MASK_INTERP, BigWarpTransform.ROT_MASK_INTERP, BigWarpTransform.SIM_MASK_INTERP, @@ -63,26 +61,10 @@ public MaskOptionsPanel( BigWarp bw ) autoEstimateMaskButton = new JCheckBox( "Auto-estimate mask", true ); autoEstimateMaskButton.setToolTipText( AUTO_ESTIMATE_HELP_TEXT ); - autoEstimateMaskButton.addChangeListener( new ChangeListener() - { - @Override - public void stateChanged( ChangeEvent e ) - { - if( autoEstimateMaskButton.isSelected() ) - bw.autoEstimateMask(); - } - } ); showMaskOverlayButton = new JCheckBox( "Show mask overlay", true ); showMaskOverlayButton.setToolTipText( SHOW_MASK_OVERLAY_HELP_TEXT ); - showMaskOverlayButton.addChangeListener( new ChangeListener() - { - @Override - public void stateChanged( ChangeEvent e ) - { - bw.setMaskOverlayVisibility( showMaskOverlayButton.isSelected() && isMask() ); - } - } ); + falloffTypeLabel = new JLabel( "Mask falloff"); falloffTypeLabel.setToolTipText( FALLOFF_HELP_TEXT ); @@ -93,17 +75,6 @@ public void stateChanged( ChangeEvent e ) maskTypeLabel.setToolTipText( INTERPOLATION_HELP_TEXT ); maskTypeDropdown = new JComboBox<>( maskTypes ); maskTypeDropdown.setToolTipText( INTERPOLATION_HELP_TEXT ); - maskTypeDropdown.addActionListener( new ActionListener() { - @Override - public void actionPerformed( ActionEvent e ) - { - bw.setMaskOverlayVisibility( autoEstimateMaskButton.isSelected() && isMask() ); - bw.getBwTransform().setMaskInterpolationType( maskTypeDropdown.getItemAt( maskTypeDropdown.getSelectedIndex() ) ); - bw.restimateTransformation(); - bw.getViewerFrameP().getViewerPanel().requestRepaint(); - bw.getViewerFrameQ().getViewerPanel().requestRepaint(); - } - }); // layout final GridBagConstraints gbc = new GridBagConstraints(); @@ -143,6 +114,22 @@ public void actionPerformed( ActionEvent e ) add( showMaskOverlayButton, gbc ); } + public void addActions() + { + autoEstimateMaskButton.addActionListener( e -> { + if ( autoEstimateMaskButton.isSelected() ) + bw.autoEstimateMask(); + } ); + + showMaskOverlayButton.addActionListener( e -> { + bw.setMaskOverlayVisibility( showMaskOverlayButton.isSelected() && isMask() ); + } ); + + maskTypeDropdown.addActionListener( e -> { + bw.updateTransformMask(); + } ); + } + public void setMask( PlateauSphericalMaskSource maskSource ) { if( falloffListener == null ) @@ -170,9 +157,14 @@ public JCheckBox getShowMaskOverlayButton() return showMaskOverlayButton; } - public JComboBox< FalloffShape > getFalloffShapeDropdown() + public JComboBox< String > getMaskTypeDropdown() { - return falloffTypeDropdown; + return maskTypeDropdown; + } + + public String getType() + { + return ( String ) maskTypeDropdown.getSelectedItem(); } /** @@ -183,4 +175,8 @@ public boolean isMask() return maskTypeDropdown.getSelectedIndex() > 0; } + public boolean showMaskOverlay() + { + return showMaskOverlayButton.isSelected(); + } } diff --git a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java index e455e448..5ecd29ed 100644 --- a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java +++ b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java @@ -34,7 +34,7 @@ public class BigWarpMaskSphereOverlay implements OverlayRenderer public BigWarpMaskSphereOverlay( final BigWarpViewerPanel viewer, boolean is3d ) { - this( viewer, new double[]{}, new Color[]{ Color.ORANGE, Color.YELLOW }, is3d ); + this( viewer, new double[]{0,0}, new Color[]{ Color.ORANGE, Color.YELLOW }, is3d ); } public BigWarpMaskSphereOverlay( final BigWarpViewerPanel viewer, final Color[] colors, boolean is3d ) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 43eee8f8..93d7b552 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -95,6 +95,7 @@ import bdv.gui.BigwarpLandmarkSelectionPanel; import bdv.gui.ExportDisplacementFieldFrame; import bdv.gui.LandmarkKeyboardProcessor; +import bdv.gui.MaskOptionsPanel; import bdv.gui.MaskedSourceEditorMouseListener; import bdv.gui.TransformTypeSelectDialog; import bdv.ij.ApplyBigwarpPlugin; @@ -1943,11 +1944,6 @@ public void toggleMaskOverlayVisibility() public void setMaskOverlayVisibility( final boolean visible ) { - if( transformMask == null) - { - addTransformMaskSource( data, ndims, "Transform mask" ); - } - getViewerFrameQ().getViewerPanel().getMaskOverlay().setVisible( visible ); } @@ -2057,11 +2053,39 @@ private static < T > SourceAndConverter< FloatType > addGridSource( final BigWar return soc; } + /** + * Call this method when the transform mask type or options have changed. + */ + public void updateTransformMask() + { + final MaskOptionsPanel maskOpts = warpVisDialog.maskOptionsPanel; + final String type = maskOpts.getType(); + if( !type.equals( BigWarpTransform.NO_MASK_INTERP ) ) + { + // add the transform mask if necessary + addTransformMaskSource(); + } + + // upddate the bigwarp transform + getBwTransform().setMaskInterpolationType( type ); + restimateTransformation(); + setMaskOverlayVisibility( maskOpts.showMaskOverlay() && maskOpts.isMask() ); + autoEstimateMask(); + getViewerFrameQ().getViewerPanel().requestRepaint(); + } + @SuppressWarnings( { "unchecked", "rawtypes" } ) - private SourceAndConverter< DoubleType > addTransformMaskSource( final BigWarpData< T > data, final int ndims, final String name ) + public SourceAndConverter< DoubleType > addTransformMaskSource() { - // think about whether its worth it to pass a type parameter. or should we just stick with Floats? + if( warpVisDialog == null ) + return null; + + if( transformMask != null) + { + return ( SourceAndConverter< DoubleType > ) data.getSourceInfo( TRANSFORM_MASK_SOURCE_ID ).getSourceAndConverter(); + } + // think about whether its worth it to pass a type parameter. or should we just stick with Floats? final BoundingBoxEstimation bbe = new BoundingBoxEstimation(); final AffineTransform3D affine = new AffineTransform3D(); data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, affine ); @@ -2079,7 +2103,16 @@ private SourceAndConverter< DoubleType > addTransformMaskSource( final BigWarpDa warpVisDialog.maskOptionsPanel.setMask( transformMask ); addMaskMouseListener(); bwTransform.setLambda( transformMask.getRandomAccessible() ); - synchronizeSources(); + + final ArrayList overlayList = new ArrayList<>(); + final BigWarpMaskSphereOverlay overlay = new BigWarpMaskSphereOverlay( viewerQ, ndims==3 ); + overlayList.add( overlay ); + + // first attach the overlay to the viewer + getViewerFrameQ().getViewerPanel().setMaskOverlay( overlay ); + transformMask.getRandomAccessible().setOverlays( overlayList ); + +// synchronizeSources(); return soc; } @@ -3660,9 +3693,7 @@ private void addInternalSource(int id) { jacDetSource = addJacobianDeterminantSource( data, "Jacobian determinant" ); break; case TRANSFORM_MASK_SOURCE_ID: - transformMaskSource = addTransformMaskSource( data, ndims, "Transform mask" ); - bwTransform.setLambda( transformMask.getRandomAccessible() ); - addMaskMouseListener(); + updateTransformMask(); break; default: break; diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 409f3814..91598bb0 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -1236,7 +1236,6 @@ public MaskVisToggle( final BigWarp< ? > bw ) @Override public void actionPerformed(ActionEvent e) { - bw.getViewerFrameP().getViewerPanel().getMaskOverlay().toggleVisible(); bw.getViewerFrameQ().getViewerPanel().getMaskOverlay().toggleVisible(); } } diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index 60bd5127..526dfabc 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -346,6 +346,7 @@ public void stateChanged( ChangeEvent e ) // mask options maskOptionsPanel = new MaskOptionsPanel( bw ); + maskOptionsPanel.addActions(); // type options transformTypePanel = new TransformTypePanel( bw ); diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 930b7b6f..200ed21c 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -58,8 +58,8 @@ public class PlateauSphericalMaskRealRandomAccessible implements RealRandomAcces public static enum FalloffShape { - GAUSSIAN( it -> new GaussianFalloff( it ) ), COSINE( it -> new CosineFalloff( it ) ), + GAUSSIAN( it -> new GaussianFalloff( it ) ), LINEAR( it -> new LinearFalloff( it ) ); private final Function< PlateauSphericalMaskRealRandomAccessible, BiConsumer< RealLocalizable, DoubleType > > fallOffProvider; diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 797a860d..a96827ff 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -65,6 +65,7 @@ public class BigWarpTransform public static final String ROTATION = "Rotation"; public static final String TRANSLATION = "Translation"; + public static final String NO_MASK_INTERP = "NONE"; public static final String MASK_INTERP = "LINEAR"; public static final String SIM_MASK_INTERP = "SIMILARITY"; public static final String ROT_MASK_INTERP = "ROTATION"; From 20287f42f0590e7780bc35cc1072b80173008997 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 22 Dec 2022 09:18:23 -0500 Subject: [PATCH 186/282] feat: toward exporting inverse displacement field --- .../bdv/gui/ExportDisplacementFieldFrame.java | 76 +++-- .../ij/BigWarpToDeformationFieldPlugIn.java | 288 ++++++++++++------ src/main/java/bigwarp/BigWarp.java | 3 +- 3 files changed, 246 insertions(+), 121 deletions(-) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index 7a08acd4..99003374 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -46,6 +46,7 @@ public class ExportDisplacementFieldFrame extends JFrame protected static final String landmarksKey = "landmarks"; protected static final String splitAffineKey = "split_affine"; protected static final String typeKey = "type"; + protected static final String directionKey = "direction"; protected static final String virtualKey = "virtual"; protected static final String threadsKey = "threads"; protected static final String sizeKey = "pixel_size"; @@ -81,6 +82,7 @@ public class ExportDisplacementFieldFrame extends JFrame private JCheckBox splitAffineCheckBox; private JCheckBox virtualCheckBox; private JComboBox< String > typeComboBox; + private JComboBox< String > directionComboBox; private JSpinner nThreadsField; private JButton okBtn; private JButton cancelBtn; @@ -238,6 +240,7 @@ public JPanel basicPanel() final int OUTER_PAD = BigWarpInitDialog.DEFAULT_OUTER_PAD; final int BUTTON_PAD = BigWarpInitDialog.DEFAULT_BUTTON_PAD; final int MID_PAD = BigWarpInitDialog.DEFAULT_MID_PAD; + final Insets defaultInsets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); final int szX = UIScale.scale( 600 ); @@ -253,7 +256,7 @@ public JPanel basicPanel() ctxt.weighty = 0.0; ctxt.anchor = GridBagConstraints.LINE_END; ctxt.fill = GridBagConstraints.NONE; - ctxt.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); + ctxt.insets = defaultInsets; final GridBagConstraints gbcBar = new GridBagConstraints(); gbcBar.gridx = 1; @@ -263,7 +266,7 @@ public JPanel basicPanel() gbcBar.weightx = 1.0; gbcBar.weighty = 0.0; gbcBar.fill = GridBagConstraints.HORIZONTAL; - gbcBar.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); + gbcBar.insets = defaultInsets; final GridBagConstraints cProjBrowse = new GridBagConstraints(); cProjBrowse.gridx = 7; @@ -271,7 +274,7 @@ public JPanel basicPanel() cProjBrowse.gridwidth = 1; cProjBrowse.weightx = 0.0; cProjBrowse.fill = GridBagConstraints.HORIZONTAL; - cProjBrowse.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); + cProjBrowse.insets = defaultInsets; // Don't ask for landmarks if running from a bigwarp instance if( bwTransform == null ) @@ -289,46 +292,65 @@ public JPanel basicPanel() panel.add( browseLandmarksButton, cProjBrowse ); } + ctxt.gridx = 0; ctxt.gridy = 1; ctxt.anchor = GridBagConstraints.LINE_END; - panel.add( new JLabel( "Split affine:" ), ctxt ); + panel.add( new JLabel( "Type:" ), ctxt ); final GridBagConstraints gbcCheck = new GridBagConstraints(); gbcCheck.gridx = 1; gbcCheck.gridy = 1; - gbcCheck.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); + gbcCheck.insets = defaultInsets; gbcCheck.anchor = GridBagConstraints.LINE_START; + typeComboBox = new JComboBox< String >( new String[] { + BigWarpToDeformationFieldPlugIn.flattenOption, + BigWarpToDeformationFieldPlugIn.sequenceOption } ); + panel.add( typeComboBox, gbcCheck ); + + // want some more padding for direction + ctxt.gridx = 3; + ctxt.insets = new Insets( OUTER_PAD, 10*BUTTON_PAD, MID_PAD, BUTTON_PAD ); + panel.add( new JLabel( "Direction:" ), ctxt ); + ctxt.insets = defaultInsets; + + gbcCheck.gridx = 4; + directionComboBox = new JComboBox< String >( new String[] { + BigWarpToDeformationFieldPlugIn.INVERSE_OPTIONS.FORWARD.toString(), + BigWarpToDeformationFieldPlugIn.INVERSE_OPTIONS.INVERSE.toString(), + BigWarpToDeformationFieldPlugIn.INVERSE_OPTIONS.BOTH.toString() } ); + panel.add( directionComboBox, gbcCheck ); + + ctxt.gridx = 5; + ctxt.anchor = GridBagConstraints.LINE_END; + panel.add( new JLabel( "Split affine:" ), ctxt ); + + gbcCheck.gridx = 6; splitAffineCheckBox = new JCheckBox(); panel.add( splitAffineCheckBox, gbcCheck ); - ctxt.gridx = 2; + // second row + ctxt.gridx = 0; + ctxt.gridy = 2; + ctxt.anchor = GridBagConstraints.LINE_END; + panel.add( new JLabel( "Threads:" ), ctxt ); + + gbcCheck.gridx = 1; + gbcCheck.gridy = 2; + gbcCheck.fill = GridBagConstraints.HORIZONTAL; + nThreadsField = new JSpinner( new SpinnerNumberModel( 1, 1, 9999, 1 ) ); + panel.add( nThreadsField, gbcCheck ); + + ctxt.gridx = 5; ctxt.anchor = GridBagConstraints.LINE_END; ctxt.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); ctxt.weightx = 0.1; panel.add( new JLabel( "Virtual:" ), ctxt ); - gbcCheck.gridx = 3; + gbcCheck.gridx = 6; gbcCheck.weightx = 0.1; virtualCheckBox = new JCheckBox(); panel.add( virtualCheckBox, gbcCheck ); - ctxt.gridx = 4; - ctxt.anchor = GridBagConstraints.LINE_END; - panel.add( new JLabel( "Type:" ), ctxt ); - - gbcCheck.gridx = 5; - typeComboBox = new JComboBox< String >( new String[] { - BigWarpToDeformationFieldPlugIn.flattenOption, - BigWarpToDeformationFieldPlugIn.sequenceOption } ); - panel.add( typeComboBox, gbcCheck ); - - ctxt.gridx = 6; - ctxt.anchor = GridBagConstraints.LINE_END; - panel.add( new JLabel( "Threads:" ), ctxt ); - - gbcCheck.gridx = 7; - nThreadsField = new JSpinner( new SpinnerNumberModel( 1, 1, 9999, 1 ) ); - panel.add( nThreadsField, gbcCheck ); return panel; } @@ -477,6 +499,7 @@ public DeformationFieldExportParameters getParams() landmarkPathTxt == null ? "" : landmarkPathTxt.getText(), splitAffineCheckBox.isSelected(), (String)typeComboBox.getSelectedItem(), + (String)directionComboBox.getSelectedItem(), virtualCheckBox.isSelected(), (Integer)nThreadsField.getValue(), fovPanel.getPixelSize(), @@ -488,7 +511,7 @@ public DeformationFieldExportParameters getParams() blockSize, BigWarpToDeformationFieldPlugIn.getCompression( (String)n5CompressionDropdown.getSelectedItem() ) ); } - + public void run() { BigWarpToDeformationFieldPlugIn.runFromParameters( getParams(), data, ltm, bwTransform ); @@ -531,6 +554,7 @@ public static void runMacro( String args ) { final String landmarks = Macro.getValue( args, landmarksKey, "" ); final String type = Macro.getValue( args, typeKey, "" ); + final String direction = Macro.getValue( args, directionKey, "" ); final boolean splitAffine = args.contains(" " + splitAffineKey ); final boolean openAsVirtual = args.contains(" " + virtualKey); final int threads = Integer.valueOf( Macro.getValue( args, threadsKey, "1" )); @@ -549,7 +573,7 @@ public static void runMacro( String args ) Arrays.stream( n5BlockSizeString.split( "," ) ).mapToInt( Integer::parseInt ).toArray(); DeformationFieldExportParameters params = new DeformationFieldExportParameters( - landmarks, splitAffine, type, openAsVirtual, threads, + landmarks, splitAffine, type, direction, openAsVirtual, threads, pixSize, spacing, min, unit, n5Root, n5Dataset, diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 7f9956f4..fdb55fd0 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -50,7 +50,6 @@ import org.janelia.saalfeldlab.n5.metadata.omengff.NgffSequenceTransformation; import bdv.gui.ExportDisplacementFieldFrame; -import bdv.viewer.SourceAndConverter; import bigwarp.BigWarp; import bigwarp.BigWarpData; import bigwarp.BigWarpExporter; @@ -67,7 +66,6 @@ import ij.plugin.PlugIn; import ij.plugin.frame.Recorder; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; -import mpicbg.spim.data.sequence.VoxelDimensions; import net.imglib2.Cursor; import net.imglib2.FinalInterval; import net.imglib2.Interval; @@ -86,9 +84,11 @@ import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.DisplacementFieldTransform; import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.InvertibleRealTransformSequence; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.ThinplateSplineTransform; +import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; @@ -107,6 +107,8 @@ */ public class BigWarpToDeformationFieldPlugIn implements PlugIn { + public static enum INVERSE_OPTIONS { FORWARD, INVERSE, BOTH }; + public static final String[] compressionOptions = new String[] { N5Exporter.RAW_COMPRESSION, N5Exporter.GZIP_COMPRESSION, @@ -143,68 +145,79 @@ public void runFromBigWarpInstance( final BigWarp bw ) ExportDisplacementFieldFrame.createAndShow( bw ); } - /** - * @deprecated not necessary access thedesired source this way anymore, use {@link #runFromBigWarpInstance(LandmarkTableModel, SourceAndConverter)} - * on the result of {@link bigwarp.BigWarpData#getTargetSource(int)} - */ - @Deprecated - public void runFromBigWarpInstanceOld( - final BigWarpData data, - final LandmarkTableModel landmarkModel, - final List> sources, - final List targetSourceIndexList ) - { - runFromBigWarpInstanceOld( data, landmarkModel, data.getTargetSource( 0 ) ); - } - - public void runFromBigWarpInstanceOld( - final BigWarpData data, final LandmarkTableModel landmarkModel, final SourceAndConverter< T > sourceAndConverter ) - { - System.out.println( "run from instance." ); - ImageJ ij = IJ.getInstance(); - if ( ij == null ) - return; - - final DeformationFieldExportParameters params = DeformationFieldExportParameters.fromDialog( false, false ); - if( params == null ) - return; - - final RandomAccessibleInterval< ? > tgtInterval = sourceAndConverter.getSpimSource().getSource( 0, 0 ); - - int ndims = landmarkModel.getNumdims(); - long[] dims = tgtInterval.dimensionsAsLongArray(); - - double[] spacing = new double[ 3 ]; - double[] offset = new double[ 3 ]; - String unit = "pix"; - VoxelDimensions voxelDim = sourceAndConverter.getSpimSource().getVoxelDimensions(); - voxelDim.dimensions( spacing ); - - if( params.spacing != null ) - spacing = params.spacing; - - if( params.offset != null ) - offset = params.offset; - - if( params.size != null ) - dims = params.size; - - if( params.n5Base.isEmpty() ) - { - toImagePlus( data, landmarkModel, null, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); - } - else - { - try - { - writeN5( params.n5Base, params.n5Dataset, landmarkModel, null, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); - } - catch ( IOException e ) - { - e.printStackTrace(); - } - } - } +// /** +// * @deprecated not necessary access thedesired source this way anymore, use {@link #runFromBigWarpInstance(LandmarkTableModel, SourceAndConverter)} +// * on the result of {@link bigwarp.BigWarpData#getTargetSource(int)} +// */ +// @Deprecated +// public void runFromBigWarpInstanceOld( +// final BigWarpData data, +// final LandmarkTableModel landmarkModel, +// final List> sources, +// final List targetSourceIndexList ) +// { +// runFromBigWarpInstanceOld( data, landmarkModel, data.getTargetSource( 0 ) ); +// } + +// public void runFromBigWarpInstanceOld( +// final BigWarpData data, final LandmarkTableModel landmarkModel, final SourceAndConverter< T > sourceAndConverter ) +// { +// System.out.println( "run from instance." ); +// ImageJ ij = IJ.getInstance(); +// if ( ij == null ) +// return; +// +// final DeformationFieldExportParameters params = DeformationFieldExportParameters.fromDialog( false, false ); +// if( params == null ) +// return; +// +// final RandomAccessibleInterval< ? > tgtInterval = sourceAndConverter.getSpimSource().getSource( 0, 0 ); +// +// int ndims = landmarkModel.getNumdims(); +// long[] dims = tgtInterval.dimensionsAsLongArray(); +// +// double[] spacing = new double[ 3 ]; +// double[] offset = new double[ 3 ]; +// String unit = "pix"; +// VoxelDimensions voxelDim = sourceAndConverter.getSpimSource().getVoxelDimensions(); +// voxelDim.dimensions( spacing ); +// +// if( params.spacing != null ) +// spacing = params.spacing; +// +// if( params.offset != null ) +// offset = params.offset; +// +// if( params.size != null ) +// dims = params.size; +// +// if( params.n5Base.isEmpty() ) +// { +//// toImagePlus( data, landmarkModel, null, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); +// if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) +// { +// toImagePlus( data, landmarkModel, null, params.ignoreAffine, params.flatten(), false, params.virtual, params.size, params.spacing, params.nThreads ); +// toImagePlus( data, landmarkModel, null, params.ignoreAffine, params.flatten(), true, params.virtual, params.size, params.spacing, params.nThreads ); +// } +// else +// { +// final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); +// toImagePlus( data, landmarkModel, null, params.ignoreAffine, params.flatten(), inverse, params.virtual, params.size, params.spacing, params.nThreads ); +// } +// } +// else +// { +// try +// { +// final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); +// writeN5( params.n5Base, params.n5Dataset, landmarkModel, null, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), inverse ); +// } +// catch ( IOException e ) +// { +// e.printStackTrace(); +// } +// } +// } public static void runFromParameters( final DeformationFieldExportParameters params, final BigWarpData data, final LandmarkTableModel landmarkModel, final BigWarpTransform bwTransform ) { @@ -241,13 +254,31 @@ public static void runFromParameters( final DeformationFieldExportParameters par if ( params.n5Base.isEmpty() ) { - toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), params.virtual, dims, spacing, params.nThreads ); + if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) + { + toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), false, params.virtual, params.size, params.spacing, params.nThreads ); + toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), true, params.virtual, params.size, params.spacing, params.nThreads ); + } + else + { + final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); + toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), inverse, params.virtual, params.size, params.spacing, params.nThreads ); + } } else { try { - writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); + if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) + { + writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), false ); + writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), true ); + } + else + { + final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); + writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), inverse ); + } } catch ( IOException e ) { @@ -297,13 +328,31 @@ public void runBackup( final String arg ) if( params.n5Base.isEmpty() ) { - toImagePlus( null, ltm, null, params.ignoreAffine, params.flatten(), params.virtual, params.size, params.spacing, params.nThreads ); + if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) + { + toImagePlus( null, ltm, null, params.ignoreAffine, params.flatten(), false, params.virtual, params.size, params.spacing, params.nThreads ); + toImagePlus( null, ltm, null, params.ignoreAffine, params.flatten(), true, params.virtual, params.size, params.spacing, params.nThreads ); + } + else + { + final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); + toImagePlus( null, ltm, null, params.ignoreAffine, params.flatten(), inverse, params.virtual, params.size, params.spacing, params.nThreads ); + } } else { try { - writeN5( params.n5Base, params.n5Dataset, ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten() ); + if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) + { + writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), false ); + writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), true ); + } + else + { + final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); + writeN5( params.n5Base, params.n5Dataset, ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), inverse ); + } } catch ( IOException e ) { @@ -317,26 +366,30 @@ public static ImagePlus toImagePlus( final BigWarpTransform bwTransform, final boolean ignoreAffine, final boolean flatten, + final boolean inverse, final boolean virtual, final long[] dims, final double[] spacing, final int nThreads ) { final double[] offset = new double[ spacing.length ]; - return toImagePlus( data, ltm, bwTransform, ignoreAffine, flatten, virtual, dims, spacing, offset, nThreads ); + return toImagePlus( data, ltm, bwTransform, ignoreAffine, flatten, inverse, virtual, dims, spacing, offset, nThreads ); } /** - * Create an {@link ImagePlus} that holds the displacement field. - *

* + * @param data the {@link BigWarpData} * @param ltm the {@link LandmarkTableModel} - * @param splitAffine whether to omit the affine part of the transformation + * @param bwTransform the {@link BigWarpTransform} + * @param ignoreAffine omit the affine part of the transformation + * @param flatten include any fixed transformation + * @param inverse output the inverse transformation + * @param virtual output of virtual image * @param dims the dimensions of the output {@link ImagePlus}'s spatial dimensions * @param spacing the pixel spacing of the output field * @param offset the physical offset (origin) of the output field * @param nThreads number of threads for copying - * @return an image holding the displacement field + * @return the image plus representing the displacement field */ public static ImagePlus toImagePlus( final BigWarpData data, @@ -344,6 +397,7 @@ public static ImagePlus toImagePlus( final BigWarpTransform bwTransform, final boolean ignoreAffine, final boolean flatten, + final boolean inverse, final boolean virtual, final long[] dims, final double[] spacing, @@ -356,7 +410,8 @@ public static ImagePlus toImagePlus( else bwXfm = bwTransform; - final RealTransform startingTransform = getTransformation( data, bwXfm, flatten ); + final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten ); + final InvertibleRealTransform startingTransform = inverse ? fwdTransform.inverse() : fwdTransform; int nd = ltm.getNumdims(); long[] ipDims = null; @@ -422,27 +477,48 @@ else if ( nd == 3 ) return dfieldIp; } - protected static RealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concat ) + /** + * Returns the transformation to be converted to a displacement field. + * + * @param data the bigwarp data storing the fixed transformations + * @param transform the current transformation + * @param concat concatenate the current with fixed transformation + * @return the transformation + */ + protected static InvertibleRealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concat ) { InvertibleRealTransform tps = transform.getTransformation( false ); if( data == null || !concat ) return tps; - RealTransform preTransform = null; - for( Entry< Integer, SourceInfo > entry : data.sourceInfos.entrySet()) + InvertibleRealTransform preTransform = null; + for ( Entry< Integer, SourceInfo > entry : data.sourceInfos.entrySet() ) { - if( entry.getValue().getTransform() != null ) + if ( entry.getValue().getTransform() != null ) { - preTransform = entry.getValue().getTransform(); + RealTransform tform = entry.getValue().getTransform(); + if( tform instanceof InvertibleRealTransform ) + { + preTransform = ( InvertibleRealTransform ) tform; + } + else + { + WrappedIterativeInvertibleRealTransform< RealTransform > ixfm = new WrappedIterativeInvertibleRealTransform<>( tform ); + // use same parameters as the passed transform, hopefully that works + // alternatively, I could wrap the sequence in the iterative invertible transform - there are tradeoffs here + // TODO consider the tradeoffs + ixfm.getOptimzer().setMaxIters( transform.getInverseMaxIterations() ); + ixfm.getOptimzer().setTolerance( transform.getInverseTolerance() ); + preTransform = ixfm; + } break; } } - final RealTransform startingTransform; - if(preTransform != null ) + final InvertibleRealTransform startingTransform; + if ( preTransform != null ) { - System.out.println( "flattening with transform");; - final RealTransformSequence seq = new RealTransformSequence(); + final InvertibleRealTransformSequence seq = new InvertibleRealTransformSequence(); seq.add( tps ); seq.add( preTransform ); startingTransform = seq; @@ -465,9 +541,10 @@ public static void writeN5( final int[] spatialBlockSize, final Compression compression, final int nThreads, - final boolean flatten ) throws IOException + final boolean flatten, + final boolean inverse ) throws IOException { - writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, flatten ); + writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, flatten, inverse ); } public static void writeN5( @@ -483,9 +560,10 @@ public static void writeN5( final int[] spatialBlockSize, final Compression compression, final int nThreads, - final boolean flatten ) throws IOException + final boolean flatten, + final boolean inverse ) throws IOException { - writeN5( n5BasePath, n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, false, flatten ); + writeN5( n5BasePath, n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, false, flatten, inverse ); } public static void writeN5( @@ -502,11 +580,26 @@ public static void writeN5( final Compression compression, final int nThreads, final boolean splitAffine, - final boolean flatten ) throws IOException + final boolean flatten, + final boolean inverse ) throws IOException { - final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; + final String mvgSpaceName = data.getMovingSource( 0 ).getSpimSource().getName(); + final String tgtSpaceName = data.getMovingSource( 1 ).getSpimSource().getName(); + final String inputSpace; + final String outputSpace; + if( inverse ) + { + inputSpace = mvgSpaceName; + outputSpace = tgtSpaceName; + } + else + { + inputSpace = tgtSpaceName; + outputSpace = mvgSpaceName; + } + final BigWarpTransform bwXfm; if( bwTransform == null ) bwXfm = new BigWarpTransform( ltm, BigWarpTransform.TPS ); @@ -514,7 +607,8 @@ public static void writeN5( bwXfm = bwTransform; // final RealTransform tpsTotal = bwXfm.getTransformation( false ); - final RealTransform totalTransform = getTransformation( data, bwXfm, flatten ); + final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten ); + final InvertibleRealTransform totalTransform = inverse ? fwdTransform.inverse() : fwdTransform; AffineGet affine = null; if ( splitAffine ) @@ -553,10 +647,10 @@ public static void writeN5( totalNoAffine.add( totalTransform ); totalNoAffine.add( affine.inverse() ); dfield = DisplacementFieldTransform.createDisplacementField( totalNoAffine, new FinalInterval( dims ), spacing ); - NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, "in", "out", spacing, offset, unit, blockSize, compression, nThreads ); + NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); // the total transform - NgffSequenceTransformation totalTform = new NgffSequenceTransformation( "in", "out", + NgffSequenceTransformation totalTform = new NgffSequenceTransformation( inputSpace, outputSpace, new CoordinateTransformation[]{ dfieldTform, ngffAffine }); N5DisplacementField.addCoordinateTransformations( n5, "/", totalTform ); @@ -564,7 +658,7 @@ public static void writeN5( else { dfield = DisplacementFieldTransform.createDisplacementField( totalTransform, new FinalInterval( dims ), spacing ); - NgffDisplacementsTransformation ngffTform = NgffTransformations.save( n5, dataset, dfield, "in", "out", spacing, offset, unit, blockSize, compression, nThreads ); + NgffDisplacementsTransformation ngffTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); N5DisplacementField.addCoordinateTransformations( n5, "/", ngffTform ); } @@ -932,6 +1026,7 @@ public static class DeformationFieldExportParameters public final String landmarkPath; public final boolean ignoreAffine; public final String option; + public final String inverseOption; public final boolean virtual; public final int nThreads; @@ -949,6 +1044,7 @@ public DeformationFieldExportParameters( final String landmarkPath, final boolean ignoreAffine, final String option, + final String inverseOption, final boolean virtual, final int nThreads, final long[] size, @@ -963,6 +1059,7 @@ public DeformationFieldExportParameters( this.landmarkPath = landmarkPath; this.ignoreAffine = ignoreAffine; this.option = option; + this.inverseOption = inverseOption; this.virtual = virtual; this.nThreads = nThreads; @@ -998,6 +1095,9 @@ public static DeformationFieldExportParameters fromDialog( final String[] choices = new String[] { flattenOption, sequenceOption }; gd.addChoice( "type", choices, flattenOption ); + final String[] invChoices = new String[] { INVERSE_OPTIONS.FORWARD.toString(), INVERSE_OPTIONS.INVERSE.toString(), INVERSE_OPTIONS.BOTH.toString() }; + gd.addChoice( "direction", invChoices, INVERSE_OPTIONS.FORWARD.toString() ); + gd.addCheckbox( "virtual", false ); gd.addNumericField( "threads", 1, 0 ); gd.addMessage( "Size and spacing" ); @@ -1036,6 +1136,7 @@ public static DeformationFieldExportParameters fromDialog( final boolean ignoreAffine = gd.getNextBoolean(); final String option = gd.getNextChoice(); + final String direction = gd.getNextChoice(); final boolean virtual = gd.getNextBoolean(); final int nThreads = ( int ) gd.getNextNumber(); @@ -1113,6 +1214,7 @@ public static DeformationFieldExportParameters fromDialog( landmarkPath, ignoreAffine, option, + direction, virtual, nThreads, size, diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 88de0c4e..d28bf66b 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2121,8 +2121,7 @@ public SourceAndConverter< DoubleType > addTransformMaskSource() transformMask.getRandomAccessible().setOverlays( overlayList ); // synchronizeSources(); - -// REMEMBER TO STASH APPLY + transformMaskSource = soc; return soc; } From df298bc92912af0af8874df6ae130e107aa8edd8 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 22 Dec 2022 14:09:14 -0500 Subject: [PATCH 187/282] fix(test): missing .zgroup in test zarr root --- src/test/resources/bigwarp/url/transformTest.zarr/.zgroup | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/test/resources/bigwarp/url/transformTest.zarr/.zgroup diff --git a/src/test/resources/bigwarp/url/transformTest.zarr/.zgroup b/src/test/resources/bigwarp/url/transformTest.zarr/.zgroup new file mode 100644 index 00000000..e69de29b From a62876eea6454d2568ebf00f68b4cd72b55d4459 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Thu, 22 Dec 2022 14:53:03 -0500 Subject: [PATCH 188/282] feat: utilize N5Url instead of an independent implementation --- pom.xml | 4 +- src/main/java/bigwarp/BigWarpInit.java | 58 ++++++++------------ src/test/java/bigwarp/SerializationTest.java | 2 +- src/test/java/bigwarp/url/UrlParseTest.java | 14 ++--- 4 files changed, 29 insertions(+), 49 deletions(-) diff --git a/pom.xml b/pom.xml index b0b0ccb2..cd782559 100644 --- a/pom.xml +++ b/pom.xml @@ -118,8 +118,8 @@ 3.0.3 4.0.0 - 2.5.1 - 3.2.1 + 2.5.2-SNAPSHOT + 3.2.3-SNAPSHOT 1.4.1 diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 926fe343..0c2154f3 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -36,6 +36,7 @@ import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer; import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.N5TreeNode; +import org.janelia.saalfeldlab.n5.N5URL; import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader; import org.janelia.saalfeldlab.n5.ij.N5Factory; import org.janelia.saalfeldlab.n5.imglib2.N5Utils; @@ -570,77 +571,62 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW return sourceInfoMap; } - private static String schemeSpecificPartWithoutQuery( URI uri ) - { - return uri.getSchemeSpecificPart().replaceAll( "\\?" + uri.getQuery(), "" ).replaceAll( "//", "" ); - } - public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( final BigWarpData< T > bwData, String uri, int setupId, boolean isMoving ) throws URISyntaxException, IOException, SpimDataException { - final URI tmpUri = new URI( "TMP", uri, null ); - String encodedUriString = tmpUri.getRawSchemeSpecificPart(); - encodedUriString = encodedUriString.replaceAll( "%23", "#" ); - URI firstUri = new URI( encodedUriString ); + + URI encodedUri = N5URL.encodeAsUri( uri ); final LinkedHashMap< Source< T >, SourceInfo > sourceStateMap = new LinkedHashMap<>(); - if ( firstUri.isOpaque() ) + if ( encodedUri.isOpaque() ) { - URI secondUri = new URI( firstUri.getSchemeSpecificPart() ); - final String firstScheme = firstUri.getScheme().toLowerCase(); - final String secondScheme = secondUri.getScheme(); - final String secondSchemeSpecificMinusQuery = schemeSpecificPartWithoutQuery( secondUri ); - final boolean dontIncludeScheme = secondScheme == null || Objects.equals( secondScheme, "" ) || Objects.equals( secondScheme.toLowerCase(), "file" ); - final String secondSchemeAndPath = dontIncludeScheme ? secondSchemeSpecificMinusQuery : secondScheme + "://" + secondSchemeSpecificMinusQuery; - final String datasetQuery = secondUri.getQuery(); - final String dataset = datasetQuery == null ? "/" : datasetQuery; + N5URL n5URL = new N5URL( encodedUri.getSchemeSpecificPart() ); + final String firstScheme = encodedUri.getScheme().toLowerCase(); final N5Reader n5reader; switch ( firstScheme ) { case "n5": - n5reader = new N5Factory().openReader( secondSchemeAndPath ); + n5reader = new N5Factory().openReader( n5URL.getContainerPath() ); break; case "zarr": - n5reader = new N5ZarrReader( secondSchemeAndPath ); + n5reader = new N5ZarrReader( n5URL.getContainerPath() ); break; case "h5": case "hdf5": case "hdf": - n5reader = new N5HDF5Reader( secondSchemeAndPath ); + n5reader = new N5HDF5Reader( n5URL.getContainerPath() ); break; default: throw new URISyntaxException( firstScheme, "Unsupported Top Level Protocol" ); } - final Source< T > source = loadN5Source( n5reader, dataset ); - sourceStateMap.put( source, new SourceInfo( setupId, isMoving, dataset ) ); + final Source< T > source = loadN5Source( n5reader, n5URL.getGroupPath() ); + sourceStateMap.put( source, new SourceInfo( setupId, isMoving, n5URL.getGroupPath() ) ); } else { - firstUri = new URI( encodedUriString.replaceAll( "%23", "#" ) ); - final String firstSchemeSpecificPartMinusQuery = schemeSpecificPartWithoutQuery( firstUri ); - final boolean skipScheme = firstUri.getScheme() == null || firstUri.getScheme().trim().isEmpty() || firstUri.getScheme().trim().equalsIgnoreCase( "n5" ) || firstUri.getScheme().trim().equalsIgnoreCase( "file" ); - final String firstSchemeAndPath = skipScheme ? firstSchemeSpecificPartMinusQuery : firstUri.getScheme() + "://" + firstSchemeSpecificPartMinusQuery; + final N5URL n5URL = new N5URL( encodedUri ); try { - final N5Reader n5reader = new N5Factory().openReader( firstSchemeAndPath ); - final String datasetQuery = firstUri.getQuery(); - final String dataset = datasetQuery == null ? "/" : datasetQuery; - final Source< T > source = loadN5Source( n5reader, dataset ); - sourceStateMap.put( source, new SourceInfo( setupId, isMoving, dataset ) ); + final String containerWithoutN5Scheme = n5URL.getContainerPath().replaceFirst( "^n5://", "" ); + final N5Reader n5reader = new N5Factory().openReader( containerWithoutN5Scheme ); + final String group = n5URL.getGroupPath(); + final Source< T > source = loadN5Source( n5reader, group ); + sourceStateMap.put( source, new SourceInfo( setupId, isMoving, group ) ); } catch ( Exception ignored ) {} if ( sourceStateMap.isEmpty() ) { - if ( firstSchemeAndPath.trim().toLowerCase().endsWith( ".xml" ) ) + final String containerPath = n5URL.getContainerPath(); + if ( containerPath.trim().toLowerCase().endsWith( ".xml" ) ) { - sourceStateMap.putAll( createSources( bwData, isMoving, setupId, firstSchemeAndPath, firstUri.getQuery() ) ); + sourceStateMap.putAll( createSources( bwData, isMoving, setupId, containerPath, n5URL.getGroupPath() ) ); } else { final ImagePlus ijp; - if ( Objects.equals( firstUri.getScheme(), "imagej" ) ) + if ( Objects.equals( encodedUri.getScheme(), "imagej" ) ) { - final String title = schemeSpecificPartWithoutQuery( firstUri ); + final String title = n5URL.getContainerPath().replaceAll( "^imagej:(///|//)", "" ); IJ.selectWindow( title ); ijp = IJ.getImage(); } diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index 6f551aad..a55bfa87 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -255,7 +255,7 @@ public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, img.setDisplayRange( 5, 15 ); img.show(); - final String imagejUri = "imagej://generated image"; + final String imagejUri = "imagej:///generated image"; final Path xmlSourceSettings = createNewSettingsWithReplacement( "src/test/resources/settings/expected.json", new HashMap< String, String >() { diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index 4677c9fd..e592aae0 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -138,22 +138,16 @@ public void n5FileUrlEquivalencyTest() throws IOException, SpimDataException, UR final String[] variants = new String[]{ "n5:file://" + absolutePath + "?img#coordinateTransformations[0]", "n5:file://" + absolutePath + "?img", + "n5:file:" + absolutePath + "?img#coordinateTransformations[0]", + "n5:file:" + absolutePath + "?img", "n5://" + absolutePath + "?img#coordinateTransformations[0]", "n5://" + absolutePath + "?img", "file://" + absolutePath + "?img#coordinateTransformations[0]", "file://" + absolutePath + "?img", - "n5:" + absolutePath + "?img#coordinateTransformations[0]", - "n5:" + absolutePath + "?img", + "file:" + absolutePath + "?img#coordinateTransformations[0]", + "file:" + absolutePath + "?img", absolutePath + "?img#coordinateTransformations[0]", absolutePath + "?img", - "n5:file://" + relativePath + "?img#coordinateTransformations[0]", - "n5:file://" + relativePath + "?img", - "n5://" + relativePath + "?img#coordinateTransformations[0]", - "n5://" + relativePath + "?img", - "file://" + relativePath + "?img#coordinateTransformations[0]", - "file://" + relativePath + "?img", - "n5:" + relativePath + "?img#coordinateTransformations[0]", - "n5:" + relativePath + "?img", relativePath + "?img#coordinateTransformations[0]", relativePath + "?img" }; From 1a6cf55ef7e5f582af5b83b34d01a23945eaa4b4 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 22 Dec 2022 16:50:16 -0500 Subject: [PATCH 189/282] feat: toward exporting inverse displacement fields --- .../bdv/gui/ExportDisplacementFieldFrame.java | 162 +++++++++++++++++- .../ij/BigWarpToDeformationFieldPlugIn.java | 4 +- 2 files changed, 161 insertions(+), 5 deletions(-) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index 99003374..eb6ba3ea 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -15,12 +15,16 @@ import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; +import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; @@ -72,6 +76,12 @@ public class ExportDisplacementFieldFrame extends JFrame private boolean imageJOpen; private boolean initialRecorderState; + private boolean n5DatasetChanged; + private DocumentListener docListener; + + private JPanel contentPanel; + private JPanel invPanel; + private JTextField landmarkPathTxt; private JButton browseLandmarksButton; private JTextField n5RootTxt; @@ -86,6 +96,11 @@ public class ExportDisplacementFieldFrame extends JFrame private JSpinner nThreadsField; private JButton okBtn; private JButton cancelBtn; + + // inverse options + private JSpinner invMaxIterationsSpinner; + private JSpinner invToleranceSpinner; + private FieldOfViewPanel fovPanel; public ExportDisplacementFieldFrame( BigWarp bw ) @@ -116,6 +131,19 @@ public ExportDisplacementFieldFrame( BigWarpData data, BigWarpTransform bwTra dispose(); setVisible( false ); }; + + // attach to the n5Dataset text field, keep track of whether user changes it + // once user change occurs, default values from direction dropdown no longer affect it + docListener = new DocumentListener() { + @Override + public void changedUpdate( DocumentEvent e ) { } + + @Override + public void insertUpdate( DocumentEvent e ) { n5DatasetChanged = true; } + + @Override + public void removeUpdate( DocumentEvent e ) { n5DatasetChanged = true; } + }; } public static void createAndShow() @@ -148,10 +176,21 @@ public static void createAndShow( BigWarpData< ? > data, BigWarpTransform bwTran public void createContent() { + n5DatasetChanged = false; final int frameSizeX = UIScale.scale( 600 ); final JPanel panel = basicPanel(); + invPanel = inverseOptionsPanel( frameSizeX ); + invPanel.setBorder( BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), + BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "Inverse options" ), + BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); + + final JPanel n5Panel = n5OptionsPanel( frameSizeX ); n5Panel.setBorder( BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), @@ -183,7 +222,7 @@ public void createContent() "Field of view" ), BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - final JPanel contentPanel = new JPanel(); + contentPanel = new JPanel(); contentPanel.setLayout( new GridBagLayout() ); final GridBagConstraints cGbc = new GridBagConstraints(); @@ -194,14 +233,18 @@ public void createContent() cGbc.gridy = 0; contentPanel.add( panel, cGbc ); cGbc.gridy = 1; - contentPanel.add( n5Panel, cGbc ); + contentPanel.add( invPanel, cGbc ); + invPanel.setEnabled( false ); + invPanel.setVisible( false ); cGbc.gridy = 2; + contentPanel.add( n5Panel, cGbc ); + cGbc.gridy = 3; contentPanel.add( fovPanel, cGbc ); // bottom button section final GridBagConstraints cbot = new GridBagConstraints(); cbot.gridx = 0; - cbot.gridy = 3; + cbot.gridy = 4; cbot.gridwidth = 1; cbot.gridheight = 1; cbot.weightx = 1.0; @@ -233,6 +276,8 @@ public void createContent() fovPanel.updateFieldsFromReference(); else fovPanel.updateFieldsFromImageJReference(); + + addDefaultN5DatasetAction(); } public JPanel basicPanel() @@ -354,6 +399,63 @@ public JPanel basicPanel() return panel; } + public JPanel inverseOptionsPanel( final int frameSizeX ) + { + final int OUTER_PAD = BigWarpInitDialog.DEFAULT_OUTER_PAD; + final int BUTTON_PAD = BigWarpInitDialog.DEFAULT_BUTTON_PAD; + final int MID_PAD = BigWarpInitDialog.DEFAULT_MID_PAD; + + JPanel panel = new JPanel(); + panel.setLayout( new GridBagLayout() ); + + final GridBagConstraints ctxt = new GridBagConstraints(); + ctxt.gridx = 0; + ctxt.gridy = 0; + ctxt.gridwidth = 1; + ctxt.gridheight = 1; + ctxt.weightx = 0.0; + ctxt.weighty = 0.0; + ctxt.anchor = GridBagConstraints.LINE_END; + ctxt.fill = GridBagConstraints.NONE; + ctxt.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); + + final GridBagConstraints gbcBar = new GridBagConstraints(); + gbcBar.gridx = 1; + gbcBar.gridy = 0; + gbcBar.gridwidth = 1; + gbcBar.gridheight = 1; + gbcBar.weightx = 1.0; + gbcBar.weighty = 0.0; + gbcBar.fill = GridBagConstraints.HORIZONTAL; + gbcBar.insets = new Insets( OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD ); + + ctxt.gridx = 0; + ctxt.anchor = GridBagConstraints.LINE_END; + panel.add( new JLabel( "Tolerance:" ), ctxt ); + + gbcBar.gridx = 1; + gbcBar.fill = GridBagConstraints.HORIZONTAL; + invToleranceSpinner = new JSpinner( new SpinnerNumberModel( 0.5, 1e-9, 999999, 0.01 ) ); + + JSpinner.NumberEditor editor = new JSpinner.NumberEditor(invToleranceSpinner, "###,###.######"); + JFormattedTextField textField = editor.getTextField(); + textField.setColumns(12); + invToleranceSpinner.setEditor(editor); + + panel.add( invToleranceSpinner, gbcBar ); + + ctxt.gridx = 3; + ctxt.anchor = GridBagConstraints.LINE_END; + panel.add( new JLabel( "Max iterations:" ), ctxt ); + + gbcBar.gridx = 4; + gbcBar.fill = GridBagConstraints.HORIZONTAL; + invMaxIterationsSpinner = new JSpinner( new SpinnerNumberModel( 200, 1, 999999, 1 ) ); + panel.add( invMaxIterationsSpinner, gbcBar ); + + return panel; + } + public JPanel n5OptionsPanel( final int frameSizeX ) { final int OUTER_PAD = BigWarpInitDialog.DEFAULT_OUTER_PAD; @@ -409,6 +511,9 @@ public JPanel n5OptionsPanel( final int frameSizeX ) n5DatasetTxt = new JTextField(); n5DatasetTxt.setPreferredSize( new Dimension( frameSizeX / 3, n5DatasetTxt.getPreferredSize().height ) ); n5DatasetTxt.setText( "dfield" ); + n5DatasetTxt.getDocument().addDocumentListener( docListener ); + + panel.add( n5DatasetTxt, gbcBar ); ctxt.gridy = 2; @@ -432,6 +537,57 @@ public JPanel n5OptionsPanel( final int frameSizeX ) return panel; } + private void addDefaultN5DatasetAction() + { + directionComboBox.addActionListener( e -> { + if( n5DatasetChanged ) { + return; + } + + final String item = (String)directionComboBox.getSelectedItem(); + if( item.equals( BigWarpToDeformationFieldPlugIn.INVERSE_OPTIONS.FORWARD.toString() )) + { + n5DatasetTxt.getDocument().removeDocumentListener( docListener ); + n5DatasetTxt.setText( "dfield" ); + n5DatasetTxt.getDocument().addDocumentListener( docListener ); + + SwingUtilities.invokeLater( () -> { + invPanel.setEnabled( false ); + invPanel.setVisible( false ); + contentPanel.revalidate(); + contentPanel.repaint(); + pack(); + }); + } + else if( item.equals( BigWarpToDeformationFieldPlugIn.INVERSE_OPTIONS.INVERSE.toString() )) + { + n5DatasetTxt.getDocument().removeDocumentListener( docListener ); + n5DatasetTxt.setText( "invdfield" ); + n5DatasetTxt.getDocument().addDocumentListener( docListener ); + SwingUtilities.invokeLater( () -> { + invPanel.setEnabled( true ); + invPanel.setVisible( true ); + contentPanel.revalidate(); + contentPanel.repaint(); + pack(); + }); + } + else if( item.equals( BigWarpToDeformationFieldPlugIn.INVERSE_OPTIONS.BOTH.toString() )) + { + n5DatasetTxt.getDocument().removeDocumentListener( docListener ); + n5DatasetTxt.setText( "transform" ); + n5DatasetTxt.getDocument().addDocumentListener( docListener ); + SwingUtilities.invokeLater( () -> { + invPanel.setEnabled( true ); + invPanel.setVisible( true ); + contentPanel.revalidate(); + contentPanel.repaint(); + pack(); + }); + } + }); + } + private String browseLandmarksDialog() { final String s = browseDialogGeneral( JFileChooser.FILES_ONLY, new FileNameExtensionFilter( "csv file", "csv" ) ); diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index fdb55fd0..02916338 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -585,8 +585,8 @@ public static void writeN5( { final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; - final String mvgSpaceName = data.getMovingSource( 0 ).getSpimSource().getName(); - final String tgtSpaceName = data.getMovingSource( 1 ).getSpimSource().getName(); + final String mvgSpaceName = data != null ? data.getMovingSource( 0 ).getSpimSource().getName() : "moving"; + final String tgtSpaceName = data != null ? data.getTargetSource( 0 ).getSpimSource().getName() : "target"; final String inputSpace; final String outputSpace; if( inverse ) From e5f1da775af913a839bf762126ffa130fab57b3a Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 23 Dec 2022 12:01:40 -0500 Subject: [PATCH 190/282] fix: fov panel unit label --- src/main/java/bdv/gui/FieldOfViewPanel.java | 40 ++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/main/java/bdv/gui/FieldOfViewPanel.java b/src/main/java/bdv/gui/FieldOfViewPanel.java index ce9e5f1c..a52107bf 100644 --- a/src/main/java/bdv/gui/FieldOfViewPanel.java +++ b/src/main/java/bdv/gui/FieldOfViewPanel.java @@ -4,30 +4,26 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.List; import javax.swing.JComboBox; -import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import com.formdev.flatlaf.util.UIScale; import bdv.ij.ApplyBigwarpPlugin; import bigwarp.BigWarpData; -import bigwarp.BigWarpInit; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.transforms.BigWarpTransform; import ij.IJ; import ij.ImagePlus; import ij.WindowManager; -import mpicbg.spim.data.SpimDataException; import net.imglib2.Interval; import net.imglib2.realtransform.BoundingBoxEstimation; @@ -58,6 +54,7 @@ public class FieldOfViewPanel extends JPanel private JComboBox referenceComboBox; private JTextField unitField; + private JLabel sizeLabel; private ImprovedFormattedTextField[] minFields; private ImprovedFormattedTextField[] sizeFields; @@ -161,6 +158,12 @@ public String getUnit() public void setUnit( String unit ) { unitField.setText( unit ); + updateSizeLabel(); + } + + private void updateSizeLabel() + { + sizeLabel.setText( String.format( "size (%s)", unitField.getText() ) ); } public void create() @@ -236,11 +239,27 @@ else if( IJ.getInstance() != null ) gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.CENTER; unitField = new JTextField("pixel"); - add( unitField, gbc ); + unitField.getDocument().addDocumentListener( new DocumentListener() { + + @Override + public void changedUpdate( DocumentEvent e ) { } + @Override + public void insertUpdate( DocumentEvent e ) + { + updateSizeLabel(); + } + + @Override + public void removeUpdate( DocumentEvent e ) + { + updateSizeLabel(); + } + }); + add( unitField, gbc ); final JLabel minLabel = new JLabel( "min" ); - final JLabel sizeLabel = new JLabel( String.format( "size (%s)", unit ) ); + sizeLabel = new JLabel( String.format( "size (%s)", unit ) ); final JLabel spacingLabel = new JLabel( "spacing" ); final JLabel pixelLabel = new JLabel( "size (pixels)" ); @@ -273,6 +292,11 @@ else if( IJ.getInstance() != null ) add( zLabel, gbc ); } + /* + * TODO investigate focus traversal, see: + * https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html#customFocusTraversal + */ + minFields = new ImprovedFormattedTextField[ ndims ]; sizeFields = new ImprovedFormattedTextField[ ndims ]; spacingFields = new ImprovedFormattedTextField[ ndims ]; From 761fec9b937b182772efc917cbcd2ddf39576331 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 4 Jan 2023 10:47:50 -0500 Subject: [PATCH 191/282] feat: correct inverse + ignoreAffine behavior for displacement field export * add test for displacement field export options --- .../bdv/gui/ExportDisplacementFieldFrame.java | 12 +- .../ij/BigWarpToDeformationFieldPlugIn.java | 168 +++++++----- .../bigwarp/transforms/BigWarpTransform.java | 19 ++ .../java/bigwarp/dfield/DfieldExportTest.java | 240 ++++++++++++++++++ 4 files changed, 375 insertions(+), 64 deletions(-) create mode 100644 src/test/java/bigwarp/dfield/DfieldExportTest.java diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index eb6ba3ea..9d0d67cd 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -51,6 +51,9 @@ public class ExportDisplacementFieldFrame extends JFrame protected static final String splitAffineKey = "split_affine"; protected static final String typeKey = "type"; protected static final String directionKey = "direction"; + protected static final String inverseToleranceKey = "inverseTolerance"; + protected static final String inverseMaxIterationsKey = "inverseMaxIterations"; + protected static final String virtualKey = "virtual"; protected static final String threadsKey = "threads"; protected static final String sizeKey = "pixel_size"; @@ -656,6 +659,8 @@ public DeformationFieldExportParameters getParams() splitAffineCheckBox.isSelected(), (String)typeComboBox.getSelectedItem(), (String)directionComboBox.getSelectedItem(), + (Double)invToleranceSpinner.getValue(), + (Integer)invMaxIterationsSpinner.getValue(), virtualCheckBox.isSelected(), (Integer)nThreadsField.getValue(), fovPanel.getPixelSize(), @@ -711,6 +716,9 @@ public static void runMacro( String args ) final String landmarks = Macro.getValue( args, landmarksKey, "" ); final String type = Macro.getValue( args, typeKey, "" ); final String direction = Macro.getValue( args, directionKey, "" ); + final double tolerance = Double.valueOf( Macro.getValue( args, inverseToleranceKey, "" )); + final int maxIters = Integer.valueOf( Macro.getValue( args, inverseMaxIterationsKey, "" )); + final boolean splitAffine = args.contains(" " + splitAffineKey ); final boolean openAsVirtual = args.contains(" " + virtualKey); final int threads = Integer.valueOf( Macro.getValue( args, threadsKey, "1" )); @@ -729,7 +737,9 @@ public static void runMacro( String args ) Arrays.stream( n5BlockSizeString.split( "," ) ).mapToInt( Integer::parseInt ).toArray(); DeformationFieldExportParameters params = new DeformationFieldExportParameters( - landmarks, splitAffine, type, direction, openAsVirtual, threads, + landmarks, splitAffine, type, + direction, tolerance, maxIters, + openAsVirtual, threads, pixSize, spacing, min, unit, n5Root, n5Dataset, diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 02916338..864b1f4e 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -69,6 +69,7 @@ import net.imglib2.Cursor; import net.imglib2.FinalInterval; import net.imglib2.Interval; +import net.imglib2.Point; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealPoint; import net.imglib2.converter.Converters; @@ -96,10 +97,17 @@ import net.imglib2.view.Views; import net.imglib2.view.composite.CompositeIntervalView; import net.imglib2.view.composite.GenericComposite; +import net.imglib2.view.composite.RealComposite; import ome.ngff.transformations.CoordinateTransformation; /** - * ImageJ plugin to convert the thin plate spline to a deformation field. + * ImageJ plugin to convert the thin plate spline to a displacement field. + *

+ * If the ignoreAffine option is true, the resulting displacement field will + * not contain the affine part of the transformation. In this case, the total + * transformation is the displacement field first, followed by the affine part + * of the transformation. + * * * @author John Bogovic <bogovicj@janelia.hhmi.org> * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> @@ -128,8 +136,8 @@ public static void main( final String[] args ) // IJ.run("Boats (356K)"); // ImagePlus imp = IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif" ); -// ImagePlus imp = IJ.openImage( "/home/john/tmp/mri-stack.tif" ); - ImagePlus imp = IJ.openImage( "/home/john/tmp/mri-stack_mm.tif" ); + ImagePlus imp = IJ.openImage( "/home/john/tmp/mri-stack.tif" ); +// ImagePlus imp = IJ.openImage( "/home/john/tmp/mri-stack_mm.tif" ); imp.show(); new BigWarpToDeformationFieldPlugIn().run( null ); @@ -271,13 +279,16 @@ public static void runFromParameters( final DeformationFieldExportParameters par { if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { - writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), false ); - writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), true ); + writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + false, params.inverseTolerance, params.inverseMaxIterations ); + writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + true, params.inverseTolerance, params.inverseMaxIterations ); } else { final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); - writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), inverse ); + writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + inverse, params.inverseTolerance, params.inverseMaxIterations ); } } catch ( IOException e ) @@ -345,13 +356,16 @@ public void runBackup( final String arg ) { if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { - writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), false ); - writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), true ); + writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + false, params.inverseTolerance, params.inverseMaxIterations ); + writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + true, params.inverseTolerance, params.inverseMaxIterations ); } else { final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); - writeN5( params.n5Base, params.n5Dataset, ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), inverse ); + writeN5( params.n5Base, params.n5Dataset, ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + inverse, params.inverseTolerance, params.inverseMaxIterations ); } } catch ( IOException e ) @@ -360,11 +374,12 @@ public void runBackup( final String arg ) } } } + public static ImagePlus toImagePlus( final BigWarpData data, final LandmarkTableModel ltm, final BigWarpTransform bwTransform, - final boolean ignoreAffine, + final boolean splitAffine, final boolean flatten, final boolean inverse, final boolean virtual, @@ -373,7 +388,7 @@ public static ImagePlus toImagePlus( final int nThreads ) { final double[] offset = new double[ spacing.length ]; - return toImagePlus( data, ltm, bwTransform, ignoreAffine, flatten, inverse, virtual, dims, spacing, offset, nThreads ); + return toImagePlus( data, ltm, bwTransform, splitAffine, flatten, inverse, virtual, dims, spacing, offset, nThreads ); } /** @@ -381,7 +396,7 @@ public static ImagePlus toImagePlus( * @param data the {@link BigWarpData} * @param ltm the {@link LandmarkTableModel} * @param bwTransform the {@link BigWarpTransform} - * @param ignoreAffine omit the affine part of the transformation + * @param splitAffine omit the affine part of the transformation * @param flatten include any fixed transformation * @param inverse output the inverse transformation * @param virtual output of virtual image @@ -395,7 +410,7 @@ public static ImagePlus toImagePlus( final BigWarpData data, final LandmarkTableModel ltm, final BigWarpTransform bwTransform, - final boolean ignoreAffine, + final boolean splitAffine, final boolean flatten, final boolean inverse, final boolean virtual, @@ -410,7 +425,7 @@ public static ImagePlus toImagePlus( else bwXfm = bwTransform; - final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten ); + final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten, splitAffine ); final InvertibleRealTransform startingTransform = inverse ? fwdTransform.inverse() : fwdTransform; int nd = ltm.getNumdims(); @@ -456,7 +471,7 @@ else if ( nd == 3 ) } String title = "bigwarp dfield"; - if ( ignoreAffine ) + if ( splitAffine ) title += " (no affine)"; dfieldIp.setTitle( title ); @@ -483,44 +498,62 @@ else if ( nd == 3 ) * @param data the bigwarp data storing the fixed transformations * @param transform the current transformation * @param concat concatenate the current with fixed transformation + * @param ignoreAffine whether the output should include the affine part of the transformation * @return the transformation */ - protected static InvertibleRealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concat ) + protected static InvertibleRealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concat, + final boolean ignoreAffine ) { - InvertibleRealTransform tps = transform.getTransformation( false ); - if( data == null || !concat ) + final InvertibleRealTransform tps = transform.getTransformation( false ); + + AffineGet affine = null; + if( ignoreAffine ) + affine = transform.affinePartOfTps(); + + if ( !ignoreAffine && ( data == null || !concat ) ) + { return tps; + } InvertibleRealTransform preTransform = null; - for ( Entry< Integer, SourceInfo > entry : data.sourceInfos.entrySet() ) + if( data != null ) { - if ( entry.getValue().getTransform() != null ) + for ( Entry< Integer, SourceInfo > entry : data.sourceInfos.entrySet() ) { - RealTransform tform = entry.getValue().getTransform(); - if( tform instanceof InvertibleRealTransform ) + if ( entry.getValue().getTransform() != null ) { - preTransform = ( InvertibleRealTransform ) tform; - } - else - { - WrappedIterativeInvertibleRealTransform< RealTransform > ixfm = new WrappedIterativeInvertibleRealTransform<>( tform ); - // use same parameters as the passed transform, hopefully that works - // alternatively, I could wrap the sequence in the iterative invertible transform - there are tradeoffs here - // TODO consider the tradeoffs - ixfm.getOptimzer().setMaxIters( transform.getInverseMaxIterations() ); - ixfm.getOptimzer().setTolerance( transform.getInverseTolerance() ); - preTransform = ixfm; + RealTransform tform = entry.getValue().getTransform(); + if( tform instanceof InvertibleRealTransform ) + { + preTransform = ( InvertibleRealTransform ) tform; + } + else + { + WrappedIterativeInvertibleRealTransform< RealTransform > ixfm = new WrappedIterativeInvertibleRealTransform<>( tform ); + // use same parameters as the passed transform, hopefully that works + // alternatively, I could wrap the sequence in the iterative invertible transform - there are tradeoffs here + // TODO consider the tradeoffs + ixfm.getOptimzer().setMaxIters( transform.getInverseMaxIterations() ); + ixfm.getOptimzer().setTolerance( transform.getInverseTolerance() ); + preTransform = ixfm; + } + break; } - break; } } final InvertibleRealTransform startingTransform; - if ( preTransform != null ) + if ( preTransform != null || affine != null ) { final InvertibleRealTransformSequence seq = new InvertibleRealTransformSequence(); seq.add( tps ); - seq.add( preTransform ); + + if( affine != null ) + seq.add( affine.inverse() ); + + if( preTransform != null ) + seq.add( preTransform ); + startingTransform = seq; } else @@ -542,9 +575,11 @@ public static void writeN5( final Compression compression, final int nThreads, final boolean flatten, - final boolean inverse ) throws IOException + final boolean inverse, + final double invTolerance, + final int invMaxIters ) throws IOException { - writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, flatten, inverse ); + writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, flatten, inverse, invTolerance, invMaxIters ); } public static void writeN5( @@ -561,9 +596,11 @@ public static void writeN5( final Compression compression, final int nThreads, final boolean flatten, - final boolean inverse ) throws IOException + final boolean inverse, + final double invTolerance, + final int invMaxIters ) throws IOException { - writeN5( n5BasePath, n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, false, flatten, inverse ); + writeN5( n5BasePath, n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, false, flatten, inverse, invTolerance, invMaxIters ); } public static void writeN5( @@ -581,7 +618,9 @@ public static void writeN5( final int nThreads, final boolean splitAffine, final boolean flatten, - final boolean inverse ) throws IOException + final boolean inverse, + final double invTolerance, + final int invMaxIters ) throws IOException { final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; @@ -606,34 +645,21 @@ public static void writeN5( else bwXfm = bwTransform; + bwXfm.setInverseMaxIterations( invMaxIters ); + bwXfm.setInverseTolerance( invTolerance ); + // final RealTransform tpsTotal = bwXfm.getTransformation( false ); - final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten ); + final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten, splitAffine ); final InvertibleRealTransform totalTransform = inverse ? fwdTransform.inverse() : fwdTransform; - - AffineGet affine = null; - if ( splitAffine ) - { - final double[][] affineArray = bwXfm.affinePartOfTpsHC(); - if ( affineArray.length == 2 ) - { - final AffineTransform2D affine2d = new AffineTransform2D(); - affine2d.set( affineArray ); - affine = affine2d; - } - else - { - final AffineTransform3D affine3d = new AffineTransform3D(); - affine3d.set( affineArray ); - affine = affine3d; - } - } + final AffineGet affine = bwXfm.affinePartOfTps(); int[] spatialBlockSize = fillBlockSize( spatialBlockSizeArg, ltm.getNumdims() ); int[] blockSize = new int[ spatialBlockSize.length + 1 ]; blockSize[ 0 ] = spatialBlockSize.length; System.arraycopy( spatialBlockSize, 0, blockSize, 1, spatialBlockSize.length ); - final N5Writer n5 = new N5Factory().openWriter( n5BasePath ); + final N5Factory factory = new N5Factory().gsonBuilder( NgffTransformations.gsonBuilder() ); + final N5Writer n5 = factory.openWriter( n5BasePath ); // N5DisplacementField.save( n5, dataset, affine, dfield, spacing, blockSize, compression ); final RandomAccessibleInterval< DoubleType > dfield; @@ -658,6 +684,13 @@ public static void writeN5( else { dfield = DisplacementFieldTransform.createDisplacementField( totalTransform, new FinalInterval( dims ), spacing ); + + Point pt = new Point( 100, 100, 10 ); + CompositeIntervalView< DoubleType, RealComposite< DoubleType > > dfImgVec = Views.collapseReal( Views.moveAxis( dfield, 0, 3 )); + RealPoint q = new RealPoint ( 3 ); + q.setPosition( dfImgVec.getAt( pt )); + System.out.println( "displacement at " + pt + " : " + q ); + NgffDisplacementsTransformation ngffTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); N5DisplacementField.addCoordinateTransformations( n5, "/", ngffTform ); } @@ -1039,12 +1072,17 @@ public static class DeformationFieldExportParameters public final String n5Dataset; public final Compression compression; public final int[] blockSize; + + public final double inverseTolerance; + public final int inverseMaxIterations; public DeformationFieldExportParameters( final String landmarkPath, final boolean ignoreAffine, final String option, final String inverseOption, + final double inverseTolerance, + final int inverseMaxIterations, final boolean virtual, final int nThreads, final long[] size, @@ -1059,7 +1097,11 @@ public DeformationFieldExportParameters( this.landmarkPath = landmarkPath; this.ignoreAffine = ignoreAffine; this.option = option; + this.inverseOption = inverseOption; + this.inverseTolerance = inverseTolerance; + this.inverseMaxIterations = inverseMaxIterations; + this.virtual = virtual; this.nThreads = nThreads; @@ -1213,8 +1255,8 @@ public static DeformationFieldExportParameters fromDialog( return new DeformationFieldExportParameters( landmarkPath, ignoreAffine, - option, - direction, + option, + direction, 0.5, 200, virtual, nThreads, size, diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index a96827ff..a936943f 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -472,6 +472,25 @@ else if( r == c ) return mtx; } + public AffineGet affinePartOfTps() + { + AffineGet affine = null; + final double[][] affineArray = affinePartOfTpsHC(); + if ( affineArray.length == 2 ) + { + final AffineTransform2D affine2d = new AffineTransform2D(); + affine2d.set( affineArray ); + affine = affine2d; + } + else + { + final AffineTransform3D affine3d = new AffineTransform3D(); + affine3d.set( affineArray ); + affine = affine3d; + } + return affine; + } + public void initializeInverseParameters( BigWarpData bwData ) { final int N = bwData.numTargetSources(); diff --git a/src/test/java/bigwarp/dfield/DfieldExportTest.java b/src/test/java/bigwarp/dfield/DfieldExportTest.java new file mode 100644 index 00000000..b744e66b --- /dev/null +++ b/src/test/java/bigwarp/dfield/DfieldExportTest.java @@ -0,0 +1,240 @@ +package bigwarp.dfield; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedHashMap; + +import org.junit.Before; +import org.junit.Test; + +import bdv.ij.BigWarpToDeformationFieldPlugIn; +import bdv.viewer.Source; +import bigwarp.BigWarpData; +import bigwarp.BigWarpInit; +import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.source.SourceInfo; +import bigwarp.transforms.BigWarpTransform; +import ij.ImagePlus; +import net.imglib2.FinalRealInterval; +import net.imglib2.Interval; +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.RealPoint; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.img.imageplus.ImagePlusImgs; +import net.imglib2.iterator.RealIntervalIterator; +import net.imglib2.realtransform.AffineGet; +import net.imglib2.realtransform.DisplacementFieldTransform; +import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.RealTransform; +import net.imglib2.realtransform.RealTransformSequence; +import net.imglib2.realtransform.Scale3D; +import net.imglib2.type.numeric.RealType; +import net.imglib2.type.numeric.real.FloatType; +import net.imglib2.util.Intervals; +import net.imglib2.util.Util; +import net.imglib2.view.Views; + +public class DfieldExportTest +{ + private BigWarpData data; + private BigWarpData dataWithTransform; + private LandmarkTableModel ltm; + + @Before + public void setup() + { + ImagePlus imp = ImagePlusImgs.bytes( 64, 64, 16 ).getImagePlus(); + data = makeData( imp, null ); + dataWithTransform = makeData( imp, new Scale3D( 0.5, 0.5, 0.5 )); + + ltm = new LandmarkTableModel( 3 ); + try + { + ltm.load( new File( "src/test/resources/mr_landmarks_p2p2p4-111.csv" )); + } + catch ( IOException e ) + { + e.printStackTrace(); + fail(); + } + } + + private static < T extends RealType< T > > BigWarpData< T > makeData( ImagePlus imp, RealTransform tform ) + { + final int id = 0; + final boolean isMoving = true; + final BigWarpData data = BigWarpInit.initData(); + final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, imp, id, 0, isMoving ); + BigWarpInit.add( data, infos, tform ); + return data; + } + + @Test + public void dfieldExportTest() + { + final BigWarpTransform bwTransform = new BigWarpTransform( ltm ); + bwTransform.setInverseTolerance( 0.05 ); + bwTransform.setInverseMaxIterations( 200 ); + + final boolean ignoreAffine = false; + final boolean flatten = true; + final boolean virtual = false; + final long[] dims = new long[] { 47, 56, 7 }; + final double[] spacing = new double[] { 0.8, 0.8, 1.6 }; + final double[] offset = new double[] { 0, 0, 0 }; + final int nThreads = 1; + + final FinalRealInterval testItvl = new FinalRealInterval( + new double[]{ 3.6, 3.6, 1.6 }, + new double[]{ 32.0, 40.0, 9.6 }); + + final RealIntervalIterator it = new RealIntervalIterator( testItvl, spacing ); + + final ImagePlus dfieldImp = BigWarpToDeformationFieldPlugIn.toImagePlus( + data, ltm, bwTransform, + ignoreAffine, flatten, false, virtual, + dims, spacing, offset, + nThreads ); + + final InvertibleRealTransform tform = bwTransform.getTransformation(); + assertTrue( "forward", compare( tform, dfieldImp, it, 1e-3 )); + + final ImagePlus dfieldInvImp = BigWarpToDeformationFieldPlugIn.toImagePlus( + data, ltm, bwTransform, + ignoreAffine, flatten, true, virtual, + dims, spacing, offset, + nThreads ); + + it.reset(); + assertTrue( "inverse", compare( tform.inverse(), dfieldInvImp, it, 0.25 )); + } + + @Test + public void dfieldIgnoreAffineExportTest() + { + final boolean ignoreAffine = true; + + final BigWarpTransform bwTransform = new BigWarpTransform( ltm ); + + // constant parameters + final boolean flatten = true; + final boolean virtual = false; + final long[] dims = new long[] { 47, 56, 7 }; + final double[] spacing = new double[] { 0.8, 0.8, 1.6 }; + final double[] offset = new double[] { 0, 0, 0 }; + final int nThreads = 1; + + final FinalRealInterval testItvl = new FinalRealInterval( + new double[]{ 3.6, 3.6, 1.6 }, + new double[]{ 32.0, 40.0, 9.6 }); + + final ImagePlus dfieldImp = BigWarpToDeformationFieldPlugIn.toImagePlus( + data, ltm, bwTransform, + ignoreAffine, flatten, false, virtual, + dims, spacing, offset, + nThreads ); + + final RealTransformSequence total = new RealTransformSequence(); + total.add( toDfield( dfieldImp ) ); + total.add( bwTransform.affinePartOfTps() ); + + final RealIntervalIterator it = new RealIntervalIterator( testItvl, spacing ); + final InvertibleRealTransform tform = bwTransform.getTransformation(); + + assertTrue( "split affine forward", compare( tform, total, it, 1e-3 )); + } + + @Test + public void dfieldConcatExportTest() + { + final BigWarpTransform bwTransform = new BigWarpTransform( ltm ); + + // constant parameters + final boolean ignoreAffine = false; + final boolean virtual = false; + final boolean inverse = false; + final long[] dims = new long[] { 47, 56, 7 }; + final double[] spacing = new double[] { 0.8, 0.8, 1.6 }; + final double[] offset = new double[] { 0, 0, 0 }; + final int nThreads = 1; + + final FinalRealInterval testItvl = new FinalRealInterval( + new double[]{ 3.6, 3.6, 1.6 }, + new double[]{ 32.0, 40.0, 9.6 }); + + // flattened + final ImagePlus dfieldImpFlat = BigWarpToDeformationFieldPlugIn.toImagePlus( + dataWithTransform, ltm, bwTransform, + ignoreAffine, true, inverse, virtual, + dims, spacing, offset, + nThreads ); + final DisplacementFieldTransform dfieldFlat = toDfield( dfieldImpFlat ); + + final InvertibleRealTransform tform = bwTransform.getTransformation(); + final RealTransform preTransform = dataWithTransform.getSourceInfo( 0 ).getTransform(); + + final RealTransformSequence totalTrueTransform = new RealTransformSequence(); + totalTrueTransform.add( tform ); + totalTrueTransform.add( preTransform ); + + final RealIntervalIterator it = new RealIntervalIterator( testItvl, spacing ); + assertTrue( "flatten forward", compare( totalTrueTransform, dfieldFlat, it, 1e-3 )); + + // not flattened + final ImagePlus dfieldImpUnFlat = BigWarpToDeformationFieldPlugIn.toImagePlus( + dataWithTransform, ltm, bwTransform, + ignoreAffine, false, inverse, virtual, + dims, spacing, offset, + nThreads ); + final DisplacementFieldTransform dfieldUnflat = toDfield( dfieldImpUnFlat ); + + it.reset(); + assertTrue( "un-flattened forward", compare( tform, dfieldUnflat, it, 1e-3 )); + } + + public static DisplacementFieldTransform toDfield( final ImagePlus dfieldImp ) + { + final double[] spacing = new double[] { + dfieldImp.getCalibration().pixelWidth, dfieldImp.getCalibration().pixelHeight, dfieldImp.getCalibration().pixelDepth + }; + final double[] offset = new double[] { + dfieldImp.getCalibration().xOrigin, dfieldImp.getCalibration().yOrigin, dfieldImp.getCalibration().zOrigin + }; + + final RandomAccessibleInterval< FloatType > img = ImageJFunctions.wrapRealNative( dfieldImp ); + final RandomAccessibleInterval< FloatType > dfimg = Views.moveAxis( img, 2, 0 ); + return new DisplacementFieldTransform( dfimg, spacing, offset ); + } + + public static boolean compare( final RealTransform tform, final ImagePlus dfieldImp, final RealIntervalIterator it, final double tol ) + { + return compare( tform, toDfield( dfieldImp ), it, tol ); + } + + public static boolean compare( final RealTransform a, final RealTransform b, final RealIntervalIterator it, final double tol ) + { + final RealPoint gt = new RealPoint( 3 ); + final RealPoint df = new RealPoint( 3 ); + while( it.hasNext()) + { + it.fwd(); + a.apply( it, gt ); + b.apply( it, df ); + final double dist = Util.distance( gt, df ); + if( dist > tol ) + { + System.out.println( "it : " + it ); + System.out.println( "dist: " + dist); + return false; + } + } + + return true; + + } + + +} From ecfd63cce3c5e164820507d260efbd3556ea5501 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 9 Jan 2023 13:34:37 -0500 Subject: [PATCH 192/282] fix: add mask source to sourceInfos (avoids NPE) --- src/main/java/bigwarp/BigWarp.java | 6 +++++- src/main/java/bigwarp/BigWarpData.java | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index d28bf66b..10df8e75 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2074,7 +2074,7 @@ public void updateTransformMask() addTransformMaskSource(); } - // upddate the bigwarp transform + // update the bigwarp transform getBwTransform().setMaskInterpolationType( type ); restimateTransformation(); setMaskOverlayVisibility( maskOpts.showMaskOverlay() && maskOpts.isMask() ); @@ -2107,6 +2107,10 @@ public SourceAndConverter< DoubleType > addTransformMaskSource() data.converterSetups.add( BigDataViewer.createConverterSetup( soc, TRANSFORM_MASK_SOURCE_ID ) ); data.sources.add( ( SourceAndConverter ) soc ); + final SourceInfo sourceInfo = new SourceInfo( TRANSFORM_MASK_SOURCE_ID, false, transformMask.getName(), null, null ); + sourceInfo.setSourceAndConverter( soc ); + data.sourceInfos.put( TRANSFORM_MASK_SOURCE_ID, sourceInfo); + // connect to UI warpVisDialog.maskOptionsPanel.setMask( transformMask ); addMaskMouseListener(); diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index ef46543a..a5016852 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -232,6 +232,19 @@ void addSource( Source src, boolean isMoving, RealTransform transform ) if( id == cs.getSetupId() ) id++; } + addSource( id, src, isMoving, transform ); + } + + /** + * Adds a {@link Source} with the given id. Does not check that the id is unused. + * + * @param id the id + * @param src the source + * @param isMoving if the source is moving + * @param transform an optional transformation + */ + void addSource( final int id, Source src, boolean isMoving, RealTransform transform ) + { BigWarpInit.add( this, src, id, 0, isMoving, transform ); final SourceInfo sourceInfo = new SourceInfo( id, isMoving, src.getName(), null, transform ); sourceInfo.setSourceAndConverter( sources.get( sources.size() -1 ) ); From b1df58c637f6130ccc947e5780b7d23d7288403c Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Mon, 9 Jan 2023 16:55:10 -0500 Subject: [PATCH 193/282] feat: change BigWarp dimensionality during runtime --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 4 + src/main/java/bdv/viewer/BigWarpOverlay.java | 14 +- src/main/java/bigwarp/BigWarp.java | 187 +++++++++++++----- src/main/java/bigwarp/BigwarpSettings.java | 7 + src/main/java/bigwarp/WarpVisFrame.java | 15 +- src/test/java/bigwarp/BigWarpTestUtils.java | 52 +++-- 6 files changed, 211 insertions(+), 68 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 0ff833cd..f06bfb5b 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -157,6 +157,10 @@ public void valueChanged( ListSelectionEvent e ) viewer.getDisplay().addHandler( mouseAndKeyHandler ); // TODO: should be a field? + updateTransformBehaviors( optional ); + } + + public void updateTransformBehaviors(BigWarpViewerOptions optional) { final Behaviours transformBehaviours = new Behaviours( optional.values.getInputTriggerConfig(), "bdv" ); transformBehaviours.install( triggerbindings, "transform" ); diff --git a/src/main/java/bdv/viewer/BigWarpOverlay.java b/src/main/java/bdv/viewer/BigWarpOverlay.java index 9a7f70c5..e1a573e4 100644 --- a/src/main/java/bdv/viewer/BigWarpOverlay.java +++ b/src/main/java/bdv/viewer/BigWarpOverlay.java @@ -52,14 +52,15 @@ public class BigWarpOverlay { private int hoveredIndex; protected final boolean isMoving; - protected final boolean is3d; - + + protected boolean is3d; + protected final double[] spot; - protected final double[] viewerCoords; + protected final double[] viewerCoords; /** The transform for the viewer current viewpoint. */ private final AffineTransform3D transform = new AffineTransform3D(); - + public BigWarpOverlay( final BigWarpViewerPanel viewer, BigWarpLandmarkPanel landmarkpanel ) { this.viewer = viewer; @@ -77,6 +78,11 @@ public BigWarpOverlay( final BigWarpViewerPanel viewer, BigWarpLandmarkPanel lan viewerCoords = new double[ 3 ]; } + public void is2D( final boolean is2d ) + { + this.is3d = !is2d; + } + public int getHoveredIndex() { diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index c5277082..019b894d 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -21,6 +21,7 @@ */ package bigwarp; +import bdv.TransformState; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; @@ -42,7 +43,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -131,7 +131,6 @@ import bdv.viewer.overlay.BigWarpSourceOverlayRenderer; import bdv.viewer.overlay.MultiBoxOverlayRenderer; import bigwarp.landmarks.LandmarkTableModel; -import bigwarp.loader.ImagePlusLoader.ColorSettings; import bigwarp.source.GridSource; import bigwarp.source.JacobianDeterminantSource; import bigwarp.source.PlateauSphericalMaskSource; @@ -299,7 +298,7 @@ public class BigWarp< T > private BoundingBoxEstimation bboxOptions; private long keyClickMaxLength = 250; - + protected TransformTypeSelectDialog transformSelector; protected AffineTransform3D tmpTransform = new AffineTransform3D(); @@ -427,7 +426,7 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final final MultiBoxOverlayRenderer overlayRenderP = new MultiBoxOverlayRenderer( DEFAULT_WIDTH, DEFAULT_HEIGHT ); final MultiBoxOverlayRenderer overlayRenderQ = new MultiBoxOverlayRenderer( DEFAULT_WIDTH, DEFAULT_HEIGHT ); - + // TODO hopefully I won't' need reflection any more final Field boxField = overlayRenderP.getClass().getDeclaredField( "box" ); boxField.setAccessible( true ); @@ -499,7 +498,7 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final transformSelector = new TransformTypeSelectDialog( landmarkFrame, this ); // dialogs have to be constructed before action maps are made - warpVisDialog = new WarpVisFrame( viewerFrameQ, this ); + warpVisDialog = new WarpVisFrame( viewerFrameQ, this ); warpVisDialog.maskOptionsPanel.setMask( transformMask ); WarpNavigationActions.installActionBindings( getViewerFrameP().getKeybindings(), viewerFrameP, keyProperties, ( ndims == 2 ) ); @@ -575,6 +574,104 @@ public BigWarp( final BigWarpData data, BigWarpViewerOptions options, final }); } + public void changeDimensionality(boolean is2D) { + + if (options.values.is2D() == is2D) + return; + + options.is2D( is2D ); + + if( options.values.is2D() ) + ndims = 2; + else + ndims = 3; + + /* update landmark model with new dimensionality */ + landmarkModel = new LandmarkTableModel( ndims ); + landmarkModel.addTableModelListener( landmarkModellistener ); + addTransformListener( landmarkModel ); + landmarkModel.setMessage( message ); + + landmarkPanel.setTableModel(landmarkModel); + + setupWarpMagBaselineOptions( baseXfmList, ndims ); + + final Class< ViewerPanel > c_vp = ViewerPanel.class; + try + { + final Field transformEventHandlerField = c_vp.getDeclaredField( "transformEventHandler" ); + transformEventHandlerField.setAccessible( true ); + transformEventHandlerField.set( viewerP, options.values.getTransformEventHandlerFactory().create( TransformState.from( viewerP.state()::getViewerTransform, viewerP.state()::setViewerTransform ) ) ); + transformEventHandlerField.set( viewerQ, options.values.getTransformEventHandlerFactory().create( TransformState.from( viewerQ.state()::getViewerTransform, viewerQ.state()::setViewerTransform ) ) ); + transformEventHandlerField.setAccessible( false ); + } + catch ( final Exception e ) + { + e.printStackTrace(); + } + + viewerFrameP.updateTransformBehaviors( options ); + viewerFrameQ.updateTransformBehaviors( options ); + + // If the images are 2d, use a transform handler that limits + // transformations to rotations and scalings of the 2d plane ( z = 0 ) + if ( options.values.is2D() ) + { + + // final Class< ViewerPanel > c_vp = ViewerPanel.class; + try + { + final Field overlayRendererField = c_vp.getDeclaredField( "multiBoxOverlayRenderer" ); + overlayRendererField.setAccessible( true ); + + final MultiBoxOverlayRenderer overlayRenderP = new MultiBoxOverlayRenderer( DEFAULT_WIDTH, DEFAULT_HEIGHT ); + final MultiBoxOverlayRenderer overlayRenderQ = new MultiBoxOverlayRenderer( DEFAULT_WIDTH, DEFAULT_HEIGHT ); + + // TODO hopefully I won't' need reflection any more + final Field boxField = overlayRenderP.getClass().getDeclaredField( "box" ); + boxField.setAccessible( true ); + boxField.set( overlayRenderP, new MultiBoxOverlay2d() ); + boxField.set( overlayRenderQ, new MultiBoxOverlay2d() ); + boxField.setAccessible( false ); + + overlayRendererField.set( viewerP, overlayRenderP ); + overlayRendererField.set( viewerQ, overlayRenderQ ); + overlayRendererField.setAccessible( false ); + + } + catch ( final Exception e ) + { + e.printStackTrace(); + } + } + + viewerP.setNumDim( ndims ); + viewerQ.setNumDim( ndims ); + + overlayP.is2D( options.values.is2D() ); + overlayQ.is2D( options.values.is2D() ); + + bwTransform = new BigWarpTransform( landmarkModel ); + bwTransform.initializeInverseParameters(data); + + transformSelector = new TransformTypeSelectDialog( landmarkFrame, this ); + + final InputTriggerConfig keyProperties = BigDataViewer.getInputTriggerConfig( options ); + WarpNavigationActions.installActionBindings( getViewerFrameP().getKeybindings(), viewerFrameP, keyProperties, ( ndims == 2 ) ); + BigWarpActions.installActionBindings( getViewerFrameP().getKeybindings(), this, keyProperties ); + + WarpNavigationActions.installActionBindings( getViewerFrameQ().getKeybindings(), viewerFrameQ, keyProperties, ( ndims == 2 ) ); + BigWarpActions.installActionBindings( getViewerFrameQ().getKeybindings(), this, keyProperties ); + + BigWarpActions.installLandmarkPanelActionBindings( landmarkFrame.getKeybindings(), this, landmarkTable, keyProperties ); + + warpVisDialog.toleranceSpinner.setValue( bwTransform.getInverseTolerance() ); + + SwingUtilities.invokeLater( () -> { + landmarkFrame.setVisible( true ); + }); + } + public void initialize() { wrapMovingSources( ndims, data ); @@ -697,7 +794,7 @@ public void synchronizeSources() /** * Create two source groups - one for moving images, * and the other for target images, for both viewer frames. - * + * * Ensure sources are synchronized with {@link #synchronizeSources()} * before calling this method. */ @@ -743,7 +840,7 @@ public int numDimensions() /** * TODO Make a PR that updates this method in InitializeViewerState in bdv-core * @deprecated Use {@link InitializeViewerState} method instead. - * + * * @param cumulativeMinCutoff the min image intensity * @param cumulativeMaxCutoff the max image intensity * @param state the viewer state @@ -922,7 +1019,7 @@ protected void setUpViewerMenu( final BigWarpViewerFrame vframe ) final JMenuItem exportToImagePlus = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_IP ) ); exportToImagePlus.setText( "Export moving image" ); fileMenu.add( exportToImagePlus ); - + final JMenuItem exportWarpField = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_WARP ) ); exportWarpField.setText( "Export warp field" ); fileMenu.add( exportWarpField ); @@ -977,7 +1074,7 @@ protected void setupImageJExportOption() final JMenuItem exportToImagePlus = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_IP ) ); exportToImagePlus.setText( "Export moving image" ); fileMenu.add( exportToImagePlus ); - + final JMenuItem exportWarpField = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_WARP ) ); exportWarpField.setText( "Export warp field" ); fileMenu.add( exportWarpField ); @@ -1027,7 +1124,7 @@ public File saveMovingImageXml( String proposedFilePath ) System.out.println( "bigWarp transform as affine 3d: " + bigWarpTransform.toString() ); - movingSpimData.getViewRegistrations().getViewRegistration( 0, 0 ).preconcatenateTransform( + movingSpimData.getViewRegistrations().getViewRegistration( 0, 0 ).preconcatenateTransform( new ViewTransformAffine( "Big Warp: " + bwTransform.getTransformType(), bigWarpTransform ) ); File proposedFile; @@ -1138,15 +1235,15 @@ public void exportAsImagePlus( boolean virtual, String path ) final GenericDialogPlus gd = new GenericDialogPlus( "Apply Big Warp transform" ); gd.addMessage( "Field of view and resolution:" ); - gd.addChoice( "Resolution", + gd.addChoice( "Resolution", new String[]{ ApplyBigwarpPlugin.TARGET, ApplyBigwarpPlugin.MOVING, ApplyBigwarpPlugin.SPECIFIED }, ApplyBigwarpPlugin.TARGET ); - gd.addChoice( "Field of view", - new String[]{ ApplyBigwarpPlugin.TARGET, + gd.addChoice( "Field of view", + new String[]{ ApplyBigwarpPlugin.TARGET, ApplyBigwarpPlugin.MOVING_WARPED, ApplyBigwarpPlugin.UNION_TARGET_MOVING, - ApplyBigwarpPlugin.LANDMARK_POINTS, + ApplyBigwarpPlugin.LANDMARK_POINTS, ApplyBigwarpPlugin.LANDMARK_POINT_CUBE_PIXEL, ApplyBigwarpPlugin.LANDMARK_POINT_CUBE_PHYSICAL, ApplyBigwarpPlugin.SPECIFIED_PIXEL, @@ -1155,25 +1252,25 @@ public void exportAsImagePlus( boolean virtual, String path ) ApplyBigwarpPlugin.TARGET ); gd.addStringField( "point filter", "" ); - + gd.addMessage( "Resolution"); gd.addNumericField( "x", 1.0, 4 ); gd.addNumericField( "y", 1.0, 4 ); gd.addNumericField( "z", 1.0, 4 ); - + gd.addMessage( "Offset"); gd.addNumericField( "x", 0.0, 4 ); gd.addNumericField( "y", 0.0, 4 ); gd.addNumericField( "z", 0.0, 4 ); - + gd.addMessage( "Field of view"); gd.addNumericField( "x", -1, 0 ); gd.addNumericField( "y", -1, 0 ); gd.addNumericField( "z", -1, 0 ); - + gd.addMessage( "Other Output options"); gd.addChoice( "Interpolation", new String[]{ "Nearest Neighbor", "Linear" }, "Linear" ); - + gd.addMessage( "Virtual: fast to display,\n" + "low memory requirements,\nbut slow to navigate" ); gd.addCheckbox( "virtual?", false ); @@ -1196,21 +1293,21 @@ public void exportAsImagePlus( boolean virtual, String path ) if ( gd.wasCanceled() ) return; - + final String resolutionOption = gd.getNextChoice(); final String fieldOfViewOption = gd.getNextChoice(); final String fieldOfViewPointFilter = gd.getNextString(); - + final double[] resolutionSpec = new double[ 3 ]; resolutionSpec[ 0 ] = gd.getNextNumber(); resolutionSpec[ 1 ] = gd.getNextNumber(); resolutionSpec[ 2 ] = gd.getNextNumber(); - + final double[] offsetSpec = new double[ 3 ]; offsetSpec[ 0 ] = gd.getNextNumber(); offsetSpec[ 1 ] = gd.getNextNumber(); offsetSpec[ 2 ] = gd.getNextNumber(); - + final double[] fovSpec = new double[ 3 ]; fovSpec[ 0 ] = gd.getNextNumber(); fovSpec[ 1 ] = gd.getNextNumber(); @@ -1239,7 +1336,7 @@ public void exportAsImagePlus( boolean virtual, String path ) final double[] res = ApplyBigwarpPlugin.getResolution( this.data, resolutionOption, resolutionSpec ); - final List outputIntervalList = ApplyBigwarpPlugin.getPixelInterval( this.data, + final List outputIntervalList = ApplyBigwarpPlugin.getPixelInterval( this.data, this.landmarkModel, this.currentTransform, fieldOfViewOption, fieldOfViewPointFilter, bboxOptions, fovSpec, offsetSpec, res ); @@ -1252,7 +1349,7 @@ public void exportAsImagePlus( boolean virtual, String path ) // landmark centers (because multiple images can be exported this way ) if( matchedPtNames.size() > 0 ) { - BigwarpLandmarkSelectionPanel selection = new BigwarpLandmarkSelectionPanel<>( + BigwarpLandmarkSelectionPanel selection = new BigwarpLandmarkSelectionPanel<>( data, data.sources, fieldOfViewOption, outputIntervalList, matchedPtNames, interp, offsetSpec, res, isVirtual, nThreads, @@ -1272,21 +1369,21 @@ public void run() progressWriter.setProgress( 0.01 ); ApplyBigwarpPlugin.runN5Export( data, data.sources, fieldOfViewOption, outputIntervalList.get( 0 ), interp, - offsetSpec, res, unit, - progressWriter, writeOpts, + offsetSpec, res, unit, + progressWriter, writeOpts, Executors.newFixedThreadPool( nThreads ) ); progressWriter.setProgress( 1.00 ); } }.start(); } - else + else { // export final boolean show = ( writeOpts.pathOrN5Root == null || writeOpts.pathOrN5Root.isEmpty() ); ApplyBigwarpPlugin.runExport( data, data.sources, fieldOfViewOption, outputIntervalList, matchedPtNames, interp, - offsetSpec, res, isVirtual, nThreads, + offsetSpec, res, isVirtual, nThreads, progressWriter, show, false, writeOpts ); } } @@ -1479,7 +1576,7 @@ public void updateRowSelection( boolean isMoving, int lastRowEdited ) } public static void updateRowSelection( - LandmarkTableModel landmarkModel, JTable table, + LandmarkTableModel landmarkModel, JTable table, boolean isMoving, int lastRowEdited ) { logger.trace( "updateRowSelection " ); @@ -1495,7 +1592,7 @@ public static void updateRowSelection( /** * Returns the index of the selected row, if it is unpaired, -1 otherwise - * + * * @param isMoving isMoving * @return index of the selected row */ @@ -1540,14 +1637,14 @@ public boolean addPoint( final double[] ptarray, final boolean isMoving ) { final boolean isWarped = ( isMoving && landmarkModel.getTransform() != null && BigWarp.this.isMovingDisplayTransformed() ); - InvertibleRealTransform transform; + InvertibleRealTransform transform; if( options.values.is2D() && currentTransform != null ) transform = ((InvertibleWrapped2DTransformAs3D)currentTransform).getTransform(); else transform = currentTransform; // TODO check this (current transform part) - final boolean didAdd = BigWarp.this.landmarkModel.pointEdit( -1, ptarray, false, isMoving, isWarped, true, transform ); + final boolean didAdd = BigWarp.this.landmarkModel.pointEdit( -1, ptarray, false, isMoving, isWarped, true, transform ); if ( BigWarp.this.landmarkFrame.isVisible() ) { @@ -1564,7 +1661,7 @@ protected int selectedLandmark( final double[] pt, final boolean isMoving ) /** * Returns the index of the landmark closest to the input point, * if it is within a certain distance threshold. - * + * * Updates the global variable ptBack * * @param pt the point location @@ -1701,7 +1798,7 @@ protected void matchWindowTransforms( final BigWarpViewerPanel panelToChange, fi { panelToChange.showMessage( "Aligning" ); panelToMatch.showMessage( "Matching alignment" ); - + // get the transform from panelToMatch final AffineTransform3D viewXfm = new AffineTransform3D(); panelToMatch.state().getViewerTransform( viewXfm ); @@ -1887,7 +1984,7 @@ public void togglePointVisibility() /** * Toggles whether the moving image is displayed after warping (in the same * space as the fixed image), or in its native space. - * + * * @return true of the display mode changed */ public boolean toggleMovingImageDisplay() @@ -2550,7 +2647,7 @@ public static int detectNumDims( List< SourceAndConverter< T > > sources ) public static void main( final String[] args ) { new ImageJ(); - + // TODO main String fnP = ""; String fnQ = ""; @@ -2588,7 +2685,7 @@ public static void main( final String[] args ) ProgressWriterIJ progress = new ProgressWriterIJ(); BigWarp bw; - BigWarpData bwdata; + BigWarpData bwdata; if ( fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) { bwdata = BigWarpInit.createBigWarpDataFromXML( fnP, fnQ ); @@ -2646,7 +2743,7 @@ else if (!fnP.isEmpty() && !fnQ.isEmpty()) e.printStackTrace(); } } - + private void viewerXfmTest() { AffineTransform3D srcTransform0 = new AffineTransform3D(); @@ -2809,7 +2906,7 @@ public void mouseReleased( final MouseEvent e ) // shift when boolean isMovingLocal = isMoving; if ( e.isShiftDown() && e.isControlDown() ) - { + { isMovingLocal = !isMoving; } else if( e.isShiftDown()) @@ -3108,7 +3205,7 @@ public void setTransformTypeUpdateUI( final String type ) /** * Update the transformation selection dialog to reflect the given transform type selection. - * + * * @param type the transformation type */ public void updateTransformTypeDialog( final String type ) @@ -3120,7 +3217,7 @@ public void updateTransformTypeDialog( final String type ) /** * Update the transformation selection panel in the options dialog to reflect the given transform type selection. - * + * * @param type the transformation type */ public void updateTransformTypePanel( final String type ) @@ -3320,7 +3417,7 @@ public void requestResolve( final boolean isMoving, final int index, final doubl notify(); } } - + } /** @@ -3349,7 +3446,7 @@ public void autoSaveLandmarks() /** * Saves landmarks to either the last File the user * saved landmarks to, or a unique location in the user's bigwarp folder. - * + * */ public void quickSaveLandmarks() { @@ -3390,7 +3487,7 @@ public File getBigwarpSettingsFolder() /** * Returns the {@link BigWarpAutoSaver}. - * + * * @return */ public BigWarpAutoSaver getAutoSaver() diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 36a0ee6d..93c11e22 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -171,8 +171,15 @@ public BigwarpSettings read( final JsonReader in ) throws IOException default: throw new RuntimeException( "Unknown BigWarpSetting: " + nextName ); } + + } in.endObject(); + final boolean is2D = BigWarp.detectNumDims(bigWarp.getSources()) == 2; + if (is2D != bigWarp.options.values.is2D()) { + bigWarp.options.is2D( is2D ); + bigWarp.changeDimensionality( is2D ); + } return this; } diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index 60bd5127..969cd021 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -34,9 +34,6 @@ import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.io.File; import java.util.Enumeration; import javax.swing.AbstractButton; @@ -51,13 +48,11 @@ import javax.swing.JColorChooser; import javax.swing.JComboBox; import javax.swing.JDialog; -import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.JSpinner; -import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.WindowConstants; @@ -70,6 +65,7 @@ import bdv.viewer.BigWarpViewerSettings; import bigwarp.source.GridSource; import net.imglib2.realtransform.BoundingBoxEstimation; +import net.miginfocom.swing.MigLayout; public class WarpVisFrame extends JDialog { @@ -396,8 +392,15 @@ public void stateChanged( ChangeEvent e ) content.add( maskOptionsPanel, gbcContent ); gbcContent.gridy = 6; + final JPanel toggle2DPanel = new JPanel(new MigLayout("", "[grow][][grow]")); + final JCheckBox toggle2D = new JCheckBox("Is 2D"); + toggle2DPanel.add(toggle2D, "cell 1 0"); + toggle2D.addActionListener(e -> bw.changeDimensionality(toggle2D.isSelected()) ); + content.add(toggle2DPanel, gbcContent); + + gbcContent.gridy = 7; content.add( getAutoSaveOptionsPanel(), gbcContent ); - + setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE ); addListeners(); diff --git a/src/test/java/bigwarp/BigWarpTestUtils.java b/src/test/java/bigwarp/BigWarpTestUtils.java index 25bbc08e..9c8a67cc 100644 --- a/src/test/java/bigwarp/BigWarpTestUtils.java +++ b/src/test/java/bigwarp/BigWarpTestUtils.java @@ -36,6 +36,13 @@ public class BigWarpTestUtils { + /** + * Create a 3D image file which is deleted on exit. + * + * @param title of the temporary image file + * @param format of the temporary image file + * @return the path to the temporary image file + */ public static String createTemp3DImage( String title, String format ) { @@ -54,28 +61,34 @@ public static String createTemp3DImage( String title, String format ) return createTemp3DImage( tmpImgPath ); } - public static String createTemp3DImage( Path tmpImgPath ) + private static String create3DImage( final Path tmpImgPath ) throws IOException + { + ImagePlus img3d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 4, NewImage.FILL_RAMP ); + IJ.save( img3d, tmpImgPath.toFile().getCanonicalPath() ); + tmpImgPath.toFile().deleteOnExit(); + return tmpImgPath.toString(); + } + + /** + * Create a 3D image file at {@code imagePath} which is deleted on exit. + * + * @param imagePath of the temporary image file + * @return the path to the temporary image file + */ + public static String createTemp3DImage( Path imagePath ) { try { - return create3DImage( tmpImgPath ); + return create3DImage( imagePath ); } catch ( Exception e ) { //noinspection ResultOfMethodCallIgnored - tmpImgPath.toFile().delete(); + imagePath.toFile().delete(); throw new RuntimeException( e ); } } - private static String create3DImage( final Path tmpImgPath ) throws IOException - { - ImagePlus img3d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 4, NewImage.FILL_RAMP ); - IJ.save( img3d, tmpImgPath.toFile().getCanonicalPath() ); - tmpImgPath.toFile().deleteOnExit(); - return tmpImgPath.toString(); - } - private static String create2DImage( final Path tmpImgPath ) throws IOException { ImagePlus img2d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 1, NewImage.FILL_RAMP ); @@ -84,6 +97,13 @@ private static String create2DImage( final Path tmpImgPath ) throws IOException return tmpImgPath.toString(); } + /** + * Create a 2D image file which is deleted on exit. + * + * @param title of the temporary image file + * @param format of the temporary image file + * @return the path to the temporary image file + */ public static String createTemp2DImage( String title, String format ) { @@ -105,6 +125,12 @@ public static String createTemp2DImage( String title, String format ) } } + /** + * Create a 3D image stack which is deleted on exit. + * + * @param title of the temporary image stack + * @return the path to the temporary image stack + */ public static String createTemp3DImageStack( String title ) { @@ -210,8 +236,8 @@ static < T > BigWarp< T > createBigWarp(boolean... moving ) throws SpimDataExcep { return createBigWarp( null, moving ); } - - static < T > BigWarp< T > createBigWarp(String sourcePath, boolean... moving ) throws SpimDataException, URISyntaxException, IOException + + static < T > BigWarp< T > createBigWarp(String sourcePath, boolean... moving ) throws SpimDataException, URISyntaxException, IOException { final BigWarpData< T > data = BigWarpInit.initData(); if (sourcePath != null) { From 725e6de470716133acb3825b064a325c916b58b8 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 10 Jan 2023 10:28:10 -0500 Subject: [PATCH 194/282] feat: improvements to warp visualization sources * add jacobian determinant source to ui * cleaner implementation --- src/main/java/bigwarp/BigWarp.java | 213 +++++++++++++----------- src/main/java/bigwarp/BigWarpData.java | 12 ++ src/main/java/bigwarp/BigWarpInit.java | 7 + src/main/java/bigwarp/WarpVisFrame.java | 24 ++- 4 files changed, 148 insertions(+), 108 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 10df8e75..ec5f4535 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -279,11 +279,11 @@ public class BigWarp< T > private final RepeatingReleasedEventsFixer repeatedKeyEventsFixer; - protected SourceAndConverter< FloatType > gridSource; + protected GridSource gridSource; - protected SourceAndConverter< FloatType > warpMagSource; + protected WarpMagnitudeSource warpMagSource; - protected SourceAndConverter< FloatType > jacDetSource; + protected JacobianDeterminantSource jacDetSource; protected SourceAndConverter< DoubleType > transformMaskSource; @@ -1976,7 +1976,7 @@ protected void addMaskMouseListener() public void setGridType( final GridSource.GRID_TYPE method ) { - ( ( GridSource< ? > ) gridSource.getSpimSource() ).setMethod( method ); + gridSource.setMethod( method ); } @SuppressWarnings( "unchecked" ) @@ -1985,7 +1985,6 @@ public static < T > void wrapMovingSources( final int ndims, final BigWarpData< int i = 0; for ( final SourceInfo sourceInfo : data.sourceInfos.values() ) { -// if ( sourceInfo.isMoving() && !(sourceInfo.getSourceAndConverter().getSpimSource() instanceof WarpedSource)) if ( sourceInfo.isMoving() ) { SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); @@ -1997,6 +1996,21 @@ public static < T > void wrapMovingSources( final int ndims, final BigWarpData< } } + public static < T > void wrapMovingSources( final int ndims, final BigWarpData< T > data, int id ) + { + final SourceInfo sourceInfo = data.getSourceInfo( id ); + if( sourceInfo == null ) + return; + + if ( sourceInfo.isMoving() ) + { + SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm", ndims ); + final int sourceIdx = data.sources.indexOf( sourceInfo.getSourceAndConverter() ); + sourceInfo.setSourceAndConverter( newSac ); + data.sources.set( sourceIdx, newSac ); + } + } + @SuppressWarnings( "unchecked" ) public static < T > List< SourceAndConverter< T > > wrapSourcesAsTransformed( final LinkedHashMap< Integer, SourceInfo > sources, final int ndims, @@ -2023,42 +2037,41 @@ public static < T > List< SourceAndConverter< T > > wrapSourcesAsTransformed( fi } @SuppressWarnings( { "rawtypes", "unchecked" } ) - private static < T > SourceAndConverter< FloatType > addJacobianDeterminantSource( final BigWarpData< T > data, final String name ) + private static < T > JacobianDeterminantSource addJacobianDeterminantSource( final int ndims, final BigWarpData< T > data, final String name ) { - // TODO think about whether its worth it to pass a type parameter. - final JacobianDeterminantSource< FloatType > jdSource = new JacobianDeterminantSource<>( name, data, new FloatType() ); - final RealARGBColorConverter< FloatType > converter = RealARGBColorConverter.create( new FloatType(), 0, 512 ); - converter.setColor( new ARGBType( 0xffffffff ) ); - final SourceAndConverter< FloatType > soc = new SourceAndConverter<>( jdSource, converter, null ); - data.converterSetups.add( BigDataViewer.createConverterSetup( soc, JACDET_SOURCE_ID ) ); - data.sources.add( ( SourceAndConverter ) soc ); - return soc; + final JacobianDeterminantSource jdSource = new JacobianDeterminantSource<>( name, data, new FloatType() ); + final LinkedHashMap< Source, SourceInfo > infos = BigWarpInit.createSources( data, jdSource, JACDET_SOURCE_ID, false ); + final LinkedHashMap< Integer, SourceInfo > id2Info = new LinkedHashMap<>( 1 ); + id2Info.put( JACDET_SOURCE_ID, infos.get( jdSource ) ); + BigWarpInit.add( data, infos ); + + return jdSource; } @SuppressWarnings( { "rawtypes", "unchecked" } ) - private static < T > SourceAndConverter< FloatType > addWarpMagnitudeSource( final BigWarpData< T > data, final boolean is2D, final String name ) + private static < T > WarpMagnitudeSource addWarpMagnitudeSource( final BigWarpData< T > data, final boolean is2D, final String name ) { - // TODO think about whether its worth it to pass a type parameter. - final WarpMagnitudeSource< FloatType > magSource = new WarpMagnitudeSource<>( name, data, new FloatType() ); - final RealARGBColorConverter< FloatType > converter = RealARGBColorConverter.create( new FloatType(), 0, 512 ); - converter.setColor( new ARGBType( 0xffffffff ) ); - final SourceAndConverter< FloatType > soc = new SourceAndConverter<>( magSource, converter, null ); - data.converterSetups.add( BigDataViewer.createConverterSetup( soc, WARPMAG_SOURCE_ID ) ); - data.sources.add( ( SourceAndConverter ) soc ); - return soc; + final WarpMagnitudeSource magSource = new WarpMagnitudeSource<>( name, data, new FloatType() ); + final LinkedHashMap< Source, SourceInfo > infos = BigWarpInit.createSources( data, magSource, WARPMAG_SOURCE_ID, false ); + final LinkedHashMap< Integer, SourceInfo > id2Info = new LinkedHashMap<>( 1 ); + id2Info.put( WARPMAG_SOURCE_ID, infos.get( magSource ) ); + BigWarpInit.add( data, infos ); + + return magSource; } - @SuppressWarnings( { "unchecked", "rawtypes" } ) - private static < T > SourceAndConverter< FloatType > addGridSource( final BigWarpData< T > data, final String name ) + private static < T > GridSource addGridSource( final int ndims, final BigWarpData< T > data, final String name ) { // TODO think about whether its worth it to pass a type parameter. - final GridSource< FloatType > gridSource = new GridSource<>( name, data, new FloatType(), null ); - final RealARGBColorConverter< FloatType > converter = RealARGBColorConverter.create( new FloatType(), 0, 512 ); - converter.setColor( new ARGBType( 0xffffffff ) ); - final SourceAndConverter< FloatType > soc = new SourceAndConverter<>( gridSource, converter, null ); - data.converterSetups.add( BigDataViewer.createConverterSetup( soc, GRID_SOURCE_ID ) ); - data.sources.add( ( SourceAndConverter ) soc ); - return soc; + final GridSource gridSource = new GridSource<>( name, data, new FloatType(), null ); + gridSource.setMethod( GridSource.GRID_TYPE.LINE ); + final LinkedHashMap< Source, SourceInfo > infos = BigWarpInit.createSources( data, gridSource, GRID_SOURCE_ID, true ); + final LinkedHashMap< Integer, SourceInfo > id2Info = new LinkedHashMap<>( 1 ); + id2Info.put( GRID_SOURCE_ID, infos.get( gridSource ) ); + BigWarpInit.add( data, infos ); + wrapMovingSources( ndims, data, GRID_SOURCE_ID ); + + return gridSource; } /** @@ -2124,7 +2137,7 @@ public SourceAndConverter< DoubleType > addTransformMaskSource() getViewerFrameQ().getViewerPanel().setMaskOverlay( overlay ); transformMask.getRandomAccessible().setOverlays( overlayList ); -// synchronizeSources(); + synchronizeSources(); transformMaskSource = soc; return soc; } @@ -2153,21 +2166,21 @@ public void setupKeyListener() public void setWarpVisGridType( final GridSource.GRID_TYPE type ) { - ( ( GridSource< ? > ) gridSource.getSpimSource() ).setMethod( type ); + gridSource.setMethod( type ); viewerP.requestRepaint(); viewerQ.requestRepaint(); } public void setWarpGridWidth( final double width ) { - ( ( GridSource< ? > ) gridSource.getSpimSource() ).setGridWidth( width ); + gridSource.setGridWidth( width ); viewerP.requestRepaint(); viewerQ.requestRepaint(); } public void setWarpGridSpacing( final double spacing ) { - ( ( GridSource< ? > ) gridSource.getSpimSource() ).setGridSpacing( spacing ); + gridSource.setGridSpacing( spacing ); viewerP.requestRepaint(); viewerQ.requestRepaint(); } @@ -2224,7 +2237,7 @@ protected void fitBaselineWarpMagModel() // the transform to compare is the inverse (because we use it for rendering) // so need to give the inverse transform for baseline as well - ( ( WarpMagnitudeSource< ? > ) warpMagSource.getSpimSource() ).setBaseline( baselineTransform.inverse() ); + warpMagSource.setBaseline( baselineTransform.inverse() ); } catch ( final IllDefinedDataPointsException | NotEnoughDataPointsException e ) { @@ -2292,19 +2305,9 @@ else if ( both ) { return; } - } -// -// int offImgIndex = 0; -// int onImgIndex = 1; -// -// if ( viewerFrame == viewerFrameP ) -// { -// offImgIndex = 1; -// onImgIndex = 0; -// } - if ( landmarkModel.getTransform() == null ) + if ( currentTransform == null ) { message.showMessage( "No warp - estimate warp first." ); return; @@ -2315,19 +2318,40 @@ else if ( both ) { case JACDET: { - // turn warp mag on - state.setSourceActive( warpMagSource, false ); - state.setSourceActive( jacDetSource, true ); - state.setSourceActive( gridSource, false ); + // turn jacobian determinant + if ( jacDetSource == null ) + { + jacDetSource = addJacobianDeterminantSource( ndims, data, "Jacobian determinant" ); + synchronizeSources(); + } + state.setSourceActive( data.getSourceInfo( JACDET_SOURCE_ID ).getSourceAndConverter(), true ); + + if ( warpMagSource != null ) + state.setSourceActive( data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(), false ); + if ( gridSource != null ) + state.setSourceActive( data.getSourceInfo( GRID_SOURCE_ID ).getSourceAndConverter(), false ); + + state.setDisplayMode( DisplayMode.FUSED ); + viewerFrame.getViewerPanel().showMessage( "Displaying Jacobian Determinant" ); + break; } case WARPMAG: { // turn warp mag on - state.setSourceActive( warpMagSource, true ); - state.setSourceActive( jacDetSource, false ); - state.setSourceActive( gridSource, false ); -// vg.setSourceActive( offImgIndex, false ); + if ( warpMagSource == null ) + { + + warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "Warp magnitude" ); + synchronizeSources(); + } + state.setSourceActive( data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(), true ); + + if ( jacDetSource != null ) + state.setSourceActive( data.getSourceInfo( JACDET_SOURCE_ID ).getSourceAndConverter(), false ); + + if ( gridSource != null ) + state.setSourceActive( data.getSourceInfo( GRID_SOURCE_ID ).getSourceAndConverter(), false ); // estimate the max warp // final WarpMagnitudeSource< ? > wmSrc = ( ( WarpMagnitudeSource< ? > ) sources.get( warpMagSourceIndex ).getSpimSource() ); @@ -2337,29 +2361,38 @@ else if ( both ) // ( ( RealARGBColorConverter< FloatType > ) ( sources.get( warpMagSourceIndex ).getConverter() ) ).setMax( maxval ); state.setDisplayMode( DisplayMode.FUSED ); - message.showMessage( "Displaying Warp Magnitude" ); + viewerFrame.getViewerPanel().showMessage( "Displaying Warp Magnitude" ); break; } case GRID: { // turn grid vis on + if ( gridSource == null ) + { + gridSource = addGridSource( ndims, data, "Transform grid" ); + synchronizeSources(); + data.getConverterSetup( GRID_SOURCE_ID ).setDisplayRange( 0, 512 ); + } + state.setSourceActive( data.getSourceInfo( GRID_SOURCE_ID ).getSourceAndConverter(), true ); + + if ( warpMagSource != null ) + state.setSourceActive( data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(), false ); - state.setSourceActive( warpMagSource, false ); - state.setSourceActive( jacDetSource, false ); - state.setSourceActive( gridSource, true ); -// vg.setSourceActive( offImgIndex, false ); + if ( jacDetSource != null ) + state.setSourceActive( data.getSourceInfo( JACDET_SOURCE_ID ).getSourceAndConverter(), false ); state.setDisplayMode( DisplayMode.FUSED ); - message.showMessage( "Displaying Warp Grid" ); + viewerFrame.getViewerPanel().showMessage( "Displaying Warp Grid" ); break; } default: { - state.setSourceActive( warpMagSource, false ); - state.setSourceActive( gridSource, false ); -// vg.setSourceActive( offImgIndex, true ); + if ( warpMagSource != null ) + state.setSourceActive( data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(), false ); + + if ( gridSource != null ) + state.setSourceActive( data.getSourceInfo( GRID_SOURCE_ID ).getSourceAndConverter(), false ); -// vg.setFusedEnabled( false ); message.showMessage( "Turning off warp vis" ); break; } @@ -2368,8 +2401,6 @@ else if ( both ) public void toggleWarpVisMode( BigWarpViewerFrame viewerFrame ) { -// int offImgIndex = 0; -// int onImgIndex = 1; if ( viewerFrame == null ) { if ( viewerFrameP.isActive() ) @@ -2384,12 +2415,6 @@ else if ( viewerFrameQ.isActive() ) return; } -// if ( viewerFrame == viewerFrameP ) -// { -// offImgIndex = 1; -// onImgIndex = 0; -// } - if ( landmarkModel.getTransform() == null ) { message.showMessage( "No warp - estimate warp first." ); @@ -2398,24 +2423,19 @@ else if ( viewerFrameQ.isActive() ) final ViewerState state = viewerFrame.getViewerPanel().state(); - // TODO consider remembering whether fused was on before displaying - // warpmag + // TODO consider remembering whether fused was on before displaying warpmag // so that its still on or off after we turn it off - if ( state.isSourceActive( warpMagSource ) ) // warp mag is visible, - // turn it off + final SourceAndConverter< ? > wmSac = data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(); + if ( state.isSourceActive( wmSac ) ) // warp mag is visible, turn it off { - state.setSourceActive( warpMagSource, false ); - -// vg.setSourceActive( offImgIndex, true ); + state.setSourceActive( wmSac, false ); state.setDisplayMode( state.getDisplayMode().withFused( false ) ); message.showMessage( "Removing Warp Magnitude" ); } else // warp mag is invisible, turn it on { - state.setSourceActive( warpMagSource, true ); - -// vg.setSourceActive( offImgIndex, false ); + state.setSourceActive( wmSac, true ); // estimate the max warp // final WarpMagnitudeSource< ? > wmSrc = ( ( WarpMagnitudeSource< ? > ) sources.get( warpMagSourceIndex ).getSpimSource() ); @@ -2480,34 +2500,26 @@ private void setTransformationAll( final InvertibleRealTransform transform ) if( warpMagSource != null ) { - final WarpMagnitudeSource< ? > wmSrc = ( ( WarpMagnitudeSource< ? > ) warpMagSource.getSpimSource() ); - wmSrc.setWarp( transform ); + warpMagSource.setWarp( transform ); fitBaselineWarpMagModel(); } if( jacDetSource != null ) { - final JacobianDeterminantSource< ? > jdSrc = ( ( JacobianDeterminantSource< ? > ) jacDetSource.getSpimSource() ); if( transform instanceof ThinplateSplineTransform ) { - jdSrc.setTransform( (ThinplateSplineTransform)transform ); + jacDetSource.setTransform( (ThinplateSplineTransform)transform ); } else if ( transform instanceof WrappedIterativeInvertibleRealTransform ) { RealTransform xfm = ((WrappedIterativeInvertibleRealTransform)transform).getTransform(); if( xfm instanceof ThinplateSplineTransform ) - jdSrc.setTransform( (ThinplateSplineTransform) xfm ); + jacDetSource.setTransform( (ThinplateSplineTransform) xfm ); else - jdSrc.setTransform( new RealTransformFiniteDerivatives( xfm )); + jacDetSource.setTransform( new RealTransformFiniteDerivatives( xfm )); } else - jdSrc.setTransform( null ); - } - - if( gridSource != null ) - { - final GridSource< ? > gSrc = ( ( GridSource< ? > ) gridSource.getSpimSource() ); - gSrc.setWarp( transform ); + jacDetSource.setTransform( null ); } } @@ -3344,7 +3356,8 @@ public void run() { // update the transform and warped point // bw.setTransformationMovingSourceOnly( invXfm ); - bw.data.updateEditableTransformation( invXfm ); +// bw.data.updateEditableTransformation( invXfm ); + bw.setTransformationAll( invXfm ); } // update fixed point - but don't allow undo/redo @@ -3719,14 +3732,14 @@ private void addInternalSource(int id) { switch ( id ) { case GRID_SOURCE_ID: - gridSource = addGridSource( data, "GridSource" ); + gridSource = addGridSource( ndims, data, "GridSource" ); setGridType( GridSource.GRID_TYPE.LINE ); break; case WARPMAG_SOURCE_ID: warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "Warp magnitude" ); break; case JACDET_SOURCE_ID: - jacDetSource = addJacobianDeterminantSource( data, "Jacobian determinant" ); + jacDetSource = addJacobianDeterminantSource( ndims, data, "Jacobian determinant" ); break; case TRANSFORM_MASK_SOURCE_ID: updateTransformMask(); diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index a5016852..1bf8f6d7 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -190,6 +190,18 @@ public List getTargetConverterSetups() return out; } + public ConverterSetup getConverterSetup( final int id ) + { + final SourceInfo[] infos = sourceInfos.values().toArray(new SourceInfo[]{} ); + for ( int i = 0; i < infos.length; i++ ) + { + final SourceInfo info = infos[ i ]; + if (info.getId() == id ) + return converterSetups.get( i ); + } + return null; + } + public SourceInfo getSourceInfo( int id ) { return sourceInfos.get( id ); diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 926fe343..d1d0fb05 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -570,6 +570,13 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW return sourceInfoMap; } + public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigWarpData bwdata, Source< T > src, int baseId, final boolean isMoving ) + { + final LinkedHashMap< Source< T >, SourceInfo > sourceInfoMap = new LinkedHashMap<>(); + sourceInfoMap.put( src, new SourceInfo( baseId, isMoving, src.getName() ) ); + return sourceInfoMap; + } + private static String schemeSpecificPartWithoutQuery( URI uri ) { return uri.getSchemeSpecificPart().replaceAll( "\\?" + uri.getQuery(), "" ).replaceAll( "//", "" ); diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index 526dfabc..81af25ce 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -82,6 +82,7 @@ public class WarpVisFrame extends JDialog protected JRadioButton setWarpVisOffButton; protected JRadioButton setWarpGridButton; protected JRadioButton setWarpMagButton; + protected JRadioButton setJacobianDetButton; protected JLabel noOptionsLabel; @@ -194,16 +195,19 @@ public WarpVisFrame( final Frame owner, final BigWarp bw ) setWarpVisOffButton = new JRadioButton( "Off" ); setWarpGridButton = new JRadioButton( "Grid" ); setWarpMagButton = new JRadioButton( "Magnitude" ); + setJacobianDetButton = new JRadioButton( "Jacobian Determinant" ); visTypeGroup.add( setWarpVisOffButton ); visTypeGroup.add( setWarpGridButton ); visTypeGroup.add( setWarpMagButton ); - + visTypeGroup.add( setJacobianDetButton ); + setWarpVisOffButton.setSelected( true ); + visTypePanel.add( setWarpVisOffButton ); visTypePanel.add( setWarpGridButton ); visTypePanel.add( setWarpMagButton ); - - + visTypePanel.add( setJacobianDetButton ); + // buttons for warp magnitude options warpMagAffineButton = new JRadioButton( "Affine baseline" ); warpMagSimilarityButton = new JRadioButton("Similarity baseline"); @@ -221,6 +225,7 @@ public WarpVisFrame( final Frame owner, final BigWarp bw ) warpGridButtons = new ButtonGroup(); warpGridButtons.add( warpGridLineButton ); warpGridButtons.add( warpGridModButton ); + warpGridLineButton.setSelected( true ); gridSpacingSlider = new JSlider( JSlider.HORIZONTAL, minGridSpacing, maxGridSpacing, defaultGridSpacing ); gridWidthSlider = new JSlider( JSlider.HORIZONTAL, minGridWidth, maxGridWidth, defaultGridWidth ); @@ -445,20 +450,23 @@ public void stateChanged( ChangeEvent e ) } }); - setWarpVisOffButton.setAction( + setWarpVisOffButton.setAction( actionMap.get( String.format( BigWarpActions.SET_WARPTYPE_VIS, BigWarp.WarpVisType.NONE ))); - setWarpGridButton.setAction( + setWarpGridButton.setAction( actionMap.get( String.format( BigWarpActions.SET_WARPTYPE_VIS, BigWarp.WarpVisType.GRID ))); - setWarpMagButton.setAction( + setWarpMagButton.setAction( actionMap.get( String.format( BigWarpActions.SET_WARPTYPE_VIS, BigWarp.WarpVisType.WARPMAG ))); + setJacobianDetButton.setAction( + actionMap.get( String.format( BigWarpActions.SET_WARPTYPE_VIS, BigWarp.WarpVisType.JACDET ))); setWarpVisOffButton.setText("Off"); setWarpGridButton.setText("Grid"); setWarpMagButton.setText("Magnitude"); + setJacobianDetButton.setText("Jacobian Determinant"); - warpMagAffineButton.setAction( + warpMagAffineButton.setAction( actionMap.get( String.format( BigWarpActions.WARPMAG_BASE, bw.baseXfmList[ 0 ].getClass().getName() ))); - warpMagSimilarityButton .setAction( + warpMagSimilarityButton .setAction( actionMap.get( String.format( BigWarpActions.WARPMAG_BASE, bw.baseXfmList[ 1 ].getClass().getName() ) )); warpMagRigidButton.setAction( actionMap.get( String.format( BigWarpActions.WARPMAG_BASE, bw.baseXfmList[ 2 ].getClass().getName() ) )); From 0895ed7f4866097f9d5bedbc5b25cfb38d4ffca2 Mon Sep 17 00:00:00 2001 From: Caleb Hulbert Date: Tue, 10 Jan 2023 16:03:28 -0500 Subject: [PATCH 195/282] fix: retain correct active sources after synchronize --- src/main/java/bigwarp/BigWarp.java | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 019b894d..7eac5ded 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -767,20 +767,29 @@ protected void setupLandmarkFrame() public void synchronizeSources() { - viewerP.state().clearSources(); - viewerQ.state().clearSources(); + final SynchronizedViewerState pState = viewerP.state(); + final SynchronizedViewerState qState = viewerQ.state(); + + final Set> activeSourcesP = new HashSet<>(pState.getActiveSources()); + final Set> activeSourcesQ = new HashSet<>(qState.getActiveSources()); + + pState.clearSources(); + qState.clearSources(); - final ArrayList converterSetupsToRemove = new ArrayList<>(); - setupAssignments.getConverterSetups().forEach( converterSetupsToRemove::add ); + final ArrayList converterSetupsToRemove = new ArrayList<>(setupAssignments.getConverterSetups()); converterSetupsToRemove.forEach( setupAssignments::removeSetup ); - final SynchronizedViewerState pState = viewerP.state(); - final SynchronizedViewerState qState = viewerQ.state(); for ( int i = 0; i < data.sources.size(); i++ ) { final SourceAndConverter< T > sac = data.sources.get( i ); pState.addSource( sac ); + if (activeSourcesP.contains(sac)) { + pState.setSourceActive(sac, true); + } qState.addSource( sac ); + if (activeSourcesQ.contains(sac)) { + qState.setSourceActive(sac, true); + } // update the viewer converter setups too final ConverterSetup setup = data.converterSetups.get( i ); From ee87ef1ec72a281b0f34e2c9223d7b3c9a328731 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 11 Jan 2023 17:59:31 -0500 Subject: [PATCH 196/282] feat: new ltm convenience add method --- src/main/java/bigwarp/landmarks/LandmarkTableModel.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java index 759ae70b..5628c1a1 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java +++ b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java @@ -729,12 +729,18 @@ public void clearPt( int row, boolean isMoving ) { pointEdit( row, PENDING_PT, false, isMoving, null, true ); } - + public boolean add( double[] pt, boolean isMoving ) { return pointEdit( -1, pt, true, isMoving, false, true, null ); } + public boolean add( final double[] mvg, final double[] tgt ) { + add( mvg, true); + setPoint( numRows - 1, false, tgt, null ); + return true; + } + public boolean add( double[] pt, boolean isMoving, final RealTransform xfm ) { return pointEdit( -1, pt, true, isMoving, false, true, xfm ); From 1dcf3e26a6a2e00d78dfd19ef1521d9501005af4 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 11 Jan 2023 18:01:26 -0500 Subject: [PATCH 197/282] feat: methods for decomposing 2d affine transforms --- .../org/janelia/utility/geom/GeomUtils.java | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/src/main/java/org/janelia/utility/geom/GeomUtils.java b/src/main/java/org/janelia/utility/geom/GeomUtils.java index e631045a..affef38d 100644 --- a/src/main/java/org/janelia/utility/geom/GeomUtils.java +++ b/src/main/java/org/janelia/utility/geom/GeomUtils.java @@ -4,6 +4,8 @@ import net.imglib2.RealLocalizable; import net.imglib2.RealPoint; +import net.imglib2.realtransform.AffineGet; +import net.imglib2.realtransform.AffineTransform2D; import net.imglib2.util.Pair; import net.imglib2.util.ValuePair; @@ -77,4 +79,123 @@ final public static double squaredDistance( final double[] position1, final doub return dist; } + public static AffineTransform2D fromScalesAngle( double... p ) + { + return fromScalesAngle( p[0], p[1], p[2] ); + } + + public static AffineTransform2D fromScalesAngle( double sx, double sy, double tht ) + { + AffineTransform2D t = new AffineTransform2D(); + double cosTht = Math.cos( tht ); + double sinTht = Math.sin( tht ); + t.set( sx * cosTht, -sx * sinTht, 0.0, + sy * sinTht, sy * cosTht, 0.0 ); + + return t; + } + + /** + * Returns an array containing [sx, sy, tht], where + * sx : the x scale + * sy : the y scale + * tht : the angle + * + * @param t the transformations + * @return + */ + public static double[] scalesAngle( final AffineTransform2D t ) + { + final double a = t.get( 0, 0 ); final double b = t.get( 0, 1 ); + final double c = t.get( 1, 0 ); final double d = t.get( 1, 1 ); + + final double sa = a >= 0 ? 1 : -1; + final double sd = d >= 0 ? 1 : -1; + + final double mab = Math.sqrt( a * a + b * b ); + final double mcd = Math.sqrt( c * c + d * d ); + + final double sx = sa * mab; + final double sy = sd * mcd; + final double tht = Math.atan2( -b, a ); + return new double[] { sx, sy, tht }; + +// final double tht1 = Math.atan2( -b, a ); +// final double tht2 = Math.atan2( c, d ); +// System.out.println( "tht1 : " + tht1 ); +// System.out.println( "tht2 : " + tht2 ); +// return new double[] { sx, sy, tht1, tht2 }; + } + + /** + * Returns an array containing [sx, sy, tht], where + * sx : the x scale + * sy : the y scale + * tht : the angle + * + * @param t the transformations + * @return + */ + public static double[] scalesAngle( final AffineTransform2D t, final double[] center ) + { + final double a = t.get( 0, 0 ); final double b = t.get( 0, 1 ); + final double c = t.get( 1, 0 ); final double d = t.get( 1, 1 ); + + // don't allow flips +// final double sa = a >= 0 ? 1 : -1; +// final double sd = d >= 0 ? 1 : -1; + final double sa = 1.0; + final double sd = 1.0; + + final double mab = Math.sqrt( a * a + b * b ); + final double mcd = Math.sqrt( c * c + d * d ); + + final double sx = sa * mab; + final double sy = sd * mcd; + final double tht = Math.atan2( -b, a ); + return new double[] { sx, sy, tht }; + +// final double tht1 = Math.atan2( -b, a ); +// final double tht2 = Math.atan2( c, d ); +// System.out.println( "tht1 : " + tht1 ); +// System.out.println( "tht2 : " + tht2 ); +// return new double[] { sx, sy, tht1, tht2 }; + } + + public static double[] evals2d( AffineGet a ) + { + final double m = trace2d( a ) / 2.0; + final double p = det2d( a ); + final double d = Math.sqrt( m * m - p ); + return new double[] { m + d, m - d }; + } + + public static double det2d( AffineGet a ) { + return a.get( 0, 0 ) * a.get( 1, 1 ) - + a.get( 1, 0 ) * a.get( 0, 1 ); + } + + public static double trace2d( AffineGet a ) { + return a.get( 0, 0 ) + a.get( 1, 1 ); + } + + public static AffineTransform2D centeredRotation( final double tht, final double[] c ) + { + final AffineTransform2D t = new AffineTransform2D(); + t.translate( -c[ 0 ], -c[ 1 ] ); + t.rotate( tht ); + t.translate( c ); + return t; + } + + public static AffineTransform2D centeredSimilarity( final double tht, final double scale, final double[] c ) + { + final AffineTransform2D t = new AffineTransform2D(); + t.translate( -c[ 0 ], -c[ 1 ] ); + t.rotate( tht ); + t.scale( scale ); + t.translate( c ); + return t; + } + } From 183e9b50aa86b07a918375add2cea4f25f140283 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 11 Jan 2023 18:03:57 -0500 Subject: [PATCH 198/282] feat: correct masked transform behavior for 2d * and fixes for 3D behavior --- .../gui/MaskedSourceEditorMouseListener.java | 23 ++- src/main/java/bigwarp/BigWarp.java | 8 + src/main/java/bigwarp/BigWarpActions.java | 3 +- .../bigwarp/transforms/BigWarpTransform.java | 21 +- .../MaskedSimRotTransformSolver.java | 77 ++++++-- .../transforms/ModelTransformSolver.java | 5 + .../realtransform/AffineInterpolator.java | 7 + .../MaskedSimilarityTransform.java | 30 +-- .../MaskedSimilarityTransform2D.java | 96 ++++++++++ .../RotationTransformInterpolator.java | 2 +- .../RotationTransformInterpolator2D.java | 181 ++++++++++++++++++ .../SimilarityTransformInterpolator2D.java | 105 ++++++++++ 12 files changed, 503 insertions(+), 55 deletions(-) create mode 100644 src/main/java/net/imglib2/realtransform/AffineInterpolator.java create mode 100644 src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform2D.java create mode 100644 src/main/java/net/imglib2/realtransform/RotationTransformInterpolator2D.java create mode 100644 src/main/java/net/imglib2/realtransform/SimilarityTransformInterpolator2D.java diff --git a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java index 4972d677..dba48386 100644 --- a/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java +++ b/src/main/java/bdv/gui/MaskedSourceEditorMouseListener.java @@ -13,6 +13,8 @@ import bdv.viewer.overlay.BigWarpMaskSphereOverlay; import bigwarp.BigWarp; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.transforms.AbstractTransformSolver; +import bigwarp.transforms.MaskedSimRotTransformSolver; import net.imglib2.RealPoint; import net.imglib2.realtransform.AffineTransform3D; @@ -47,9 +49,9 @@ public MaskedSourceEditorMouseListener( int nd, BigWarp bw, BigWarpViewerPane overlays.add( bw.getViewerFrameP().getViewerPanel().getMaskOverlay() ); overlays.add( bw.getViewerFrameQ().getViewerPanel().getMaskOverlay() ); - p = new RealPoint( nd ); - c = new RealPoint( nd ); - pressPt = new RealPoint( nd ); + p = new RealPoint( 3 ); + c = new RealPoint( 3 ); + pressPt = new RealPoint( 3 ); active = false; } @@ -109,7 +111,8 @@ public void mouseDragged( MouseEvent e ) // store starting center at start of drag if( !dragged ) { - c.setPosition( mask.getCenter() ); +// c.setPosition( mask.getCenter() ); + mask.getCenter().localize( c ); viewer.getGlobalMouseCoordinates( pressPt ); dragged = true; } @@ -119,7 +122,8 @@ public void mouseDragged( MouseEvent e ) if( e.isControlDown() ) { - final double d = PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() ); + mask.getCenter().localize( c ); + final double d = PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, c ); synchronized ( mask ) { mask.setSquaredRadius( d ); @@ -127,7 +131,8 @@ public void mouseDragged( MouseEvent e ) } else if( e.isShiftDown() ) { - final double d = Math.sqrt( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, mask.getCenter() )); + mask.getCenter().localize( c ); + final double d = Math.sqrt( PlateauSphericalMaskRealRandomAccessible.squaredDistance( p, c )); synchronized ( mask ) { mask.setSigma( d - Math.sqrt( mask.getSquaredRadius()) ); @@ -145,6 +150,12 @@ else if( e.isShiftDown() ) { mask.setCenter(p); } + + AbstractTransformSolver< ? > solver = bw.getBwTransform().getSolver(); + if( solver instanceof MaskedSimRotTransformSolver ) + { + ((MaskedSimRotTransformSolver)solver).setCenter( p ); + } } bw.getViewerFrameP().getViewerPanel().requestRepaint(); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index ec5f4535..59c18afd 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -140,7 +140,9 @@ import bigwarp.source.PlateauSphericalMaskSource; import bigwarp.source.SourceInfo; import bigwarp.source.WarpMagnitudeSource; +import bigwarp.transforms.AbstractTransformSolver; import bigwarp.transforms.BigWarpTransform; +import bigwarp.transforms.MaskedSimRotTransformSolver; import bigwarp.transforms.WrappedCoordinateTransform; import bigwarp.transforms.io.TransformWriterJson; import bigwarp.util.BigWarpUtils; @@ -2275,6 +2277,12 @@ public void autoEstimateMask() final Sphere sph = BoundingSphereRitter.boundingSphere(landmarkModel.getFixedPointsCopy()); transformMask.getRandomAccessible().setCenter(sph.getCenter()); transformMask.getRandomAccessible().setRadius(sph.getRadius()); + + AbstractTransformSolver< ? > solver = getBwTransform().getSolver(); + if( solver instanceof MaskedSimRotTransformSolver ) + { + ((MaskedSimRotTransformSolver)solver).setCenter( sph.getCenter() ); + } } } diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index d42ca9b6..cc5f5c9e 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -1219,7 +1219,8 @@ public MaskSizeEdit( final BigWarp< ? > bw ) @Override public void actionPerformed(ActionEvent e) { - bw.maskSourceMouseListenerQ.toggleActive(); + if( bw.maskSourceMouseListenerQ != null ) + bw.maskSourceMouseListenerQ.toggleActive(); } } diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index a936943f..f3566a47 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -124,6 +124,11 @@ public boolean isMasked() return maskInterpolationType.equals( MASK_INTERP ) || maskInterpolationType.equals( ROT_MASK_INTERP ) || maskInterpolationType.equals( SIM_MASK_INTERP ); } + public AbstractTransformSolver< ? > getSolver() + { + return solver; + } + public void updateSolver() { if ( transformType.equals( TPS ) ) @@ -144,10 +149,10 @@ else if ( maskInterpolationType.equals( ROT_MASK_INTERP ) || maskInterpolationTy final double[] center = new double[ 3 ]; if ( lambda instanceof PlateauSphericalMaskRealRandomAccessible ) { - ((PlateauSphericalMaskRealRandomAccessible) lambda).getCenter() - .localize( center ); + ( ( PlateauSphericalMaskRealRandomAccessible ) lambda ).getCenter().localize( center ); } - solver = new MaskedSimRotTransformSolver( solver, lambda, center, Interpolators.valueOf( maskInterpolationType ) ); + + solver = new MaskedSimRotTransformSolver( tableModel.getNumdims(), solver, lambda, center, Interpolators.valueOf( maskInterpolationType ) ); } } @@ -557,9 +562,9 @@ public static AffineTransform2D affine2d( AbstractAffineModel2D model2d, AffineT affine[ 1 ] = mtx[ 0 ][ 1 ]; affine[ 2 ] = mtx[ 0 ][ 2 ]; - affine[ 4 ] = mtx[ 1 ][ 0 ]; - affine[ 5 ] = mtx[ 1 ][ 1 ]; - affine[ 6 ] = mtx[ 1 ][ 2 ]; + affine[ 3 ] = mtx[ 1 ][ 0 ]; + affine[ 4 ] = mtx[ 1 ][ 1 ]; + affine[ 5 ] = mtx[ 1 ][ 2 ]; out.set( affine ); return out; @@ -642,7 +647,7 @@ public AffineGet toImglib2( Model< ? > model ) return toAffine3D( ( AbstractAffineModel3D ) model ); } - public AffineGet toAffine2D( AbstractAffineModel2D model ) + public static AffineGet toAffine2D( AbstractAffineModel2D model ) { if( model instanceof TranslationModel2D ) { @@ -658,7 +663,7 @@ public AffineGet toAffine2D( AbstractAffineModel2D model ) } } - public AffineGet toAffine3D( AbstractAffineModel3D model ) + public static AffineTransform3D toAffine3D( AbstractAffineModel3D model ) { return affine3d( model, new AffineTransform3D() ); } diff --git a/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java b/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java index b0ff1d85..1b5e87f7 100644 --- a/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java +++ b/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java @@ -21,16 +21,23 @@ */ package bigwarp.transforms; +import java.util.Arrays; + import bdv.viewer.animate.SimilarityModel3D; import bigwarp.landmarks.LandmarkTableModel; +import mpicbg.models.AbstractAffineModel2D; import mpicbg.models.AbstractAffineModel3D; +import mpicbg.models.RigidModel2D; import mpicbg.models.RigidModel3D; +import mpicbg.models.SimilarityModel2D; +import net.imglib2.RealLocalizable; import net.imglib2.RealRandomAccessible; -import net.imglib2.realtransform.SpatiallyInterpolatedRealTransform; +import net.imglib2.realtransform.AffineTransform2D; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.MaskedSimilarityTransform; import net.imglib2.realtransform.MaskedSimilarityTransform.Interpolators; +import net.imglib2.realtransform.MaskedSimilarityTransform2D; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; @@ -43,38 +50,82 @@ public class MaskedSimRotTransformSolver> extends Abstract private final RealRandomAccessible lambda; private final double[] center; private final Interpolators interp; + private final int ndims; public MaskedSimRotTransformSolver( AbstractTransformSolver solver, RealRandomAccessible lambda, double[] center, Interpolators interp ) { + this( 3, solver, lambda, center, interp ); + } + + public MaskedSimRotTransformSolver( int nd, AbstractTransformSolver solver, RealRandomAccessible lambda, double[] center, Interpolators interp ) + { + this.ndims = nd; this.lambda = lambda; this.center = center; this.interp = interp; baseSolver = solver; if( interp == Interpolators.SIMILARITY ) - interpSolver = new ModelTransformSolver( new SimilarityModel3D() ); + if( nd == 2 ) + interpSolver = new ModelTransformSolver( new SimilarityModel2D() ); + else + interpSolver = new ModelTransformSolver( new SimilarityModel3D() ); else - interpSolver = new ModelTransformSolver( new RigidModel3D() ); + if( nd == 2 ) + interpSolver = new ModelTransformSolver( new RigidModel2D() ); + else + interpSolver = new ModelTransformSolver( new RigidModel3D() ); + + System.out.println( this ); + } + + @Override + public String toString() + { + return String.format( "MaskedSolver. center %s; interp: %s ", Arrays.toString( center ), this.interp.toString() ); + } + + public void setCenter( double[] c ) + { + // assume center is always longer than c + System.arraycopy( c, 0, center, 0, c.length ); + } + + public void setCenter( RealLocalizable c ) + { + c.localize( center ); } @SuppressWarnings("rawtypes") public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { - WrappedCoordinateTransform simXfm = interpSolver.solve( mvgPts, tgtPts ); +// WrappedCoordinateTransform simXfm = interpSolver.solve( mvgPts, tgtPts ); + WrappedCoordinateTransform simXfm = interpSolver.solve( tgtPts, mvgPts ); - AffineTransform3D sim = new AffineTransform3D(); - BigWarpTransform.affine3d( (AbstractAffineModel3D)simXfm.getTransform(), sim ); + RealTransform msim; + if ( ndims == 2 ) + { + final AffineTransform2D sim = new AffineTransform2D(); + BigWarpTransform.affine2d( ( AbstractAffineModel2D ) interpSolver.getModel(), sim ); + msim = new MaskedSimilarityTransform2D( sim, lambda, center, interp ); + } + else + { + final AffineTransform3D sim = BigWarpTransform.toAffine3D( ( AbstractAffineModel3D ) interpSolver.getModel() ); + msim = new MaskedSimilarityTransform( sim, lambda, center, interp ); + } - final MaskedSimilarityTransform msim = new MaskedSimilarityTransform( sim, lambda, center, interp ); +// final double[][] xfmMvg = transformPoints( msim, mvgPts ); +// final InvertibleRealTransform baseTransform = baseSolver.solve( xfmMvg, tgtPts ); - final double[][] xfmMvg = transformPoints( simXfm, mvgPts ); - final InvertibleRealTransform baseTransform = baseSolver.solve( xfmMvg, tgtPts ); + final double[][] xfmTgt = transformPoints( msim, tgtPts ); + final InvertibleRealTransform baseTransform = baseSolver.solve( mvgPts, xfmTgt ); final RealTransformSequence seq = new RealTransformSequence(); seq.add( msim ); seq.add( baseTransform ); - return wrap( seq, lambda ); + return new WrappedIterativeInvertibleRealTransform<>( MaskedTransformSolver.wrap( seq, lambda ) ); } public WrappedIterativeInvertibleRealTransform solve( @@ -88,12 +139,6 @@ public WrappedIterativeInvertibleRealTransform solve( return solve( mvgPts, tgtPts ); } - public static > WrappedIterativeInvertibleRealTransform wrap( RealTransform base, RealRandomAccessible lambda ) - { - final RealTransformSequence identity = new RealTransformSequence(); - return new WrappedIterativeInvertibleRealTransform<>( new SpatiallyInterpolatedRealTransform( base, identity, lambda )); - } - private static double[][] transformPoints( RealTransform xfm, double[][] pts ) { int nd = pts.length; diff --git a/src/main/java/bigwarp/transforms/ModelTransformSolver.java b/src/main/java/bigwarp/transforms/ModelTransformSolver.java index a2ed00fc..e98c0f7d 100644 --- a/src/main/java/bigwarp/transforms/ModelTransformSolver.java +++ b/src/main/java/bigwarp/transforms/ModelTransformSolver.java @@ -37,6 +37,11 @@ public ModelTransformSolver( Model< ? > model ) this.model = model; } + public Model< ? > getModel() + { + return model; + } + public WrappedCoordinateTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { final double[] w = new double[ mvgPts[ 0 ].length ]; diff --git a/src/main/java/net/imglib2/realtransform/AffineInterpolator.java b/src/main/java/net/imglib2/realtransform/AffineInterpolator.java new file mode 100644 index 00000000..f07c8f0b --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/AffineInterpolator.java @@ -0,0 +1,7 @@ +package net.imglib2.realtransform; + +public interface AffineInterpolator +{ + + public AffineGet get( final double t ); +} diff --git a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java index ed3ab75e..7ad34922 100644 --- a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java +++ b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform.java @@ -31,39 +31,29 @@ public static enum Interpolators { SIMILARITY, ROTATION }; private final double[] c; - private final boolean flip; +// private final boolean flip; public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda ) { - this( transform, lambda, new double[3], Interpolators.SIMILARITY, false ); + this( transform, lambda, new double[3], Interpolators.SIMILARITY ); } public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, boolean flip ) { - this( transform, lambda, new double[3], Interpolators.SIMILARITY, flip ); + this( transform, lambda, new double[3], Interpolators.SIMILARITY ); } public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c ) { - this( transform, lambda, c, Interpolators.SIMILARITY, false ); + this( transform, lambda, c, Interpolators.SIMILARITY ); } public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, Interpolators interp ) { - this( transform, lambda, new double[3], interp, false ); - } - - public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, Interpolators interp, boolean flip ) { - this( transform, lambda, new double[3], interp, flip ); + this( transform, lambda, new double[3], interp ); } public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c, Interpolators interp ) { - this( transform, lambda, c, interp, false ); - } - - public MaskedSimilarityTransform(final AffineTransform3D transform, final RealRandomAccessible lambda, double[] c, Interpolators interp, boolean flip ) { assert ( transform.numSourceDimensions() == lambda.numDimensions() ); this.transform = transform; this.c = c; - this.flip = flip; - this.lambda = lambda; lambdaAccess = lambda.realRandomAccess(); @@ -89,20 +79,14 @@ public int numTargetDimensions() { public void apply(double[] source, double[] target) { lambdaAccess.setPosition(source); final double lam = lambdaAccess.get().getRealDouble(); - if( flip ) - interpolator.get( 1-lam ).apply( source, target ); - else - interpolator.get( lam ).apply( source, target ); + interpolator.get( lam ).apply( source, target ); } @Override public void apply(RealLocalizable source, RealPositionable target) { lambdaAccess.setPosition(source); final double lam = lambdaAccess.get().getRealDouble(); - if( flip ) - interpolator.get( 1-lam ).apply( source, target ); - else - interpolator.get( lam ).apply( source, target ); + interpolator.get( lam ).apply( source, target ); } @Override diff --git a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform2D.java b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform2D.java new file mode 100644 index 00000000..00283ea8 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform2D.java @@ -0,0 +1,96 @@ +package net.imglib2.realtransform; + +import bdv.viewer.animate.AbstractTransformAnimator; +import net.imglib2.RealLocalizable; +import net.imglib2.RealPositionable; +import net.imglib2.RealRandomAccess; +import net.imglib2.RealRandomAccessible; +import net.imglib2.realtransform.MaskedSimilarityTransform.Interpolators; +import net.imglib2.type.numeric.RealType; + +/** + * Spatially-varying mask for a {@link RealTransform}. + * + * @author John Bogovic + * + */ +public class MaskedSimilarityTransform2D> implements RealTransform { + + private final RealRandomAccessible lambda; + + private RealRandomAccess lambdaAccess; + + private final AffineTransform2D transform; + + private final AffineInterpolator interpolator; + + private final double[] c; + + private final Interpolators interp; + +// private final boolean flip; + + public MaskedSimilarityTransform2D(final AffineTransform2D transform, final RealRandomAccessible lambda ) { + this( transform, lambda, new double[3], Interpolators.SIMILARITY ); + } + + public MaskedSimilarityTransform2D(final AffineTransform2D transform, final RealRandomAccessible lambda, boolean flip ) { + this( transform, lambda, new double[3], Interpolators.SIMILARITY ); + } + + public MaskedSimilarityTransform2D(final AffineTransform2D transform, final RealRandomAccessible lambda, double[] c ) { + this( transform, lambda, c, Interpolators.SIMILARITY ); + } + + public MaskedSimilarityTransform2D(final AffineTransform2D transform, final RealRandomAccessible lambda, Interpolators interp ) { + this( transform, lambda, new double[3], interp ); + } + + public MaskedSimilarityTransform2D(final AffineTransform2D transform, final RealRandomAccessible lambda, double[] c, Interpolators interp ) { + + assert ( transform.numSourceDimensions() == lambda.numDimensions() ); + this.transform = transform; + this.c = c; + this.lambda = lambda; + this.interp = interp; + lambdaAccess = lambda.realRandomAccess(); + + if( interp == Interpolators.SIMILARITY ) + interpolator = new SimilarityTransformInterpolator2D( transform, c ); + else + interpolator = new RotationTransformInterpolator2D( transform, c ); + } + + @Override + public int numSourceDimensions() { + + return transform.numSourceDimensions(); + } + + @Override + public int numTargetDimensions() { + + return transform.numTargetDimensions(); + } + + @Override + public void apply(double[] source, double[] target) { + lambdaAccess.setPosition(source); + final double lam = lambdaAccess.get().getRealDouble(); + interpolator.get( lam ).apply( source, target ); + } + + @Override + public void apply(RealLocalizable source, RealPositionable target) { + lambdaAccess.setPosition(source); + final double lam = lambdaAccess.get().getRealDouble(); + interpolator.get( lam ).apply( source, target ); + } + + @Override + public RealTransform copy() { + + return new MaskedSimilarityTransform2D(transform.copy(), lambda, c, interp ); + } + +} diff --git a/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator.java b/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator.java index 5b56282c..78d1c84e 100644 --- a/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator.java +++ b/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator.java @@ -64,9 +64,9 @@ public AffineTransform3D get(final double t) { transform.set(m); double[] pCurrent = new double[3]; + double[] pTgt = new double[3]; transform.apply(p, pCurrent); - double[] pTgt = new double[3]; LinAlgHelpers.scale( pDiff, t, pTgt ); LinAlgHelpers.add( p, pTgt, pTgt ); LinAlgHelpers.subtract( pTgt, pCurrent, pTgt ); diff --git a/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator2D.java b/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator2D.java new file mode 100644 index 00000000..8ebb9c01 --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/RotationTransformInterpolator2D.java @@ -0,0 +1,181 @@ +package net.imglib2.realtransform; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +import org.janelia.utility.geom.GeomUtils; + +import bigwarp.landmarks.LandmarkTableModel; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffShape; +import bigwarp.transforms.BigWarpTransform; +import bigwarp.transforms.MaskedSimRotTransformSolver; +import bigwarp.transforms.TpsTransformSolver; +import net.imglib2.RealPoint; +import net.imglib2.RealRandomAccessible; +import net.imglib2.realtransform.MaskedSimilarityTransform.Interpolators; +import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; +import net.imglib2.type.numeric.RealType; +import net.imglib2.util.LinAlgHelpers; + +public class RotationTransformInterpolator2D implements AffineInterpolator +{ + private final double thtDiff; + + private final AffineTransform2D tform; + + private final double[] c; + + private final double[] pDiff; + + public RotationTransformInterpolator2D( final AffineTransform2D transform, final double[] c ) + { + tform = new AffineTransform2D(); + + final AffineTransform2D transformEnd = new AffineTransform2D(); + transformEnd.set( transform ); + transformEnd.translate( -c[0], -c[1] ); + + thtDiff = GeomUtils.scalesAngle( transformEnd )[ 2 ]; + + // translation needed to from reconstructed to target transformation + this.c = new double[ 2 ]; + System.arraycopy( c, 0, this.c, 0, 2 ); + + pDiff = new double[ 2 ]; + double[] tmp = new double[ 2 ]; + AffineTransform2D t1 = get( 1 ); + t1.apply( c, tmp ); + transform.apply( c, pDiff ); + LinAlgHelpers.subtract( pDiff, tmp, pDiff ); + } + + public AffineTransform2D get( final double t ) + { + // make identity + tform.set( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0 ); + + // the rotation + final double thtCurrent = t * thtDiff; + tform.rotate( thtCurrent ); + + // the translation + final double[] pCurrent = new double[ 2 ]; + final double[] pTgt = new double[ 2 ]; + tform.apply( c, pCurrent ); + + LinAlgHelpers.scale( pDiff, t, pTgt ); + LinAlgHelpers.add( pTgt, c, pTgt ); + LinAlgHelpers.subtract( pTgt, pCurrent, pTgt ); + tform.translate( pTgt ); + + return tform; + } + + public static void main( String[] args ) throws IOException + { +// final AffineTransform2D t = new AffineTransform2D(); +// t.rotate( 0.2 ); +// t.translate( 10, 20 ); +// System.out.println( t ); + +// test90deg(); + testReal2d(); + } + + public static void testReal2d() throws IOException + { + final LandmarkTableModel ltm = LandmarkTableModel.loadFromCsv( new File("/home/john/tmp/boats-bigrotation.csv"), false ); + + final RealPoint c = new RealPoint( 0.0, 0.0 ); + final PlateauSphericalMaskRealRandomAccessible lambda = new PlateauSphericalMaskRealRandomAccessible( c ); + lambda.setFalloffShape( FalloffShape.COSINE ); + lambda.setSquaredRadius( 28111.13100490283 ); + lambda.setSquaredSigma( 24251.31739665425 ); + lambda.setCenter( new double[] { 380.26234219457774, 284.5915704375881 } ); + + final RealPoint p = new RealPoint( 0.0, 0.0 ); + final RealPoint q = new RealPoint( 0.0, 0.0 ); + + final TpsTransformSolver baseSolver = new TpsTransformSolver(); + + final MaskedSimRotTransformSolver solver = new MaskedSimRotTransformSolver<>( 2, baseSolver, lambda, c.positionAsDoubleArray(), Interpolators.ROTATION ); + WrappedIterativeInvertibleRealTransform xfm = solver.solve( ltm ); + + int idx = 0; + + final int nd = ltm.getNumdims(); + final RealPoint x = new RealPoint( nd ); + final RealPoint y = new RealPoint( nd ); + + x.setPosition( Arrays.stream( ltm.getFixedPoint( idx ) ).mapToDouble( Double::doubleValue ).toArray() ); + xfm.apply( x, y ); + System.out.println("est pt : " + y ); + + final double[] ytrue = Arrays.stream( ltm.getMovingPoint( idx ) ).mapToDouble( Double::doubleValue ).toArray(); + System.out.println( "tru pt :" + new RealPoint( ytrue )); + + } + + public static > void transformLandmarkPoint( final LandmarkTableModel ltm, final int idx, + final BigWarpTransform bwTform, RealRandomAccessible< T > lambda ) + { + final int nd = ltm.getNumdims(); + final RealPoint x = new RealPoint( nd ); + final RealPoint y = new RealPoint( nd ); + + x.setPosition( Arrays.stream( ltm.getFixedPoint( idx ) ).mapToDouble( Double::doubleValue ).toArray() ); + + if( lambda != null ) + System.out.println( "l(x): " + lambda.getAt( x ) ); + + final InvertibleRealTransform xfm = bwTform.getTransformation(false); + + xfm.apply( x, y ); + System.out.println( y ); + + final double[] ytrue = Arrays.stream( ltm.getMovingPoint( idx ) ).mapToDouble( Double::doubleValue ).toArray(); + System.out.println( "true pt :" + Arrays.toString( ytrue )); + } + + + public static void test90deg() + { + final LandmarkTableModel ltm = new LandmarkTableModel(2); + ltm.add( new double[] { 0.0, 0.0 }, new double[] { 0.0, 0.0 } ); + ltm.add( new double[] { -1.0, 0.0 }, new double[] { 0.0, 1.0 } ); + ltm.add( new double[] { 0.0, 1.0 }, new double[] { 1.0, 0.0 } ); + ltm.add( new double[] { 1.0, 0.0 }, new double[] { 0.0, -1.0 } ); + ltm.add( new double[] { 0.0, -1.0 }, new double[] { -1.0, 0.0 } ); + + final RealPoint c = new RealPoint( 0.0, 0.0 ); + final PlateauSphericalMaskRealRandomAccessible lambda = new PlateauSphericalMaskRealRandomAccessible( c ); + lambda.setFalloffShape( FalloffShape.COSINE ); + lambda.setRadius( 1.0 ); + lambda.setSigma( 1.0 ); + + final RealPoint p = new RealPoint( 0.0, 0.0 ); + final RealPoint q = new RealPoint( 0.0, 0.0 ); + + final TpsTransformSolver baseSolver = new TpsTransformSolver(); + final MaskedSimRotTransformSolver solver = new MaskedSimRotTransformSolver<>( 2, baseSolver, lambda, c.positionAsDoubleArray(), Interpolators.ROTATION ); + + WrappedIterativeInvertibleRealTransform xfm = solver.solve( ltm ); + xfm.apply( p, q ); + System.out.println( p + " > " + q ); + + System.out.println( "" ); + p.setPosition( 2.0, 0 );; + xfm.apply( p, q ); + System.out.println( p + " > " + q ); + + System.out.println( "" ); + p.setPosition( 1.0, 0 ); + xfm.apply( p, q ); + System.out.println( p + " > " + q ); + + } + + +} \ No newline at end of file diff --git a/src/main/java/net/imglib2/realtransform/SimilarityTransformInterpolator2D.java b/src/main/java/net/imglib2/realtransform/SimilarityTransformInterpolator2D.java new file mode 100644 index 00000000..943950fc --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/SimilarityTransformInterpolator2D.java @@ -0,0 +1,105 @@ +package net.imglib2.realtransform; + +import java.util.Arrays; + +import org.janelia.utility.geom.GeomUtils; + +import net.imglib2.util.LinAlgHelpers; + +public class SimilarityTransformInterpolator2D implements AffineInterpolator +{ + private final double thtDiff; + + private final AffineTransform2D tform; + + private final double[] c; + + private final double[] pDiff; + +// private final double sStart; + + private final double sDiff; + + public SimilarityTransformInterpolator2D( final AffineTransform2D transform, final double[] c ) + { + tform = new AffineTransform2D(); + + final AffineTransform2D transformEnd = new AffineTransform2D(); + transformEnd.set( transform ); + transformEnd.translate( -c[0], -c[1] ); + + double[] params = GeomUtils.scalesAngle( transformEnd ); + thtDiff = params[ 2 ]; +// double s = ( params[ 0 ] + params[ 1 ] ) / 2.0 ; +// sDiff = s - 1.0; + + sDiff = ( params[ 0 ] + params[ 1 ] ) / 2.0 - 1.0; + + // translation needed to from reconstructed to target transformation + this.c = new double[ 2 ]; + System.arraycopy( c, 0, this.c, 0, 2 ); + + pDiff = new double[ 2 ]; + final double[] tmp = new double[ 2 ]; + final AffineTransform2D t1 = get( 1 ); + t1.apply( c, tmp ); + transform.apply( c, pDiff ); + LinAlgHelpers.subtract( pDiff, tmp, pDiff ); + } + + public AffineTransform2D get( final double t ) + { + // make identity + tform.set( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0 ); + + // the rotation + tform.rotate( t * thtDiff ); + + // the scale + tform.scale( 1.0 + t * sDiff ); + + // the translation + final double[] pCurrent = new double[ 2 ]; + final double[] pTgt = new double[ 2 ]; + tform.apply( c, pCurrent ); + + LinAlgHelpers.scale( pDiff, t, pTgt ); + LinAlgHelpers.add( c, pTgt, pTgt ); + LinAlgHelpers.subtract( pTgt, pCurrent, pTgt ); + tform.translate( pTgt ); + + return tform; + } + + public static void main( String[] args ) + { + final double tht = Math.PI - 0.1; + final double scale = 2.2; + final double[] c = new double[]{ -10.0, 20.0 }; + final AffineTransform2D t = GeomUtils.centeredSimilarity( tht, scale, c ); + System.out.println( t ); + + double[] ps = GeomUtils.scalesAngle( t, c ); + System.out.println( Arrays.toString( ps )); + double sx = ps[0]; + double sy = ps[1]; + double thtEst = ps[2]; + double sEst = 0.5 * ( sx + sy ); + + + System.out.println( "\ntht: " + tht + " vs " + thtEst ); + System.out.println( "scl: " + sEst + " vs " + scale + "\n" ); + + AffineTransform2D tEst = GeomUtils.centeredSimilarity( thtEst, sEst, c ); + System.out.println( tEst ); + + + final SimilarityTransformInterpolator2D interp = new SimilarityTransformInterpolator2D( t, c ); +//// System.out.println( interp ); +// System.out.println( interp.get( 0 ) ); + + System.out.println( t ); + System.out.println( interp.get( 1 ) ); + } + +} \ No newline at end of file From 4043d9119d7814f45035cecd7afeaf7fc324a684 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 13 Jan 2023 14:19:26 -0500 Subject: [PATCH 199/282] fix: SimilarityTransformInterpolationExample --- .../realtransform/SimilarityTransformInterpolationExample.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java index 4b9c6b97..30cb7949 100644 --- a/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java +++ b/src/test/java/net/imglib2/realtransform/SimilarityTransformInterpolationExample.java @@ -145,7 +145,7 @@ public static void expSeq( String imgFile, String jsonFile ) { // masked similarity final MaskedSimilarityTransform msim = new MaskedSimilarityTransform( transform, lambda, center ); - final MaskedSimilarityTransform msimInv = new MaskedSimilarityTransform( transform.inverse(), lambda, center, Interpolators.SIMILARITY, true ); + final MaskedSimilarityTransform msimInv = new MaskedSimilarityTransform( transform.inverse(), lambda, center, Interpolators.SIMILARITY ); final WrappedIterativeInvertibleRealTransform tpsXfm = new TpsTransformSolver().solve( ltm ); final Scale3D id = new Scale3D(1,1,1); From 918f59fe0734c297fad05b8821c06cebf08b186d Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 8 Feb 2023 16:54:26 -0500 Subject: [PATCH 200/282] feat: start of slicer-style dfield format --- .../bdv/gui/ExportDisplacementFieldFrame.java | 16 ++- .../ij/BigWarpToDeformationFieldPlugIn.java | 68 ++++++++----- .../transforms/SlicerTransformations.java | 99 +++++++++++++++++++ 3 files changed, 159 insertions(+), 24 deletions(-) create mode 100644 src/main/java/bigwarp/transforms/SlicerTransformations.java diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index 9d0d67cd..919d3885 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -45,6 +45,10 @@ public class ExportDisplacementFieldFrame extends JFrame { private static final long serialVersionUID = -6179153725489981013L; + // formats + public static final String FMT_NGFF = "NGFF"; + public static final String FMT_SLICER = "Slicer"; + // macro recording public static final String commandName = "Big Warp to Displacement field"; protected static final String landmarksKey = "landmarks"; @@ -56,6 +60,7 @@ public class ExportDisplacementFieldFrame extends JFrame protected static final String virtualKey = "virtual"; protected static final String threadsKey = "threads"; + protected static final String formatKey = "format"; protected static final String sizeKey = "pixel_size"; protected static final String spacingKey = "pixel_spacing"; protected static final String minKey = "min"; @@ -97,6 +102,7 @@ public class ExportDisplacementFieldFrame extends JFrame private JComboBox< String > typeComboBox; private JComboBox< String > directionComboBox; private JSpinner nThreadsField; + private JComboBox< String > formatComboBox; private JButton okBtn; private JButton cancelBtn; @@ -388,6 +394,12 @@ public JPanel basicPanel() nThreadsField = new JSpinner( new SpinnerNumberModel( 1, 1, 9999, 1 ) ); panel.add( nThreadsField, gbcCheck ); + ctxt.gridx = 3; + panel.add( new JLabel( "Format:" ), ctxt ); + gbcCheck.gridx = 4; + formatComboBox = new JComboBox< String >( new String[] { FMT_NGFF, FMT_SLICER } ); + panel.add( formatComboBox, gbcCheck ); + ctxt.gridx = 5; ctxt.anchor = GridBagConstraints.LINE_END; ctxt.insets = new Insets( OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD ); @@ -663,6 +675,7 @@ public DeformationFieldExportParameters getParams() (Integer)invMaxIterationsSpinner.getValue(), virtualCheckBox.isSelected(), (Integer)nThreadsField.getValue(), + (String)formatComboBox.getSelectedItem(), fovPanel.getPixelSize(), fovPanel.getSpacing(), fovPanel.getMin(), @@ -722,6 +735,7 @@ public static void runMacro( String args ) final boolean splitAffine = args.contains(" " + splitAffineKey ); final boolean openAsVirtual = args.contains(" " + virtualKey); final int threads = Integer.valueOf( Macro.getValue( args, threadsKey, "1" )); + final String format = Macro.getValue( args, formatKey, FMT_NGFF ); final double[] min = Arrays.stream( Macro.getValue( args, minKey, "" ).split( "," ) ).mapToDouble( Double::valueOf ).toArray(); final double[] spacing = Arrays.stream( Macro.getValue( args, spacingKey, "" ).split( "," ) ).mapToDouble( Double::valueOf ).toArray(); @@ -739,7 +753,7 @@ public static void runMacro( String args ) DeformationFieldExportParameters params = new DeformationFieldExportParameters( landmarks, splitAffine, type, direction, tolerance, maxIters, - openAsVirtual, threads, + openAsVirtual, threads, format, pixSize, spacing, min, unit, n5Root, n5Dataset, diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 864b1f4e..27605ca2 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -32,6 +32,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import javax.swing.JFrame; @@ -57,6 +60,7 @@ import bigwarp.source.SourceInfo; import bigwarp.transforms.BigWarpTransform; import bigwarp.transforms.NgffTransformations; +import bigwarp.transforms.SlicerTransformations; import fiji.util.gui.GenericDialogPlus; import ij.IJ; import ij.ImageJ; @@ -279,15 +283,15 @@ public static void runFromParameters( final DeformationFieldExportParameters par { if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { - writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), false, params.inverseTolerance, params.inverseMaxIterations ); - writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), true, params.inverseTolerance, params.inverseMaxIterations ); } else { final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); - writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), inverse, params.inverseTolerance, params.inverseMaxIterations ); } } @@ -356,15 +360,15 @@ public void runBackup( final String arg ) { if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { - writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), false, params.inverseTolerance, params.inverseMaxIterations ); - writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), true, params.inverseTolerance, params.inverseMaxIterations ); } else { final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); - writeN5( params.n5Base, params.n5Dataset, ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.ignoreAffine, params.flatten(), + writeN5( params.n5Base, params.n5Dataset, ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), inverse, params.inverseTolerance, params.inverseMaxIterations ); } } @@ -574,12 +578,13 @@ public static void writeN5( final int[] spatialBlockSize, final Compression compression, final int nThreads, + final String format, final boolean flatten, final boolean inverse, final double invTolerance, final int invMaxIters ) throws IOException { - writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, flatten, inverse, invTolerance, invMaxIters ); + writeN5( n5BasePath, N5DisplacementField.FORWARD_ATTR, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, format, flatten, inverse, invTolerance, invMaxIters ); } public static void writeN5( @@ -595,12 +600,13 @@ public static void writeN5( final int[] spatialBlockSize, final Compression compression, final int nThreads, + final String format, final boolean flatten, final boolean inverse, final double invTolerance, final int invMaxIters ) throws IOException { - writeN5( n5BasePath, n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, false, flatten, inverse, invTolerance, invMaxIters ); + writeN5( n5BasePath, n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, format, false, flatten, inverse, invTolerance, invMaxIters ); } public static void writeN5( @@ -616,6 +622,7 @@ public static void writeN5( final int[] spatialBlockSizeArg, final Compression compression, final int nThreads, + final String format, final boolean splitAffine, final boolean flatten, final boolean inverse, @@ -648,7 +655,6 @@ public static void writeN5( bwXfm.setInverseMaxIterations( invMaxIters ); bwXfm.setInverseTolerance( invTolerance ); -// final RealTransform tpsTotal = bwXfm.getTransformation( false ); final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten, splitAffine ); final InvertibleRealTransform totalTransform = inverse ? fwdTransform.inverse() : fwdTransform; final AffineGet affine = bwXfm.affinePartOfTps(); @@ -660,7 +666,6 @@ public static void writeN5( final N5Factory factory = new N5Factory().gsonBuilder( NgffTransformations.gsonBuilder() ); final N5Writer n5 = factory.openWriter( n5BasePath ); -// N5DisplacementField.save( n5, dataset, affine, dfield, spacing, blockSize, compression ); final RandomAccessibleInterval< DoubleType > dfield; if( affine != null ) @@ -673,26 +678,36 @@ public static void writeN5( totalNoAffine.add( totalTransform ); totalNoAffine.add( affine.inverse() ); dfield = DisplacementFieldTransform.createDisplacementField( totalNoAffine, new FinalInterval( dims ), spacing ); - NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); - // the total transform - NgffSequenceTransformation totalTform = new NgffSequenceTransformation( inputSpace, outputSpace, - new CoordinateTransformation[]{ dfieldTform, ngffAffine }); + if( format.equals( ExportDisplacementFieldFrame.FMT_SLICER )) + { + final ThreadPoolExecutor exec = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue() ); + SlicerTransformations.saveDisplacementField( n5, dataset, dfield, blockSize, compression, exec ); + } + else + { + NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); + // the total transform + NgffSequenceTransformation totalTform = new NgffSequenceTransformation( inputSpace, outputSpace, + new CoordinateTransformation[]{ dfieldTform, ngffAffine }); - N5DisplacementField.addCoordinateTransformations( n5, "/", totalTform ); + N5DisplacementField.addCoordinateTransformations( n5, "/", totalTform ); + } } else { dfield = DisplacementFieldTransform.createDisplacementField( totalTransform, new FinalInterval( dims ), spacing ); - Point pt = new Point( 100, 100, 10 ); - CompositeIntervalView< DoubleType, RealComposite< DoubleType > > dfImgVec = Views.collapseReal( Views.moveAxis( dfield, 0, 3 )); - RealPoint q = new RealPoint ( 3 ); - q.setPosition( dfImgVec.getAt( pt )); - System.out.println( "displacement at " + pt + " : " + q ); - - NgffDisplacementsTransformation ngffTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); - N5DisplacementField.addCoordinateTransformations( n5, "/", ngffTform ); + if( format.equals( ExportDisplacementFieldFrame.FMT_SLICER )) + { + final ThreadPoolExecutor exec = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue() ); + SlicerTransformations.saveDisplacementField( n5, dataset, dfield, blockSize, compression, exec ); + } + else + { + NgffDisplacementsTransformation ngffTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); + N5DisplacementField.addCoordinateTransformations( n5, "/", ngffTform ); + } } n5.close(); @@ -1062,6 +1077,8 @@ public static class DeformationFieldExportParameters public final String inverseOption; public final boolean virtual; public final int nThreads; + public final String format; + public final long[] size; public final double[] spacing; @@ -1085,6 +1102,7 @@ public DeformationFieldExportParameters( final int inverseMaxIterations, final boolean virtual, final int nThreads, + final String format, final long[] size, final double[] spacing, final double[] offset, @@ -1104,6 +1122,7 @@ public DeformationFieldExportParameters( this.virtual = virtual; this.nThreads = nThreads; + this.format = format; this.size = size; this.spacing = spacing; @@ -1142,6 +1161,7 @@ public static DeformationFieldExportParameters fromDialog( gd.addCheckbox( "virtual", false ); gd.addNumericField( "threads", 1, 0 ); + gd.addStringField( "format", ExportDisplacementFieldFrame.FMT_NGFF ); gd.addMessage( "Size and spacing" ); final int[] ids = WindowManager.getIDList(); @@ -1181,6 +1201,7 @@ public static DeformationFieldExportParameters fromDialog( final String direction = gd.getNextChoice(); final boolean virtual = gd.getNextBoolean(); final int nThreads = ( int ) gd.getNextNumber(); + final String format = gd.getNextString(); ImagePlus ref_imp = null; if( promptReference ) @@ -1259,6 +1280,7 @@ public static DeformationFieldExportParameters fromDialog( direction, 0.5, 200, virtual, nThreads, + format, size, spacing, offset, diff --git a/src/main/java/bigwarp/transforms/SlicerTransformations.java b/src/main/java/bigwarp/transforms/SlicerTransformations.java new file mode 100644 index 00000000..28c30ba9 --- /dev/null +++ b/src/main/java/bigwarp/transforms/SlicerTransformations.java @@ -0,0 +1,99 @@ +package bigwarp.transforms; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; + +import org.janelia.saalfeldlab.n5.Compression; +import org.janelia.saalfeldlab.n5.N5Writer; +import org.janelia.saalfeldlab.n5.imglib2.N5DisplacementField; +import org.janelia.saalfeldlab.n5.imglib2.N5Utils; + +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.realtransform.AffineGet; +import net.imglib2.type.NativeType; +import net.imglib2.type.numeric.RealType; +import net.imglib2.view.IntervalView; +import net.imglib2.view.Views; + +public class SlicerTransformations +{ + + public static final String AFFINE_ATTR = "Transformation_Matrix"; + + /* + * Saves an arbitrary {@link RealTransform} as a deformation field + * into a specified n5 dataset using slicer's convention. + * + * @param the type parameter + * @param n5Writer the n5 writer + * @param dataset the dataset path + * @param dfield the displacement field + * @param blockSize the block size + * @param compression the compression type + * @param exec the executor service + * @throws IOException the exception + */ + public static final & RealType> void saveDisplacementField( + final N5Writer n5Writer, + final String dataset, + final RandomAccessibleInterval dfield, + final int[] blockSize, + final Compression compression, + ExecutorService exec ) throws IOException { + + int[] vecBlkSz; + if( blockSize.length >= dfield.numDimensions() ) + vecBlkSz = blockSize; + else { + vecBlkSz = new int[ blockSize.length + 1 ]; + vecBlkSz[ 0 ] = (int)dfield.dimension( 0 ); + for( int i = 1; i < vecBlkSz.length; i++ ) + { + vecBlkSz[ i ] = blockSize[ i - 1 ]; + } + } + + final RandomAccessibleInterval< T > dfieldPerm = dxyz2dzyx( dfield ); + try + { + N5Utils.save( dfieldPerm, n5Writer, dataset, vecBlkSz, compression, exec ); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( InterruptedException e ) + { + e.printStackTrace(); + } + catch ( ExecutionException e ) + { + e.printStackTrace(); + } + } + + public static final int[] permXYZ = new int[] { 2, 1, 0 }; + public static final int[] perm = new int[] { 1, 2, 3, 0 }; + + public static final & RealType> RandomAccessibleInterval dxyz2dzyx( RandomAccessibleInterval df ) + { + final IntervalView< T > dx = Views.hyperSlice( df, 0, 0 ); + final IntervalView< T > dy = Views.hyperSlice( df, 0, 1 ); + final IntervalView< T > dz = Views.hyperSlice( df, 0, 2 ); + + // besides permuting the axes, we also need to re-order the components of the displacement vectors + final IntervalView< T > dxp = N5DisplacementField.permute( dx, permXYZ ); + final IntervalView< T > dyp = N5DisplacementField.permute( dy, permXYZ ); + final IntervalView< T > dzp = N5DisplacementField.permute( dz, permXYZ ); + final RandomAccessibleInterval< T > dfp = Views.stack( dxp, dyp, dzp ); + + return N5DisplacementField.permute( dfp, perm ); + } + + public static final & RealType> void saveAffine( final N5Writer n5Writer, final String dataset, final AffineGet affine) + { + // TODO implement me + } + +} From 4de81663a99be4427a04604c7ceff07a90505e99 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 21 Feb 2023 16:13:23 -0500 Subject: [PATCH 201/282] fix: toward better mask behavior in 2d * and SlicerTransformations affine support --- .../ij/BigWarpToDeformationFieldPlugIn.java | 3 ++ src/main/java/bigwarp/BigWarp.java | 2 +- ...teauSphericalMaskRealRandomAccessible.java | 2 +- .../transforms/NgffTransformations.java | 2 +- .../transforms/SlicerTransformations.java | 46 ++++++++++++++++++- .../MaskedSimilarityTransform2D.java | 6 ++- .../SpatiallyInterpolatedRealTransform.java | 5 +- 7 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 27605ca2..4bc03a1a 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -683,10 +683,13 @@ public static void writeN5( { final ThreadPoolExecutor exec = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue() ); SlicerTransformations.saveDisplacementField( n5, dataset, dfield, blockSize, compression, exec ); + SlicerTransformations.saveAffine( n5, dataset, affine ); } else { NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); + // TODO save affine + // the total transform NgffSequenceTransformation totalTform = new NgffSequenceTransformation( inputSpace, outputSpace, new CoordinateTransformation[]{ dfieldTform, ngffAffine }); diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 59c18afd..8aa725b4 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2114,7 +2114,7 @@ public SourceAndConverter< DoubleType > addTransformMaskSource() data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, affine ); final Interval itvl = bbe.estimatePixelInterval( affine, data.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ) ); - transformMask = PlateauSphericalMaskSource.build( new RealPoint( ndims ), itvl ); + transformMask = PlateauSphericalMaskSource.build( new RealPoint( 3 ), itvl ); final RealARGBColorConverter< DoubleType > converter = RealARGBColorConverter.create( new DoubleType(), 0, 1 ); converter.setColor( new ARGBType( 0xffffffff ) ); diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 200ed21c..24abafb8 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -243,7 +243,7 @@ private void updateGaussSigma() public void setCenter( RealLocalizable p ) { - center.setPosition( p ); + p.localize( center ); if ( overlays != null ) overlays.stream().forEach( o -> o.setCenter( p ) ); } diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index bda4b1c5..8d06a3bb 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -13,11 +13,11 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.janelia.saalfeldlab.n5.N5URL; import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.DatasetAttributes; import org.janelia.saalfeldlab.n5.N5FSReader; import org.janelia.saalfeldlab.n5.N5Reader; -import org.janelia.saalfeldlab.n5.N5URL; import org.janelia.saalfeldlab.n5.N5Writer; import org.janelia.saalfeldlab.n5.ij.N5Factory; import org.janelia.saalfeldlab.n5.imglib2.N5DisplacementField; diff --git a/src/main/java/bigwarp/transforms/SlicerTransformations.java b/src/main/java/bigwarp/transforms/SlicerTransformations.java index 28c30ba9..58b08dfb 100644 --- a/src/main/java/bigwarp/transforms/SlicerTransformations.java +++ b/src/main/java/bigwarp/transforms/SlicerTransformations.java @@ -6,11 +6,15 @@ import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.N5Writer; +import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Writer; +import org.janelia.saalfeldlab.n5.ij.N5Factory; import org.janelia.saalfeldlab.n5.imglib2.N5DisplacementField; import org.janelia.saalfeldlab.n5.imglib2.N5Utils; import net.imglib2.RandomAccessibleInterval; import net.imglib2.realtransform.AffineGet; +import net.imglib2.realtransform.AffineTransform2D; +import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.type.NativeType; import net.imglib2.type.numeric.RealType; import net.imglib2.view.IntervalView; @@ -93,7 +97,47 @@ public static final & RealType> RandomAccessibleInte public static final & RealType> void saveAffine( final N5Writer n5Writer, final String dataset, final AffineGet affine) { - // TODO implement me + try + { + final double[][] mtx; + if ( affine instanceof AffineTransform3D ) + { + AffineTransform3D a3d = ( AffineTransform3D ) affine; + mtx = new double[ 4 ][ 4 ]; + a3d.toMatrix( mtx ); + } + else if ( affine instanceof AffineTransform2D ) + { + AffineTransform2D a2d = ( AffineTransform2D ) affine; + mtx = new double[ 3 ][ 3 ]; + a2d.toMatrix( mtx ); + } + else { + // src and tgt dims always the same for AffineGets + final int nd = affine.numTargetDimensions(); + mtx = new double[nd][nd]; + for( int i = 0; i < nd; i++ ) + for( int j = 0; j < nd; j++ ) + mtx[i][j] = affine.get( i, j ); + } + n5Writer.setAttribute( dataset, AFFINE_ATTR, mtx ); + } + catch ( IOException e ) {} + } + + public static void main( String[] args ) throws IOException + { + double[][] mtx = new double[4][4]; + mtx[0][0] = 2; + mtx[1][1] = 3; + mtx[2][2] = 4; + mtx[3][3] = 1; + + final N5HDF5Writer h5 = new N5Factory().openHDF5Writer( "/home/john/tmp/mri-stack-landmarks-df-slicer.h5" ); + h5.setAttribute( "dfield", AFFINE_ATTR, mtx ); + h5.close(); + + System.out.println( "done" ); } } diff --git a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform2D.java b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform2D.java index 00283ea8..c77e7cdb 100644 --- a/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform2D.java +++ b/src/main/java/net/imglib2/realtransform/MaskedSimilarityTransform2D.java @@ -2,6 +2,7 @@ import bdv.viewer.animate.AbstractTransformAnimator; import net.imglib2.RealLocalizable; +import net.imglib2.RealPoint; import net.imglib2.RealPositionable; import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; @@ -75,7 +76,10 @@ public int numTargetDimensions() { @Override public void apply(double[] source, double[] target) { - lambdaAccess.setPosition(source); +// lambdaAccess.setPosition(source); + for( int i = 0; i < source.length; i++ ) + lambdaAccess.setPosition( source[ i ], i ); + final double lam = lambdaAccess.get().getRealDouble(); interpolator.get( lam ).apply( source, target ); } diff --git a/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java index 05bb0f6b..a550ca70 100644 --- a/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java +++ b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java @@ -69,7 +69,10 @@ public void apply(double[] source, double[] target) { a.apply(source, arrA); b.apply(source, arrB); - lambdaAccess.setPosition(source); +// lambdaAccess.setPosition(source); + for( int i = 0; i < source.length; i++ ) + lambdaAccess.setPosition( source[ i ], i ); + final double am = lambdaAccess.get().getRealDouble(); final double bm = (1 - am); From 7160a51af40beb25bf1d09931bff0774213953cf Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 23 Feb 2023 12:14:28 -0500 Subject: [PATCH 202/282] fix: format slicer dfield as xyz3 --- .../java/bigwarp/transforms/SlicerTransformations.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/transforms/SlicerTransformations.java b/src/main/java/bigwarp/transforms/SlicerTransformations.java index 58b08dfb..4bec1442 100644 --- a/src/main/java/bigwarp/transforms/SlicerTransformations.java +++ b/src/main/java/bigwarp/transforms/SlicerTransformations.java @@ -58,7 +58,8 @@ public static final & RealType> void saveDisplacemen } } - final RandomAccessibleInterval< T > dfieldPerm = dxyz2dzyx( dfield ); + /* Converts [3,X,Y,Z] to [X,Y,Z,3] displacement field */ + final RandomAccessibleInterval< T > dfieldPerm = Views.moveAxis( dfield, 0, 3 ); try { N5Utils.save( dfieldPerm, n5Writer, dataset, vecBlkSz, compression, exec ); @@ -80,6 +81,13 @@ public static final & RealType> void saveDisplacemen public static final int[] permXYZ = new int[] { 2, 1, 0 }; public static final int[] perm = new int[] { 1, 2, 3, 0 }; + /** + * Converts a [3,X,Y,Z] displacement field to a [3,Z,Y,X] displacement field + * + * @param the type + * @param df the displacement field + * @return a permuted displacement field + */ public static final & RealType> RandomAccessibleInterval dxyz2dzyx( RandomAccessibleInterval df ) { final IntervalView< T > dx = Views.hyperSlice( df, 0, 0 ); From b63047cd2b789513b249a1c25f13be24cdd51db4 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 4 Apr 2023 16:59:26 -0400 Subject: [PATCH 203/282] fix: FovPanel min --- src/main/java/bdv/gui/FieldOfViewPanel.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/bdv/gui/FieldOfViewPanel.java b/src/main/java/bdv/gui/FieldOfViewPanel.java index a52107bf..d63c0322 100644 --- a/src/main/java/bdv/gui/FieldOfViewPanel.java +++ b/src/main/java/bdv/gui/FieldOfViewPanel.java @@ -320,6 +320,10 @@ public void removeUpdate( DocumentEvent e ) minFields[ i ].setPreferredSize( textFieldSize ); minFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); minFields[ i ].setValue( new Double( initMin[i]) ); + minFields[ i ].addActionListener( a -> + { + min[ idx ] = Double.parseDouble( minFields[ idx ].getText() ); + }); add( minFields[ i ], gbc ); gbc.gridx = 2; From a7927659e1ed31a9a6d4a3601b613124d7d31244 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 4 Apr 2023 17:00:53 -0400 Subject: [PATCH 204/282] fix: dfield export error checking --- .../ij/BigWarpToDeformationFieldPlugIn.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 4bc03a1a..c1f43cda 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -237,7 +237,13 @@ public static void runFromParameters( final DeformationFieldExportParameters par LandmarkTableModel ltm; if( landmarkModel == null ) { - // load + if( params.landmarkPath == null || params.landmarkPath.isEmpty() ) + { + IJ.showMessage( "Must provide landmark file." ); // TODO message differently + return; + } + + // load landmarks try { ltm = LandmarkTableModel.loadFromCsv( new File( params.landmarkPath ), false ); @@ -505,7 +511,7 @@ else if ( nd == 3 ) * @param ignoreAffine whether the output should include the affine part of the transformation * @return the transformation */ - protected static InvertibleRealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concat, + protected static InvertibleRealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concatPreTransforms, final boolean ignoreAffine ) { final InvertibleRealTransform tps = transform.getTransformation( false ); @@ -514,13 +520,13 @@ protected static InvertibleRealTransform getTransformation( final BigWarpData if( ignoreAffine ) affine = transform.affinePartOfTps(); - if ( !ignoreAffine && ( data == null || !concat ) ) + if ( !ignoreAffine && ( data == null || !concatPreTransforms ) ) { return tps; } InvertibleRealTransform preTransform = null; - if( data != null ) + if( data != null && concatPreTransforms ) { for ( Entry< Integer, SourceInfo > entry : data.sourceInfos.entrySet() ) { @@ -631,8 +637,8 @@ public static void writeN5( { final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; - final String mvgSpaceName = data != null ? data.getMovingSource( 0 ).getSpimSource().getName() : "moving"; - final String tgtSpaceName = data != null ? data.getTargetSource( 0 ).getSpimSource().getName() : "target"; + final String mvgSpaceName = data != null && data.numMovingSources() > 0 ? data.getMovingSource( 0 ).getSpimSource().getName() : "moving"; + final String tgtSpaceName = data != null && data.numTargetSources() > 0 ? data.getTargetSource( 0 ).getSpimSource().getName() : "target"; final String inputSpace; final String outputSpace; if( inverse ) From 4db09ed607b5ab1f1b0c3f36598a92ebb3ffb346 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 4 Apr 2023 17:01:27 -0400 Subject: [PATCH 205/282] fix: wip dfield export slicer format fixing --- .../bdv/ij/BigWarpToDeformationFieldPlugIn.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index c1f43cda..6764555c 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -663,7 +663,6 @@ public static void writeN5( final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten, splitAffine ); final InvertibleRealTransform totalTransform = inverse ? fwdTransform.inverse() : fwdTransform; - final AffineGet affine = bwXfm.affinePartOfTps(); int[] spatialBlockSize = fillBlockSize( spatialBlockSizeArg, ltm.getNumdims() ); int[] blockSize = new int[ spatialBlockSize.length + 1 ]; @@ -674,13 +673,14 @@ public static void writeN5( final N5Writer n5 = factory.openWriter( n5BasePath ); final RandomAccessibleInterval< DoubleType > dfield; - if( affine != null ) + if( splitAffine ) { // the affine part - NgffAffineTransformation ngffAffine = new NgffAffineTransformation( affine.getRowPackedCopy() ); + final AffineGet affine = bwXfm.affinePartOfTps(); + final NgffAffineTransformation ngffAffine = new NgffAffineTransformation( affine.getRowPackedCopy() ); // displacement field (with the affine removed) - RealTransformSequence totalNoAffine = new RealTransformSequence(); + final RealTransformSequence totalNoAffine = new RealTransformSequence(); totalNoAffine.add( totalTransform ); totalNoAffine.add( affine.inverse() ); dfield = DisplacementFieldTransform.createDisplacementField( totalNoAffine, new FinalInterval( dims ), spacing ); @@ -693,11 +693,9 @@ public static void writeN5( } else { - NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); - // TODO save affine - + final NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); // the total transform - NgffSequenceTransformation totalTform = new NgffSequenceTransformation( inputSpace, outputSpace, + final NgffSequenceTransformation totalTform = new NgffSequenceTransformation( inputSpace, outputSpace, new CoordinateTransformation[]{ dfieldTform, ngffAffine }); N5DisplacementField.addCoordinateTransformations( n5, "/", totalTform ); @@ -711,6 +709,9 @@ public static void writeN5( { final ThreadPoolExecutor exec = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue() ); SlicerTransformations.saveDisplacementField( n5, dataset, dfield, blockSize, compression, exec ); + + // for slicer, this affine represents the pixel to physical transformation + SlicerTransformations.saveAffine( n5, dataset, new ScaleAndTranslation( spacing, offset ) ); } else { From caa50b2eb44029992ac63ddc7ad49c0451e8b50e Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 6 Sep 2023 14:29:23 -0400 Subject: [PATCH 206/282] update to use new ngff classes in n5-universe --- .../ij/BigWarpToDeformationFieldPlugIn.java | 30 +-- .../transforms/NgffTransformations.java | 236 ++++++++++++++---- .../transforms/SlicerTransformations.java | 2 +- 3 files changed, 201 insertions(+), 67 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 8af9e447..39ca533b 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -48,10 +48,11 @@ import org.janelia.saalfeldlab.n5.blosc.BloscCompression; import org.janelia.saalfeldlab.n5.ij.N5Exporter; import org.janelia.saalfeldlab.n5.imglib2.N5DisplacementField; -import org.janelia.saalfeldlab.n5.metadata.omengff.NgffAffineTransformation; -import org.janelia.saalfeldlab.n5.metadata.omengff.NgffDisplacementsTransformation; -import org.janelia.saalfeldlab.n5.metadata.omengff.NgffSequenceTransformation; import org.janelia.saalfeldlab.n5.universe.N5Factory; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.AffineCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.DisplacementFieldCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.SequenceCoordinateTransform; import bdv.gui.ExportDisplacementFieldFrame; import bigwarp.BigWarp; @@ -102,7 +103,6 @@ import net.imglib2.view.Views; import net.imglib2.view.composite.CompositeIntervalView; import net.imglib2.view.composite.GenericComposite; -import ome.ngff.transformations.CoordinateTransformation; /** * ImageJ plugin to convert the thin plate spline to a displacement field. @@ -258,9 +258,9 @@ public static void runFromParameters( final DeformationFieldExportParameters par ltm = landmarkModel; final int ndims = ltm.getNumdims(); - final double[] spacing = new double[ ndims ]; - final double[] offset = new double[ ndims ]; - final long[] dims = new long[ ndims ]; + double[] spacing = new double[ ndims ]; + double[] offset = new double[ ndims ]; + long[] dims = new long[ ndims ]; if ( params.spacing != null ) spacing = params.spacing; @@ -635,7 +635,7 @@ public static void writeN5( final boolean flatten, final boolean inverse, final double invTolerance, - final int invMaxIters ) throws IOException + final int invMaxIters ) { final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; @@ -679,7 +679,7 @@ public static void writeN5( { // the affine part final AffineGet affine = bwXfm.affinePartOfTps(); - final NgffAffineTransformation ngffAffine = new NgffAffineTransformation( affine.getRowPackedCopy() ); + final AffineCoordinateTransform ngffAffine = new AffineCoordinateTransform( affine.getRowPackedCopy() ); // displacement field (with the affine removed) final RealTransformSequence totalNoAffine = new RealTransformSequence(); @@ -695,12 +695,12 @@ public static void writeN5( } else { - final NgffDisplacementsTransformation dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); + final DisplacementFieldCoordinateTransform dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); // the total transform - final NgffSequenceTransformation totalTform = new NgffSequenceTransformation( inputSpace, outputSpace, - new CoordinateTransformation[]{ dfieldTform, ngffAffine }); + final SequenceCoordinateTransform totalTform = new SequenceCoordinateTransform( inputSpace, outputSpace, + new CoordinateTransform[]{ dfieldTform, ngffAffine }); - N5DisplacementField.addCoordinateTransformations( n5, "/", totalTform ); + NgffTransformations.addCoordinateTransformations( n5, "/", totalTform ); } } else @@ -717,8 +717,8 @@ public static void writeN5( } else { - final NgffDisplacementsTransformation ngffTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); - N5DisplacementField.addCoordinateTransformations( n5, "/", ngffTform ); + final DisplacementFieldCoordinateTransform ngffTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); + NgffTransformations.addCoordinateTransformations( n5, "/", ngffTform ); } } diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index 53d37e79..6107ce07 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -4,7 +4,10 @@ import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -14,24 +17,38 @@ import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.N5URI; import org.janelia.saalfeldlab.n5.N5Writer; -import org.janelia.saalfeldlab.n5.imglib2.N5DisplacementField; +import org.janelia.saalfeldlab.n5.imglib2.N5Utils; import org.janelia.saalfeldlab.n5.universe.N5Factory; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.Axis; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.coordinateTransformations.CoordinateTransformation; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.coordinateTransformations.CoordinateTransformationAdapter; +import org.janelia.saalfeldlab.n5.universe.metadata.axes.Axis; +import org.janelia.saalfeldlab.n5.universe.metadata.axes.CoordinateSystem; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.Common; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.graph.TransformGraph; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.AffineCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransformAdapter; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.DisplacementFieldCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.IdentityCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.InvertibleCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.ScaleCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.SequenceCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.TranslationCoordinateTransform; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.RealTransform; +import net.imglib2.realtransform.ScaleGet; +import net.imglib2.realtransform.TranslationGet; import net.imglib2.type.NativeType; import net.imglib2.type.numeric.RealType; import net.imglib2.util.Pair; import net.imglib2.util.ValuePair; + public class NgffTransformations { @@ -147,48 +164,31 @@ public static void main( final String[] args ) throws Exception } -// public static TransformGraph openGraph( final N5Reader n5 ) -// { -// return openGraph( n5, "/" ); -// } -// -// public static TransformGraph openGraph( final N5Reader n5, final String dataset ) -// { -// return new TransformGraph( n5, dataset ); -// } -// -// public static RealTransform open( final N5Reader n5, final String dataset ) -// { -// // TODO error handling -// return openGraph( n5, dataset ).getTransforms().get( 0 ).getTransform( n5 ); -// } -// -// public static RealTransform open( final N5Reader n5, final String dataset, final String name ) -// { -// // TODO error handling -// return openGraph( n5, dataset ).getTransform( name ).get().getTransform( n5 ); -// } -// + @SuppressWarnings("unchecked") public static < T extends RealTransform> T open( final N5Reader n5, final String dataset, final String input, final String output ) { // TODO error handling - final TransformGraph g = openGraph( n5, dataset ); + final TransformGraph g = Common.openGraph( n5, dataset ); return (T)g.path( input, output ).get().totalTransform( n5, g ); } public static RealTransform open( final String url ) { - final Pair< NgffCoordinateTransformation< ? >, N5Reader > pair = openTransformN5( url ); + final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( url ); return pair.getA().getTransform( pair.getB() ); } - public static InvertibleRealTransform openInvertible( final String url ) - { - final Pair< NgffCoordinateTransformation< ? >, N5Reader > pair = openTransformN5( url ); - return pair.getA().getInvertibleTransform( pair.getB() ); + public static InvertibleRealTransform openInvertible(final String url) { + + final Pair, N5Reader> pair = openTransformN5(url); + final CoordinateTransform ct = pair.getA(); + if (ct instanceof InvertibleCoordinateTransform) + return ((InvertibleCoordinateTransform)ct).getInvertibleTransform(pair.getB()); + else + return null; } - public static Pair,N5Reader> openTransformN5( final String url ) + public static Pair,N5Reader> openTransformN5( final String url ) { try { @@ -204,8 +204,8 @@ public static Pair,N5Reader> openTransformN5( fi final String dataset = n5url.getGroupPath() != null ? n5url.getGroupPath() : "/"; final String attribute = n5url.getAttributePath() != null ? n5url.getAttributePath() : "coordinateTransformations/[0]"; - final CoordinateTransformation ct = n5.getAttribute( dataset, attribute, CoordinateTransformation.class ); - final NgffCoordinateTransformation< ? > nct = NgffCoordinateTransformation.create( ct ); + final CoordinateTransform ct = n5.getAttribute(dataset, attribute, CoordinateTransform.class); + final CoordinateTransform nct = CoordinateTransform.create(ct); return new ValuePair<>( nct, n5 ); } } @@ -216,7 +216,7 @@ public static Pair,N5Reader> openTransformN5( fi } } - public static NgffCoordinateTransformation openJson( final String url ) + public static CoordinateTransform openJson( final String url ) { final Path path = Paths.get( url ); String string; @@ -234,10 +234,10 @@ public static NgffCoordinateTransformation openJson( final String url ) // System.out.println( elem ); // final CoordinateTransformation ct = gson.fromJson( elem.getAsJsonArray().get( 0 ), CoordinateTransformation.class ); - final CoordinateTransformation ct = gson.fromJson( elem, CoordinateTransformation.class ); + final CoordinateTransform ct = gson.fromJson( elem, CoordinateTransform.class ); // System.out.println( ct ); - final CoordinateTransformation< ? > nct = CoordinateTransformation.create( ct ); + final CoordinateTransform< ? > nct = CoordinateTransform.create( ct ); return nct; // final RealTransform tform = nct.getTransform( null ); // System.out.println( tform ); @@ -245,10 +245,10 @@ public static NgffCoordinateTransformation openJson( final String url ) // return tform; } - public static void save( final String jsonFile, final CoordinateTransformation transform ) + public static void save( final String jsonFile, final CoordinateTransform transform ) { final GsonBuilder gb = new GsonBuilder(); - gb.registerTypeAdapter(CoordinateTransformation.class, new CoordinateTransformationAdapter() ); + gb.registerTypeAdapter(CoordinateTransform.class, new CoordinateTransformAdapter() ); final Gson gson = gb.create(); try( FileWriter writer = new FileWriter( jsonFile )) { @@ -261,7 +261,7 @@ public static void save( final String jsonFile, final CoordinateTransformation & RealType< T > > NgffDisplacementsTransformation save( + public static < T extends NativeType< T > & RealType< T > > DisplacementFieldCoordinateTransform save( final N5Writer n5, final String dataset, final RandomAccessibleInterval< T > dfield, @@ -272,21 +272,144 @@ public static < T extends NativeType< T > & RealType< T > > NgffDisplacementsTra final String unit, final int[] blockSize, final Compression compression, - final int nThreads ) throws IOException + final int nThreads ) { final String[] axisNames = ( spacing.length == 2 ) ? new String[] { "x", "y" } : new String[] { "x", "y", "z"}; final CoordinateSystem inputCoordinates = new CoordinateSystem( inName, Axis.space( unit, axisNames ) ); final CoordinateSystem outputCoordinates = new CoordinateSystem( outName, Axis.space( unit, axisNames ) ); final ThreadPoolExecutor threadPool = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue() ); - N5DisplacementField.saveDisplacementFieldNgff( n5, dataset, "/", inputCoordinates, outputCoordinates, + final DisplacementFieldCoordinateTransform ngffDfield = saveDisplacementFieldNgff( n5, dataset, "/", inputCoordinates, outputCoordinates, dfield, spacing, offset, blockSize, compression, threadPool ); - final NgffDisplacementsTransformation ngffDfield = new NgffDisplacementsTransformation( dataset, "linear" ); return ngffDfield; + +// final DisplacementFieldCoordinateTransform ngffDfield = new DisplacementFieldCoordinateTransform( "", dataset, "linear" ); +// return ngffDfield; // N5DisplacementField.addCoordinateTransformations( n5, "/", ngffDfield ); } + public static void addCoordinateTransformations( final N5Writer n5, final String groupPath, final CoordinateTransform transform ) { + + // TODO untested + final CoordinateTransform[] cts = n5.getAttribute(groupPath, CoordinateTransform.KEY, CoordinateTransform[].class); + final CoordinateTransform[] ctsOut = new CoordinateTransform[ cts.length + 1 ]; + System.arraycopy(cts, 0, ctsOut, 0, cts.length); + ctsOut[ cts.length ] = transform; + + n5.setAttribute(groupPath, CoordinateTransform.KEY, ctsOut); + } + + public static final & RealType> DisplacementFieldCoordinateTransform saveDisplacementFieldNgff( + final N5Writer n5Writer, + final String dataset, + final String metadataDataset, + final CoordinateSystem inputCoordinates, + final CoordinateSystem outputCoordinates, + final RandomAccessibleInterval dfield, + final double[] spacing, + final double[] offset, + final int[] blockSize, + final Compression compression, + ExecutorService exec ) { + + int[] vecBlkSz; + if( blockSize.length >= dfield.numDimensions() ) + vecBlkSz = blockSize; + else { + vecBlkSz = new int[ blockSize.length + 1 ]; + vecBlkSz[ 0 ] = (int)dfield.dimension( 0 ); + for( int i = 1; i < vecBlkSz.length; i++ ) + { + vecBlkSz[ i ] = blockSize[ i - 1 ]; + } + } + + try + { + N5Utils.save(dfield, n5Writer, dataset, vecBlkSz, compression, exec); + } + catch ( final InterruptedException e ) + { + e.printStackTrace(); + } + catch ( final ExecutionException e ) + { + e.printStackTrace(); + } + + final String vecFieldCsName = inputCoordinates.getName() + "_dfield"; + final CoordinateSystem[] cs = new CoordinateSystem[] { + createVectorFieldCoordinateSystem( vecFieldCsName, inputCoordinates ) }; + n5Writer.setAttribute(dataset, CoordinateSystem.KEY, cs); + + final CoordinateTransform[] ct = new CoordinateTransform[] { + createTransformation( "", spacing, offset, dataset, cs[0] ) }; + n5Writer.setAttribute(dataset, CoordinateTransform.KEY, ct ); + + return new DisplacementFieldCoordinateTransform( "", dataset, "linear" ); + } + + + public static CoordinateTransform createTransformation(final String name, + final double[] scale, final double[] offset, + final String dataset, final CoordinateSystem output) { + + CoordinateTransform ct; + if ((scale != null || allOnes(scale)) && (offset != null || allZeros(offset))) { + ct = new SequenceCoordinateTransform(name, dataset, output.getName(), + new CoordinateTransform[]{ + new ScaleCoordinateTransform(prepend(1, scale)), + new TranslationCoordinateTransform(prepend(0, offset))}); + } else if (offset != null || !allZeros(offset)) + ct = new TranslationCoordinateTransform(name, dataset, output.getName(), prepend(0, offset)); + else if (scale != null || !allOnes(scale)) + ct = new ScaleCoordinateTransform(name, dataset, output.getName(), prepend(1, scale)); + else + ct = new IdentityCoordinateTransform(name, dataset, output.getName()); + + return ct; + } + + private static boolean allZeros(final double[] x) { + + for (int i = 0; i < x.length; i++) + if (x[i] != 0.0) + return false; + + return true; + } + + private static boolean allOnes(final double[] x) { + + for (int i = 0; i < x.length; i++) + if (x[i] != 1.0) + return false; + + return true; + } + + private static double[] prepend(double val, double[] array) { + + final double[] out = new double[array.length + 1]; + out[0] = val; + for (int i = 1; i < out.length; i++) { + out[i] = array[i - 1]; + } + return out; + } + + public static CoordinateSystem createVectorFieldCoordinateSystem(final String name, final CoordinateSystem input) { + + final Axis[] vecAxes = new Axis[input.getAxes().length + 1]; + vecAxes[0] = new Axis("d", "displacement", null, true); + for (int i = 1; i < vecAxes.length; i++) + vecAxes[i] = input.getAxes()[i - 1]; + + return new CoordinateSystem(name, vecAxes); + } + + /** * returns null if no permutation needed * @@ -299,7 +422,7 @@ public static final int[] vectorAxisLastNgff( final CoordinateSystem cs ) throws final Axis[] axes = cs.getAxes(); final int n = axes.length; - if ( axes[ n - 1 ].getType().equals( Axis.DISPLACEMENT_TYPE )) + if ( axes[ n - 1 ].getType().equals( Axis.DISPLACEMENT)) return null; else { @@ -318,7 +441,7 @@ public static final int[] vectorAxisLastNgff( final CoordinateSystem cs ) throws int k = 0; for( int i = 0; i < n; i++ ) { - if ( axes[ i ].getType().equals( Axis.DISPLACEMENT_TYPE )) + if ( axes[ i ].getType().equals( Axis.DISPLACEMENT)) vecDim = i; else permutation[i] = k++; @@ -340,18 +463,29 @@ public static final int[] vectorAxisLastNgff( final N5Reader n5, final String dataset ) throws Exception { // TODO move to somewhere more central - final TransformGraph g = openGraph( n5, dataset ); + final TransformGraph g = Common.openGraph( n5, dataset ); // TODO need to be smarter about which coordinate system to get - final CoordinateSystem cs = g.getCoordinateSystems().iterator().next(); + final CoordinateSystem cs = g.getCoordinateSystems().getCollection().iterator().next(); return vectorAxisLastNgff( cs ); } - public static GsonBuilder gsonBuilder() - { + public static GsonBuilder gsonBuilder() { + final GsonBuilder gb = new GsonBuilder(); - gb.registerTypeAdapter(CoordinateTransformation.class, new CoordinateTransformationAdapter() ); + gb.registerTypeAdapter(CoordinateTransform.class, new CoordinateTransformAdapter()); return gb; } + public static CoordinateTransform createAffine(AffineGet transform) { + + if (transform instanceof TranslationGet) { + return new TranslationCoordinateTransform(((TranslationGet)transform).getTranslationCopy()); + } else if (transform instanceof ScaleGet) { + return new ScaleCoordinateTransform(((ScaleGet)transform).getScaleCopy()); + } else { + return new AffineCoordinateTransform(transform.getRowPackedCopy()); + } + } + } diff --git a/src/main/java/bigwarp/transforms/SlicerTransformations.java b/src/main/java/bigwarp/transforms/SlicerTransformations.java index 06f8d767..37881a24 100644 --- a/src/main/java/bigwarp/transforms/SlicerTransformations.java +++ b/src/main/java/bigwarp/transforms/SlicerTransformations.java @@ -45,7 +45,7 @@ public static final & RealType> void saveDisplacemen final RandomAccessibleInterval dfield, final int[] blockSize, final Compression compression, - final ExecutorService exec ) throws IOException { + final ExecutorService exec ) { int[] vecBlkSz; if( blockSize.length >= dfield.numDimensions() ) From 41e7ba2104d02694b69753385019606abafaca9d Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 6 Sep 2023 17:30:58 -0400 Subject: [PATCH 207/282] feat: import transform mask from file --- src/main/java/bigwarp/BigWarp.java | 230 ++++++++++++------ src/main/java/bigwarp/BigWarpActions.java | 124 ++++++---- .../transforms/io/TransformWriterJson.java | 14 +- 3 files changed, 232 insertions(+), 136 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 7cf5dae7..97fe9c24 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -39,12 +39,16 @@ import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; +import java.net.URI; +import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.HashSet; import java.util.List; +import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; @@ -68,7 +72,10 @@ import javax.swing.table.TableCellEditor; import org.janelia.saalfeldlab.n5.Compression; +import org.janelia.saalfeldlab.n5.N5Reader; +import org.janelia.saalfeldlab.n5.N5URI; import org.janelia.saalfeldlab.n5.ij.N5Exporter; +import org.janelia.saalfeldlab.n5.universe.N5Factory; import org.janelia.utility.geom.BoundingSphereRitter; import org.janelia.utility.geom.Sphere; import org.janelia.utility.ui.RepeatingReleasedEventsFixer; @@ -110,6 +117,7 @@ import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.SetupAssignments; import bdv.util.Bounds; +import bdv.util.RealRandomAccessibleIntervalSource; import bdv.viewer.BigWarpDragOverlay; import bdv.viewer.BigWarpLandmarkFrame; import bdv.viewer.BigWarpOverlay; @@ -149,6 +157,8 @@ import ij.IJ; import ij.ImageJ; import ij.ImagePlus; +import ij.plugin.FolderOpener; + import java.util.LinkedHashMap; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; import jitk.spline.XfmUtils; @@ -182,6 +192,7 @@ import net.imglib2.realtransform.inverse.RealTransformFiniteDerivatives; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.ARGBType; +import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; @@ -286,9 +297,11 @@ public class BigWarp< T > protected JacobianDeterminantSource jacDetSource; - protected SourceAndConverter< DoubleType > transformMaskSource; + protected SourceAndConverter< ? extends RealType> transformMaskSource; + + protected Source< ? extends RealType> transformMask; - protected PlateauSphericalMaskSource transformMask; + protected PlateauSphericalMaskSource plateauTransformMask; protected final AbstractModel< ? >[] baseXfmList; @@ -860,7 +873,7 @@ public void createMovingTargetGroups() qState.setGroupName( mvgGrp, "moving images" ); qState.setGroupName( tgtGrp, "target images" ); - for ( SourceAndConverter< ? > sac : data.sources ) + for ( final SourceAndConverter< ? > sac : data.sources ) { if ( data.isMoving( sac ) ) { @@ -1027,7 +1040,7 @@ protected void setUpViewerMenu( final BigWarpViewerFrame vframe ) final ActionMap actionMap = vframe.getKeybindings().getConcatenatedActionMap(); final JMenuBar viewerMenuBar = new JMenuBar(); - JMenu fileMenu = new JMenu( "File" ); + final JMenu fileMenu = new JMenu( "File" ); viewerMenuBar.add( fileMenu ); final JMenuItem loadProject = new JMenuItem( actionMap.get( BigWarpActions.LOAD_PROJECT ) ); @@ -1048,22 +1061,27 @@ protected void setUpViewerMenu( final BigWarpViewerFrame vframe ) fileMenu.add( saveItem ); fileMenu.addSeparator(); - final JMenuItem miLoadSettings = new JMenuItem( actionMap.get( BigWarpActions.LOAD_SETTINGS ) ); + final JMenuItem openMask = new JMenuItem( actionMap.get( BigWarpActions.MASK_IMPORT )); + openMask.setText( "Import mask" ); + fileMenu.add( openMask ); + + fileMenu.addSeparator(); + final JMenuItem miLoadSettings = new JMenuItem( actionMap.get( BigWarpActions.LOAD_SETTINGS )); miLoadSettings.setText( "Load settings" ); fileMenu.add( miLoadSettings ); - final JMenuItem miSaveSettings = new JMenuItem( actionMap.get( BigWarpActions.SAVE_SETTINGS ) ); + final JMenuItem miSaveSettings = new JMenuItem( actionMap.get( BigWarpActions.SAVE_SETTINGS )); miSaveSettings.setText( "Save settings" ); fileMenu.add( miSaveSettings ); if( ij != null ) { fileMenu.addSeparator(); - final JMenuItem exportToImagePlus = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_IP ) ); + final JMenuItem exportToImagePlus = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_IP )); exportToImagePlus.setText( "Export moving image" ); fileMenu.add( exportToImagePlus ); - final JMenuItem exportWarpField = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_WARP ) ); + final JMenuItem exportWarpField = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_WARP )); exportWarpField.setText( "Export warp field" ); fileMenu.add( exportWarpField ); } @@ -1191,7 +1209,7 @@ public File saveMovingImageXml( String proposedFilePath ) try { new XmlIoSpimData().save( movingSpimData, proposedFile.getAbsolutePath() ); - } catch ( SpimDataException e ) + } catch ( final SpimDataException e ) { e.printStackTrace(); } @@ -1201,8 +1219,8 @@ public File saveMovingImageXml( String proposedFilePath ) public AffineTransform3D getMovingToFixedTransformAsAffineTransform3D() { - double[][] affine3DMatrix = new double[ 3 ][ 4 ]; - double[][] affine2DMatrix = new double[ 2 ][ 3 ]; + final double[][] affine3DMatrix = new double[ 3 ][ 4 ]; + final double[][] affine2DMatrix = new double[ 2 ][ 3 ]; if ( currentTransform == null ) { @@ -1317,7 +1335,7 @@ public void exportAsImagePlus( boolean virtual, String path ) gd.addMessage( "Virtual: fast to display,\n" + "low memory requirements,\nbut slow to navigate" ); gd.addCheckbox( "virtual?", false ); - int defaultCores = (int)Math.ceil( Runtime.getRuntime().availableProcessors()/4); + final int defaultCores = (int)Math.ceil( Runtime.getRuntime().availableProcessors()/4); gd.addNumericField( "threads", defaultCores, 0 ); gd.addMessage( "Writing options (leave empty to opena new image window)" ); @@ -1392,7 +1410,7 @@ public void exportAsImagePlus( boolean virtual, String path ) // landmark centers (because multiple images can be exported this way ) if( matchedPtNames.size() > 0 ) { - BigwarpLandmarkSelectionPanel selection = new BigwarpLandmarkSelectionPanel<>( + final BigwarpLandmarkSelectionPanel selection = new BigwarpLandmarkSelectionPanel<>( data, data.sources, fieldOfViewOption, outputIntervalList, matchedPtNames, interp, offsetSpec, res, isVirtual, nThreads, @@ -1623,7 +1641,7 @@ public static void updateRowSelection( { logger.trace( "updateRowSelection " ); - int i = landmarkModel.getNextRow( isMoving ); + final int i = landmarkModel.getNextRow( isMoving ); if ( i < table.getRowCount() ) { logger.trace( " landmarkTable ( updateRowSelection ) selecting row " + i ); @@ -1640,7 +1658,7 @@ public static void updateRowSelection( */ public int getSelectedUnpairedRow( boolean isMoving ) { - int row = landmarkTable.getSelectedRow(); + final int row = landmarkTable.getSelectedRow(); if( row >= 0 && ( isMoving ? !landmarkModel.isMovingPoint( row ) : !landmarkModel.isFixedPoint( row ))) return row; @@ -1708,7 +1726,7 @@ protected int selectedLandmark( final double[] pt, final boolean isMoving ) * * @param pt the point location * @param isMoving is the point location in moving image space - * @param selectInTable also select the landmark in the table + * @param selectInTable also select the landmark in the table * @return the index of the selected landmark */ protected int selectedLandmark( final double[] pt, final boolean isMoving, final boolean selectInTable ) @@ -1808,10 +1826,10 @@ protected void enableTransformHandlers() private void printSourceTransforms() { final AffineTransform3D xfm = new AffineTransform3D(); - for( SourceAndConverter sac : data.sources ) + for( final SourceAndConverter sac : data.sources ) { sac.getSpimSource().getSourceTransform(0, 0, xfm ); - double det = BigWarpUtils.det( xfm ); + final double det = BigWarpUtils.det( xfm ); System.out.println( "source xfm ( " + sac.getSpimSource().getName() + " ) : " + xfm ); System.out.println( " det = " + det ); } @@ -1832,7 +1850,7 @@ private void printViewerTransforms() } /** - * Changes the view transformation of 'panelToChange' to match that of 'panelToMatch' + * Changes the view transformation of 'panelToChange' to match that of 'panelToMatch' * @param panelToChange the viewer panel whose transform will change * @param panelToMatch the viewer panel the transform will come from */ @@ -1911,7 +1929,7 @@ public void warpToNearest( BigWarpViewerPanel viewer ) return; } - RealPoint mousePt = new RealPoint( 3 ); // need 3d point even for 2d images + final RealPoint mousePt = new RealPoint( 3 ); // need 3d point even for 2d images viewer.getGlobalMouseCoordinates( mousePt ); warpToLandmark( landmarkModel.getIndexNearestTo( mousePt, viewer.getIsMoving() ), viewer ); } @@ -1925,7 +1943,7 @@ public void warpToLandmark( int row, BigWarpViewerPanel viewer ) } int offset = 0; - int ndims = landmarkModel.getNumdims(); + final int ndims = landmarkModel.getNumdims(); double[] pt = null; if( viewer.getIsMoving() && viewer.getOverlay().getIsTransformed() ) { @@ -2032,9 +2050,9 @@ public void togglePointVisibility() public boolean toggleMovingImageDisplay() { // If this is the first time calling the toggle, there may not be enough - // points to estimate a reasonable transformation. + // points to estimate a reasonable transformation. // return early if an re-estimation did not occur - boolean success = restimateTransformation(); + final boolean success = restimateTransformation(); logger.trace( "toggleMovingImageDisplay, success: " + success ); if ( !success ) { @@ -2056,12 +2074,16 @@ public boolean toggleMovingImageDisplay() public void toggleMaskOverlayVisibility() { - getViewerFrameQ().getViewerPanel().getMaskOverlay().toggleVisible(); + final BigWarpMaskSphereOverlay overlay = getViewerFrameQ().getViewerPanel().getMaskOverlay(); + if( overlay != null ) + overlay.toggleVisible(); } public void setMaskOverlayVisibility( final boolean visible ) { - getViewerFrameQ().getViewerPanel().getMaskOverlay().setVisible( visible ); + final BigWarpMaskSphereOverlay overlay = getViewerFrameQ().getViewerPanel().getMaskOverlay(); + if( overlay != null ) + overlay.setVisible( visible ); } protected void addDefaultTableMouseListener() @@ -2078,9 +2100,9 @@ protected void addMaskMouseListener() maskSourceMouseListenerQ = new MaskedSourceEditorMouseListener( getLandmarkPanel().getTableModel().getNumdims(), this, viewerQ ); maskSourceMouseListenerQ.setActive( false ); - maskSourceMouseListenerQ.setMask( transformMask.getRandomAccessible() ); + maskSourceMouseListenerQ.setMask( plateauTransformMask.getRandomAccessible() ); - transformMask.getRandomAccessible().setOverlays( Arrays.asList( viewerQ.getMaskOverlay() )); + plateauTransformMask.getRandomAccessible().setOverlays( Arrays.asList( viewerQ.getMaskOverlay() )); } public void setGridType( final GridSource.GRID_TYPE method ) @@ -2096,7 +2118,7 @@ public static < T > void wrapMovingSources( final int ndims, final BigWarpData< { if ( sourceInfo.isMoving() ) { - SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); + final SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); final int sourceIdx = data.sources.indexOf( sourceInfo.getSourceAndConverter() ); sourceInfo.setSourceAndConverter( newSac ); data.sources.set( sourceIdx, newSac ); @@ -2113,7 +2135,7 @@ public static < T > void wrapMovingSources( final int ndims, final BigWarpData< if ( sourceInfo.isMoving() ) { - SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm", ndims ); + final SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm", ndims ); final int sourceIdx = data.sources.indexOf( sourceInfo.getSourceAndConverter() ); sourceInfo.setSourceAndConverter( newSac ); data.sources.set( sourceIdx, newSac ); @@ -2132,7 +2154,7 @@ public static < T > List< SourceAndConverter< T > > wrapSourcesAsTransformed( fi { if ( sourceInfo.isMoving() ) { - SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); + final SourceAndConverter< T > newSac = ( SourceAndConverter< T > ) wrapSourceAsTransformed( sourceInfo.getSourceAndConverter(), "xfm_" + i, ndims ); wrappedSource.add( newSac ); } else @@ -2190,7 +2212,7 @@ public void updateTransformMask() { final MaskOptionsPanel maskOpts = warpVisDialog.maskOptionsPanel; final String type = maskOpts.getType(); - if( !type.equals( BigWarpTransform.NO_MASK_INTERP ) ) + if( !type.equals( BigWarpTransform.NO_MASK_INTERP ) && transformMaskSource == null ) { // add the transform mask if necessary addTransformMaskSource(); @@ -2205,14 +2227,59 @@ public void updateTransformMask() } @SuppressWarnings( { "unchecked", "rawtypes" } ) - public SourceAndConverter< DoubleType > addTransformMaskSource() + public void importTransformMaskSource( final String uri ) { + + URI encodedUri; + try { + encodedUri = N5URI.encodeAsUri( uri ); + } catch (final URISyntaxException e) { + e.printStackTrace(); + return; + } + + final N5URI n5Uri = new N5URI( encodedUri ); + final JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES ); +// fileChooser.setCurrentDirectory( startingFolder ); + + final int ret = fileChooser.showOpenDialog(landmarkFrame); + if ( ret == JFileChooser.APPROVE_OPTION ) { + + LinkedHashMap, SourceInfo> infos; + try { + final File selection = fileChooser.getSelectedFile(); + infos = BigWarpInit.createSources(data, selection.getAbsolutePath(), TRANSFORM_MASK_SOURCE_ID, false); + BigWarpInit.add( data, infos, null ); + + synchronizeSources(); + infos.entrySet().stream().map( e -> { return e.getKey(); }).findFirst().ifPresent( x -> { + transformMask = (Source>)x; + }); + + } catch (final URISyntaxException e) { + e.printStackTrace(); + } catch (final IOException e) { + e.printStackTrace(); + } catch (final SpimDataException e) { + e.printStackTrace(); + } + } + +// updateTransformMask(); + bwTransform.setLambda( transformMask.getInterpolatedSource(0, 0, Interpolation.NLINEAR)); + + synchronizeSources(); + } + + @SuppressWarnings( { "unchecked", "rawtypes", "hiding" } ) + public > SourceAndConverter< T > addTransformMaskSource() { if( warpVisDialog == null ) return null; if( transformMask != null) { - return ( SourceAndConverter< DoubleType > ) data.getSourceInfo( TRANSFORM_MASK_SOURCE_ID ).getSourceAndConverter(); + return ( SourceAndConverter< T > ) data.getSourceInfo( TRANSFORM_MASK_SOURCE_ID ).getSourceAndConverter(); } // think about whether its worth it to pass a type parameter. or should we just stick with Floats? @@ -2221,11 +2288,13 @@ public SourceAndConverter< DoubleType > addTransformMaskSource() data.getTargetSource( 0 ).getSpimSource().getSourceTransform( 0, 0, affine ); final Interval itvl = bbe.estimatePixelInterval( affine, data.getTargetSource( 0 ).getSpimSource().getSource( 0, 0 ) ); - transformMask = PlateauSphericalMaskSource.build( new RealPoint( 3 ), itvl ); + plateauTransformMask = PlateauSphericalMaskSource.build( new RealPoint( 3 ), itvl ); + transformMask = plateauTransformMask; + - final RealARGBColorConverter< DoubleType > converter = RealARGBColorConverter.create( new DoubleType(), 0, 1 ); + final RealARGBColorConverter< T > converter = (RealARGBColorConverter)RealARGBColorConverter.create( plateauTransformMask.getType(), 0, 1 ); converter.setColor( new ARGBType( 0xffffffff ) ); - final SourceAndConverter< DoubleType > soc = new SourceAndConverter( transformMask, converter, null ); + final SourceAndConverter< T > soc = new SourceAndConverter( (Source)transformMask, converter, null ); data.converterSetups.add( BigDataViewer.createConverterSetup( soc, TRANSFORM_MASK_SOURCE_ID ) ); data.sources.add( ( SourceAndConverter ) soc ); @@ -2234,9 +2303,9 @@ public SourceAndConverter< DoubleType > addTransformMaskSource() data.sourceInfos.put( TRANSFORM_MASK_SOURCE_ID, sourceInfo); // connect to UI - warpVisDialog.maskOptionsPanel.setMask( transformMask ); + warpVisDialog.maskOptionsPanel.setMask( plateauTransformMask ); addMaskMouseListener(); - bwTransform.setLambda( transformMask.getRandomAccessible() ); + bwTransform.setLambda( plateauTransformMask.getRandomAccessible() ); final ArrayList overlayList = new ArrayList<>(); final BigWarpMaskSphereOverlay overlay = new BigWarpMaskSphereOverlay( viewerQ, ndims==3 ); @@ -2244,18 +2313,23 @@ public SourceAndConverter< DoubleType > addTransformMaskSource() // first attach the overlay to the viewer getViewerFrameQ().getViewerPanel().setMaskOverlay( overlay ); - transformMask.getRandomAccessible().setOverlays( overlayList ); + plateauTransformMask.getRandomAccessible().setOverlays( overlayList ); synchronizeSources(); transformMaskSource = soc; return soc; } - public PlateauSphericalMaskSource getTransformMaskSource() + public Source> getTransformMaskSource() { return transformMask; } + public PlateauSphericalMaskSource getTransformPlateauMaskSource() + { + return plateauTransformMask; + } + private static < T > SourceAndConverter< T > wrapSourceAsTransformed( final SourceAndConverter< T > src, final String name, final int ndims ) { if ( src.asVolatile() == null ) @@ -2341,7 +2415,7 @@ protected void fitBaselineWarpMagModel() { final AbstractModel< ? > baseline = this.baseXfmList[ baselineModelIndex ]; baseline.fit( p, q, w ); // FITBASELINE - WrappedCoordinateTransform baselineTransform = new WrappedCoordinateTransform( + final WrappedCoordinateTransform baselineTransform = new WrappedCoordinateTransform( (InvertibleCoordinateTransform)baseline, ndims ); // the transform to compare is the inverse (because we use it for rendering) @@ -2379,13 +2453,13 @@ public void autoEstimateMask() if( landmarkModel.numActive() < 4 ) return; - if( warpVisDialog.autoEstimateMask() && bwTransform.isMasked() ) + if( warpVisDialog.autoEstimateMask() && bwTransform.isMasked() && transformMask instanceof PlateauSphericalMaskSource ) { final Sphere sph = BoundingSphereRitter.boundingSphere(landmarkModel.getFixedPointsCopy()); - transformMask.getRandomAccessible().setCenter(sph.getCenter()); - transformMask.getRandomAccessible().setRadius(sph.getRadius()); + plateauTransformMask.getRandomAccessible().setCenter(sph.getCenter()); + plateauTransformMask.getRandomAccessible().setRadius(sph.getRadius()); - AbstractTransformSolver< ? > solver = getBwTransform().getSolver(); + final AbstractTransformSolver< ? > solver = getBwTransform().getSolver(); if( solver instanceof MaskedSimRotTransformSolver ) { ((MaskedSimRotTransformSolver)solver).setCenter( sph.getCenter() ); @@ -2446,7 +2520,7 @@ else if ( both ) if ( gridSource != null ) state.setSourceActive( data.getSourceInfo( GRID_SOURCE_ID ).getSourceAndConverter(), false ); - + state.setDisplayMode( DisplayMode.FUSED ); viewerFrame.getViewerPanel().showMessage( "Displaying Jacobian Determinant" ); break; @@ -2456,7 +2530,7 @@ else if ( both ) // turn warp mag on if ( warpMagSource == null ) { - + warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "Warp magnitude" ); synchronizeSources(); } @@ -2627,7 +2701,7 @@ private void setTransformationAll( final InvertibleRealTransform transform ) } else if ( transform instanceof WrappedIterativeInvertibleRealTransform ) { - RealTransform xfm = ((WrappedIterativeInvertibleRealTransform)transform).getTransform(); + final RealTransform xfm = ((WrappedIterativeInvertibleRealTransform)transform).getTransform(); if( xfm instanceof ThinplateSplineTransform ) jacDetSource.setTransform( (ThinplateSplineTransform) xfm ); else @@ -2701,7 +2775,7 @@ public synchronized void setIsMovingDisplayTransformed( final boolean isTransfor */ public boolean isRowIncomplete() { - LandmarkTableModel ltm = landmarkPanel.getTableModel(); + final LandmarkTableModel ltm = landmarkPanel.getTableModel(); return ltm.isPointUpdatePending() || ltm.isPointUpdatePendingMoving(); } @@ -2736,9 +2810,9 @@ protected int detectNumDims() public static int detectNumDims( List< SourceAndConverter< T > > sources ) { boolean isAnySource3d = false; - for ( SourceAndConverter< T > sac : sources ) + for ( final SourceAndConverter< T > sac : sources ) { - long[] dims = new long[ sac.getSpimSource().getSource( 0, 0 ).numDimensions() ]; + final long[] dims = new long[ sac.getSpimSource().getSource( 0, 0 ).numDimensions() ]; sac.getSpimSource().getSource( 0, 0 ).dimensions( dims ); if ( sac.getSpimSource().getSource( 0, 0 ).dimension( 2 ) > 1 ) @@ -2794,7 +2868,7 @@ public static void main( final String[] args ) System.setProperty( "apple.laf.useScreenMenuBar", "false" ); - ProgressWriterIJ progress = new ProgressWriterIJ(); + final ProgressWriterIJ progress = new ProgressWriterIJ(); BigWarp bw; BigWarpData bwdata; if ( fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) @@ -2857,16 +2931,16 @@ else if (!fnP.isEmpty() && !fnQ.isEmpty()) private void viewerXfmTest() { - AffineTransform3D srcTransform0 = new AffineTransform3D(); + final AffineTransform3D srcTransform0 = new AffineTransform3D(); data.sources.get( 0 ).getSpimSource().getSourceTransform(0, 0, srcTransform0 ); - AffineTransform3D srcTransform1 = new AffineTransform3D(); + final AffineTransform3D srcTransform1 = new AffineTransform3D(); data.sources.get( 1 ).getSpimSource().getSourceTransform(0, 0, srcTransform1 ); - AffineTransform3D viewerTransformM = new AffineTransform3D(); + final AffineTransform3D viewerTransformM = new AffineTransform3D(); viewerP.state().getViewerTransform( viewerTransformM ); - AffineTransform3D viewerTransformT = new AffineTransform3D(); + final AffineTransform3D viewerTransformT = new AffineTransform3D(); viewerQ.state().getViewerTransform( viewerTransformT ); System.out.println( " " ); @@ -3009,7 +3083,7 @@ public void mousePressed( final MouseEvent e ) @Override public void mouseReleased( final MouseEvent e ) { - long clickLength = System.currentTimeMillis() - pressTime; + final long clickLength = System.currentTimeMillis() - pressTime; if( clickLength < keyClickMaxLength && selectedPointIndex != -1 ) return; @@ -3118,7 +3192,7 @@ public void mouseDragged( final MouseEvent e ) public void mouseMoved( final MouseEvent e ) { thisViewer.getGlobalMouseCoordinates( hoveredPoint ); - int hoveredIndex = BigWarp.this.selectedLandmark( hoveredArray, isMoving, false ); + final int hoveredIndex = BigWarp.this.selectedLandmark( hoveredArray, isMoving, false ); thisViewer.setHoveredIndex( hoveredIndex ); } @@ -3154,8 +3228,8 @@ public class WarningTableCellRenderer extends DefaultTableCellRenderer @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column ) { - LandmarkTableModel model = ( LandmarkTableModel ) table.getModel(); - Component c = super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column ); + final LandmarkTableModel model = ( LandmarkTableModel ) table.getModel(); + final Component c = super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column ); if ( model.rowNeedsWarning( row ) ) c.setBackground( LandmarkTableModel.WARNINGBGCOLOR ); else @@ -3450,7 +3524,7 @@ public void run() { try { - InvertibleRealTransform invXfm = bw.bwTransform.getTransformation( index ); + final InvertibleRealTransform invXfm = bw.bwTransform.getTransformation( index ); if ( invXfm == null ) return; @@ -3484,7 +3558,7 @@ public void run() } /* - * repaint both panels so that: + * repaint both panels so that: * 1) new transform is displayed * 2) points are rendered */ @@ -3543,7 +3617,7 @@ public void autoSaveLandmarks() else baseFolder = getBigwarpSettingsFolder(); - File proposedLandmarksFile = new File( baseFolder.getAbsolutePath() + + final File proposedLandmarksFile = new File( baseFolder.getAbsolutePath() + File.separator + "bigwarp_landmarks_" + new SimpleDateFormat( "yyyyMMdd-HHmmss" ).format( Calendar.getInstance().getTime() ) + ".csv" ); @@ -3552,7 +3626,7 @@ public void autoSaveLandmarks() { saveLandmarks( proposedLandmarksFile.getCanonicalPath() ); } - catch ( IOException e ) { e.printStackTrace(); } + catch ( final IOException e ) { e.printStackTrace(); } } /** @@ -3568,7 +3642,7 @@ public void quickSaveLandmarks() { saveLandmarks( lastLandmarks.getCanonicalPath() ); } - catch ( IOException e ) { e.printStackTrace(); } + catch ( final IOException e ) { e.printStackTrace(); } } else { @@ -3579,7 +3653,7 @@ public void quickSaveLandmarks() /** * Returns the default location for bigwarp settings / auto saved files: ~/.bigwarp - * @return the folder + * @return the folder */ public File getBigwarpSettingsFolder() { @@ -3671,7 +3745,7 @@ protected void loadLandmarks() public void loadLandmarks( final String filename ) { - File file = new File( filename ); + final File file = new File( filename ); setLastDirectory( file.getParentFile() ); if( filename.endsWith( "csv" )) @@ -3690,7 +3764,7 @@ else if( filename.endsWith( "json" )) TransformWriterJson.read( file, this ); } - boolean didCompute = restimateTransformation(); + final boolean didCompute = restimateTransformation(); // didCompute = false means that there were not enough points // in the loaded points, so we should display the 'raw' moving @@ -3707,14 +3781,14 @@ else if( filename.endsWith( "json" )) protected void saveSettings() { - File proposedSettingsFile = new File( "bigwarp.settings.xml" ); + final File proposedSettingsFile = new File( "bigwarp.settings.xml" ); saveSettingsOrProject( proposedSettingsFile ); } protected void saveProject() { System.out.println( "save project" ); - File proposedSettingsFile = new File( "bigwarp-project.json" ); + final File proposedSettingsFile = new File( "bigwarp-project.json" ); saveSettingsOrProject( proposedSettingsFile ); } @@ -3751,8 +3825,8 @@ protected void saveSettings( final String xmlFilename ) throws IOException { final Element root = new Element( "Settings" ); - Element viewerPNode = new Element( "viewerP" ); - Element viewerQNode = new Element( "viewerQ" ); + final Element viewerPNode = new Element( "viewerP" ); + final Element viewerQNode = new Element( "viewerQ" ); root.addContent( viewerPNode ); root.addContent( viewerQNode ); @@ -3780,7 +3854,8 @@ protected void saveSettings( final String xmlFilename ) throws IOException root.addContent( autoSaveNode ); if ( transformMask != null ) { - root.addContent( transformMask.getRandomAccessible().toXml() ); + // TODO check if is imported mask + root.addContent( plateauTransformMask.getRandomAccessible().toXml() ); } final Document doc = new Document( root ); @@ -3790,7 +3865,7 @@ protected void saveSettings( final String xmlFilename ) throws IOException protected void saveSettingsJson( final String jsonFilename ) throws IOException { - BigwarpSettings settings = getSettings(); + final BigwarpSettings settings = getSettings(); settings.serialize( jsonFilename ); } @@ -3881,7 +3956,7 @@ public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSourc /* add default sources if present */ final List< Element > converterSetups = root.getChild( "SetupAssignments" ).getChild( "ConverterSetups" ).getChildren( "ConverterSetup" ); - for ( Element converterSetup : converterSetups ) + for ( final Element converterSetup : converterSetups ) { final int id = Integer.parseInt( converterSetup.getChild( "id" ).getText() ); addInternalSource( id ); @@ -3896,14 +3971,15 @@ public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSourc activeSourcesDialogQ.update(); // auto-save settings - Element autoSaveElem = root.getChild( "autosave" ); + final Element autoSaveElem = root.getChild( "autosave" ); final String autoSavePath = autoSaveElem.getChild( "location" ).getText(); final long autoSavePeriod = Integer.parseInt( autoSaveElem.getChild( "period" ).getText() ); BigWarpAutoSaver.setAutosaveOptions( this, autoSavePeriod, autoSavePath ); + // TODO check if is imported mask final Element maskSettings = root.getChild( "transform-mask" ); if ( maskSettings != null ) - transformMask.getRandomAccessible().fromXml( maskSettings ); + plateauTransformMask.getRandomAccessible().fromXml( maskSettings ); } else { diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index cc5f5c9e..bf28bbab 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -85,6 +85,7 @@ public class BigWarpActions public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; + public static final String MASK_IMPORT = "import mask"; public static final String MASK_SIZE_EDIT = "mask edit"; public static final String MASK_VIS_TOGGLE = "mask vis toggle"; @@ -92,8 +93,8 @@ public class BigWarpActions public static final String SAVE_WARPED_XML = "save warped xml"; public static final String EXPORT_IP = "export imageplus"; - public static final String EXPORT_WARP = "export warp field"; - public static final String EXPORT_AFFINE = "export affine"; + public static final String EXPORT_WARP = "export warp field"; + public static final String EXPORT_AFFINE = "export affine"; public static final String WARP_TO_SELECTED_POINT = "warp to selected landmark"; public static final String WARP_TO_NEXT_POINT = "warp to next landmark %s"; @@ -133,7 +134,7 @@ public static void installActionBindings( inputActionBindings.addActionMap( "bwv", createActionMapViewer( bw ) ); inputActionBindings.addInputMap( "bwv", createInputMapViewer( keyProperties ) ); } - + public static void installLandmarkPanelActionBindings( final InputActionBindings inputActionBindings, final BigWarp< ? > bw, @@ -142,14 +143,14 @@ public static void installLandmarkPanelActionBindings( { inputActionBindings.addActionMap( "bw", createActionMap( bw ) ); inputActionBindings.addInputMap( "bw", createInputMap( keyProperties ) ); - - TableCellEditor celled = landmarkTable.getCellEditor( 0, 1 ); - Component c = celled.getTableCellEditorComponent(landmarkTable, Boolean.TRUE, true, 0, 1 ); - InputMap parentInputMap = ((JCheckBox)c).getInputMap().getParent(); + final TableCellEditor celled = landmarkTable.getCellEditor( 0, 1 ); + final Component c = celled.getTableCellEditorComponent(landmarkTable, Boolean.TRUE, true, 0, 1 ); + + final InputMap parentInputMap = ((JCheckBox)c).getInputMap().getParent(); parentInputMap.clear(); - KeyStroke enterDownKS = KeyStroke.getKeyStroke("pressed ENTER" ); - KeyStroke enterUpKS = KeyStroke.getKeyStroke("released ENTER" ); + final KeyStroke enterDownKS = KeyStroke.getKeyStroke("pressed ENTER" ); + final KeyStroke enterUpKS = KeyStroke.getKeyStroke("released ENTER" ); parentInputMap.put( enterDownKS, "pressed" ); parentInputMap.put( enterUpKS, "released" ); @@ -161,11 +162,11 @@ public static InputMap createInputMapViewer( final KeyStrokeAdder.Factory keyPro final KeyStrokeAdder map = keyProperties.keyStrokeAdder( inputMap ); map.put(RESET_VIEWER, "R"); - + map.put( String.format( VISIBILITY_AND_GROUPING, "moving" ), "F3" ); map.put( String.format( VISIBILITY_AND_GROUPING, "target" ), "F4" ); map.put( TRANSFORM_TYPE, "F2" ); - + map.put( String.format( ALIGN_VIEW_TRANSFORMS, AlignViewerPanelAction.TYPE.OTHER_TO_ACTIVE ), "Q" ); map.put( String.format( ALIGN_VIEW_TRANSFORMS, AlignViewerPanelAction.TYPE.ACTIVE_TO_OTHER ), "W" ); @@ -337,6 +338,7 @@ public static ActionMap createActionMap( final BigWarp< ? > bw ) // MASK new MaskSizeEdit( bw ).put(actionMap); new MaskVisToggle( bw ).put(actionMap); + new MaskImport( bw ).put(actionMap); for( int i = 0; i < bw.baseXfmList.length; i++ ){ final AbstractModel xfm = bw.baseXfmList[ i ]; @@ -368,7 +370,7 @@ public UndoRedoAction( final String name, BigWarp< ? > bw ) { super( name ); this.bw = bw; - + isRedo = false; if ( name.equals( REDO ) ) @@ -388,7 +390,7 @@ public void actionPerformed( ActionEvent e ) // I would love for this check to work instead of using a try-catch // bug it doesn't seem to be consistent // if( isRedo && manager.canRedo() ){ - try { + try { if( isRedo ) { @@ -413,7 +415,7 @@ public void actionPerformed( ActionEvent e ) // repaint this.bw.getLandmarkPanel().repaint(); } - catch( Exception ex ) + catch( final Exception ex ) { if( isRedo ) { @@ -472,7 +474,7 @@ public void actionPerformed( ActionEvent e ) } } - public static class ToggleAlwaysEstimateTransformAction extends AbstractNamedAction + public static class ToggleAlwaysEstimateTransformAction extends AbstractNamedAction { private static final long serialVersionUID = 2909830484701853577L; @@ -491,7 +493,7 @@ public void actionPerformed( ActionEvent e ) } } - public static class GarbageCollectionAction extends AbstractNamedAction + public static class GarbageCollectionAction extends AbstractNamedAction { private static final long serialVersionUID = -4487441057212703143L; @@ -507,13 +509,13 @@ public void actionPerformed( ActionEvent e ) System.gc(); } } - + public static class PrintTransformAction extends AbstractNamedAction { private static final long serialVersionUID = 6065343788485350279L; private BigWarp< ? > bw; - + public PrintTransformAction( final String name, final BigWarp< ? > bw ) { super( name ); @@ -551,8 +553,8 @@ public void actionPerformed( ActionEvent e ) // System.out.println( ltm.getChangedSinceWarp() ); // System.out.println( ltm.getWarpedPoints() ); // ltm.printWarpedPoints(); - - AffineTransform3D xfm = new AffineTransform3D(); + + final AffineTransform3D xfm = new AffineTransform3D(); bw.viewerP.state().getViewerTransform( xfm ); System.out.println( "mvg xfm " + xfm + " DET = " + BigWarpUtils.det( xfm )); @@ -575,7 +577,7 @@ public void actionPerformed( ActionEvent e ) // System.out.println( " " ); } } - + public static class EstimateWarpAction extends AbstractNamedAction { private static final long serialVersionUID = -210012348709096037L; @@ -594,13 +596,13 @@ public void actionPerformed( ActionEvent e ) bw.restimateTransformation(); } } - + public static class ToggleMovingImageDisplayAction extends AbstractNamedAction { private static final long serialVersionUID = 6495981071796613953L; - + private BigWarp< ? > bw; - + public ToggleMovingImageDisplayAction( final String name, final BigWarp< ? > bw ) { super( name ); @@ -613,7 +615,7 @@ public void actionPerformed( ActionEvent e ) bw.toggleMovingImageDisplay(); } } - + public static class TogglePointNameVisibleAction extends AbstractNamedAction { private static final long serialVersionUID = 2639535533224809586L; @@ -629,7 +631,7 @@ public TogglePointNameVisibleAction( final String name, final BigWarp< ? > bw ) @Override public void actionPerformed( ActionEvent e ) { - bw.toggleNameVisibility(); + bw.toggleNameVisibility(); } } @@ -661,7 +663,7 @@ public static class TogglePointsVisibleAction extends AbstractNamedAction { private static final long serialVersionUID = 8747830204501341125L; private BigWarp< ? > bw; - + public TogglePointsVisibleAction( final String name, final BigWarp< ? > bw ) { super( name ); @@ -671,45 +673,45 @@ public TogglePointsVisibleAction( final String name, final BigWarp< ? > bw ) @Override public void actionPerformed( ActionEvent e ) { - bw.togglePointVisibility(); + bw.togglePointVisibility(); } } - + public static class ResetActiveViewerAction extends AbstractNamedAction { private static final long serialVersionUID = -130575800163574517L; - + private BigWarp< ? > bw; - + public ResetActiveViewerAction( final BigWarp< ? > bw ) { super( String.format( RESET_VIEWER ) ); this.bw = bw; } - + @Override public void actionPerformed( ActionEvent e ) { bw.resetView(); } } - + public static class AlignViewerPanelAction extends AbstractNamedAction { private static final long serialVersionUID = -7023242695323421450L; - + public enum TYPE { ACTIVE_TO_OTHER, OTHER_TO_ACTIVE } private BigWarp< ? >bw; private TYPE type; - + public AlignViewerPanelAction( final BigWarp< ? > bw, TYPE type ) { super( String.format( ALIGN_VIEW_TRANSFORMS, type ) ); this.bw = bw; this.type = type; } - + @Override public void actionPerformed( ActionEvent e ) { @@ -723,10 +725,10 @@ public void actionPerformed( ActionEvent e ) public static class SetWarpMagBaseAction extends AbstractNamedAction { private static final long serialVersionUID = 7370813069619338918L; - + private BigWarp< ? > bw; private int i; - + public SetWarpMagBaseAction( final String name, final BigWarp< ? > bw, int i ) { super( name ); @@ -740,14 +742,14 @@ public void actionPerformed( ActionEvent e ) bw.setWarpMagBaselineIndex( i ); } } - + public static class SetWarpVisGridTypeAction extends AbstractNamedAction { private static final long serialVersionUID = 7370813069619338918L; - + private final BigWarp< ? > bw; private final GridSource.GRID_TYPE type; - + public SetWarpVisGridTypeAction( final String name, final BigWarp< ? > bw, final GridSource.GRID_TYPE type ) { super( name ); @@ -761,20 +763,20 @@ public void actionPerformed( ActionEvent e ) bw.setWarpVisGridType( type ); } } - + public static class SetWarpVisTypeAction extends AbstractNamedAction { private static final long serialVersionUID = 7370813069619338918L; - + private BigWarp< ? > bw; private BigWarpViewerFrame p; private BigWarp.WarpVisType type; - + public SetWarpVisTypeAction( final BigWarp.WarpVisType type, final BigWarp< ? > bw ) { this( type, bw, null ); } - + public SetWarpVisTypeAction( final BigWarp.WarpVisType type, final BigWarp< ? > bw, BigWarpViewerFrame p ) { super( getName( type, p )); @@ -791,7 +793,7 @@ public void actionPerformed( ActionEvent e ) else bw.setWarpVisMode( type, p, false ); } - + public static String getName( final BigWarp.WarpVisType type, BigWarpViewerFrame p ) { if( p == null ) @@ -802,7 +804,7 @@ else if( p.isMoving() ) return String.format( SET_WARPTYPE_VIS_Q, type.name() ); } } - + public static class TableSelectionAction extends AbstractNamedAction { private static final long serialVersionUID = -4647679094757721276L; @@ -972,7 +974,7 @@ public WarpToSelectedAction( final BigWarp< ? > bw ) @Override public void actionPerformed( ActionEvent e ) { - int[] selectedRows = bw.getLandmarkPanel().getJTable().getSelectedRows(); + final int[] selectedRows = bw.getLandmarkPanel().getJTable().getSelectedRows(); int row = 0; if( selectedRows.length > 0 ) @@ -1025,7 +1027,7 @@ public WarpToNextAction( final BigWarp< ? > bw, boolean fwd ) @Override public void actionPerformed( ActionEvent e ) { - int[] selectedRows = bw.getLandmarkPanel().getJTable().getSelectedRows(); + final int[] selectedRows = bw.getLandmarkPanel().getJTable().getSelectedRows(); int row = 0; if( selectedRows.length > 0 ) @@ -1118,7 +1120,7 @@ public void actionPerformed(ActionEvent e) bw.exportAsImagePlus( false ); } } - + public static class ExportWarpAction extends AbstractNamedAction { private static final long serialVersionUID = 4626378501415886468L; @@ -1242,4 +1244,22 @@ public void actionPerformed(ActionEvent e) } } + public static class MaskImport extends AbstractNamedAction + { + private static final long serialVersionUID = 493457851797644046L; + private final BigWarp< ? > bw; + + public MaskImport( final BigWarp< ? > bw ) + { + super( MASK_IMPORT ); + this.bw = bw; + } + + @Override + public void actionPerformed(ActionEvent e) + { + bw.importTransformMaskSource(""); + } + } + } diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index fca47338..5eb71076 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -30,7 +30,7 @@ public static void write(LandmarkTableModel ltm, BigWarpTransform bwTransform, F final Writer writer = Channels.newWriter(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); BigwarpSettings.gson.toJson(transformObj, writer); writer.flush(); - } catch (IOException e) { + } catch (final IOException e) { e.printStackTrace(); } } @@ -42,11 +42,11 @@ public static void read( final File f, final BigWarp bw ) final Path path = Paths.get(f.getCanonicalPath()); final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; final Reader reader = Channels.newReader(FileChannel.open(path, options), StandardCharsets.UTF_8.name()); - JsonObject json = BigwarpSettings.gson.fromJson( reader, JsonObject.class ); + final JsonObject json = BigwarpSettings.gson.fromJson( reader, JsonObject.class ); read( bw, json ); - } catch ( IOException e ) + } catch ( final IOException e ) { // TODO Auto-generated catch block e.printStackTrace(); @@ -55,14 +55,14 @@ public static void read( final File f, final BigWarp bw ) public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransform) { - JsonObject transformObj = new JsonObject(); + final JsonObject transformObj = new JsonObject(); transformObj.addProperty("type", bwTransform.getTransformType() ); transformObj.addProperty("maskInterpolationType", bwTransform.getMaskInterpolationType() ); transformObj.add("landmarks", ltm.toJson()); if( bwTransform.isMasked() ) { - PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); + final PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); transformObj.add("mask", BigwarpSettings.gson.toJsonTree( mask )); } @@ -79,10 +79,10 @@ public static void read( final BigWarp< ? > bw, final JsonObject json ) if( json.has( "mask" )) { - JsonObject maskParams = json.get("mask").getAsJsonObject(); + final JsonObject maskParams = json.get("mask").getAsJsonObject(); final PlateauSphericalMaskRealRandomAccessible maskFromJson = BigwarpSettings.gson.fromJson( maskParams, PlateauSphericalMaskRealRandomAccessible.class ); - final PlateauSphericalMaskRealRandomAccessible mask = bw.getTransformMaskSource().getRandomAccessible(); + final PlateauSphericalMaskRealRandomAccessible mask = bw.getTransformPlateauMaskSource().getRandomAccessible(); mask.setFalloffShape( maskFromJson.getFallOffShape() ); mask.setSquaredRadius( maskFromJson.getSquaredRadius() ); mask.setCenter( maskFromJson.getCenter() ); From 076759a3fcdc407dde100b1686d3fb396c473bfa Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 7 Sep 2023 11:35:09 -0400 Subject: [PATCH 208/282] fix: BigWarpCommand uses DatasetService --- src/main/java/bdv/ij/BigWarpCommand.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/bdv/ij/BigWarpCommand.java b/src/main/java/bdv/ij/BigWarpCommand.java index 4d45afbc..6dab575c 100644 --- a/src/main/java/bdv/ij/BigWarpCommand.java +++ b/src/main/java/bdv/ij/BigWarpCommand.java @@ -10,12 +10,16 @@ import ij.Macro; import ij.plugin.PlugIn; import ij.plugin.frame.Recorder; +import net.imagej.DatasetService; @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp Command" ) public class BigWarpCommand implements Command, PlugIn { private boolean initialRecorderState; + @Parameter + private DatasetService datasetService; + public BigWarpCommand() { initialRecorderState = Recorder.record; @@ -36,7 +40,7 @@ public void run( String args ) BigWarpInitDialog.runMacro( macroOptions ); else { - final BigWarpInitDialog dialog = BigWarpInitDialog.createAndShow( null ); + final BigWarpInitDialog dialog = BigWarpInitDialog.createAndShow( datasetService ); // dialog sets recorder to its initial state on cancel or execution dialog.setInitialRecorderState( initialRecorderState ); } From 0f258c9658e05c58185b9ec2a8bb74a0f879238a Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 7 Sep 2023 11:59:27 -0400 Subject: [PATCH 209/282] fix: BigWarpCommand enable passing of landmarks --- src/main/java/bdv/gui/BigWarpInitDialog.java | 30 +++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 37ace954..20bc5eda 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -102,7 +102,7 @@ public class BigWarpInitDialog extends JFrame public static final String ImageJPrefix = "imagej://"; - private String projectPath; + private String projectLandmarkPath; private String imageList; private String movingList; private String transformList; @@ -186,10 +186,12 @@ public static void main( final String[] args ) throws IOException createAndShow(); } - public static void runBigWarp( final String projectPath, final String[] images, final String[] moving, final String[] transforms ) + public static void runBigWarp( final String projectLandmarkPath, final String[] images, final String[] moving, final String[] transforms ) { final BigWarpData< T > data = BigWarpInit.initData(); - final boolean haveProject = projectPath != null && !projectPath.isEmpty(); + final boolean haveProjectLandmarkArg = projectLandmarkPath != null && !projectLandmarkPath.isEmpty(); + final boolean haveProject = haveProjectLandmarkArg && projectLandmarkPath.endsWith(".json"); + final boolean haveLandmarks = haveProjectLandmarkArg && projectLandmarkPath.endsWith(".csv"); final int nThreads = IJ.getInstance() != null ? Prefs.getThreads() : 1; final BigWarpViewerOptions bwOpts = ( BigWarpViewerOptions ) BigWarpViewerOptions.options().numRenderingThreads( nThreads ); @@ -236,9 +238,9 @@ public static void runBigWarp( final String projectPath, final String[] imag data.applyTransformations(); bw = new BigWarp<>( data, bwOpts, new ProgressWriterIJ() ); if( haveProject ) - { - bw.loadSettings( projectPath, true ); - } + bw.loadSettings( projectLandmarkPath, true ); + else if( haveLandmarks ) + bw.loadLandmarks(projectLandmarkPath); } catch ( final SpimDataException e ) { @@ -265,7 +267,11 @@ public void runBigWarp() } final BigWarpData< T > data = BigWarpInit.initData(); - final boolean haveProject = projectPath != null && !projectPath.isEmpty(); + + projectLandmarkPath = projectLandmarkPath == null ? projectPathTxt.getText() : projectLandmarkPath; + final boolean haveProjectLandmarkArg = projectLandmarkPath != null && !projectLandmarkPath.isEmpty(); + final boolean haveProject = haveProjectLandmarkArg && projectLandmarkPath.endsWith(".json"); + final boolean haveLandmarks = haveProjectLandmarkArg && projectLandmarkPath.endsWith(".csv"); if( !haveProject ) { @@ -322,7 +328,9 @@ else if( tableRow.type.equals( SourceType.DATASET )) data.applyTransformations(); bw = new BigWarp<>( data, new ProgressWriterIJ() ); if( haveProject ) - bw.loadSettings( projectPath, true ); + bw.loadSettings( projectLandmarkPath, true ); + else if( haveLandmarks ) + bw.loadLandmarks(projectLandmarkPath); } catch ( final SpimDataException e ) { @@ -360,7 +368,7 @@ public JPanel createContent() ctxt.anchor = GridBagConstraints.LINE_END; ctxt.fill = GridBagConstraints.NONE; ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); - panel.add( new JLabel("Open BigWarp project:"), ctxt ); + panel.add( new JLabel("BigWarp project or landmarks:"), ctxt ); final GridBagConstraints gbcBar = new GridBagConstraints(); gbcBar.gridx = 1; @@ -815,8 +823,8 @@ private String browseTransformDialog() return s; } - public void setParameters( final String projectPath, final String images, final String moving, final String transforms ) { - this.projectPath = projectPath; + public void setParameters( final String projectLandmarkPath, final String images, final String moving, final String transforms ) { + this.projectLandmarkPath = projectLandmarkPath; this.imageList = images; this.movingList = moving; this.transformList = transforms; From 9ab596daf79f4aef999cc17ec4f5a766e690d84d Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 19 Sep 2023 14:03:32 -0400 Subject: [PATCH 210/282] fix: changeDimensionality * loading a 2d project on an empty bigwarp now behaves better --- .../java/bdv/gui/BigWarpLandmarkPanel.java | 39 +++--- .../bdv/gui/TransformTypeSelectDialog.java | 16 +-- src/main/java/bdv/viewer/BigWarpOverlay.java | 111 ++++++++---------- src/main/java/bigwarp/BigWarp.java | 17 ++- src/main/java/bigwarp/BigwarpSettings.java | 14 +-- 5 files changed, 102 insertions(+), 95 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpLandmarkPanel.java b/src/main/java/bdv/gui/BigWarpLandmarkPanel.java index 1750004f..1cfcc96b 100644 --- a/src/main/java/bdv/gui/BigWarpLandmarkPanel.java +++ b/src/main/java/bdv/gui/BigWarpLandmarkPanel.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -45,23 +45,23 @@ import bigwarp.landmarks.LandmarkTableModel; public class BigWarpLandmarkPanel extends JPanel { - + private static final long serialVersionUID = 8470689265638231579L; protected LandmarkTableModel tableModel; protected JTable table; - + public final Logger logger = LoggerFactory.getLogger( BigWarpLandmarkPanel.class ); public BigWarpLandmarkPanel( LandmarkTableModel tableModel ) { - + super(new GridLayout(1,0)); setTableModel( tableModel ); - + genJTable(); - + //Create the scroll pane and add the table to it. - JScrollPane scrollPane = new JScrollPane(table); + final JScrollPane scrollPane = new JScrollPane(table); //Add the scroll pane to this panel. add(scrollPane); @@ -70,7 +70,11 @@ public BigWarpLandmarkPanel( LandmarkTableModel tableModel ) { public LandmarkTableModel getTableModel() { return tableModel; } - + + public int numDimensions() { + return tableModel.getNumdims(); + } + public void genJTable() { table = new JTableChecking( getTableModel() ); @@ -93,7 +97,7 @@ public void genJTable() /* * Add a listener to update the next row the tableModel will edit * based on the selected row. - * + * * Specifically, when the user changes the selected row of the table, the * listener checks whether any of those rows are "incomplete." * If so, the first row in the selection that does not have a moving image @@ -108,7 +112,7 @@ public void valueChanged( ListSelectionEvent e ) logger.trace( "table selection changed" ); boolean setMoving = false; boolean setFixed = false; - int row = table.getSelectedRow(); + final int row = table.getSelectedRow(); // if no rows are selected, the next edit should add a new row if( row < 0 ) @@ -137,18 +141,18 @@ public void valueChanged( ListSelectionEvent e ) } }); } - + public void setTableModel( LandmarkTableModel tableModel ) { this.tableModel = tableModel; genJTable(); } - + public JTable getJTable() { return table; } - + /** * A JTable implementation that prevents keybindings from being propagated * while editing cells. This prevents hotkeys from being activated. @@ -163,6 +167,7 @@ public JTableChecking( AbstractTableModel tableModel ) super( tableModel ); } + @Override protected boolean processKeyBinding( KeyStroke ks, KeyEvent e, int condition, boolean pressed ) @@ -196,7 +201,7 @@ public void focusGained( FocusEvent e ) @Override public void focusLost( FocusEvent e ) { - CellEditor cellEditor = table.getCellEditor(); + final CellEditor cellEditor = table.getCellEditor(); if ( cellEditor != null ) { if ( cellEditor.getCellEditorValue() != null ) @@ -240,7 +245,7 @@ public boolean stopCellEditing() public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected, int row, int column ) { - TextFieldCell tf = (TextFieldCell) super.getTableCellEditorComponent( table, + final TextFieldCell tf = (TextFieldCell) super.getTableCellEditorComponent( table, value, isSelected, row, column ); if ( value != null ) { @@ -268,7 +273,7 @@ else if (columnClass.equals(Byte.class)) else if (columnClass.equals(String.class)) return textField.getText(); } - catch (NumberFormatException ex) { + catch (final NumberFormatException ex) { } diff --git a/src/main/java/bdv/gui/TransformTypeSelectDialog.java b/src/main/java/bdv/gui/TransformTypeSelectDialog.java index 7e2001d2..c662b450 100644 --- a/src/main/java/bdv/gui/TransformTypeSelectDialog.java +++ b/src/main/java/bdv/gui/TransformTypeSelectDialog.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -39,7 +39,7 @@ public class TransformTypeSelectDialog extends JDialog { private static final long serialVersionUID = 1L; - + @Deprecated public static final String TPS = "Thin Plate Spline"; @Deprecated @@ -70,7 +70,7 @@ public class TransformTypeSelectDialog extends JDialog /** * Instantiates and displays a JFrame that enables * the selection of the transformation type. - * + * * @param owner the parent frame * @param bw a bigwarp instance */ @@ -88,7 +88,7 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) similarityButton = new JRadioButton( BigWarpTransform.SIMILARITY ); rotationButton = new JRadioButton( BigWarpTransform.ROTATION ); translationButton = new JRadioButton( BigWarpTransform.TRANSLATION ); - + group = new ButtonGroup(); group.add( tpsButton ); group.add( affineButton ); @@ -104,13 +104,13 @@ public TransformTypeSelectDialog( final Frame owner, final BigWarp< ? > bw ) addActionListender( rotationButton ); addActionListender( translationButton ); - JPanel radioPanel = new JPanel( new GridLayout(0, 1)); + final JPanel radioPanel = new JPanel( new GridLayout(0, 1)); radioPanel.add( tpsButton ); radioPanel.add( affineButton ); radioPanel.add( similarityButton ); radioPanel.add( rotationButton ); radioPanel.add( translationButton ); - + radioPanel.setBorder( BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), BorderFactory.createCompoundBorder( @@ -168,7 +168,7 @@ public void addFalloffActionListender( final JRadioButton button ) @Override public void actionPerformed( ActionEvent e ) { - bw.getTransformMaskSource().getRandomAccessible().setFalloffShape( button.getText() ); + bw.getTransformPlateauMaskSource().getRandomAccessible().setFalloffShape( button.getText() ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } diff --git a/src/main/java/bdv/viewer/BigWarpOverlay.java b/src/main/java/bdv/viewer/BigWarpOverlay.java index e1a573e4..2ab164aa 100644 --- a/src/main/java/bdv/viewer/BigWarpOverlay.java +++ b/src/main/java/bdv/viewer/BigWarpOverlay.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -40,76 +40,51 @@ public class BigWarpOverlay { private BigWarpViewerPanel viewer; - - protected JTable table; - protected LandmarkTableModel landmarkModel; + private BigWarpLandmarkPanel landmarkPanel; protected RealTransform estimatedXfm; - + protected boolean isTransformed = false; private int hoveredIndex; protected final boolean isMoving; - protected boolean is3d; - protected final double[] spot; protected final double[] viewerCoords; /** The transform for the viewer current viewpoint. */ private final AffineTransform3D transform = new AffineTransform3D(); - public BigWarpOverlay( final BigWarpViewerPanel viewer, BigWarpLandmarkPanel landmarkpanel ) + + public BigWarpOverlay( final BigWarpViewerPanel viewer, BigWarpLandmarkPanel landmarkPanel ) { this.viewer = viewer; - this.table = landmarkpanel.getJTable(); - this.landmarkModel = landmarkpanel.getTableModel(); - - if( landmarkModel.getNumdims() == 3 ) - is3d = true; - else - is3d = false; - + setLandmarkPanel(landmarkPanel); isMoving = viewer.getIsMoving(); spot = new double[ 3 ]; viewerCoords = new double[ 3 ]; } - public void is2D( final boolean is2d ) - { - this.is3d = !is2d; - } - - public int getHoveredIndex() { return hoveredIndex; } - public void setHoveredIndex( int hoveredIndex ) { this.hoveredIndex = hoveredIndex; } + public void setLandmarkPanel( final BigWarpLandmarkPanel landmarkPanel ) + { + this.landmarkPanel = landmarkPanel; + } public void paint( final Graphics2D g ) { - // Save graphic device original settings - final Composite originalComposite = g.getComposite(); - final Stroke originalStroke = g.getStroke(); - final Color originalColor = g.getColor(); - - // get selected points - int[] selectedRows = table.getSelectedRows(); - Arrays.sort( selectedRows ); - boolean[] isSelected = new boolean[ landmarkModel.getRowCount() ]; - for( int i : selectedRows ) - isSelected[ i ] = true; - /* * Draw spots. @@ -117,17 +92,34 @@ public void paint( final Graphics2D g ) if ( viewer.getSettings().areLandmarksVisible() ) { + final LandmarkTableModel landmarkModel = landmarkPanel.getTableModel(); + final JTable table = landmarkPanel.getJTable(); + final boolean is3d = landmarkPanel.numDimensions() == 3; + + // Save graphic device original settings + final Composite originalComposite = g.getComposite(); + final Stroke originalStroke = g.getStroke(); + final Color originalColor = g.getColor(); + + // get selected points + final int[] selectedRows = table.getSelectedRows(); + Arrays.sort( selectedRows ); + final boolean[] isSelected = new boolean[ landmarkModel.getRowCount() ]; + for( final int i : selectedRows ) + isSelected[ i ] = true; + + final BasicStroke hlStroke = new BasicStroke( (int)viewer.getSettings().strokeWeight ); - final BasicStroke selStroke = new BasicStroke( (int)viewer.getSettings().strokeWeight / 2 ); + // final BasicStroke selStroke = new BasicStroke( (int)viewer.getSettings().strokeWeight / 2 ); - final double radiusRatio = ( Double ) viewer.getSettings().get( + final double radiusRatio = ( Double ) viewer.getSettings().get( BigWarpViewerSettings.KEY_SPOT_RADIUS_RATIO ); - + final double radius = viewer.getSettings().getSpotSize(); Stroke stroke; stroke = BigWarpViewerSettings.NORMAL_STROKE; - + FontMetrics fm = null; Font font = null; int fonthgt = 0; @@ -149,7 +141,7 @@ public void paint( final Graphics2D g ) textBoxColorHl = new Color( color.getRed(), color.getGreen(), color.getBlue(), 255 ); textBoxColor = new Color( color.getRed(), color.getGreen(), color.getBlue(), 128 ); - } final Color desaturatedColor = null; + } final int nRows = landmarkModel.getRowCount(); for( int index = 0; index < nRows; index++ ) @@ -201,13 +193,13 @@ public void paint( final Graphics2D g ) else arad = rad; - double srad = arad + strokeW; + final double srad = arad + strokeW; // vary size - g.fillOval( ( int ) ( viewerCoords[ 0 ] - arad ), - ( int ) ( viewerCoords[ 1 ] - arad ), + g.fillOval( ( int ) ( viewerCoords[ 0 ] - arad ), + ( int ) ( viewerCoords[ 1 ] - arad ), ( int ) ( 2 * arad + 1 ), ( int ) ( 2 * arad + 1) ); - + if( isSelected[ index ] ) { g.setStroke( hlStroke ); @@ -234,30 +226,31 @@ public void paint( final Graphics2D g ) { final int tx = ( int ) ( viewerCoords[ 0 ] + arad + 5 ); final int ty = ( int ) viewerCoords[ 1 ]; - - String name = landmarkModel.getNames().get(index); - int strwidth = fm.stringWidth( name ); - + + final String name = landmarkModel.getNames().get(index); + final int strwidth = fm.stringWidth( name ); + if( hoveredIndex == index ) g.setColor( textBoxColorHl ); else g.setColor( textBoxColor ); - + g.fillRect( tx - 1, ty - fonthgt + 2, strwidth + 2, fonthgt); - + g.setColor( Color.BLACK ); g.setFont( font ); g.drawString( name, tx, ty ); - + } } } + + // Restore graphic device original settings + g.setComposite( originalComposite ); + g.setStroke( originalStroke ); + g.setColor( originalColor ); } - // Restore graphic device original settings - g.setComposite( originalComposite ); - g.setStroke( originalStroke ); - g.setColor( originalColor ); } @@ -272,17 +265,17 @@ public void setViewerState( final ViewerState state ) */ state.getViewerTransform( transform ); } - + public void setEstimatedTransform( final RealTransform estimatedXfm ) { this.estimatedXfm = estimatedXfm; } - + public boolean getIsTransformed() { return isTransformed; } - + public void setIsTransformed( boolean isTransformed ) { this.isTransformed = isTransformed; diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 97fe9c24..26455242 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -614,6 +614,7 @@ public void changeDimensionality(boolean is2D) { landmarkModel.setMessage( message ); landmarkPanel.setTableModel(landmarkModel); + setupLandmarkFrame(); setupWarpMagBaselineOptions( baseXfmList, ndims ); @@ -669,8 +670,8 @@ public void changeDimensionality(boolean is2D) { viewerP.setNumDim( ndims ); viewerQ.setNumDim( ndims ); - overlayP.is2D( options.values.is2D() ); - overlayQ.is2D( options.values.is2D() ); +// overlayP.is2D( options.values.is2D() ); +// overlayQ.is2D( options.values.is2D() ); bwTransform = new BigWarpTransform( landmarkModel ); bwTransform.initializeInverseParameters(data); @@ -802,6 +803,12 @@ protected void setupLandmarkFrame() addDefaultTableMouseListener(); landmarkFrame = new BigWarpLandmarkFrame( "Landmarks", landmarkPanel, this ); + if( overlayP != null ) + overlayP.setLandmarkPanel(landmarkPanel); + + if( overlayQ != null ) + overlayQ.setLandmarkPanel(landmarkPanel); + if ( loc != null ) landmarkFrame.setLocation( loc ); @@ -2226,7 +2233,7 @@ public void updateTransformMask() getViewerFrameQ().getViewerPanel().requestRepaint(); } - @SuppressWarnings( { "unchecked", "rawtypes" } ) + @SuppressWarnings( { "unchecked" } ) public void importTransformMaskSource( final String uri ) { URI encodedUri; @@ -2809,6 +2816,10 @@ protected int detectNumDims() */ public static int detectNumDims( List< SourceAndConverter< T > > sources ) { + // default to 3D if bigwarp is opened without any sources + if( sources.size() == 0 ) + return 3; + boolean isAnySource3d = false; for ( final SourceAndConverter< T > sac : sources ) { diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 93c11e22..4dfdcce1 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -177,7 +177,6 @@ public BigwarpSettings read( final JsonReader in ) throws IOException in.endObject(); final boolean is2D = BigWarp.detectNumDims(bigWarp.getSources()) == 2; if (is2D != bigWarp.options.values.is2D()) { - bigWarp.options.is2D( is2D ); bigWarp.changeDimensionality( is2D ); } return this; @@ -204,14 +203,14 @@ public void write( final JsonWriter out, final Map< Integer, SourceInfo > value /* We only want the lowest setupId with the same url*/ - for ( Map.Entry< Integer, SourceInfo > entry : value.entrySet() ) + for ( final Map.Entry< Integer, SourceInfo > entry : value.entrySet() ) { if ( !entry.getValue().isSerializable() ) continue; - SourceInfo sourceInfo = entry.getValue(); - int id = sourceInfo.getId(); - URI uriObj; + final SourceInfo sourceInfo = entry.getValue(); + final int id = sourceInfo.getId(); + final URI uriObj; String uri = sourceInfo.getUri(); final String name = sourceInfo.getName(); out.name( "" + id ); @@ -241,7 +240,7 @@ public Map< Integer, SourceInfo > read( final JsonReader in ) throws IOException while ( in.hasNext() ) { //TODO Caleb: What to do if `data` alrread has a source for this `id`? - int id = Integer.parseInt( in.nextName() ); + final int id = Integer.parseInt( in.nextName() ); in.beginObject(); String uri = null; String name = null; @@ -439,7 +438,6 @@ private void readGroups( final JsonReader in ) throws IOException final SynchronizedViewerState state = panel.state(); state.setGroupsActive( state.getActiveGroups(), false ); state.removeGroups( state.getGroups() ); - int i = 0; while ( in.hasNext() ) { in.beginObject(); @@ -677,7 +675,7 @@ public List< MinMaxGroup > read( final JsonReader in ) throws IOException in.beginObject(); while ( in.hasNext() ) { - int id = Integer.parseInt( in.nextName() ); + final int id = Integer.parseInt( in.nextName() ); double fullRangeMin = 0; double fullRangeMax = 0; double rangeMin = 0; From ed9f05a65a724fd2bf006ada958691fcdd6ffff9 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 19 Sep 2023 14:04:40 -0400 Subject: [PATCH 211/282] fix: loading 2D Datasets --- src/main/java/bigwarp/BigWarpInit.java | 70 ++++++++++++++++---------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 64482286..216a312b 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -99,6 +99,7 @@ import net.imglib2.type.numeric.integer.UnsignedIntType; import net.imglib2.type.volatiles.VolatileARGBType; import net.imglib2.util.Util; +import net.imglib2.view.IntervalView; import net.imglib2.view.Views; public class BigWarpInit @@ -187,7 +188,7 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > @SuppressWarnings( { "rawtypes", "unchecked" } ) public static BigWarpData< ? > createBigWarpData( final Source< ? >[] movingSourceList, final Source< ? >[] fixedSourceList, final String[] names ) { - BigWarpData data = initData(); + final BigWarpData data = initData(); int nameIdx = 0; int setupId = 0; // moving @@ -248,11 +249,11 @@ public static < T > int add( BigWarpData< T > bwdata, ImagePlus ip, int setupId, public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigWarpData< T > bwdata, ImagePlus ip, int setupId, int numTimepoints, boolean isMoving ) { - ImagePlusLoader loader = new ImagePlusLoader( ip ); - SpimDataMinimal[] dataList = loader.loadAll( setupId ); + final ImagePlusLoader loader = new ImagePlusLoader( ip ); + final SpimDataMinimal[] dataList = loader.loadAll( setupId ); final LinkedHashMap< Source< T >, SourceInfo > sourceInfoMap = new LinkedHashMap<>(); - for ( SpimDataMinimal data : dataList ) + for ( final SpimDataMinimal data : dataList ) { final LinkedHashMap< Source< T >, SourceInfo > map = createSources( bwdata, data, setupId, isMoving ); sourceInfoMap.putAll( map ); @@ -359,12 +360,22 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW boolean first = true; final LinkedHashMap< Source< T >, SourceInfo > sourceInfoMap = new LinkedHashMap<>(); - AffineTransform3D res = datasetResolution( data ); + final AffineTransform3D res = datasetResolution( data ); final long nc = data.getChannels(); + boolean hasZ = false; + + final CalibratedAxis[] axes = new CalibratedAxis[ data.numDimensions() ]; + data.axes( axes ); + for (int i = 0; i < data.numDimensions(); i++) { + if (axes[i].type().equals(Axes.Z)) + { + hasZ = true; + break; + } + } + if ( nc > 1 ) { - CalibratedAxis[] axes = new CalibratedAxis[ data.numDimensions() ]; - data.axes( axes ); int channelIdx = -1; for ( int i = 0; i < data.numDimensions(); i++ ) { @@ -377,8 +388,11 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW for ( int c = 0; c < nc; c++ ) { + final IntervalView> channelRaw = Views.hyperSlice( data, channelIdx, c ); + final IntervalView> channel = hasZ ? channelRaw : Views.addDimension( channelRaw, 0, 0 ); + @SuppressWarnings( "unchecked" ) - RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( Views.hyperSlice( data, channelIdx, c ), Util.getTypeFromInterval( data ), res, data.getName() ); + final RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( channel, Util.getTypeFromInterval( data ), res, data.getName() ); final SourceInfo info = new SourceInfo( baseId + c, isMoving, data.getName(), () -> data.getSource() ); info.setSerializable( first ); @@ -390,8 +404,10 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW } else { + final RandomAccessibleInterval> img = hasZ ? data : Views.addDimension( data, 0, 0 ); + @SuppressWarnings( "unchecked" ) - RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( data, Util.getTypeFromInterval( data ), res, data.getName() ); + final RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( img, Util.getTypeFromInterval( data ), res, data.getName() ); final SourceInfo info = new SourceInfo( baseId, isMoving, data.getName(), () -> data.getSource() ); info.setSerializable( true ); @@ -428,7 +444,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW final LinkedHashMap< Source< T >, SourceInfo > sourceInfoMap = new LinkedHashMap<>(); int setupId = baseId; - for ( SourceAndConverter sac : tmpSources ) + for ( final SourceAndConverter sac : tmpSources ) { final Source< T > source = sac.getSpimSource(); sourceInfoMap.put( source, new SourceInfo( setupId++, isMoving, source.getName() ) ); @@ -452,11 +468,11 @@ private static String schemeSpecificPartWithoutQuery( URI uri ) public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( final BigWarpData< T > bwData, String uri, int setupId, boolean isMoving ) throws URISyntaxException, IOException, SpimDataException { - URI encodedUri = N5URI.encodeAsUri( uri ); + final URI encodedUri = N5URI.encodeAsUri( uri ); final LinkedHashMap< Source< T >, SourceInfo > sourceStateMap = new LinkedHashMap<>(); if ( encodedUri.isOpaque() ) { - N5URI n5URL = new N5URI( encodedUri.getSchemeSpecificPart() ); + final N5URI n5URL = new N5URI( encodedUri.getSchemeSpecificPart() ); final String firstScheme = encodedUri.getScheme().toLowerCase(); final N5Reader n5reader; switch ( firstScheme ) @@ -490,7 +506,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina final Source< T > source = loadN5Source( n5reader, group ); sourceStateMap.put( source, new SourceInfo( setupId, isMoving, group ) ); } - catch ( Exception ignored ) + catch ( final Exception ignored ) {} if ( sourceStateMap.isEmpty() ) { @@ -581,7 +597,7 @@ private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fin { return spimData.getBasePath().getCanonicalPath(); } - catch ( IOException e ) + catch ( final IOException e ) { return null; } @@ -596,7 +612,7 @@ private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fin } return sources; } - catch ( SpimDataException e ) + catch ( final SpimDataException e ) { e.printStackTrace(); } @@ -907,8 +923,8 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source final int numMovingSources = seqP.getViewSetups().size(); final int numTargetSources = seqQ.getViewSetups().size(); - int[] movingSourceIndices = ImagePlusLoader.range( 0, numMovingSources ); - int[] targetSourceIndices = ImagePlusLoader.range( numMovingSources, numTargetSources ); + final int[] movingSourceIndices = ImagePlusLoader.range( 0, numMovingSources ); + final int[] targetSourceIndices = ImagePlusLoader.range( numMovingSources, numTargetSources ); // List movingSourceIndices = IntStream.range( 0, numMovingSources ).collect( Collectors.toList()); // List targetSourceIndices = IntStream.range( numMovingSources, numTargetSources + numMovingSources ) // .collect( Collectors.toList()); @@ -1034,15 +1050,15 @@ public static < T > BigWarpData< T > createBigWarpDataFromXML( final String xmlF BigWarpInit.add( bwdata, mvgSrcs ); BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, xmlFilenameQ, id, false ) ); } - catch ( URISyntaxException e ) + catch ( final URISyntaxException e ) { e.printStackTrace(); } - catch ( IOException e ) + catch ( final IOException e ) { e.printStackTrace(); } - catch ( SpimDataException e ) + catch ( final SpimDataException e ) { e.printStackTrace(); } @@ -1065,7 +1081,7 @@ public static < T > BigWarpData< T > createBigWarpDataFromImages( final ImagePlu int id = 0; final BigWarpData< T > bwdata = BigWarpInit.initData(); - LinkedHashMap< Source< T >, SourceInfo > mvgSrcs = BigWarpInit.createSources( bwdata, impP, id, 0, true ); + final LinkedHashMap< Source< T >, SourceInfo > mvgSrcs = BigWarpInit.createSources( bwdata, impP, id, 0, true ); id += mvgSrcs.size(); BigWarpInit.add( bwdata, mvgSrcs ); BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, impQ, id, 0, false ) ); @@ -1138,15 +1154,15 @@ public static < T > BigWarpData< T > createBigWarpDataFromXMLImagePlus( final St BigWarpInit.add( bwdata, mvgSrcs ); BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, impQ, id, 0, false ) ); } - catch ( URISyntaxException e ) + catch ( final URISyntaxException e ) { e.printStackTrace(); } - catch ( IOException e ) + catch ( final IOException e ) { e.printStackTrace(); } - catch ( SpimDataException e ) + catch ( final SpimDataException e ) { e.printStackTrace(); } @@ -1191,15 +1207,15 @@ public static < T > BigWarpData< T > createBigWarpDataFromImagePlusXML( final Im BigWarpInit.add( bwdata, mvgSrcs ); BigWarpInit.add( bwdata, BigWarpInit.createSources( bwdata, xmlFilenameQ, id, false ) ); } - catch ( URISyntaxException e ) + catch ( final URISyntaxException e ) { e.printStackTrace(); } - catch ( IOException e ) + catch ( final IOException e ) { e.printStackTrace(); } - catch ( SpimDataException e ) + catch ( final SpimDataException e ) { e.printStackTrace(); } From 89d4ecee3d2571f892809cff6503b7d1c8c64ec4 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 19 Sep 2023 14:07:49 -0400 Subject: [PATCH 212/282] feat: toward setting intensity range for imported mask --- src/main/java/bdv/gui/MaskOptionsPanel.java | 36 ++++- .../MaskBoundsRangePanel.java | 32 +++++ src/main/java/bigwarp/BigWarp.java | 10 ++ .../bigwarp/transforms/BigWarpTransform.java | 134 ++++++++++++------ .../MaskedSimRotTransformSolver.java | 25 ++-- .../transforms/MaskedTransformSolver.java | 14 +- 6 files changed, 190 insertions(+), 61 deletions(-) create mode 100644 src/main/java/bdv/ui/convertersetupeditor/MaskBoundsRangePanel.java diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index bf7b8105..b0806706 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -15,6 +15,8 @@ import javax.swing.JLabel; import javax.swing.JPanel; +import bdv.ui.convertersetupeditor.MaskBoundsRangePanel; + public class MaskOptionsPanel extends JPanel { private static final long serialVersionUID = -8614381106547838575L; @@ -26,7 +28,7 @@ public class MaskOptionsPanel extends JPanel + "in the mask transition region.\n" + "If your transformation has lots of rotation, try selecting \"ROTATION\" or \"SIMILARITY\"."; - public static final String[] maskTypes = new String[] { + public static final String[] maskTypes = new String[] { BigWarpTransform.NO_MASK_INTERP, BigWarpTransform.MASK_INTERP, BigWarpTransform.ROT_MASK_INTERP, @@ -44,6 +46,8 @@ public class MaskOptionsPanel extends JPanel private final JLabel maskTypeLabel; private final JComboBox< String > maskTypeDropdown; + private final MaskBoundsRangePanel maskRangePanel; + private ActionListener falloffListener; public MaskOptionsPanel( BigWarp bw ) @@ -58,7 +62,7 @@ public MaskOptionsPanel( BigWarp bw ) BorderFactory.createEtchedBorder(), "Mask options" ), BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - + autoEstimateMaskButton = new JCheckBox( "Auto-estimate mask", true ); autoEstimateMaskButton.setToolTipText( AUTO_ESTIMATE_HELP_TEXT ); @@ -76,6 +80,8 @@ public MaskOptionsPanel( BigWarp bw ) maskTypeDropdown = new JComboBox<>( maskTypes ); maskTypeDropdown.setToolTipText( INTERPOLATION_HELP_TEXT ); + maskRangePanel = new MaskBoundsRangePanel(bw); + // layout final GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; @@ -87,21 +93,21 @@ public MaskOptionsPanel( BigWarp bw ) gbc.anchor = GridBagConstraints.LINE_END; gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets( 5, 5, 5, 5 ); - add( maskTypeLabel, gbc ); + add( maskTypeLabel, gbc ); gbc.gridx = 2; gbc.weightx = 0.0; gbc.anchor = GridBagConstraints.LINE_START; - add( maskTypeDropdown, gbc ); + add( maskTypeDropdown, gbc ); gbc.gridx = 0; gbc.gridy = 1; gbc.anchor = GridBagConstraints.LINE_END; - add( falloffTypeLabel, gbc ); + add( falloffTypeLabel, gbc ); gbc.gridx = 2; gbc.anchor = GridBagConstraints.LINE_START; - add( falloffTypeDropdown, gbc ); + add( falloffTypeDropdown, gbc ); gbc.gridx = 0; gbc.gridy = 2; @@ -112,6 +118,17 @@ public MaskOptionsPanel( BigWarp bw ) gbc.gridy = 2; gbc.anchor = GridBagConstraints.LINE_START; add( showMaskOverlayButton, gbc ); + + gbc.gridx = 0; + gbc.gridy = 3; + gbc.anchor = GridBagConstraints.LINE_START; + add( new JLabel("Imported mask intensity range:"), gbc ); + + gbc.gridy = 4; + gbc.gridwidth = 3; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.anchor = GridBagConstraints.LINE_START; + add( maskRangePanel, gbc ); } public void addActions() @@ -141,7 +158,7 @@ public void actionPerformed( ActionEvent e ) { maskSource.getRandomAccessible().setFalloffShape( (FalloffShape)falloffTypeDropdown.getSelectedItem() ); bw.getViewerFrameP().getViewerPanel().requestRepaint(); - bw.getViewerFrameQ().getViewerPanel().requestRepaint(); + bw.getViewerFrameQ().getViewerPanel().requestRepaint(); } }); @@ -162,6 +179,11 @@ public JComboBox< String > getMaskTypeDropdown() return maskTypeDropdown; } + public MaskBoundsRangePanel getMaskRangeSlider() + { + return maskRangePanel; + } + public String getType() { return ( String ) maskTypeDropdown.getSelectedItem(); diff --git a/src/main/java/bdv/ui/convertersetupeditor/MaskBoundsRangePanel.java b/src/main/java/bdv/ui/convertersetupeditor/MaskBoundsRangePanel.java new file mode 100644 index 00000000..018aab8a --- /dev/null +++ b/src/main/java/bdv/ui/convertersetupeditor/MaskBoundsRangePanel.java @@ -0,0 +1,32 @@ +package bdv.ui.convertersetupeditor; + +import bdv.util.BoundedRange; +import bigwarp.BigWarp; + +public class MaskBoundsRangePanel extends BoundedRangePanel { + + private static final long serialVersionUID = -4065636040399818543L; + + public MaskBoundsRangePanel(BigWarp bw ) + { + super(); + setConsistent( true ); + setup( bw ); + } + + public MaskBoundsRangePanel( final BigWarp bw, final BoundedRange range ) { + super( range ); + setConsistent( true ); + setup( bw ); + } + + protected void setup( BigWarp bw ) { + changeListeners().add(new ChangeListener() { + @Override + public void boundedRangeChanged() { + bw.getBwTransform().setMaskIntensityBounds( getRange().getMin(), getRange().getMax()); + } + }); + } + +} diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 26455242..33041780 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -116,6 +116,7 @@ import bdv.tools.bookmarks.BookmarksEditor; import bdv.tools.brightness.ConverterSetup; import bdv.tools.brightness.SetupAssignments; +import bdv.util.BoundedRange; import bdv.util.Bounds; import bdv.util.RealRandomAccessibleIntervalSource; import bdv.viewer.BigWarpDragOverlay; @@ -2275,6 +2276,15 @@ public void importTransformMaskSource( final String uri ) { // updateTransformMask(); bwTransform.setLambda( transformMask.getInterpolatedSource(0, 0, Interpolation.NLINEAR)); + final RealType type = transformMask.getType(); + if( !(type instanceof DoubleType ) && !(type instanceof FloatType )) + { + final double min = type.getMinValue(); + final double max = type.getMaxValue(); + bwTransform.setMaskIntensityBounds( min, max ); + warpVisDialog.maskOptionsPanel.getMaskRangeSlider().setRange(new BoundedRange( min, max, min, max )); + } + synchronizeSources(); } diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index f3566a47..89ca889a 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -22,6 +22,7 @@ package bigwarp.transforms; import java.util.Arrays; +import java.util.function.Supplier; import bdv.gui.TransformTypeSelectDialog; import bdv.viewer.SourceAndConverter; @@ -45,6 +46,8 @@ import mpicbg.models.TranslationModel2D; import mpicbg.models.TranslationModel3D; import net.imglib2.RealRandomAccessible; +import net.imglib2.converter.Converter; +import net.imglib2.converter.Converters; import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.AffineTransform2D; import net.imglib2.realtransform.AffineTransform3D; @@ -56,6 +59,7 @@ import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.type.numeric.RealType; +import net.imglib2.type.numeric.real.DoubleType; public class BigWarpTransform { @@ -84,8 +88,16 @@ public class BigWarpTransform private int maxIterations = 200; + private RealRandomAccessible> lambdaRaw; + private RealRandomAccessible> lambda; + private Converter,? extends RealType> lambdaConverter; + + private double lambdaConverterMin; + + private double lambdaConverterMax; + private AbstractTransformSolver solver; public BigWarpTransform( final LandmarkTableModel tableModel ) @@ -108,6 +120,43 @@ public void setTransformType( final String transformType ) updateSolver(); } + public void setMaskIntensityBounds( final double min, final double max ) { + + System.out.println( "setMaskIntensityBounds " + min + " " + max ); + lambdaConverterMin = min; + lambdaConverterMax = max; + lambdaConverter = new Converter,RealType>() { + @Override + public void convert(RealType input, RealType output) { + final double v = input.getRealDouble(); + if( v <= min ) + output.setZero(); + else if ( v >= max ) + output.setOne(); + else + output.setReal((v - min) / (max - min)); + } + }; + updateLambda(); + } + + @SuppressWarnings("unchecked") + protected void updateLambda() { + + if( lambdaConverter == null ) + lambda = lambdaRaw; + else + lambda = Converters.convert2(lambdaRaw, + (Converter, RealType>)lambdaConverter, + (Supplier>)DoubleType::new); + + if( solver instanceof MaskedTransformSolver ) + ((MaskedTransformSolver)solver).setMask(lambda); + else if( solver instanceof MaskedSimRotTransformSolver ) + ((MaskedSimRotTransformSolver)solver).setMask(lambda); + + } + public void setMaskInterpolationType( String maskType ) { this.maskInterpolationType = maskType; @@ -188,14 +237,15 @@ public RealRandomAccessible> getLambda( ) public void setLambda( final RealRandomAccessible< ? extends RealType< ? > > lambda ) { - this.lambda = lambda; + this.lambdaRaw = lambda; + updateLambda(); } public InvertibleRealTransform getTransformation() { return getTransformation( -1, true ); } - + public InvertibleRealTransform getTransformation( final int index ) { return getTransformation( index, true ); @@ -211,7 +261,7 @@ public InvertibleRealTransform getTransformation( final int index, final boolean InvertibleRealTransform invXfm = null; if( transformType.equals( TPS )) { - WrappedIterativeInvertibleRealTransform tpsXfm = (WrappedIterativeInvertibleRealTransform< ? >) solver.solve( tableModel, index ); + final WrappedIterativeInvertibleRealTransform tpsXfm = (WrappedIterativeInvertibleRealTransform< ? >) solver.solve( tableModel, index ); tpsXfm.getOptimzer().setMaxIters(maxIterations); tpsXfm.getOptimzer().setTolerance(inverseTolerance); invXfm = tpsXfm; @@ -232,21 +282,21 @@ public InvertibleRealTransform getTransformation( final int index, final boolean public void fitModel( final Model model ) { - int numActive = tableModel.numActive(); + final int numActive = tableModel.numActive(); - double[][] mvgPts = new double[ ndims ][ numActive ]; - double[][] tgtPts = new double[ ndims ][ numActive ]; + final double[][] mvgPts = new double[ ndims ][ numActive ]; + final double[][] tgtPts = new double[ ndims ][ numActive ]; tableModel.copyLandmarks( mvgPts, tgtPts ); - double[] w = new double[ numActive ]; + final double[] w = new double[ numActive ]; Arrays.fill( w, 1.0 ); try { model.fit( mvgPts, tgtPts, w ); - } catch (NotEnoughDataPointsException e) { + } catch (final NotEnoughDataPointsException e) { e.printStackTrace(); - } catch (IllDefinedDataPointsException e) { + } catch (final IllDefinedDataPointsException e) { e.printStackTrace(); } } @@ -293,7 +343,7 @@ public InvertibleCoordinateTransform getCoordinateTransform() { if( !transformType.equals( TPS )) { - WrappedCoordinateTransform wct = (WrappedCoordinateTransform)( unwrap2d( getTransformation() )); + final WrappedCoordinateTransform wct = (WrappedCoordinateTransform)( unwrap2d( getTransformation() )); return wct.getTransform(); } return null; @@ -310,14 +360,14 @@ public InvertibleRealTransform unwrap2d( InvertibleRealTransform ixfm ) /** * Returns an AffineTransform3D that represents the the transform if the transform * is linear, or is the affine part of the transform if it is non-linear. - * + * * Returns a valid transform even if the estimated transformation is 2d. - * + * * @return the affine transform */ public AffineTransform3D affine3d() { - AffineTransform3D out = new AffineTransform3D(); + final AffineTransform3D out = new AffineTransform3D(); if( transformType.equals( TransformTypeSelectDialog.TPS )) { return affine3d( getTpsBase(), out ); @@ -326,13 +376,13 @@ public AffineTransform3D affine3d() { if( ndims == 2 ) { - AbstractAffineModel2D model2d = (AbstractAffineModel2D)getCoordinateTransform(); + final AbstractAffineModel2D model2d = (AbstractAffineModel2D)getCoordinateTransform(); return affine3d( model2d, out ); } else if( ndims == 3 ) { - AbstractAffineModel3D model3d = (AbstractAffineModel3D)getCoordinateTransform(); + final AbstractAffineModel3D model3d = (AbstractAffineModel3D)getCoordinateTransform(); return affine3d( model3d, out ); } else @@ -345,7 +395,7 @@ else if( ndims == 3 ) public ThinPlateR2LogRSplineKernelTransform getTpsBase() { - ThinplateSplineTransform tps = getTps(); + final ThinplateSplineTransform tps = getTps(); if( tps == null ) return null; else @@ -358,7 +408,7 @@ public ThinplateSplineTransform getTps() { if( transformType.equals( TPS )) { - WrappedIterativeInvertibleRealTransform wiirt = (WrappedIterativeInvertibleRealTransform)( unwrap2d( getTransformation()) ); + final WrappedIterativeInvertibleRealTransform wiirt = (WrappedIterativeInvertibleRealTransform)( unwrap2d( getTransformation()) ); return ((ThinplateSplineTransform)wiirt.getTransform()); } return null; @@ -411,7 +461,7 @@ public String affineToString() String s = ""; if( getTransformType().equals( TPS )) { - double[][] affine = affinePartOfTpsHC(); + final double[][] affine = affinePartOfTpsHC(); for( int r = 0; r < affine.length; r++ ) { s += Arrays.toString(affine[r]).replaceAll("\\[|\\]||\\s", ""); @@ -426,11 +476,11 @@ else if( currentTransform instanceof WrappedCoordinateTransform ) } /** - * Returns the affine part of the thin plate spline model, + * Returns the affine part of the thin plate spline model, * as a matrix in homogeneous coordinates. - * + * * double[i][:] contains the i^th row of the matrix. - * + * * @return the matrix as a double array */ public double[][] affinePartOfTpsHC() @@ -448,10 +498,10 @@ public double[][] affinePartOfTpsHC() { mtx = new double[3][4]; } - - ThinPlateR2LogRSplineKernelTransform tps = getTpsBase(); - double[][] tpsAffine = tps.getAffine(); - double[] translation = tps.getTranslation(); + + final ThinPlateR2LogRSplineKernelTransform tps = getTpsBase(); + final double[][] tpsAffine = tps.getAffine(); + final double[] translation = tps.getTranslation(); for( int r = 0; r < nr; r++ ) for( int c = 0; c < nc; c++ ) { @@ -463,7 +513,7 @@ else if( r == c ) { /* the affine doesn't contain the identity "part" of the affine. * i.e., the tps builds the affine A such that - * y = x + Ax + * y = x + Ax * o * y = ( A + I )x */ @@ -531,10 +581,10 @@ public void initializeInverseParameters( BigWarpData bwData ) public static AffineTransform3D affine3d( AbstractAffineModel2D model2d, AffineTransform3D out ) { - double[][] mtx = new double[2][3]; + final double[][] mtx = new double[2][3]; model2d.toMatrix( mtx ); - double[] affine = new double[ 12 ]; + final double[] affine = new double[ 12 ]; affine[ 0 ] = mtx[ 0 ][ 0 ]; affine[ 1 ] = mtx[ 0 ][ 1 ]; // dont set affine 2 @@ -554,10 +604,10 @@ public static AffineTransform3D affine3d( AbstractAffineModel2D model2d, AffineT public static AffineTransform2D affine2d( AbstractAffineModel2D model2d, AffineTransform2D out ) { - double[][] mtx = new double[2][3]; + final double[][] mtx = new double[2][3]; model2d.toMatrix( mtx ); - double[] affine = new double[ 6 ]; + final double[] affine = new double[ 6 ]; affine[ 0 ] = mtx[ 0 ][ 0 ]; affine[ 1 ] = mtx[ 0 ][ 1 ]; affine[ 2 ] = mtx[ 0 ][ 2 ]; @@ -572,10 +622,10 @@ public static AffineTransform2D affine2d( AbstractAffineModel2D model2d, AffineT public static AffineTransform3D affine3d( AbstractAffineModel3D model3d, AffineTransform3D out ) { - double[][] mtx = new double[3][4]; + final double[][] mtx = new double[3][4]; model3d.toMatrix( mtx ); - double[] affine = new double[ 12 ]; + final double[] affine = new double[ 12 ]; affine[ 0 ] = mtx[ 0 ][ 0 ]; affine[ 1 ] = mtx[ 0 ][ 1 ]; affine[ 2 ] = mtx[ 0 ][ 2 ]; @@ -597,11 +647,11 @@ public static AffineTransform3D affine3d( AbstractAffineModel3D model3d, AffineT public static AffineTransform3D affine3d( ThinPlateR2LogRSplineKernelTransform tps, AffineTransform3D out ) { - double[][] tpsAffine = tps.getAffine(); - double[] translation = tps.getTranslation(); - int ndims = tps.getNumDims(); + final double[][] tpsAffine = tps.getAffine(); + final double[] translation = tps.getTranslation(); + final int ndims = tps.getNumDims(); - double[] affine = new double[ 12 ]; + final double[] affine = new double[ 12 ]; if( ndims == 2 ) { affine[ 0 ] = 1 + tpsAffine[ 0 ][ 0 ]; @@ -647,23 +697,23 @@ public AffineGet toImglib2( Model< ? > model ) return toAffine3D( ( AbstractAffineModel3D ) model ); } - public static AffineGet toAffine2D( AbstractAffineModel2D model ) + public static AffineGet toAffine2D( AbstractAffineModel2D model ) { if( model instanceof TranslationModel2D ) { final TranslationModel2D t = (TranslationModel2D)model; return new Translation2D( t.getTranslation() ); } - else + else { // affine, rigid, and similarity // TODO split out rigid? - AffineTransform2D out = new AffineTransform2D(); + final AffineTransform2D out = new AffineTransform2D(); return affine2d( model, out ); } } - public static AffineTransform3D toAffine3D( AbstractAffineModel3D model ) + public static AffineTransform3D toAffine3D( AbstractAffineModel3D model ) { return affine3d( model, new AffineTransform3D() ); } diff --git a/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java b/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java index 1b5e87f7..5c0ca5e8 100644 --- a/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java +++ b/src/main/java/bigwarp/transforms/MaskedSimRotTransformSolver.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -47,7 +47,7 @@ public class MaskedSimRotTransformSolver> extends Abstract { private final AbstractTransformSolver baseSolver; private final ModelTransformSolver interpSolver; - private final RealRandomAccessible lambda; + private RealRandomAccessible lambda; private final double[] center; private final Interpolators interp; private final int ndims; @@ -79,6 +79,11 @@ public MaskedSimRotTransformSolver( int nd, AbstractTransformSolver solver, R System.out.println( this ); } + public void setMask( final RealRandomAccessible lambda ) + { + this.lambda = lambda; + } + @Override public String toString() { @@ -96,11 +101,12 @@ public void setCenter( RealLocalizable c ) c.localize( center ); } + @Override @SuppressWarnings("rawtypes") public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { // WrappedCoordinateTransform simXfm = interpSolver.solve( mvgPts, tgtPts ); - WrappedCoordinateTransform simXfm = interpSolver.solve( tgtPts, mvgPts ); + final WrappedCoordinateTransform simXfm = interpSolver.solve( tgtPts, mvgPts ); RealTransform msim; if ( ndims == 2 ) @@ -128,7 +134,8 @@ public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts return new WrappedIterativeInvertibleRealTransform<>( MaskedTransformSolver.wrap( seq, lambda ) ); } - public WrappedIterativeInvertibleRealTransform solve( + @Override + public WrappedIterativeInvertibleRealTransform solve( final LandmarkTableModel landmarkTable ) { final int numActive = landmarkTable.numActive(); @@ -141,12 +148,12 @@ public WrappedIterativeInvertibleRealTransform solve( private static double[][] transformPoints( RealTransform xfm, double[][] pts ) { - int nd = pts.length; - int np = pts[0].length; + final int nd = pts.length; + final int np = pts[0].length; final double[] tmp = new double[nd]; final double[][] out = new double[ nd ][ np ]; - + for( int i = 0; i < np; i++ ) { for( int d = 0; d < nd; d++ ) @@ -157,7 +164,7 @@ private static double[][] transformPoints( RealTransform xfm, double[][] pts ) for( int d = 0; d < nd; d++ ) out[d][i] = tmp[d]; } - + return out; } } diff --git a/src/main/java/bigwarp/transforms/MaskedTransformSolver.java b/src/main/java/bigwarp/transforms/MaskedTransformSolver.java index f43bf9e7..7382bd59 100644 --- a/src/main/java/bigwarp/transforms/MaskedTransformSolver.java +++ b/src/main/java/bigwarp/transforms/MaskedTransformSolver.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -36,7 +36,7 @@ public class MaskedTransformSolver, S extends AbstractTran { private final S solver; - private final RealRandomAccessible lambda; + private RealRandomAccessible lambda; public MaskedTransformSolver( final S solver, final RealRandomAccessible lambda ) { @@ -49,16 +49,24 @@ public S getSolver() return solver; } + public void setMask( final RealRandomAccessible lambda ) + { + this.lambda = lambda; + } + + @Override public WrappedIterativeInvertibleRealTransform solve( final double[][] mvgPts, final double[][] tgtPts ) { return wrap( solver.solve( mvgPts, tgtPts ), lambda ); } + @Override public WrappedIterativeInvertibleRealTransform< ? > solve( final LandmarkTableModel landmarkTable ) { return wrap( solver.solve( landmarkTable ), lambda ); } + @Override public WrappedIterativeInvertibleRealTransform< ? > solve( final LandmarkTableModel landmarkTable, final int indexChanged ) { return wrap( solver.solve( landmarkTable, indexChanged ), lambda ); From 445117a268567591f2291323cbe39b800df18c1f Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 19 Sep 2023 14:50:15 -0400 Subject: [PATCH 213/282] fix: load 2d landmarks correctly on project loading --- src/main/java/bigwarp/BigwarpSettings.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 4dfdcce1..17d6157e 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -146,6 +146,10 @@ public BigwarpSettings read( final JsonReader in ) throws IOException { case "Sources": new BigWarpSourcesAdapter<>( bigWarp, overwriteSources ).read( in ); + final boolean is2D = BigWarp.detectNumDims(bigWarp.getSources()) == 2; + if (is2D != bigWarp.options.values.is2D()) { + bigWarp.changeDimensionality( is2D ); + } break; case "ViewerP": new BigWarpViewerPanelAdapter( viewerP ).read( in ); @@ -175,10 +179,6 @@ public BigwarpSettings read( final JsonReader in ) throws IOException } in.endObject(); - final boolean is2D = BigWarp.detectNumDims(bigWarp.getSources()) == 2; - if (is2D != bigWarp.options.values.is2D()) { - bigWarp.changeDimensionality( is2D ); - } return this; } From 74f3cf358b0efff88e95c05d0d3b98f50fc84011 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 20 Sep 2023 15:55:42 -0400 Subject: [PATCH 214/282] chore: some code style and clean up --- src/main/java/bigwarp/BigWarpData.java | 45 ++++----- src/main/java/bigwarp/WarpVisFrame.java | 116 ++++++++++++------------ 2 files changed, 81 insertions(+), 80 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 1bf8f6d7..51ed6b1e 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -42,9 +42,9 @@ public BigWarpData() this( new ArrayList<>(), new ArrayList<>(), null ); } - public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, - final CacheControl cache, - final int[] movingIndexes, + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + final CacheControl cache, + final int[] movingIndexes, final int[] targetIndexes ) { this( sources, converterSetups, cache, @@ -58,7 +58,7 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, { this( sources, null, converterSetups, cache ); } - + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< RealTransform > transforms, final List< ConverterSetup > converterSetups, @@ -73,9 +73,9 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, this.cache = cache; } - public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, - final CacheControl cache, - final List movingIndexes, + public BigWarpData( final List< SourceAndConverter< T > > sources, final List< ConverterSetup > converterSetups, + final CacheControl cache, + final List movingIndexes, final List targetIndexes ) { this.sources = sources; @@ -94,11 +94,11 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, final List< C else this.cache = cache; } - + private static ArrayList listOf( int[] x ) { final ArrayList< Integer > out = new ArrayList(); - for( int i : x ) + for( final int i : x ) out.add( i ); return out; @@ -159,7 +159,7 @@ public SourceAndConverter< T > getTargetSource( int i ) } return null; } - + public List getMovingConverterSetups() { final ArrayList out = new ArrayList<>(); @@ -174,7 +174,7 @@ public List getMovingConverterSetups() } return out; } - + public List getTargetConverterSetups() { final ArrayList out = new ArrayList<>(); @@ -239,7 +239,7 @@ void addSource( Source src, boolean isMoving, RealTransform transform ) { // find an unused id int id = 0; - for( ConverterSetup cs : converterSetups ) + for( final ConverterSetup cs : converterSetups ) { if( id == cs.getSetupId() ) id++; @@ -272,9 +272,10 @@ int remove( SourceInfo sourceInfo) void remove( int i ) { - SourceAndConverter< T > sac = sources.get( i ); - final int sacId = sourceInfos.entrySet().stream().filter( it -> it.getValue().getSourceAndConverter() == sac ).map( Map.Entry::getKey ).findFirst().get(); - final SourceInfo sourceInfo = sourceInfos.remove( sacId ); + final SourceAndConverter< T > sac = sources.get( i ); + sourceInfos.entrySet().stream().filter( it -> it.getValue().getSourceAndConverter() == sac ).map( Map.Entry::getKey ).findFirst().ifPresent( + sacId -> { sourceInfos.remove( sacId ); } ); + sources.remove( i ); converterSetups.remove( i ); } @@ -288,7 +289,7 @@ public void applyTransformations() final RealTransform transform = info.getTransform(); if ( transform != null ) { - SourceAndConverter newSac = inheritConverter( + final SourceAndConverter newSac = inheritConverter( applyFixedTransform( sac.getSpimSource(), transform), sac ); @@ -318,10 +319,10 @@ public static < T > SourceAndConverter< T > inheritConverter( final Source sr *

* The returned source will be a new instance than unless the transform * is a instance of {@link AffineGet} and source is an instance of {@link TransformedSource}. - * + * * @param the type * @param src the original source - * @param transform the transformation + * @param transform the transformation * @return the transformed source */ public Source applyFixedTransform( final Source src, final RealTransform transform ) @@ -373,7 +374,7 @@ public Source applyFixedTransform( final Source src, final RealTransfo /** * Updates the moving sources' transformation with the transform currently * being edited by BigWarp. - * + * * @param transform the transformation */ public void updateEditableTransformation( RealTransform transform ) @@ -394,9 +395,9 @@ public void updateEditableTransformation( RealTransform transform ) /* * There was a time when I had a single WarpedSource manage a RealTransformSequence * instead of a WarpedSource wrapping a different WarpedSource as I'm doing now. - * + * * But I decided against having a single source because warped sources can toggle their transforms. - * That toggling makes sense for the editable transform, but the fixex should be "on" + * That toggling makes sense for the editable transform, but the fixex should be "on" * always, and therefore be handled by either a TransformedSource or a different * WarpedSource instance. */ @@ -409,7 +410,7 @@ public void transferChannelSettings( final BigWarpViewerFrame viewer ) final SynchronizedViewerState state = viewer.getViewerPanel().state(); final ConverterSetups setups = viewer.getConverterSetups(); - for( Entry< Integer, SourceInfo > infoEntry : sourceInfos.entrySet() ) + for( final Entry< Integer, SourceInfo > infoEntry : sourceInfos.entrySet() ) { final int id = infoEntry.getKey(); final SourceInfo info = infoEntry.getValue(); diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index bd4b9708..1b1b96d5 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -67,32 +67,32 @@ import net.imglib2.realtransform.BoundingBoxEstimation; import net.miginfocom.swing.MigLayout; -public class WarpVisFrame extends JDialog +public class WarpVisFrame extends JDialog { private static final long serialVersionUID = 7561228647761694686L; private final BigWarp bw; private final BigWarpViewerSettings settings; - + protected ButtonGroup visTypeGroup; protected JRadioButton setWarpVisOffButton; protected JRadioButton setWarpGridButton; protected JRadioButton setWarpMagButton; protected JRadioButton setJacobianDetButton; - + protected JLabel noOptionsLabel; - + // landmark point options protected final JButton landmarkColorButton; private final JColorChooser colorChooser; protected final JSlider landmarkSizeSlider; - + // warp magnitude protected ButtonGroup warpMagButtons; protected JRadioButton warpMagAffineButton; protected JRadioButton warpMagSimilarityButton; protected JRadioButton warpMagRigidButton; - + // grid spacing protected ButtonGroup warpGridButtons; protected JRadioButton warpGridLineButton; @@ -125,32 +125,32 @@ public class WarpVisFrame extends JDialog public static final int minGridSpacing = 5; public static final int maxGridSpacing = 400; public static final int defaultGridSpacing = 100; - + public static final int minGridWidth = 1; public static final int maxGridWidth = 50; public static final int defaultGridWidth = 5; - + public WarpVisFrame( final Frame owner, final BigWarp bw ) { super( owner, "Bigwarp options", false ); this.bw = bw; this.settings = bw.viewerSettings; - + final Container content = getContentPane(); - + setSize( 500, 400 ); - - JPanel landmarkPointOptionsPanel = new JPanel(); + + final JPanel landmarkPointOptionsPanel = new JPanel(); landmarkPointOptionsPanel.setLayout( new BoxLayout( landmarkPointOptionsPanel, BoxLayout.X_AXIS )); landmarkColorButton = new JButton( new ColorIcon( settings.getSpotColor() ) ); colorChooser = new JColorChooser(); - + landmarkSizeSlider = new JSlider(); landmarkSizeSlider.setValue( (int)settings.getSpotSize() ); landmarkSizeSlider.setMinimum( 1 ); landmarkSizeSlider.setMaximum( 96 ); - + landmarkPointOptionsPanel.add( landmarkColorButton ); landmarkPointOptionsPanel.add( landmarkSizeSlider ); landmarkPointOptionsPanel.setBorder( BorderFactory.createCompoundBorder( @@ -160,9 +160,9 @@ public WarpVisFrame( final Frame owner, final BigWarp bw ) BorderFactory.createEtchedBorder(), "landmark size & color" ), BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - - // - JPanel visTypePanel = new JPanel(); + + // + final JPanel visTypePanel = new JPanel(); visTypePanel.setLayout( new BoxLayout( visTypePanel, BoxLayout.Y_AXIS) ); visTypePanel.setBorder( BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), @@ -172,8 +172,8 @@ public WarpVisFrame( final Frame owner, final BigWarp bw ) "warp display" ), BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - - JPanel typeOptionPanel = new JPanel(); + + final JPanel typeOptionPanel = new JPanel(); typeOptionPanel.setLayout( new BoxLayout( typeOptionPanel, BoxLayout.Y_AXIS) ); typeOptionPanel.setBorder( BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), @@ -182,17 +182,17 @@ public WarpVisFrame( final Frame owner, final BigWarp bw ) BorderFactory.createEtchedBorder(), "options" ), BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); - + // label indicating that there are no options to be had noOptionsLabel = new JLabel( "None" ); - + // buttons choosing if and how the warp should be visualized visTypeGroup = new ButtonGroup(); setWarpVisOffButton = new JRadioButton( "Off" ); setWarpGridButton = new JRadioButton( "Grid" ); setWarpMagButton = new JRadioButton( "Magnitude" ); setJacobianDetButton = new JRadioButton( "Jacobian Determinant" ); - + visTypeGroup.add( setWarpVisOffButton ); visTypeGroup.add( setWarpGridButton ); visTypeGroup.add( setWarpMagButton ); @@ -213,16 +213,16 @@ public WarpVisFrame( final Frame owner, final BigWarp bw ) warpMagButtons.add( warpMagAffineButton ); warpMagButtons.add( warpMagSimilarityButton ); warpMagButtons.add( warpMagRigidButton ); - - // buttons for warp grid options + + // buttons for warp grid options warpGridLineButton = new JRadioButton( "Line grid " ); warpGridModButton = new JRadioButton( "Modulo grid" ); - + warpGridButtons = new ButtonGroup(); warpGridButtons.add( warpGridLineButton ); warpGridButtons.add( warpGridModButton ); warpGridLineButton.setSelected( true ); - + gridSpacingSlider = new JSlider( JSlider.HORIZONTAL, minGridSpacing, maxGridSpacing, defaultGridSpacing ); gridWidthSlider = new JSlider( JSlider.HORIZONTAL, minGridWidth, maxGridWidth, defaultGridWidth ); // label the sliders @@ -236,7 +236,7 @@ public WarpVisFrame( final Frame owner, final BigWarp bw ) typeOptionPanel.add( warpMagAffineButton ); typeOptionPanel.add( warpMagSimilarityButton ); typeOptionPanel.add( warpMagRigidButton ); - + typeOptionPanel.add( warpGridLineButton ); typeOptionPanel.add( warpGridModButton ); typeOptionPanel.add( bigSpace ); @@ -289,7 +289,7 @@ public void stateChanged( ChangeEvent e ) } ); maxIterPanel.add( new JLabel( "Max iterations", SwingConstants.CENTER ), BorderLayout.WEST ); maxIterPanel.add( maxIterSpinner, BorderLayout.EAST ); - + inverseOptionsPanel.add( tolerancePanel, BorderLayout.NORTH ); inverseOptionsPanel.add( maxIterPanel, BorderLayout.SOUTH ); @@ -317,7 +317,7 @@ public void stateChanged( ChangeEvent e ) bboxMethodDropdown.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - String methodString = (String)(bboxMethodDropdown.getSelectedItem()); + final String methodString = (String)(bboxMethodDropdown.getSelectedItem()); bw.getBoxEstimation().setMethod( methodString ); bw.updateSourceBoundingBoxEstimators(); } @@ -439,20 +439,20 @@ public void actionPerformed( final ActionEvent arg0 ) d.setVisible( true ); } } ); - + landmarkSizeSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( ChangeEvent e ) { if( e.getSource() != landmarkSizeSlider ) return; - + settings.setSpotSize( landmarkSizeSlider.getValue() ); bw.viewerP.requestRepaint(); bw.viewerQ.requestRepaint(); } }); - + setWarpVisOffButton.setAction( actionMap.get( String.format( BigWarpActions.SET_WARPTYPE_VIS, BigWarp.WarpVisType.NONE ))); setWarpGridButton.setAction( @@ -461,67 +461,67 @@ public void stateChanged( ChangeEvent e ) actionMap.get( String.format( BigWarpActions.SET_WARPTYPE_VIS, BigWarp.WarpVisType.WARPMAG ))); setJacobianDetButton.setAction( actionMap.get( String.format( BigWarpActions.SET_WARPTYPE_VIS, BigWarp.WarpVisType.JACDET ))); - + setWarpVisOffButton.setText("Off"); setWarpGridButton.setText("Grid"); setWarpMagButton.setText("Magnitude"); setJacobianDetButton.setText("Jacobian Determinant"); - + warpMagAffineButton.setAction( actionMap.get( String.format( BigWarpActions.WARPMAG_BASE, bw.baseXfmList[ 0 ].getClass().getName() ))); warpMagSimilarityButton .setAction( actionMap.get( String.format( BigWarpActions.WARPMAG_BASE, bw.baseXfmList[ 1 ].getClass().getName() ) )); - warpMagRigidButton.setAction( + warpMagRigidButton.setAction( actionMap.get( String.format( BigWarpActions.WARPMAG_BASE, bw.baseXfmList[ 2 ].getClass().getName() ) )); - + warpMagAffineButton.setText("Affine"); warpMagSimilarityButton.setText("Similarity"); warpMagRigidButton.setText("Rigid"); - - warpGridLineButton.setAction( + + warpGridLineButton.setAction( actionMap.get( String.format( BigWarpActions.WARPVISGRID, GridSource.GRID_TYPE.LINE ))); - warpGridModButton.setAction( + warpGridModButton.setAction( actionMap.get( String.format( BigWarpActions.WARPVISGRID, GridSource.GRID_TYPE.MOD ))); - + warpGridLineButton.setText( "Line" ); warpGridModButton.setText( "Modulo" ); - + // turn on the default values // setWarpVisOffButton.doClick(); // warpMagAffineButton.doClick(); // warpGridLineButton.doClick(); } - + public void addListeners() { - MyChangeListener mylistener = new MyChangeListener(); + final MyChangeListener mylistener = new MyChangeListener(); setWarpVisOffButton.addChangeListener( mylistener ); setWarpGridButton.addChangeListener( mylistener ); setWarpMagButton.addChangeListener( mylistener ); - + gridSpacingSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( ChangeEvent e ) { if( e.getSource() != gridSpacingSlider ) return; - + WarpVisFrame.this.bw.setWarpGridSpacing( gridSpacingSlider.getValue() ); } }); - + gridWidthSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged( ChangeEvent e ) { if( e.getSource() != gridWidthSlider ) return; - + WarpVisFrame.this.bw.setWarpGridWidth( gridWidthSlider.getValue() ); } }); } - + public class MyChangeListener implements ChangeListener { @Override @@ -530,13 +530,13 @@ public void stateChanged( ChangeEvent e ) WarpVisFrame.this.updateOptions(); } } - + private void setGridOptionsVisibility( boolean isVisible ) { // disable all options - Enumeration< AbstractButton > elems = warpGridButtons.getElements(); + final Enumeration< AbstractButton > elems = warpGridButtons.getElements(); while( elems.hasMoreElements()) - elems.nextElement().setVisible( isVisible ); + elems.nextElement().setVisible( isVisible ); gridSpacingSlider.setVisible( isVisible ); gridWidthSlider.setVisible( isVisible ); @@ -544,15 +544,15 @@ private void setGridOptionsVisibility( boolean isVisible ) gridSpacingLabel.setVisible( isVisible ); gridWidthLabel.setVisible( isVisible ); } - + private void setMagOptionsVisibility( boolean isVisible ) { // disable all options - Enumeration< AbstractButton > elems = warpMagButtons.getElements(); + final Enumeration< AbstractButton > elems = warpMagButtons.getElements(); while( elems.hasMoreElements()) - elems.nextElement().setVisible( isVisible ); + elems.nextElement().setVisible( isVisible ); } - + public synchronized void updateOptions() { if( setWarpVisOffButton.isSelected() ) @@ -579,7 +579,7 @@ else if( setWarpMagButton.isSelected() ) } pack(); } - + private static class ColorIcon implements Icon { private final int size = 16; From 7e6e8456d5b8ddd379ce0b80e83e53e1588d9612 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 20 Sep 2023 15:57:07 -0400 Subject: [PATCH 215/282] feat: can now (de)serialize mask or remove mask --- src/main/java/bdv/gui/MaskOptionsPanel.java | 7 +- .../MaskBoundsRangePanel.java | 7 +- src/main/java/bigwarp/BigWarp.java | 176 ++++++++++++++---- src/main/java/bigwarp/BigWarpActions.java | 22 ++- src/main/java/bigwarp/BigwarpSettings.java | 63 +++---- .../bigwarp/transforms/BigWarpTransform.java | 15 +- .../transforms/io/TransformWriterJson.java | 50 +++-- 7 files changed, 239 insertions(+), 101 deletions(-) diff --git a/src/main/java/bdv/gui/MaskOptionsPanel.java b/src/main/java/bdv/gui/MaskOptionsPanel.java index b0806706..9117f2de 100644 --- a/src/main/java/bdv/gui/MaskOptionsPanel.java +++ b/src/main/java/bdv/gui/MaskOptionsPanel.java @@ -179,6 +179,11 @@ public JComboBox< String > getMaskTypeDropdown() return maskTypeDropdown; } + public JComboBox< FalloffShape > getMaskFalloffTypeDropdown() + { + return falloffTypeDropdown; + } + public MaskBoundsRangePanel getMaskRangeSlider() { return maskRangePanel; @@ -189,7 +194,7 @@ public String getType() return ( String ) maskTypeDropdown.getSelectedItem(); } - /** + /* * @return true if a mask is applied to the transformation */ public boolean isMask() diff --git a/src/main/java/bdv/ui/convertersetupeditor/MaskBoundsRangePanel.java b/src/main/java/bdv/ui/convertersetupeditor/MaskBoundsRangePanel.java index 018aab8a..e617fa48 100644 --- a/src/main/java/bdv/ui/convertersetupeditor/MaskBoundsRangePanel.java +++ b/src/main/java/bdv/ui/convertersetupeditor/MaskBoundsRangePanel.java @@ -7,11 +7,8 @@ public class MaskBoundsRangePanel extends BoundedRangePanel { private static final long serialVersionUID = -4065636040399818543L; - public MaskBoundsRangePanel(BigWarp bw ) - { - super(); - setConsistent( true ); - setup( bw ); + public MaskBoundsRangePanel(BigWarp bw ) { + this(bw, new BoundedRange(0, 1, 0, 1)); } public MaskBoundsRangePanel( final BigWarp bw, final BoundedRange range ) { diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 33041780..5161125a 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -39,7 +39,7 @@ import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; -import java.net.URI; +import java.lang.reflect.InvocationTargetException; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -47,8 +47,6 @@ import java.util.Calendar; import java.util.HashSet; import java.util.List; -import java.util.Map.Entry; -import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; @@ -72,10 +70,7 @@ import javax.swing.table.TableCellEditor; import org.janelia.saalfeldlab.n5.Compression; -import org.janelia.saalfeldlab.n5.N5Reader; -import org.janelia.saalfeldlab.n5.N5URI; import org.janelia.saalfeldlab.n5.ij.N5Exporter; -import org.janelia.saalfeldlab.n5.universe.N5Factory; import org.janelia.utility.geom.BoundingSphereRitter; import org.janelia.utility.geom.Sphere; import org.janelia.utility.ui.RepeatingReleasedEventsFixer; @@ -118,7 +113,6 @@ import bdv.tools.brightness.SetupAssignments; import bdv.util.BoundedRange; import bdv.util.Bounds; -import bdv.util.RealRandomAccessibleIntervalSource; import bdv.viewer.BigWarpDragOverlay; import bdv.viewer.BigWarpLandmarkFrame; import bdv.viewer.BigWarpOverlay; @@ -145,6 +139,8 @@ import bigwarp.landmarks.LandmarkTableModel; import bigwarp.source.GridSource; import bigwarp.source.JacobianDeterminantSource; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; +import bigwarp.source.PlateauSphericalMaskRealRandomAccessible.FalloffShape; import bigwarp.source.PlateauSphericalMaskSource; import bigwarp.source.SourceInfo; import bigwarp.source.WarpMagnitudeSource; @@ -158,7 +154,6 @@ import ij.IJ; import ij.ImageJ; import ij.ImagePlus; -import ij.plugin.FolderOpener; import java.util.LinkedHashMap; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; @@ -179,7 +174,6 @@ import mpicbg.spim.data.SpimDataException; import mpicbg.spim.data.XmlIoSpimData; import mpicbg.spim.data.registration.ViewTransformAffine; -import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealPoint; @@ -1073,6 +1067,10 @@ protected void setUpViewerMenu( final BigWarpViewerFrame vframe ) openMask.setText( "Import mask" ); fileMenu.add( openMask ); + final JMenuItem removeMask = new JMenuItem( actionMap.get( BigWarpActions.MASK_REMOVE )); + removeMask.setText( "Remove mask" ); + fileMenu.add( removeMask ); + fileMenu.addSeparator(); final JMenuItem miLoadSettings = new JMenuItem( actionMap.get( BigWarpActions.LOAD_SETTINGS )); miLoadSettings.setText( "Load settings" ); @@ -2220,7 +2218,11 @@ public void updateTransformMask() { final MaskOptionsPanel maskOpts = warpVisDialog.maskOptionsPanel; final String type = maskOpts.getType(); - if( !type.equals( BigWarpTransform.NO_MASK_INTERP ) && transformMaskSource == null ) + + if( type.equals( BigWarpTransform.NO_MASK_INTERP )) + return; + + if( transformMaskSource == null ) { // add the transform mask if necessary addTransformMaskSource(); @@ -2234,43 +2236,94 @@ public void updateTransformMask() getViewerFrameQ().getViewerPanel().requestRepaint(); } - @SuppressWarnings( { "unchecked" } ) - public void importTransformMaskSource( final String uri ) { + public void refreshTransformMask() + { + getBwTransform().setLambda( + transformMaskSource.getSpimSource().getInterpolatedSource(0, 0, Interpolation.NLINEAR)); + } - URI encodedUri; - try { - encodedUri = N5URI.encodeAsUri( uri ); - } catch (final URISyntaxException e) { - e.printStackTrace(); - return; - } + public void setTransformMaskRange( double min, double max ) + { + getBwTransform().setMaskIntensityBounds(min, max); + warpVisDialog.maskOptionsPanel.getMaskRangeSlider().setRange( + new BoundedRange( min, max, min, max )); + } + + public void setTransformMaskType( final String maskInterpolationType ) + { + getBwTransform().setMaskInterpolationType(maskInterpolationType); + warpVisDialog.maskOptionsPanel.getMaskTypeDropdown().setSelectedItem(maskInterpolationType); + } + + public void setTransformMaskProperties( final FalloffShape falloffShape, + final double squaredRadius, double[] center ) + { + warpVisDialog.maskOptionsPanel.getMaskFalloffTypeDropdown().setSelectedItem(falloffShape); + + final PlateauSphericalMaskRealRandomAccessible mask = getTransformPlateauMaskSource().getRandomAccessible(); + mask.setFalloffShape( falloffShape ); + mask.setSquaredRadius( squaredRadius ); + mask.setCenter( center ); + } + + public void importTransformMaskSourceDialog() { + +// URI encodedUri; +// try { +// encodedUri = N5URI.encodeAsUri( initialUri ); +// } catch (final URISyntaxException e) { +// e.printStackTrace(); +// return; +// } +// +// final N5URI n5Uri = new N5URI( encodedUri ); - final N5URI n5Uri = new N5URI( encodedUri ); final JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES ); -// fileChooser.setCurrentDirectory( startingFolder ); + fileChooser.setCurrentDirectory(lastDirectory); final int ret = fileChooser.showOpenDialog(landmarkFrame); if ( ret == JFileChooser.APPROVE_OPTION ) { - LinkedHashMap, SourceInfo> infos; - try { - final File selection = fileChooser.getSelectedFile(); - infos = BigWarpInit.createSources(data, selection.getAbsolutePath(), TRANSFORM_MASK_SOURCE_ID, false); - BigWarpInit.add( data, infos, null ); + final File selection = fileChooser.getSelectedFile(); + importTransformMaskSource( selection.getAbsolutePath() ); + } - synchronizeSources(); - infos.entrySet().stream().map( e -> { return e.getKey(); }).findFirst().ifPresent( x -> { - transformMask = (Source>)x; - }); + } - } catch (final URISyntaxException e) { - e.printStackTrace(); - } catch (final IOException e) { - e.printStackTrace(); - } catch (final SpimDataException e) { - e.printStackTrace(); - } + @SuppressWarnings( { "unchecked" } ) + public void importTransformMaskSource( final String uri ) { + + // first remove any existing mask source + removeMaskSource(false); + + // TODO do i build an N5URI? +// URI encodedUri; +// try { +// encodedUri = N5URI.encodeAsUri( uri ); +// } catch (final URISyntaxException e) { +// e.printStackTrace(); +// return; +// } +// final N5URI n5Uri = new N5URI( encodedUri ); + + + LinkedHashMap, SourceInfo> infos; + try { + infos = BigWarpInit.createSources(data, uri, TRANSFORM_MASK_SOURCE_ID, false); + BigWarpInit.add( data, infos, null ); + + synchronizeSources(); + infos.entrySet().stream().map( e -> { return e.getKey(); }).findFirst().ifPresent( x -> { + transformMask = (Source>)x; + }); + + } catch (final URISyntaxException e) { + e.printStackTrace(); + } catch (final IOException e) { + e.printStackTrace(); + } catch (final SpimDataException e) { + e.printStackTrace(); } // updateTransformMask(); @@ -2288,6 +2341,34 @@ public void importTransformMaskSource( final String uri ) { synchronizeSources(); } + /** + * Run this after loading projet to set the transform mask from a loaded source + */ + @SuppressWarnings("unchecked") + public void connectMaskSource() + { + transformMask = (Source>)data.sourceInfos.get(TRANSFORM_MASK_SOURCE_ID).getSourceAndConverter().getSpimSource(); + bwTransform.setLambda( transformMask.getInterpolatedSource(0, 0, Interpolation.NLINEAR)); + } + + public void removeMaskSource( ) { + removeMaskSource( true ); + } + + public void removeMaskSource( boolean reAdd ) { + + final SourceInfo srcInfo = data.sourceInfos.get(TRANSFORM_MASK_SOURCE_ID); + if( srcInfo != null ) + removeSource(srcInfo); + + transformMask = null; + transformMaskSource = null; + bwTransform.setLambda(null); + + if( reAdd ) + updateTransformMask(); + } + @SuppressWarnings( { "unchecked", "rawtypes", "hiding" } ) public > SourceAndConverter< T > addTransformMaskSource() { @@ -2323,6 +2404,7 @@ public > SourceAndConverter< T > addTransformMaskSource() warpVisDialog.maskOptionsPanel.setMask( plateauTransformMask ); addMaskMouseListener(); bwTransform.setLambda( plateauTransformMask.getRandomAccessible() ); + bwTransform.setMaskIntensityBounds(0, 1); final ArrayList overlayList = new ArrayList<>(); final BigWarpMaskSphereOverlay overlay = new BigWarpMaskSphereOverlay( viewerQ, ndims==3 ); @@ -2332,12 +2414,13 @@ public > SourceAndConverter< T > addTransformMaskSource() getViewerFrameQ().getViewerPanel().setMaskOverlay( overlay ); plateauTransformMask.getRandomAccessible().setOverlays( overlayList ); + synchronizeSources(); transformMaskSource = soc; return soc; } - public Source> getTransformMaskSource() + public Source> getTansformMaskSource() { return transformMask; } @@ -3808,7 +3891,6 @@ protected void saveSettings() protected void saveProject() { - System.out.println( "save project" ); final File proposedSettingsFile = new File( "bigwarp-project.json" ); saveSettingsOrProject( proposedSettingsFile ); } @@ -4006,7 +4088,21 @@ public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSourc { final BigwarpSettings settings = getSettings(); settings.setOverwriteSources( overwriteSources ); - settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); + + try { + SwingUtilities.invokeAndWait( () -> { + try { + settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); + } catch (final IOException e) { + e.printStackTrace(); + } + }); + } catch (final InvocationTargetException e) { + e.printStackTrace(); + } catch (final InterruptedException e) { + e.printStackTrace(); + } + activeSourcesDialogP.update(); activeSourcesDialogQ.update(); } diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index bf28bbab..18caa5f1 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -86,6 +86,7 @@ public class BigWarpActions public static final String LANDMARK_GRID_DIALOG = "landmark grid dialog"; public static final String MASK_IMPORT = "import mask"; + public static final String MASK_REMOVE = "remove mask"; public static final String MASK_SIZE_EDIT = "mask edit"; public static final String MASK_VIS_TOGGLE = "mask vis toggle"; @@ -339,6 +340,7 @@ public static ActionMap createActionMap( final BigWarp< ? > bw ) new MaskSizeEdit( bw ).put(actionMap); new MaskVisToggle( bw ).put(actionMap); new MaskImport( bw ).put(actionMap); + new MaskRemove( bw ).put(actionMap); for( int i = 0; i < bw.baseXfmList.length; i++ ){ final AbstractModel xfm = bw.baseXfmList[ i ]; @@ -1258,7 +1260,25 @@ public MaskImport( final BigWarp< ? > bw ) @Override public void actionPerformed(ActionEvent e) { - bw.importTransformMaskSource(""); + bw.importTransformMaskSourceDialog(); + } + } + + public static class MaskRemove extends AbstractNamedAction + { + private static final long serialVersionUID = 4103338122650843631L; + private final BigWarp< ? > bw; + + public MaskRemove( final BigWarp< ? > bw ) + { + super( MASK_REMOVE ); + this.bw = bw; + } + + @Override + public void actionPerformed(ActionEvent e) + { + bw.removeMaskSource(); } } diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 17d6157e..2db2e39d 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -138,47 +138,35 @@ public void write( final JsonWriter out, final BigwarpSettings value ) throws IO @Override public BigwarpSettings read( final JsonReader in ) throws IOException { - in.beginObject(); - while ( in.hasNext() ) + final JsonObject json = JsonParser.parseReader(in).getAsJsonObject(); + if( json.has("Sources")) { - final String nextName = in.nextName(); - switch ( nextName ) - { - case "Sources": - new BigWarpSourcesAdapter<>( bigWarp, overwriteSources ).read( in ); - final boolean is2D = BigWarp.detectNumDims(bigWarp.getSources()) == 2; - if (is2D != bigWarp.options.values.is2D()) { - bigWarp.changeDimensionality( is2D ); - } - break; - case "ViewerP": - new BigWarpViewerPanelAdapter( viewerP ).read( in ); - break; - case "ViewerQ": - new BigWarpViewerPanelAdapter( viewerQ ).read( in ); - break; - case "SetupAssignments": - new SetupAssignmentsAdapter( setupAssignments ).read( in ); - break; - case "Bookmarks": - bookmarks = gson.fromJson( in, Bookmarks.class ); - bigWarp.setBookmarks( bookmarks ); - break; - case "Autosave": - autoSaver = gson.fromJson( in, BigWarpAutoSaver.class ); - bigWarp.setAutoSaver( autoSaver ); - break; - case "Transform": - final JsonObject transformObject = ( JsonObject ) JsonParser.parseReader( in ); - TransformWriterJson.read( bigWarp, transformObject ); - break; - default: - throw new RuntimeException( "Unknown BigWarpSetting: " + nextName ); + new BigWarpSourcesAdapter<>( bigWarp, overwriteSources ).fromJsonTree(json.get("Sources")); + final boolean is2D = BigWarp.detectNumDims(bigWarp.getSources()) == 2; + if (is2D != bigWarp.options.values.is2D()) { + bigWarp.changeDimensionality( is2D ); } + } + // need to parse transform first + if( json.has("Transform")) + TransformWriterJson.read( bigWarp, json.get("Transform").getAsJsonObject()); + + if( json.has("ViewerP")) + new BigWarpViewerPanelAdapter( viewerP ).fromJsonTree( json.get("ViewerP") ); + + if( json.has("ViewerQ")) + new BigWarpViewerPanelAdapter( viewerQ ).fromJsonTree( json.get("ViewerQ") ); + + if( json.has("SetupAssignments")) + new SetupAssignmentsAdapter(setupAssignments).fromJsonTree(json.get("SetupAssignments")); + + if( json.has("Bookmarks")) + bigWarp.setBookmarks(gson.fromJson(json.get("Bookmarks"), Bookmarks.class)); + + if( json.has("Autosave")) + bigWarp.setAutoSaver( gson.fromJson( json.get("Autosave"), BigWarpAutoSaver.class )); - } - in.endObject(); return this; } @@ -191,7 +179,6 @@ public static class BigWarpSourcesAdapter< T > extends TypeAdapter< Map< Integer public BigWarpSourcesAdapter( final BigWarp< T > bigwarp, boolean overwriteSources ) { - this.bigwarp = bigwarp; this.overwriteExisting = overwriteSources; } diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 89ca889a..7be6e943 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -25,6 +25,7 @@ import java.util.function.Supplier; import bdv.gui.TransformTypeSelectDialog; +import bdv.util.BoundedRange; import bdv.viewer.SourceAndConverter; import bdv.viewer.animate.SimilarityModel3D; import bigwarp.BigWarpData; @@ -122,7 +123,6 @@ public void setTransformType( final String transformType ) public void setMaskIntensityBounds( final double min, final double max ) { - System.out.println( "setMaskIntensityBounds " + min + " " + max ); lambdaConverterMin = min; lambdaConverterMax = max; lambdaConverter = new Converter,RealType>() { @@ -140,21 +140,26 @@ else if ( v >= max ) updateLambda(); } + public BoundedRange getMaskIntensityBounds() { + return new BoundedRange(lambdaConverterMin, lambdaConverterMax, lambdaConverterMin, lambdaConverterMax); + } + @SuppressWarnings("unchecked") protected void updateLambda() { - if( lambdaConverter == null ) - lambda = lambdaRaw; - else + if( lambdaConverter != null && !(lambdaRaw instanceof PlateauSphericalMaskRealRandomAccessible) ) + { lambda = Converters.convert2(lambdaRaw, (Converter, RealType>)lambdaConverter, (Supplier>)DoubleType::new); + } + else + lambda = lambdaRaw; if( solver instanceof MaskedTransformSolver ) ((MaskedTransformSolver)solver).setMask(lambda); else if( solver instanceof MaskedSimRotTransformSolver ) ((MaskedSimRotTransformSolver)solver).setMask(lambda); - } public void setMaskInterpolationType( String maskType ) diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index 5eb71076..ac73e5a7 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -1,11 +1,15 @@ package bigwarp.transforms.io; + import bigwarp.BigWarp; import bigwarp.BigwarpSettings; import bigwarp.landmarks.LandmarkTableModel; import bigwarp.source.PlateauSphericalMaskRealRandomAccessible; import bigwarp.transforms.BigWarpTransform; import com.google.gson.JsonObject; + +import bdv.util.BoundedRange; + import java.io.File; import java.io.IOException; import java.io.Reader; @@ -57,13 +61,18 @@ public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransf final JsonObject transformObj = new JsonObject(); transformObj.addProperty("type", bwTransform.getTransformType() ); - transformObj.addProperty("maskInterpolationType", bwTransform.getMaskInterpolationType() ); transformObj.add("landmarks", ltm.toJson()); if( bwTransform.isMasked() ) { - final PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); - transformObj.add("mask", BigwarpSettings.gson.toJsonTree( mask )); + final JsonObject maskObj = new JsonObject(); + if (bwTransform.getLambda() instanceof PlateauSphericalMaskRealRandomAccessible) { + final PlateauSphericalMaskRealRandomAccessible mask = (PlateauSphericalMaskRealRandomAccessible)bwTransform.getLambda(); + maskObj.add("parameters", BigwarpSettings.gson.toJsonTree(mask)); + } + maskObj.add("range", BigwarpSettings.gson.toJsonTree(bwTransform.getMaskIntensityBounds())); + maskObj.addProperty("interpolationType", bwTransform.getMaskInterpolationType() ); + transformObj.add("mask", maskObj); } return transformObj; @@ -72,21 +81,40 @@ public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransf public static void read( final BigWarp< ? > bw, final JsonObject json ) { if( json.has( "landmarks" )) - bw.getLandmarkPanel().getTableModel().fromJson( json ); + { + final int nd = json.get("landmarks").getAsJsonObject().get("numDimensions").getAsInt(); + if( bw.numDimensions() != nd ) + bw.changeDimensionality(nd == 2); - final String maskInterpolationType = json.get( "maskInterpolationType" ).getAsString(); - bw.getBwTransform().setMaskInterpolationType( maskInterpolationType ); + bw.getLandmarkPanel().getTableModel().fromJson( json ); + } if( json.has( "mask" )) { final JsonObject maskParams = json.get("mask").getAsJsonObject(); - final PlateauSphericalMaskRealRandomAccessible maskFromJson = BigwarpSettings.gson.fromJson( maskParams, PlateauSphericalMaskRealRandomAccessible.class ); - final PlateauSphericalMaskRealRandomAccessible mask = bw.getTransformPlateauMaskSource().getRandomAccessible(); - mask.setFalloffShape( maskFromJson.getFallOffShape() ); - mask.setSquaredRadius( maskFromJson.getSquaredRadius() ); - mask.setCenter( maskFromJson.getCenter() ); + if( maskParams.has("parameters")) + { + bw.addTransformMaskSource(); + final JsonObject paramsObj = maskParams.get("parameters").getAsJsonObject(); + final PlateauSphericalMaskRealRandomAccessible maskFromJson = BigwarpSettings.gson.fromJson( paramsObj, PlateauSphericalMaskRealRandomAccessible.class ); + bw.setTransformMaskProperties( + maskFromJson.getFallOffShape(), + maskFromJson.getSquaredRadius(), + maskFromJson.getCenter().positionAsDoubleArray()); + }else + bw.connectMaskSource(); + + bw.setTransformMaskType(maskParams.get("interpolationType").getAsString()); + + if( maskParams.has("range")) + { + final BoundedRange maskRange = BigwarpSettings.gson.fromJson(maskParams.get("range"), BoundedRange.class); + bw.getBwTransform().setMaskIntensityBounds(maskRange.getMin(), maskRange.getMax()); + bw.setTransformMaskRange(maskRange.getMin(), maskRange.getMax()); + } } + } } From 9687150aa9fb685625d448c298e65f99c7a9d8a5 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 11:23:05 -0400 Subject: [PATCH 216/282] fix: 2d viewer transform bug --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index f06bfb5b..a7e025f9 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -166,6 +166,8 @@ public void updateTransformBehaviors(BigWarpViewerOptions optional) { final TransformEventHandler tfHandler = viewer.getTransformEventHandler(); tfHandler.install( transformBehaviours ); + + viewer.getDisplay().setTransformEventHandler(tfHandler); } public boolean isMoving() From 06d2600e1c487a9a9e2285d4d7e64c0bf8e8921c Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 11:24:16 -0400 Subject: [PATCH 217/282] fix: behavior when removing transform masks --- src/main/java/bigwarp/BigWarp.java | 73 ++++++++++++------------------ 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 5161125a..8f38422b 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -596,7 +596,6 @@ public void changeDimensionality(boolean is2D) { return; options.is2D( is2D ); - if( options.values.is2D() ) ndims = 2; else @@ -2218,22 +2217,28 @@ public void updateTransformMask() { final MaskOptionsPanel maskOpts = warpVisDialog.maskOptionsPanel; final String type = maskOpts.getType(); + final boolean masked = maskOpts.isMask(); - if( type.equals( BigWarpTransform.NO_MASK_INTERP )) - return; - - if( transformMaskSource == null ) - { - // add the transform mask if necessary + // add the transform mask if necessary + if( masked && transformMaskSource == null ) addTransformMaskSource(); - } // update the bigwarp transform + final boolean isVirtualMask = isVirtualMask(); getBwTransform().setMaskInterpolationType( type ); + setMaskOverlayVisibility( maskOpts.showMaskOverlay() && masked && isVirtualMask ); + + if (masked && isVirtualMask) + autoEstimateMask(); + restimateTransformation(); - setMaskOverlayVisibility( maskOpts.showMaskOverlay() && maskOpts.isMask() ); - autoEstimateMask(); getViewerFrameQ().getViewerPanel().requestRepaint(); + getViewerFrameP().getViewerPanel().requestRepaint(); + } + + private boolean isVirtualMask() { + + return plateauTransformMask == transformMask; } public void refreshTransformMask() @@ -2268,16 +2273,6 @@ public void setTransformMaskProperties( final FalloffShape falloffShape, public void importTransformMaskSourceDialog() { -// URI encodedUri; -// try { -// encodedUri = N5URI.encodeAsUri( initialUri ); -// } catch (final URISyntaxException e) { -// e.printStackTrace(); -// return; -// } -// -// final N5URI n5Uri = new N5URI( encodedUri ); - final JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES ); fileChooser.setCurrentDirectory(lastDirectory); @@ -2295,28 +2290,19 @@ public void importTransformMaskSourceDialog() { public void importTransformMaskSource( final String uri ) { // first remove any existing mask source - removeMaskSource(false); - - // TODO do i build an N5URI? -// URI encodedUri; -// try { -// encodedUri = N5URI.encodeAsUri( uri ); -// } catch (final URISyntaxException e) { -// e.printStackTrace(); -// return; -// } -// final N5URI n5Uri = new N5URI( encodedUri ); - + final SourceInfo srcInfo = data.sourceInfos.get(TRANSFORM_MASK_SOURCE_ID); + if( srcInfo != null ) + removeSource(srcInfo); LinkedHashMap, SourceInfo> infos; try { infos = BigWarpInit.createSources(data, uri, TRANSFORM_MASK_SOURCE_ID, false); BigWarpInit.add( data, infos, null ); - synchronizeSources(); infos.entrySet().stream().map( e -> { return e.getKey(); }).findFirst().ifPresent( x -> { transformMask = (Source>)x; }); + synchronizeSources(); } catch (final URISyntaxException e) { e.printStackTrace(); @@ -2326,8 +2312,8 @@ public void importTransformMaskSource( final String uri ) { e.printStackTrace(); } -// updateTransformMask(); bwTransform.setLambda( transformMask.getInterpolatedSource(0, 0, Interpolation.NLINEAR)); + updateTransformMask(); final RealType type = transformMask.getType(); if( !(type instanceof DoubleType ) && !(type instanceof FloatType )) @@ -2337,8 +2323,6 @@ public void importTransformMaskSource( final String uri ) { bwTransform.setMaskIntensityBounds( min, max ); warpVisDialog.maskOptionsPanel.getMaskRangeSlider().setRange(new BoundedRange( min, max, min, max )); } - - synchronizeSources(); } /** @@ -2351,11 +2335,7 @@ public void connectMaskSource() bwTransform.setLambda( transformMask.getInterpolatedSource(0, 0, Interpolation.NLINEAR)); } - public void removeMaskSource( ) { - removeMaskSource( true ); - } - - public void removeMaskSource( boolean reAdd ) { + public void removeMaskSource() { final SourceInfo srcInfo = data.sourceInfos.get(TRANSFORM_MASK_SOURCE_ID); if( srcInfo != null ) @@ -2364,9 +2344,16 @@ public void removeMaskSource( boolean reAdd ) { transformMask = null; transformMaskSource = null; bwTransform.setLambda(null); + bwTransform.setMaskInterpolationType(BigWarpTransform.NO_MASK_INTERP); + warpVisDialog.maskOptionsPanel.getMaskTypeDropdown().setSelectedItem(BigWarpTransform.NO_MASK_INTERP); - if( reAdd ) - updateTransformMask(); + final BigWarpMaskSphereOverlay overlay = getViewerFrameQ().getViewerPanel().getMaskOverlay(); + if( overlay != null ) + overlay.setVisible(false); + + updateTransformMask(); + + restimateTransformation(); } @SuppressWarnings( { "unchecked", "rawtypes", "hiding" } ) From 0ac447ec2986864b8a7b86a33e05dfc9ceedafd2 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 11:25:16 -0400 Subject: [PATCH 218/282] fix: EDT Exception when loading project --- src/main/java/bigwarp/BigWarp.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 8f38422b..a7f84c8f 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3994,13 +3994,17 @@ protected void loadSettingsOrProject( final File f ) if ( returnVal == JFileChooser.APPROVE_OPTION ) { settingsFile = fileChooser.getSelectedFile(); - try - { - loadSettings( settingsFile.getCanonicalPath(), true ); - } catch ( final Exception e ) - { - e.printStackTrace(); - } + + Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override + public void run() { + try { + loadSettings(settingsFile.getCanonicalPath(), true); + } catch (final Exception e) { + e.printStackTrace(); + } + } + }); } } From 27ae9a3a1ddf689f028f5543c84719dbfe4ee627 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 11:53:03 -0400 Subject: [PATCH 219/282] fix: transform mask overlay rendering in 2d --- .../overlay/BigWarpMaskSphereOverlay.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java index 5ecd29ed..0776abd7 100644 --- a/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java +++ b/src/main/java/bdv/viewer/overlay/BigWarpMaskSphereOverlay.java @@ -82,10 +82,10 @@ public void setRadii( double[] radii ) { this.radii = radii; } - + public void setInnerRadius( double inner ) { - double del = radii[1] - radii[0]; + final double del = radii[1] - radii[0]; radii[0] = inner; radii[1] = inner + del; } @@ -125,16 +125,14 @@ public void drawOverlays( final Graphics g ) g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); g2d.setComposite( AlphaComposite.SrcOver ); - final double scale; viewer.state().getViewerTransform( viewerTransform ); // synchronized - scale = Affine3DHelpers.extractScale( viewerTransform, 0 ); - + final double scale = Affine3DHelpers.extractScale( viewerTransform, 0 ); viewerTransform.apply( center, viewerCoords ); final double zv; if( is3d ) zv = viewerCoords[ 2 ]; - else + else zv = 0; final double dz2 = zv * zv; @@ -142,16 +140,18 @@ public void drawOverlays( final Graphics g ) { final double rad = radii[i]; final double scaledRadius = scale * rad; - final double arad; - if( is3d ) - arad = Math.sqrt( scaledRadius * scaledRadius - dz2 ); - else - arad = rad; - - final int rarad = (int)Math.round( arad ); - if ( viewerCoords[0] + scaledRadius > 0 && viewerCoords[0] - scaledRadius < width - && viewerCoords[1] + scaledRadius > 0 && viewerCoords[1] - scaledRadius < height ) + + if ( viewerCoords[0] + scaledRadius > 0 && viewerCoords[0] - scaledRadius < width && + viewerCoords[1] + scaledRadius > 0 && viewerCoords[1] - scaledRadius < height ) { + final double arad; + if( is3d ) + arad = Math.sqrt( scaledRadius * scaledRadius - dz2 ); + else + arad = scaledRadius; + + final int rarad = (int)Math.round( arad ); + g2d.setColor( colors[ i ] ); g2d.setStroke( stroke ); g2d.drawOval( (int)viewerCoords[0] - rarad, (int)viewerCoords[1] - rarad, From 067685c4896710c5dac1275104d54f185ff3e587 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 11:54:18 -0400 Subject: [PATCH 220/282] fix: json export of unspecified landmarks (infs) --- .../java/bigwarp/landmarks/LandmarkTableModel.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java index 5628c1a1..32ce2275 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java +++ b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java @@ -1550,15 +1550,15 @@ public void save( File f ) throws IOException modifiedSinceLastSave = false; } } - + public JsonElement toJson() { - final Gson gson = new Gson(); + final Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); final JsonObject out = new JsonObject(); - JsonElement mvgPtsObj = gson.toJsonTree(getMovingPoints(), new TypeToken >() {}.getType()); - JsonElement fixedPtsObj = gson.toJsonTree(getFixedPoints(), new TypeToken >() {}.getType()); - JsonElement activeObj = gson.toJsonTree( activeList ); - JsonElement namesObj = gson.toJsonTree( names ); + final JsonElement mvgPtsObj = gson.toJsonTree(getMovingPoints(), new TypeToken >() {}.getType()); + final JsonElement fixedPtsObj = gson.toJsonTree(getFixedPoints(), new TypeToken >() {}.getType()); + final JsonElement activeObj = gson.toJsonTree( activeList ); + final JsonElement namesObj = gson.toJsonTree( names ); out.add("type", new JsonPrimitive("BigWarpLandmarks")); out.add("numDimensions", new JsonPrimitive( ndims )); From 074bbd5f4ac41a2ecd1856f0f0c16b69d1daddc6 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 11:54:31 -0400 Subject: [PATCH 221/282] chore: LandmarkTableModel code style --- .../bigwarp/landmarks/LandmarkTableModel.java | 287 +++++++++--------- 1 file changed, 146 insertions(+), 141 deletions(-) diff --git a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java index 32ce2275..76f82674 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java +++ b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java @@ -8,19 +8,19 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . * #L% */ /** - * + * */ package bigwarp.landmarks; @@ -65,6 +65,7 @@ import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -83,7 +84,7 @@ public class LandmarkTableModel extends AbstractTableModel implements TransformListener< InvertibleRealTransform >{ private static final long serialVersionUID = -5865789085410559166L; - + private final double[] PENDING_PT; public static final int NAMECOLUMN = 0; @@ -91,14 +92,14 @@ public class LandmarkTableModel extends AbstractTableModel implements TransformL public static Color WARNINGBGCOLOR = new Color( 255, 204, 0 ); public static Color DEFAULTBGCOLOR = new Color( 255, 255, 255 ); - + private boolean DEBUG = false; - + protected int ndims = 3; - + protected int numCols = 8; protected int numRows = 0; - + protected int nextRowP = 0; protected int nextRowQ = 0; @@ -110,26 +111,26 @@ public class LandmarkTableModel extends AbstractTableModel implements TransformL protected ArrayList targetPts; // this list contains as many elemnts as the table, and - // contains a unique integer >= 0 if the row is active, or -1 otherwise + // contains a unique integer >= 0 if the row is active, or -1 otherwise protected ArrayList tableIndexToActiveIndex; protected boolean pointUpdatePending = false; // protected boolean pointUpdatePendingMoving = false; // protected Double[] pointToOverride; // hold a backup of a point for fallback - + // keeps track of whether points have been updated protected ArrayList doesPointHaveAndNeedWarp; protected ArrayList indicesOfChangedPoints; protected boolean elementDeleted = false; protected ArrayList needsInverse; - + // true for a row if, after the transform is updated, // the warped point has a higher error than the specified tolerance protected ArrayList movingDisplayPointUnreliable; - // the transformation + // the transformation protected ThinPlateR2LogRSplineKernelTransform estimatedXfm; - + // keeps track of warped points so we don't always have to do it on the fly protected ArrayList warpedPoints; @@ -143,13 +144,13 @@ public class LandmarkTableModel extends AbstractTableModel implements TransformL // keep track of the value of the last point that was edited but not-undoable // this lets us both render points correctly, and create desirable undo behavior // for point drags. - protected double[] lastPoint; + protected double[] lastPoint; protected double[] tmp; // keep track of edits for undo's and redo's protected LandmarkUndoManager undoRedoManager; - + protected BigWarpMessageAnimator message; protected boolean modifiedSinceLastSave; @@ -160,16 +161,16 @@ public class LandmarkTableModel extends AbstractTableModel implements TransformL "mvg-x","mvg-y","mvg-z", "fix-x","fix-y","fix-z" }; - + final static String[] columnNames2d = new String[] { "Name", "Active", "mvg-x","mvg-y", "fix-x","fix-y" }; - + final String[] columnNames; - + public final Logger logger = LoggerFactory.getLogger( LandmarkTableModel.class ); public LandmarkTableModel( int ndims ) @@ -179,32 +180,32 @@ public LandmarkTableModel( int ndims ) PENDING_PT = new double[ ndims ]; Arrays.fill( PENDING_PT, Double.POSITIVE_INFINITY ); lastPoint = PENDING_PT; - + names = new ArrayList<>(); activeList = new ArrayList<>(); tableIndexToActiveIndex = new ArrayList<>(); - + movingPts = new ArrayList(); targetPts = new ArrayList(); pointToOverride = new Double[ ndims ]; Arrays.fill( pointToOverride, Double.POSITIVE_INFINITY ); - + if( ndims == 2 ){ columnNames = columnNames2d; numCols = 6; }else{ columnNames = columnNames3d; } - + warpedPoints = new ArrayList(); doesPointHaveAndNeedWarp = new ArrayList(); movingDisplayPointUnreliable = new ArrayList(); indicesOfChangedPoints = new ArrayList(); needsInverse = new ArrayList(); - + setTableListener(); - + undoRedoManager = new LandmarkUndoManager(); estimatedXfm = new ThinPlateR2LogRSplineKernelTransform ( ndims ); @@ -221,7 +222,7 @@ public int getNumdims() { return ndims; } - + public double[] getPendingPoint() { return PENDING_PT; @@ -232,7 +233,7 @@ public ThinPlateR2LogRSplineKernelTransform getTransform() { return estimatedXfm; } - + @Deprecated public void printDistances() { @@ -246,13 +247,14 @@ public void printDistances() } } } - + public void printState() { System.out.println("nextRowP: " + nextRowP ); System.out.println("nextRowQ: " + nextRowQ ); } + @Override public String toString() { String str = ""; @@ -278,10 +280,10 @@ public boolean validateTransformPoints() } } } - + return true; } - + public void setTableListener() { addTableModelListener( new TableModelListener() @@ -289,9 +291,9 @@ public void setTableListener() @Override public void tableChanged( TableModelEvent e ) { - if( estimatedXfm != null && e.getColumn() == 1 && e.getType() == TableModelEvent.UPDATE ) // if its active + if( estimatedXfm != null && e.getColumn() == 1 && e.getType() == TableModelEvent.UPDATE ) // if its active { - int row = e.getFirstRow(); + final int row = e.getFirstRow(); indicesOfChangedPoints.add( row ); } } @@ -305,13 +307,13 @@ public boolean isModifiedSinceSave() protected void importTransformation( File ffwd, File finv ) throws IOException { - byte[] data = FileUtils.readFileToByteArray( ffwd ); + final byte[] data = FileUtils.readFileToByteArray( ffwd ); estimatedXfm = (ThinPlateR2LogRSplineKernelTransform) SerializationUtils.deserialize( data ); } - + protected void exportTransformation( File ffwd, File finv ) throws IOException { - byte[] data = SerializationUtils.serialize( estimatedXfm ); + final byte[] data = SerializationUtils.serialize( estimatedXfm ); FileUtils.writeByteArrayToFile( ffwd, data ); } @@ -319,16 +321,16 @@ public boolean isPointUpdatePending() { return pointUpdatePending; } - + public boolean isPointUpdatePendingMoving() { return pointUpdatePendingMoving; } - + public void restorePendingUpdate( ) { ArrayList< Double[] > pts; - + int i = 0; if( pointUpdatePendingMoving ) { @@ -340,17 +342,17 @@ public void restorePendingUpdate( ) i = nextRowQ; pts = movingPts; } - + for( int d = 0; d < ndims; d++ ) pts.get( i )[ d ] = pointToOverride[ d ]; - + activeList.set( i, true ); buildTableToActiveIndex(); pointUpdatePending = false; - + fireTableRowsUpdated( i, i ); } - + @Override public int getColumnCount() { @@ -370,30 +372,30 @@ public int getActiveRowCount() // //TODO consider keeping track of this actively instead of recomputing // int N = 0; // for( Boolean b : activeList ) -// if( b ) +// if( b ) // N++; // // return N; } - @Override + @Override public String getColumnName( int col ){ return columnNames[col]; } - + public ArrayList getPoints( boolean moving ) { if( moving ) return movingPts; - else + else return targetPts; } - public ArrayList getNames() + public ArrayList getNames() { return names; } - + public void setColumnName( int row, String name ) { names.set( row, name ); @@ -451,6 +453,7 @@ public int getActiveIndex( int tableIndex ) return tableIndexToActiveIndex.get( tableIndex ); } + @Override public Class getColumnClass( int col ){ if( col == NAMECOLUMN ){ return String.class; @@ -460,7 +463,7 @@ public Class getColumnClass( int col ){ return Double.class; } } - + public boolean isActive( int i ){ if( i < 0 || i >= getRowCount() ){ return false; @@ -519,25 +522,25 @@ public void deleteRowHelper( int i ) } /** - * Returns true if the ith row is unpaired - i.e., + * Returns true if the ith row is unpaired - i.e., * if either of the moving or target points are unset. - * + * * @param i row index - * @return true of the + * @return true of the */ public boolean isRowUnpaired( final int i ) { for( int d = 0; d < ndims; d++ ) - if( Double.isInfinite( movingPts.get( i )[ d ] ) || + if( Double.isInfinite( movingPts.get( i )[ d ] ) || Double.isInfinite( targetPts.get( i )[ d ] )) return true; return false; } - + /** * Returns true if any row is unpaired. - * + * * @return is update pending */ public boolean isUpdatePending() @@ -545,7 +548,7 @@ public boolean isUpdatePending() for( int i = 0; i < movingPts.size(); i++ ) if( isRowUnpaired( i )) return true; - + return false; } @@ -601,10 +604,10 @@ public void updateNextRows( int lastAddedIndex ) // nextRowQ = ( nextRowQ == numRows ) ? -1 : numRows; } } - + /** * Returns the next row to be updated for the moving or target columns. - * + * * @param isMoving isMoving * @return index of the next row */ @@ -636,11 +639,11 @@ public void updateWarpedPoint( int i, double[] pt ) doesPointHaveAndNeedWarp.set( i, true ); } } - + public void printWarpedPoints() { String s = ""; - int N = doesPointHaveAndNeedWarp.size(); + final int N = doesPointHaveAndNeedWarp.size(); for( int i = 0; i < N; i++ ) { if( doesPointHaveAndNeedWarp.get( i )) @@ -649,7 +652,7 @@ public void printWarpedPoints() s += String.format("%04d : ", i); for ( int d = 0; d < ndims; d++ ) s += String.format("%f\t", warpedPoints.get( i )[ d ] ); - + s+="\n"; } } @@ -660,7 +663,7 @@ public ArrayList< Double[] > getWarpedPoints() { return warpedPoints; } - + public ArrayList getChangedSinceWarp() { return doesPointHaveAndNeedWarp; @@ -681,7 +684,7 @@ public void resetWarpedPoints() public void resetNeedsInverse(){ Collections.fill( needsInverse, false ); } - + public void setNeedsInverse( int i ) { needsInverse.set( i, true ); @@ -691,7 +694,7 @@ public boolean rowNeedsWarning( int row ) { return movingDisplayPointUnreliable.get( row ); } - + protected void firePointUpdated( int row, boolean isMoving ) { modifiedSinceLastSave = true; @@ -702,29 +705,29 @@ protected void firePointUpdated( int row, boolean isMoving ) private void addEmptyRow( int index ) { synchronized(this) { - Double[] movingPt = new Double[ ndims ]; - Double[] targetPt = new Double[ ndims ]; + final Double[] movingPt = new Double[ ndims ]; + final Double[] targetPt = new Double[ ndims ]; Arrays.fill( targetPt, Double.POSITIVE_INFINITY ); Arrays.fill( movingPt, Double.POSITIVE_INFINITY ); movingPts.add( index, movingPt ); targetPts.add( index, targetPt ); - + names.add( index, nextName( index )); activeList.add( index, false ); warpedPoints.add( index, new Double[ ndims ] ); doesPointHaveAndNeedWarp.add( index, false ); movingDisplayPointUnreliable.add( index, false ); tableIndexToActiveIndex.add( -1 ); - + numRows++; modifiedSinceLastSave = true; } fireTableRowsInserted( index, index ); } - + public void clearPt( int row, boolean isMoving ) { pointEdit( row, PENDING_PT, false, isMoving, null, true ); @@ -745,12 +748,12 @@ public boolean add( double[] pt, boolean isMoving, final RealTransform xfm ) { return pointEdit( -1, pt, true, isMoving, false, true, xfm ); } - + public void setPoint( int row, boolean isMoving, double[] pt, final RealTransform xfm ) { setPoint( row, isMoving, pt, true, xfm ); } - + public void setPoint( int row, boolean isMoving, double[] pt, boolean isUndoable, final RealTransform xfm ) { pointEdit( row, pt, false, isMoving, false, isUndoable, xfm ); @@ -771,7 +774,7 @@ public boolean pointEdit( final int index, final double[] pt, final boolean forc /** * Changes a point's position, or adds a new point. *

- * + * * @param index The index into this table that this edit will affect ( a value of -1 will add a new point ) * @param pt the point position * @param forceAdd force addition of a new point at the specified index @@ -785,7 +788,7 @@ public boolean pointEdit( int index, double[] pt, boolean forceAdd, boolean isMo boolean isAdd; synchronized ( this ) { - // this means we should add a new point. + // this means we should add a new point. // index of this point should be the next free row in the table if( index == -1 ) { @@ -815,7 +818,7 @@ public boolean pointEdit( int index, double[] pt, boolean forceAdd, boolean isMo oldpt = toPrimitive( targetPts.get( index ) ); } } - + ArrayList< Double[] > pts; /******************** @@ -828,7 +831,7 @@ public boolean pointEdit( int index, double[] pt, boolean forceAdd, boolean isMo pts = targetPts; // create a new point and add it - Double[] exPts = new Double[ ndims ]; + final Double[] exPts = new Double[ ndims ]; for( int i = 0; i < ndims; i++ ){ exPts[ i ] = pt[ i ]; } @@ -895,7 +898,7 @@ public void resetLastPoint() /** * Looks through the table for points where there is a point in moving space but not fixed space. * For any such landmarks that are found, compute the inverse transform and add the result to the fixed points line. - * + * * @param xfm the new transformation */ public void updateAllWarpedPoints( final InvertibleRealTransform xfm ) @@ -924,7 +927,7 @@ public void updateAllWarpedPoints( final InvertibleRealTransform xfm ) * If these conditions are satisfied, the position of the moving point in * target space by iteratively estimating the inverse of the thin plate * spline transformation. - * + * * @param i the row in the table * @param xfm the invertible transformation */ @@ -936,15 +939,15 @@ public void computeWarpedPoint( int i, final InvertibleRealTransform xfm ) // TODO Perhaps move this into its own thread. and expose the parameters for solving the inverse. if ( !isFixedPoint( i ) && isMovingPoint( i ) && xfm != null ) { - double[] tgt = toPrimitive( movingPts.get( i ) ); + final double[] tgt = toPrimitive( movingPts.get( i ) ); - double[] warpedPt = new double[ ndims ]; + final double[] warpedPt = new double[ ndims ]; xfm.applyInverse( warpedPt, tgt ); if( xfm instanceof WrappedIterativeInvertibleRealTransform ) { - WrappedIterativeInvertibleRealTransform inv = (WrappedIterativeInvertibleRealTransform)xfm; - double error = inv.getOptimzer().getError(); + final WrappedIterativeInvertibleRealTransform inv = (WrappedIterativeInvertibleRealTransform)xfm; + final double error = inv.getOptimzer().getError(); if( error > inverseThreshold ) { @@ -957,8 +960,8 @@ public void computeWarpedPoint( int i, final InvertibleRealTransform xfm ) } // TODO should check for failure or non-convergence here - // can use the error returned by the inverse method to do this. - // BUT - it's not clear what to do upon failure + // can use the error returned by the inverse method to do this. + // BUT - it's not clear what to do upon failure updateWarpedPoint( i, warpedPt ); } } @@ -981,7 +984,7 @@ public int getIndexNearestTo( double[] pt, boolean isMoving ) for( int i = 0; i < numRows; i++ ) { p = getPoint( isMoving, i ); - double thisdist = squaredDistance( p, pt ); + final double thisdist = squaredDistance( p, pt ); if( thisdist < minDist ) { minDist = thisdist; @@ -1009,7 +1012,7 @@ public int getIndexNearestTo( RealLocalizable pt, boolean isMoving ) for( int i = 0; i < numRows; i++ ) { p = getPoint( isMoving, i ); - double thisdist = squaredDistance( p, pt ); + final double thisdist = squaredDistance( p, pt ); if( thisdist < minDist ) { minDist = thisdist; @@ -1060,9 +1063,9 @@ public ArrayList< Double[] > getFixedPoints() public ArrayList getMovingPointsCopy() { final ArrayList< double[] > out = new ArrayList(); - for( Double[] p : movingPts ) + for( final Double[] p : movingPts ) { - double[] q = new double[ ndims ]; + final double[] q = new double[ ndims ]; for( int d = 0; d < ndims; d++ ) q[d] = p[d]; @@ -1074,9 +1077,9 @@ public ArrayList getMovingPointsCopy() public ArrayList getFixedPointsCopy() { final ArrayList< double[] > out = new ArrayList(); - for( Double[] p : targetPts ) + for( final Double[] p : targetPts ) { - double[] q = new double[ ndims ]; + final double[] q = new double[ ndims ]; for( int d = 0; d < ndims; d++ ) q[d] = p[d]; @@ -1120,7 +1123,7 @@ public void activateRow( int index ) { activate = false; break; - } + } } changed = activate != activeList.get( index ); @@ -1139,7 +1142,7 @@ public void activateRow( int index ) /** * Returns a name for a row to be inserted at the given index. - * + * * @param index index of the row * @return a name for the new row */ @@ -1158,18 +1161,18 @@ private String nextName( int index ) // Increment the index in the name of the previous row i = 1 + Integer.parseInt( names.get( index - 1 ).replaceAll( "Pt-", "" )); } - catch ( Exception e ){} + catch ( final Exception e ){} s = String.format( "Pt-%d", i ); } return s; } - + /** * Sets a flag that indicates the point at the input index has changed * since the last time a transform was estimated. - * - * Not currently in use, but may be in the future + * + * Not currently in use, but may be in the future * @param index the row index */ @SuppressWarnings("unused") @@ -1178,7 +1181,7 @@ private void markAsChanged( int index ) for( int i = 0; i < this.numRows; i++ ) { if( !indicesOfChangedPoints.contains( i )) - indicesOfChangedPoints.add( i ); + indicesOfChangedPoints.add( i ); } } @@ -1188,7 +1191,7 @@ public void resetUpdated() indicesOfChangedPoints.clear(); elementDeleted = false; } - + @Deprecated public void transferUpdatesToModel() { @@ -1222,14 +1225,14 @@ else if( f.getCanonicalPath().endsWith("json")) public static LandmarkTableModel loadFromCsv( File f, boolean invert ) throws IOException { - CSVReader reader = new CSVReader( new FileReader( f.getAbsolutePath() ) ); + final CSVReader reader = new CSVReader( new FileReader( f.getAbsolutePath() ) ); List< String[] > rows = null; try { rows = reader.readAll(); reader.close(); } - catch ( CsvException e ) {} + catch ( final CsvException e ) {} LandmarkTableModel ltm = null; if ( rows.get( 0 ).length == 6 ) @@ -1251,14 +1254,14 @@ else if ( rows.get( 0 ).length == 8 ) */ public void loadCsv( File f, boolean invert ) throws IOException { - CSVReader reader = new CSVReader( new FileReader( f.getAbsolutePath() )); + final CSVReader reader = new CSVReader( new FileReader( f.getAbsolutePath() )); List< String[] > rows = null; try { rows = reader.readAll(); reader.close(); } - catch( CsvException e ){} + catch( final CsvException e ){} loadCsvHelper( invert, rows ); } @@ -1284,7 +1287,7 @@ protected void loadCsvHelper( boolean invert, final List rows ) throws int expectedRowLength = 8; int i = 0; - for( String[] row : rows ) + for( final String[] row : rows ) { // detect a file with 2d landmarks if( i == 0 && // only check for the first row @@ -1300,8 +1303,8 @@ protected void loadCsvHelper( boolean invert, final List rows ) throws names.add( row[ 0 ] ); activeList.add( Boolean.parseBoolean( row[ 1 ]) ); - Double[] movingPt = new Double[ ndims ]; - Double[] targetPt = new Double[ ndims ]; + final Double[] movingPt = new Double[ ndims ]; + final Double[] targetPt = new Double[ ndims ]; int k = 2; for( int d = 0; d < ndims; d++ ) @@ -1346,7 +1349,7 @@ public int numActive() /** * Copies point values from this table into a destination array. - * Checks whether the provided index exists, returns false if no + * Checks whether the provided index exists, returns false if no * point exists for the requested index. * * @param point the destination array @@ -1371,7 +1374,7 @@ public boolean copyPointSafe(double[] point, int index, boolean moving) { /** * Copies moving point values from this table into a destination array. - * Checks whether the provided index exists, returns false if no + * Checks whether the provided index exists, returns false if no * point exists for the requested index. * * @param point the destination array @@ -1392,7 +1395,7 @@ public boolean copyMovingPointSafe(double[] point, int index) { /** * Copies warped moving point values from this table into a destination array. - * Checks whether the provided index exists, returns false if no + * Checks whether the provided index exists, returns false if no * point exists for the requested index. * * @param point the destination array @@ -1413,7 +1416,7 @@ public boolean copyWarpedPointSafe(double[] point, int index) { /** * Copies target point values from this table into a destination array. - * Checks whether the provided index exists, returns false if no + * Checks whether the provided index exists, returns false if no * point exists for the requested index. * * @param point the destination array @@ -1466,7 +1469,7 @@ public void copyLandmarks( int tableIndex, double[][] movingLandmarks, double[][ if ( activeList.get( tableIndex ) ) { - int activeIndex = getActiveIndex( tableIndex ); + final int activeIndex = getActiveIndex( tableIndex ); for ( int d = 0; d < ndims; d++ ) { movingLandmarks[ d ][ activeIndex ] = movingPts.get( tableIndex )[ d ]; @@ -1502,18 +1505,18 @@ public void copyLandmarks( double[][] movingLandmarks, double[][] targetLandmark @Deprecated public void initTransformation() { - int numActive = numActive(); + final int numActive = numActive(); // TODO: better to pass a factory here so the transformation can be any // CoordinateTransform ( not just a TPS ) - double[][] mvgPts = new double[ ndims ][ numActive ]; - double[][] tgtPts = new double[ ndims ][ numActive ]; + final double[][] mvgPts = new double[ ndims ][ numActive ]; + final double[][] tgtPts = new double[ ndims ][ numActive ]; copyLandmarks( mvgPts, tgtPts ); // need to find the "inverse TPS" so exchange moving and tgt estimatedXfm = new ThinPlateR2LogRSplineKernelTransform( ndims, tgtPts, mvgPts ); } - + /** * Saves the table to a file * @param f the file @@ -1521,16 +1524,16 @@ public void initTransformation() */ public void save( File f ) throws IOException { - CSVWriter csvWriter = new CSVWriter(new FileWriter( f.getAbsoluteFile() )); + final CSVWriter csvWriter = new CSVWriter(new FileWriter( f.getAbsoluteFile() )); - synchronized(this) { - int N = names.size(); - List rows = new ArrayList( N ); - - int rowLength = 2 * ndims + 2; + synchronized(this) { + final int N = names.size(); + final List rows = new ArrayList( N ); + + final int rowLength = 2 * ndims + 2; for( int i = 0; i < N; i++ ) { - String[] row = new String[ rowLength ]; + final String[] row = new String[ rowLength ]; row[ 0 ] = names.get( i ); row[ 1 ] = activeList.get( i ).toString(); @@ -1577,7 +1580,7 @@ public void fromJson( File f ) try { final Reader reader = Channels.newReader(FileChannel.open(Paths.get( f.getCanonicalPath()), options), StandardCharsets.UTF_8.name()); fromJson( gson.fromJson(reader, JsonObject.class )); - } catch (IOException e) { + } catch (final IOException e) { e.printStackTrace(); } } @@ -1593,10 +1596,10 @@ public void fromJson( JsonElement json ) synchronized(this) { clear(); - JsonArray namesArr = landmarks.get("names").getAsJsonArray(); - JsonArray activeArr = landmarks.get("active").getAsJsonArray(); - JsonArray mvgArr = landmarks.get("movingPoints").getAsJsonArray(); - JsonArray fixedArr = landmarks.get("fixedPoints").getAsJsonArray(); + final JsonArray namesArr = landmarks.get("names").getAsJsonArray(); + final JsonArray activeArr = landmarks.get("active").getAsJsonArray(); + final JsonArray mvgArr = landmarks.get("movingPoints").getAsJsonArray(); + final JsonArray fixedArr = landmarks.get("fixedPoints").getAsJsonArray(); numRows = namesArr.size(); final int ndims = landmarks.get("numDimensions").getAsInt(); @@ -1608,7 +1611,7 @@ public void fromJson( JsonElement json ) activeList.add( activeArr.get(i).getAsBoolean() ); final JsonElement mvg = mvgArr.get( i ); - JsonElement fixed = fixedArr.get( i ); + final JsonElement fixed = fixedArr.get( i ); final Double[] movingPt = new Double[ ndims ]; final Double[] targetPt = new Double[ ndims ]; @@ -1640,13 +1643,14 @@ public static String print( Double[] d ) String out = ""; for( int i=0; i= numRows || col >= numCols ) @@ -1673,12 +1677,12 @@ else if( col == ACTIVECOLUMN ) } else if( col < 2 + ndims ) { - Double[] thesePts = movingPts.get(row); + final Double[] thesePts = movingPts.get(row); thesePts[ col - 2 ] = ((Double)value).doubleValue(); } else { - Double[] thesePts = targetPts.get(row); + final Double[] thesePts = targetPts.get(row); thesePts[ col - ndims - 2 ] = ((Double)value).doubleValue(); } @@ -1686,7 +1690,7 @@ else if( col < 2 + ndims ) fireTableCellUpdated(row, col); } - + @Override public Object getValueAt( int rowIndex, int columnIndex ) { @@ -1703,9 +1707,10 @@ else if( columnIndex < 2 + ndims ) } /** - * Only allow editing of the first ("Name") and + * Only allow editing of the first ("Name") and * second ("Active") column */ + @Override public boolean isCellEditable( int row, int col ) { return ( col <= ACTIVECOLUMN ); @@ -1718,15 +1723,15 @@ public boolean isCellEditable( int row, int col ) */ public LandmarkTableModel invert() { - LandmarkTableModel inv = new LandmarkTableModel( ndims ); + final LandmarkTableModel inv = new LandmarkTableModel( ndims ); - int N = this.getRowCount(); + final int N = this.getRowCount(); - double[] tmp = new double[ ndims ]; + final double[] tmp = new double[ ndims ]; for ( int i = 0; i < N; i++ ) { - Double[] thisMoving = movingPts.get( i ); - Double[] thisTarget = targetPts.get( i ); + final Double[] thisMoving = movingPts.get( i ); + final Double[] thisTarget = targetPts.get( i ); for ( int d = 0; d < ndims; d++ ) tmp[ d ] = thisMoving[ d ]; @@ -1749,16 +1754,16 @@ public LandmarkUndoManager getUndoManager() public static double[] copy( double[] in ) { - double[] out = new double[ in.length ]; + final double[] out = new double[ in.length ]; for ( int i = 0; i < in.length; i++ ) out[ i ] = in [ i ]; - + return out; } - + public static double[] toPrimitive( Double[] in ) { - double[] out = new double[ in.length ]; + final double[] out = new double[ in.length ]; for ( int i = 0; i < in.length; i++ ) out[ i ] = in[ i ]; From 104164117a216a555259e2134377a6a6902b324c Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 13:14:08 -0400 Subject: [PATCH 222/282] fix: NPE in NgffTransformations addCoordinateTransformations --- .../bigwarp/transforms/NgffTransformations.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index 6107ce07..a8783537 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -291,12 +291,16 @@ public static < T extends NativeType< T > & RealType< T > > DisplacementFieldCoo public static void addCoordinateTransformations( final N5Writer n5, final String groupPath, final CoordinateTransform transform ) { - // TODO untested final CoordinateTransform[] cts = n5.getAttribute(groupPath, CoordinateTransform.KEY, CoordinateTransform[].class); - final CoordinateTransform[] ctsOut = new CoordinateTransform[ cts.length + 1 ]; - System.arraycopy(cts, 0, ctsOut, 0, cts.length); - ctsOut[ cts.length ] = transform; - + final CoordinateTransform[] ctsOut; + if (cts == null) + ctsOut = new CoordinateTransform[] { transform }; + else + { + ctsOut = new CoordinateTransform[cts.length + 1]; + System.arraycopy(cts, 0, ctsOut, 0, cts.length); + ctsOut[ ctsOut.length - 1 ] = transform; + } n5.setAttribute(groupPath, CoordinateTransform.KEY, ctsOut); } From 236e42ee59259bf99b806543d9f2d476b404f9df Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 16:07:20 -0400 Subject: [PATCH 223/282] feat: add detect NgffTransformation --- .../transforms/NgffTransformations.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index a8783537..59a36cb8 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -6,6 +6,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; @@ -36,6 +37,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import net.imglib2.RandomAccessibleInterval; import net.imglib2.realtransform.AffineGet; @@ -54,6 +56,50 @@ public class NgffTransformations public static void main( final String[] args ) throws Exception { + // detect transformations + final String loc = "/home/john/Desktop/dfield.n5"; + final N5URI uri = new N5URI(loc); + +// final CoordinateTransform[] cts = detectTransforms(loc); +// System.out.println(Arrays.toString(cts)); + + System.out.println(detectTransforms(loc)); + +// System.out.println( uri ); +// System.out.println( uri.getURI() ); +// +// final String grp = ( uri.getGroupPath() != null ) ? uri.getGroupPath() : ""; +// System.out.println( grp ); +// +// final String attr = ( uri.getAttributePath() != null ) ? uri.getAttributePath() : ""; +// System.out.println( attr ); + +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( uri.getContainerPath() ); +// final JsonObject json = n5.getAttribute(grp, attr, JsonObject.class); +// final String ver = n5.getAttribute(grp, "n5", String.class); +// final JsonElement jcts = n5.getAttribute(grp, "coordinateTransformations", JsonElement.class); +// final JsonElement jct = n5.getAttribute(grp, "coordinateTransformations[0]", JsonElement.class); +// final CoordinateTransform ct = n5.getAttribute(grp, "coordinateTransformations[0]", CoordinateTransform.class); +// final CoordinateTransform[] cts = n5.getAttribute(grp, "coordinateTransformations", CoordinateTransform[].class); + +// System.out.println(""); +// System.out.println(json); +// System.out.println(""); +// System.out.println(ver); +// System.out.println(""); +// System.out.println(jcts); +// System.out.println(""); +// System.out.println(jct); +// System.out.println(""); +// System.out.println(ct); +// System.out.println(ct.getType()); +// System.out.println(""); +// System.out.println(Arrays.toString(cts)); + + +// openTransformN5( url ); + + // full // final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5?/#/coordinateTransformations[0]"; @@ -188,6 +234,42 @@ public static InvertibleRealTransform openInvertible(final String url) { return null; } + /** + * Finds a candidate transformation in the n5 attributes at the given url and returns the + * complete URI for that transformation if found, otherwise null. + * + * @param url the base url + * @return the complete n5uri for a transformation, or null + */ + public static String detectTransforms( final String url ) + { + // detect transformations + N5URI uri; + try { + uri = new N5URI(url); + } catch (final URISyntaxException e) { + return null; + } + + final String grp = ( uri.getGroupPath() != null ) ? uri.getGroupPath() : ""; + final String attr = ( uri.getAttributePath() != null && !uri.getAttributePath().equals("/")) ? uri.getAttributePath() : "coordinateTransformations"; + + final N5Reader n5; + try { + + n5 = new N5Factory().gsonBuilder(gsonBuilder()).openReader(uri.getContainerPath()); + final CoordinateTransform[] cts = n5.getAttribute(grp, attr, CoordinateTransform[].class); + + if (cts != null && cts.length > 0) + try { + return N5URI.from(uri.getContainerPath(), grp, "coordinateTransformations[0]").toString(); + } catch (final URISyntaxException e) {} + + } catch (final N5Exception e) {} + + return null; + } + public static Pair,N5Reader> openTransformN5( final String url ) { try From 814169aeb0d8f433e5aa34de34fd5f390a88f598 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 25 Sep 2023 16:09:41 -0400 Subject: [PATCH 224/282] feat: toward detect and auto-completing transform uri in bw dialog --- src/main/java/bdv/gui/BigWarpInitDialog.java | 40 +++++++++++++- .../sourceList/BigWarpSourceTableModel.java | 54 ++++++++++++++----- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 20bc5eda..d39e8f82 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -5,6 +5,8 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; @@ -22,6 +24,7 @@ import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; +import javax.swing.Timer; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; @@ -495,7 +498,7 @@ public JPanel createContent() panel.add( addN5TransformButton, cn5 ); addN5TransformButton.addActionListener( e -> { - selectionDialog.run( this::n5DialogCallback ); + selectionDialog.run( this::n5DialogTransformCallback ); }); // source list @@ -509,10 +512,20 @@ public JPanel createContent() clist.fill = GridBagConstraints.BOTH; clist.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); - sourceTableModel = new BigWarpSourceTableModel(); + sourceTableModel = new BigWarpSourceTableModel( t -> { + final String val = NgffTransformations.detectTransforms(t); + if( val == null ) + showMessage(1000, "No transformation found"); + else + showMessage(1000, "Found transformation"); + + return val; + }); + final BigWarpSourceListPanel srcListPanel = new BigWarpSourceListPanel( sourceTableModel ); sourceTableModel.setContainer( srcListPanel ); sourceTable = srcListPanel.getJTable(); + sourceTable.putClientProperty("terminateEditOnFocusLost", true); panel.add( srcListPanel, clist ); // bottom button section @@ -594,6 +607,16 @@ public void n5DialogCallback( final DataSelection selection ) repaint(); } + public void n5DialogTransformCallback( final DataSelection selection ) + { + final String n5RootPath = selectionDialog.getN5RootPath(); + final int i = sourceTable.getSelectedRow(); + if( selection.metadata.size() > 0 ) + sourceTableModel.setTransform(i, n5RootPath + "?" + selection.metadata.get(0).getPath() ); + + repaint(); + } + protected void addImage() { if ( !imageJOpen && datasetService == null) @@ -898,6 +921,19 @@ public String macroRecord() return Recorder.getCommandOptions(); } + protected void showMessage( int timeMillis, String message ) + { + messageLabel.setText(message); + final Timer timer = new Timer( timeMillis, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + messageLabel.setText(""); + } + }); + timer.setRepeats(false); + timer.start(); + } + public static void runMacro( final String args ) { final String project = Macro.getValue( args, projectKey, "" ); diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index 0a2e393b..bf4eb452 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -4,6 +4,8 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; +import java.util.function.Consumer; +import java.util.function.Function; import javax.swing.DefaultCellEditor; import javax.swing.JButton; @@ -16,7 +18,7 @@ import bigwarp.transforms.NgffTransformations; import net.imglib2.realtransform.RealTransform; -public class BigWarpSourceTableModel extends AbstractTableModel +public class BigWarpSourceTableModel extends AbstractTableModel { private static final long serialVersionUID = 5923947651732788341L; @@ -33,19 +35,27 @@ public static enum SourceType { IMAGEPLUS, DATASET, URL }; protected static int transformColIdx = 2; protected static int removeColIdx = 3; + protected Function transformChangedCallback; + private Component container; public BigWarpSourceTableModel() + { + this(null); + } + + public BigWarpSourceTableModel(final Function transformChangedCallback ) { super(); columnNames = colNames; sources = new ArrayList<>(); rmRowButtons = new ArrayList<>(); + this.transformChangedCallback = transformChangedCallback; } - + /** * Set the {@link Component} to repaint when a row is removed. - * + * * @param container the component containing this table */ public void setContainer( Component container ) @@ -58,7 +68,7 @@ public SourceRow get( int i ) return sources.get( i ); } - @Override + @Override public String getColumnName( int col ){ return columnNames[col]; } @@ -84,6 +94,7 @@ public Object getValueAt( int r, int c ) return sources.get( r ).get( c ); } + @Override public Class getColumnClass( int col ){ if ( col == 1 ) return Boolean.class; @@ -104,10 +115,23 @@ public void setValueAt(Object value, int row, int col) { if( col == movingColIdx ) sources.get( row ).moving = (Boolean)value; - if( col == imageColIdx ) + else if( col == imageColIdx ) sources.get( row ).srcName = (String)value; - if( col == transformColIdx ) - sources.get( row ).transformUrl = (String)value; + else if( col == transformColIdx ) + setTransform( (String)value, row ); + } + + protected void setTransform(String value, int row) + { + if (transformChangedCallback != null) + { + final String res = transformChangedCallback.apply(value); + if (res != null) + sources.get(row).transformUrl = res; + else + sources.get(row).transformUrl = value; + } else + sources.get(row).transformUrl = value; } public void add( String srcName, boolean moving, SourceType type ) @@ -186,9 +210,9 @@ public static class SourceRow public String srcName; public boolean moving; public String transformUrl; - + public SourceType type; - + public SourceRow( String srcName, boolean moving, String transformUrl, SourceType type ) { this.srcName = srcName; @@ -244,7 +268,7 @@ public void setRow(int row) } /** - * From + * From * http://www.java2s.com/Code/Java/Swing-Components/ButtonTableExample.htm */ protected static class ButtonRenderer extends JButton implements TableCellRenderer @@ -254,6 +278,7 @@ public ButtonRenderer() setOpaque( true ); } + @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column ) { if ( isSelected ) @@ -272,7 +297,7 @@ public Component getTableCellRendererComponent( JTable table, Object value, bool } /** - * From + * From * http://www.java2s.com/Code/Java/Swing-Components/ButtonTableExample.htm */ protected static class ButtonEditor extends DefaultCellEditor @@ -280,7 +305,7 @@ protected static class ButtonEditor extends DefaultCellEditor protected JButton button; private String label; - + private RemoveRowButton thisButton; private BigWarpSourceTableModel model; @@ -297,6 +322,7 @@ public ButtonEditor( JCheckBox checkBox, BigWarpSourceTableModel model ) button.setOpaque( true ); button.addActionListener( new ActionListener() { + @Override public void actionPerformed( ActionEvent e ) { fireEditingStopped(); @@ -304,6 +330,7 @@ public void actionPerformed( ActionEvent e ) } ); } + @Override public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected, int row, int column ) { if ( isSelected ) @@ -323,6 +350,7 @@ public Component getTableCellEditorComponent( JTable table, Object value, boolea return button; } + @Override public Object getCellEditorValue() { if ( isPushed ) @@ -333,12 +361,14 @@ public Object getCellEditorValue() return new String( label ); } + @Override public boolean stopCellEditing() { isPushed = false; return super.stopCellEditing(); } + @Override protected void fireEditingStopped() { super.fireEditingStopped(); From d5f2398a16044b413f15dc83dce6ea0b0a9de817 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 27 Sep 2023 11:43:29 -0400 Subject: [PATCH 225/282] feat: transform export dialog changes when exporting an affine * add BigWarpTransform.isNonLinear --- .../bdv/gui/ExportDisplacementFieldFrame.java | 81 ++++++++++--------- .../bigwarp/transforms/BigWarpTransform.java | 5 ++ 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index 919d3885..d06200d7 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -126,7 +126,7 @@ public ExportDisplacementFieldFrame( BigWarpData data, BigWarpTransform bwTra this.data = data; this.bwTransform = bwTransform; this.ltm = ltm; - + cancelCallback = x -> { dispose(); setVisible( false ); @@ -176,7 +176,7 @@ public static void createAndShow( final BigWarp< ? > bw ) public static void createAndShow( BigWarpData< ? > data, BigWarpTransform bwTransform, LandmarkTableModel ltm ) { - ExportDisplacementFieldFrame frame = new ExportDisplacementFieldFrame( data, bwTransform, ltm ); + final ExportDisplacementFieldFrame frame = new ExportDisplacementFieldFrame( data, bwTransform, ltm ); frame.createContent(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.pack(); @@ -185,6 +185,8 @@ public static void createAndShow( BigWarpData< ? > data, BigWarpTransform bwTran public void createContent() { + final boolean isNonlinear = bwTransform.isNonlinear(); + n5DatasetChanged = false; final int frameSizeX = UIScale.scale( 600 ); @@ -217,19 +219,22 @@ public void createContent() unit = src.getVoxelDimensions().unit(); } - fovPanel = new FieldOfViewPanel( data, ltm, bwTransform, unit, 150, - new double[] { 0, 0, 0 }, - new double[] { 1, 1, 1 }, - new long[] { 256, 256, 128 } - ); - - fovPanel.setBorder( BorderFactory.createCompoundBorder( - BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), - BorderFactory.createCompoundBorder( - BorderFactory.createTitledBorder( - BorderFactory.createEtchedBorder(), - "Field of view" ), - BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); + if( isNonlinear ) + { + fovPanel = new FieldOfViewPanel( data, ltm, bwTransform, unit, 150, + new double[] { 0, 0, 0 }, + new double[] { 1, 1, 1 }, + new long[] { 256, 256, 128 } + ); + + fovPanel.setBorder( BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 4, 2, 4, 2 ), + BorderFactory.createCompoundBorder( + BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "Field of view" ), + BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ) ) ); + } contentPanel = new JPanel(); contentPanel.setLayout( new GridBagLayout() ); @@ -248,7 +253,8 @@ public void createContent() cGbc.gridy = 2; contentPanel.add( n5Panel, cGbc ); cGbc.gridy = 3; - contentPanel.add( fovPanel, cGbc ); + if( isNonlinear ) + contentPanel.add( fovPanel, cGbc ); // bottom button section final GridBagConstraints cbot = new GridBagConstraints(); @@ -281,10 +287,13 @@ public void createContent() final Container content = getContentPane(); content.add( contentPanel ); - if( data != null ) - fovPanel.updateFieldsFromReference(); - else - fovPanel.updateFieldsFromImageJReference(); + if( isNonlinear ) + { + if( data != null ) + fovPanel.updateFieldsFromReference(); + else + fovPanel.updateFieldsFromImageJReference(); + } addDefaultN5DatasetAction(); } @@ -356,7 +365,7 @@ public JPanel basicPanel() gbcCheck.gridy = 1; gbcCheck.insets = defaultInsets; gbcCheck.anchor = GridBagConstraints.LINE_START; - typeComboBox = new JComboBox< String >( new String[] { + typeComboBox = new JComboBox< String >( new String[] { BigWarpToDeformationFieldPlugIn.flattenOption, BigWarpToDeformationFieldPlugIn.sequenceOption } ); panel.add( typeComboBox, gbcCheck ); @@ -382,7 +391,7 @@ public JPanel basicPanel() splitAffineCheckBox = new JCheckBox(); panel.add( splitAffineCheckBox, gbcCheck ); - // second row + // second row ctxt.gridx = 0; ctxt.gridy = 2; ctxt.anchor = GridBagConstraints.LINE_END; @@ -420,7 +429,7 @@ public JPanel inverseOptionsPanel( final int frameSizeX ) final int BUTTON_PAD = BigWarpInitDialog.DEFAULT_BUTTON_PAD; final int MID_PAD = BigWarpInitDialog.DEFAULT_MID_PAD; - JPanel panel = new JPanel(); + final JPanel panel = new JPanel(); panel.setLayout( new GridBagLayout() ); final GridBagConstraints ctxt = new GridBagConstraints(); @@ -452,8 +461,8 @@ public JPanel inverseOptionsPanel( final int frameSizeX ) gbcBar.fill = GridBagConstraints.HORIZONTAL; invToleranceSpinner = new JSpinner( new SpinnerNumberModel( 0.5, 1e-9, 999999, 0.01 ) ); - JSpinner.NumberEditor editor = new JSpinner.NumberEditor(invToleranceSpinner, "###,###.######"); - JFormattedTextField textField = editor.getTextField(); + final JSpinner.NumberEditor editor = new JSpinner.NumberEditor(invToleranceSpinner, "###,###.######"); + final JFormattedTextField textField = editor.getTextField(); textField.setColumns(12); invToleranceSpinner.setEditor(editor); @@ -477,7 +486,7 @@ public JPanel n5OptionsPanel( final int frameSizeX ) final int BUTTON_PAD = BigWarpInitDialog.DEFAULT_BUTTON_PAD; final int MID_PAD = BigWarpInitDialog.DEFAULT_MID_PAD; - JPanel panel = new JPanel(); + final JPanel panel = new JPanel(); panel.setLayout( new GridBagLayout() ); final GridBagConstraints ctxt = new GridBagConstraints(); @@ -659,13 +668,13 @@ else if ( homeDir != null ) return path; } - + public DeformationFieldExportParameters getParams() { final String n5BlockSizeString = n5BlockSizeTxt.getText(); - final int[] blockSize = n5BlockSizeString.isEmpty() ? null : + final int[] blockSize = n5BlockSizeString.isEmpty() ? null : Arrays.stream( n5BlockSizeString.split( "," ) ).mapToInt( Integer::parseInt ).toArray(); - + return new DeformationFieldExportParameters( landmarkPathTxt == null ? "" : landmarkPathTxt.getText(), splitAffineCheckBox.isSelected(), @@ -676,13 +685,13 @@ public DeformationFieldExportParameters getParams() virtualCheckBox.isSelected(), (Integer)nThreadsField.getValue(), (String)formatComboBox.getSelectedItem(), - fovPanel.getPixelSize(), - fovPanel.getSpacing(), - fovPanel.getMin(), - fovPanel.getUnit(), + fovPanel == null ? null : fovPanel.getPixelSize(), + fovPanel == null ? null : fovPanel.getSpacing(), + fovPanel == null ? null : fovPanel.getMin(), + fovPanel == null ? null : fovPanel.getUnit(), n5RootTxt.getText(), n5DatasetTxt.getText(), - blockSize, + blockSize, BigWarpToDeformationFieldPlugIn.getCompression( (String)n5CompressionDropdown.getSelectedItem() ) ); } @@ -747,10 +756,10 @@ public static void runMacro( String args ) final String n5BlockSizeString = Macro.getValue( args, n5BlockSizeKey, "" ); final String n5Compression = Macro.getValue( args, n5CompressionKey, "" ); - final int[] blockSize = n5BlockSizeString.isEmpty() ? null : + final int[] blockSize = n5BlockSizeString.isEmpty() ? null : Arrays.stream( n5BlockSizeString.split( "," ) ).mapToInt( Integer::parseInt ).toArray(); - DeformationFieldExportParameters params = new DeformationFieldExportParameters( + final DeformationFieldExportParameters params = new DeformationFieldExportParameters( landmarks, splitAffine, type, direction, tolerance, maxIters, openAsVirtual, threads, format, diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 7be6e943..460b42e3 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -246,6 +246,11 @@ public void setLambda( final RealRandomAccessible< ? extends RealType< ? > > lam updateLambda(); } + public boolean isNonlinear() + { + return getTransformType().equals(BigWarpTransform.TPS); + } + public InvertibleRealTransform getTransformation() { return getTransformation( -1, true ); From ab49809cab6e7c26557b5c2b8972e1c0f6e13995 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 27 Sep 2023 11:44:05 -0400 Subject: [PATCH 226/282] chore: cleaning --- .../java/bdv/gui/sourceList/BigWarpSourceTableModel.java | 8 -------- .../bigwarp/metadata/BwN5CosemMultiScaleMetadata.java | 1 - .../metadata/BwN5ViewerMultiscaleMetadataParser.java | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index bf4eb452..a794d0b5 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -137,11 +137,6 @@ protected void setTransform(String value, int row) public void add( String srcName, boolean moving, SourceType type ) { final RemoveRowButton rmButton = new RemoveRowButton( sources.size() ); -// rmButton.addActionListener( e -> { -// System.out.println( "pushed rm row button " + rmButton.getRow() ); -// remove( rmButton.getRow() ); -// }); - rmRowButtons.add( rmButton ); sources.add( new SourceRow( srcName, moving, "", type )); } @@ -184,10 +179,7 @@ public void addDataset( String srcName, boolean isMoving ) public boolean remove( int i ) { if( i >= sources.size() ) - { - //System.out.println( "NOT REMOVED - SHOULD NEVER BE CALLED" ); return false; - } sources.remove( i ); rmRowButtons.remove( i ); diff --git a/src/main/java/bigwarp/metadata/BwN5CosemMultiScaleMetadata.java b/src/main/java/bigwarp/metadata/BwN5CosemMultiScaleMetadata.java index 1d220e34..438cf6a1 100644 --- a/src/main/java/bigwarp/metadata/BwN5CosemMultiScaleMetadata.java +++ b/src/main/java/bigwarp/metadata/BwN5CosemMultiScaleMetadata.java @@ -118,7 +118,6 @@ public class BwN5CosemMultiScaleMetadata //extends MultiscaleMetadata paths = new ArrayList<>(); // // children.forEach( c -> { -//// System.out.println( c.getPath() ); // if( scaleLevelNodes.containsKey( c.getNodeName() )) // { // paths.add( c .getPath()); diff --git a/src/main/java/bigwarp/metadata/BwN5ViewerMultiscaleMetadataParser.java b/src/main/java/bigwarp/metadata/BwN5ViewerMultiscaleMetadataParser.java index bbebea9d..8651de50 100644 --- a/src/main/java/bigwarp/metadata/BwN5ViewerMultiscaleMetadataParser.java +++ b/src/main/java/bigwarp/metadata/BwN5ViewerMultiscaleMetadataParser.java @@ -88,7 +88,7 @@ public class BwN5ViewerMultiscaleMetadataParser //implements N5GroupParser< N5Mu // final List paths = new ArrayList<>(); // // children.forEach( c -> { -//// System.out.println( c.getPath() ); +//// System.out.println( c.getPath() ) // if( scaleLevelNodes.containsKey( c.getNodeName() )) // { // paths.add( c .getPath()); From e4e5ad5702185d319587457a15c8b1821fa2e213 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Wed, 27 Sep 2023 11:50:57 -0400 Subject: [PATCH 227/282] fix/feat: dfield export of 2d masked transformations --- .../ij/BigWarpToDeformationFieldPlugIn.java | 204 +++++++++++------- src/main/java/bigwarp/BigWarpData.java | 4 +- .../bigwarp/transforms/BigWarpTransform.java | 14 +- .../transforms/NgffTransformations.java | 195 ++++++++++++++--- .../InvertibleWrapped2DIntermediate3D.java | 108 ++++++++++ .../SpatiallyInterpolatedRealTransform.java | 14 +- 6 files changed, 414 insertions(+), 125 deletions(-) create mode 100644 src/main/java/net/imglib2/realtransform/InvertibleWrapped2DIntermediate3D.java diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 39ca533b..59794100 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -41,7 +41,6 @@ import org.janelia.saalfeldlab.n5.Compression; import org.janelia.saalfeldlab.n5.GzipCompression; import org.janelia.saalfeldlab.n5.Lz4Compression; -import org.janelia.saalfeldlab.n5.N5Exception; import org.janelia.saalfeldlab.n5.N5Writer; import org.janelia.saalfeldlab.n5.RawCompression; import org.janelia.saalfeldlab.n5.XzCompression; @@ -53,6 +52,7 @@ import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.DisplacementFieldCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.SequenceCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.TranslationCoordinateTransform; import bdv.gui.ExportDisplacementFieldFrame; import bigwarp.BigWarp; @@ -72,6 +72,15 @@ import ij.plugin.PlugIn; import ij.plugin.frame.Recorder; import jitk.spline.ThinPlateR2LogRSplineKernelTransform; +import mpicbg.models.AffineModel2D; +import mpicbg.models.AffineModel3D; +import mpicbg.models.InvertibleCoordinateTransform; +import mpicbg.models.RigidModel2D; +import mpicbg.models.RigidModel3D; +import mpicbg.models.SimilarityModel2D; +import mpicbg.models.SimilarityModel3D; +import mpicbg.models.TranslationModel2D; +import mpicbg.models.TranslationModel3D; import net.imglib2.Cursor; import net.imglib2.FinalInterval; import net.imglib2.Interval; @@ -91,6 +100,7 @@ import net.imglib2.realtransform.DisplacementFieldTransform; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.InvertibleRealTransformSequence; +import net.imglib2.realtransform.InvertibleWrapped2DIntermediate3D; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.RealTransformSequence; import net.imglib2.realtransform.ScaleAndTranslation; @@ -149,7 +159,6 @@ public static void main( final String[] args ) public void runFromBigWarpInstance( final BigWarp bw ) { -// System.out.println( "run from instance." ); // ImageJ ij = IJ.getInstance(); // if ( ij == null ) // return; @@ -174,7 +183,6 @@ public void runFromBigWarpInstance( final BigWarp bw ) // public void runFromBigWarpInstanceOld( // final BigWarpData data, final LandmarkTableModel landmarkModel, final SourceAndConverter< T > sourceAndConverter ) // { -// System.out.println( "run from instance." ); // ImageJ ij = IJ.getInstance(); // if ( ij == null ) // return; @@ -235,6 +243,7 @@ public static void runFromParameters( final DeformationFieldExportParameters par { final String unit = "pixel"; LandmarkTableModel ltm; + if( landmarkModel == null ) { if( params.landmarkPath == null || params.landmarkPath.isEmpty() ) @@ -273,7 +282,11 @@ public static void runFromParameters( final DeformationFieldExportParameters par if ( params.n5Base.isEmpty() ) { - if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) + if( !bwTransform.isNonlinear() ) // is linear + { + IJ.showMessage("unsupported at the moment"); + } + else if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), false, params.virtual, params.size, params.spacing, params.nThreads ); toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), true, params.virtual, params.size, params.spacing, params.nThreads ); @@ -286,25 +299,22 @@ public static void runFromParameters( final DeformationFieldExportParameters par } else { - try + if( !bwTransform.isNonlinear() ) // is linear { - if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) - { - writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), - false, params.inverseTolerance, params.inverseMaxIterations ); - writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), - true, params.inverseTolerance, params.inverseMaxIterations ); - } - else - { - final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); - writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), - inverse, params.inverseTolerance, params.inverseMaxIterations ); - } + writeAffineN5(params.n5Base, params.n5Dataset, "input", "output", bwTransform ); } - catch ( final N5Exception e ) + else if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { - e.printStackTrace(); + writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), + false, params.inverseTolerance, params.inverseMaxIterations ); + writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), + true, params.inverseTolerance, params.inverseMaxIterations ); + } + else + { + final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); + writeN5( params.n5Base, params.n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), + inverse, params.inverseTolerance, params.inverseMaxIterations ); } } } @@ -328,65 +338,6 @@ public void run( final String args ) ExportDisplacementFieldFrame.createAndShow(); } - public void runBackup( final String arg ) - { - if ( IJ.versionLessThan( "1.40" ) ) - return; - - final DeformationFieldExportParameters params = DeformationFieldExportParameters.fromDialog( true, true ); - final int nd = params.size.length; - - final String unit = "pixel"; - // load - final LandmarkTableModel ltm = new LandmarkTableModel( nd ); - try - { - ltm.load( new File( params.landmarkPath ) ); - } - catch ( final IOException e ) - { - e.printStackTrace(); - return; - } - - if( params.n5Base.isEmpty() ) - { - if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) - { - toImagePlus( null, ltm, null, params.ignoreAffine, params.flatten(), false, params.virtual, params.size, params.spacing, params.nThreads ); - toImagePlus( null, ltm, null, params.ignoreAffine, params.flatten(), true, params.virtual, params.size, params.spacing, params.nThreads ); - } - else - { - final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); - toImagePlus( null, ltm, null, params.ignoreAffine, params.flatten(), inverse, params.virtual, params.size, params.spacing, params.nThreads ); - } - } - else - { - try - { - if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) - { - writeN5( params.n5Base, params.n5Dataset + "/dfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), - false, params.inverseTolerance, params.inverseMaxIterations ); - writeN5( params.n5Base, params.n5Dataset + "/invdfield", ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), - true, params.inverseTolerance, params.inverseMaxIterations ); - } - else - { - final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); - writeN5( params.n5Base, params.n5Dataset, ltm, null, null, params.size, params.spacing, params.offset, unit, params.blockSize, params.compression, params.nThreads, params.format, params.ignoreAffine, params.flatten(), - inverse, params.inverseTolerance, params.inverseMaxIterations ); - } - } - catch ( final N5Exception e ) - { - e.printStackTrace(); - } - } - } - public static ImagePlus toImagePlus( final BigWarpData data, final LandmarkTableModel ltm, @@ -440,6 +391,7 @@ public static ImagePlus toImagePlus( final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten, splitAffine ); final InvertibleRealTransform startingTransform = inverse ? fwdTransform.inverse() : fwdTransform; + final InvertibleRealTransform transform; final int nd = ltm.getNumdims(); long[] ipDims = null; if ( nd == 2 ) @@ -449,6 +401,11 @@ public static ImagePlus toImagePlus( ipDims[ 1 ] = dims[ 1 ]; ipDims[ 2 ] = 2; ipDims[ 3 ] = 1; + + if (bwXfm.isMasked()) + transform = new InvertibleWrapped2DIntermediate3D(startingTransform); + else + transform = startingTransform; } else if ( nd == 3 ) { @@ -457,11 +414,13 @@ else if ( nd == 3 ) ipDims[ 1 ] = dims[ 1 ]; ipDims[ 2 ] = 3; ipDims[ 3 ] = dims[ 2 ]; + + transform = startingTransform; } else return null; - final RandomAccessibleInterval< DoubleType > dfieldVirt = DisplacementFieldTransform.createDisplacementField( startingTransform, new FinalInterval( dims ), spacing, offset ); + final RandomAccessibleInterval< DoubleType > dfieldVirt = DisplacementFieldTransform.createDisplacementField( transform, new FinalInterval( dims ), spacing, offset ); ImagePlus dfieldIp; if( virtual ) @@ -477,7 +436,8 @@ else if ( nd == 3 ) final FloatImagePlus< FloatType > dfield = ImagePlusImgs.floats( ipDims ); // make the "vector" axis the first dimension - final RandomAccessibleInterval< FloatType > dfieldImpPerm = Views.moveAxis( dfield, 2, 0 ); + // 2d displacement fields will have an extraneous singleton z-dimension + final RandomAccessibleInterval< FloatType > dfieldImpPerm = Views.dropSingletonDimensions( Views.moveAxis( dfield, 2, 0 )); LoopBuilder.setImages( dfieldVirt, dfieldImpPerm ).multiThreaded( TaskExecutors.fixedThreadPool( nThreads ) ).forEachPixel( (x,y) -> { y.setReal(x.get()); }); dfieldIp = dfield.getImagePlus(); } @@ -574,6 +534,78 @@ protected static InvertibleRealTransform getTransformation( final BigWarpData return startingTransform; } + public static void writeAffineN5( + final String n5BasePath, + final String n5Dataset, + final String input, + final String output, + final BigWarpTransform bwTransform ) + { + CoordinateTransform ct = null; + final InvertibleCoordinateTransform tform = bwTransform.getCoordinateTransform(); + switch( bwTransform.getTransformType()) { + case BigWarpTransform.TRANSLATION: + if (tform instanceof TranslationModel2D) + ct = new TranslationCoordinateTransform("translation transformation", input, output, ((TranslationModel2D)tform).getTranslation()); + else if (tform instanceof TranslationModel3D) + ct = new TranslationCoordinateTransform("translation transformation", input, output, ((TranslationModel3D)tform).getTranslation()); + break; + case BigWarpTransform.SIMILARITY: + double[] simparams; + if (tform instanceof SimilarityModel2D) + { + simparams = new double[ 6 ]; + ((SimilarityModel2D)tform).toArray(simparams); + ct = new AffineCoordinateTransform("translation transformation", input, output, simparams); + } + else if (tform instanceof SimilarityModel3D) + { + simparams = new double[ 12 ]; + ((SimilarityModel3D)tform).toArray(simparams); + ct = new AffineCoordinateTransform("translation transformation", input, output, simparams); + } + break; + case BigWarpTransform.ROTATION: + double[] rotparams; + if (tform instanceof RigidModel2D) + { + rotparams = new double[ 6 ]; + ((RigidModel2D)tform).toArray(rotparams); + ct = new AffineCoordinateTransform("translation transformation", input, output, rotparams); + } + else if (tform instanceof RigidModel3D) + { + rotparams = new double[ 12 ]; + ((RigidModel3D)tform).toArray(rotparams); + ct = new AffineCoordinateTransform("translation transformation", input, output, rotparams); + } + break; + case BigWarpTransform.AFFINE: + double[] affparams; + if (tform instanceof AffineModel2D) + { + affparams = new double[ 6 ]; + ((AffineModel2D)tform).toArray(affparams); + ct = new AffineCoordinateTransform("translation transformation", input, output, affparams); + } + else if (tform instanceof AffineModel3D) + { + affparams = new double[ 12 ]; + ((AffineModel3D)tform).toArray(affparams); + ct = new AffineCoordinateTransform("translation transformation", input, output, affparams); + } + break; + } + + if( ct == null ) + return; + + final String dataset = (n5Dataset == null) ? "" : n5Dataset; + final N5Factory factory = new N5Factory().gsonBuilder( NgffTransformations.gsonBuilder() ); + final N5Writer n5 = factory.openWriter( n5BasePath ); + NgffTransformations.addCoordinateTransformations(n5, dataset, ct); + } + public static void writeN5( final String n5BasePath, final LandmarkTableModel ltm, @@ -665,6 +697,12 @@ public static void writeN5( final InvertibleRealTransform fwdTransform = getTransformation( data, bwXfm, flatten, splitAffine ); final InvertibleRealTransform totalTransform = inverse ? fwdTransform.inverse() : fwdTransform; + final InvertibleRealTransform transform; + + if (totalTransform.numSourceDimensions() == 2 && bwXfm.isMasked()) + transform = new InvertibleWrapped2DIntermediate3D(totalTransform); + else + transform = totalTransform; final int[] spatialBlockSize = fillBlockSize( spatialBlockSizeArg, ltm.getNumdims() ); final int[] blockSize = new int[ spatialBlockSize.length + 1 ]; @@ -683,7 +721,7 @@ public static void writeN5( // displacement field (with the affine removed) final RealTransformSequence totalNoAffine = new RealTransformSequence(); - totalNoAffine.add( totalTransform ); + totalNoAffine.add( transform ); totalNoAffine.add( affine.inverse() ); dfield = DisplacementFieldTransform.createDisplacementField( totalNoAffine, new FinalInterval( dims ), spacing ); @@ -705,7 +743,7 @@ public static void writeN5( } else { - dfield = DisplacementFieldTransform.createDisplacementField( totalTransform, new FinalInterval( dims ), spacing ); + dfield = DisplacementFieldTransform.createDisplacementField( transform, new FinalInterval( dims ), spacing ); if( format.equals( ExportDisplacementFieldFrame.FMT_SLICER )) { diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index 51ed6b1e..a3271f27 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -331,9 +331,9 @@ public Source applyFixedTransform( final Source src, final RealTransfo if( transform.numSourceDimensions() < 3 ) { if( transform instanceof InvertibleRealTransform ) - tform = new Wrapped2DTransformAs3D( transform ); - else tform = new InvertibleWrapped2DTransformAs3D( ( InvertibleRealTransform ) transform ); + else + tform = new Wrapped2DTransformAs3D( transform ); } if( transform instanceof AffineGet ) diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java index 460b42e3..71c089b3 100644 --- a/src/main/java/bigwarp/transforms/BigWarpTransform.java +++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java @@ -115,12 +115,6 @@ public BigWarpTransform( final LandmarkTableModel tableModel, final String trans updateSolver(); } - public void setTransformType( final String transformType ) - { - this.transformType = transformType; - updateSolver(); - } - public void setMaskIntensityBounds( final double min, final double max ) { lambdaConverterMin = min; @@ -230,6 +224,12 @@ public int getInverseMaxIterations() return maxIterations; } + public void setTransformType( final String transformType ) + { + this.transformType = transformType; + updateSolver(); + } + public String getTransformType() { return transformType; @@ -378,7 +378,7 @@ public InvertibleRealTransform unwrap2d( InvertibleRealTransform ixfm ) public AffineTransform3D affine3d() { final AffineTransform3D out = new AffineTransform3D(); - if( transformType.equals( TransformTypeSelectDialog.TPS )) + if( transformType.equals( TPS )) { return affine3d( getTpsBase(), out ); } diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index 59a36cb8..4217e180 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -37,13 +37,14 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import net.imglib2.RandomAccessibleInterval; import net.imglib2.realtransform.AffineGet; +import net.imglib2.realtransform.AffineTransform; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.ScaleGet; +import net.imglib2.realtransform.Translation2D; import net.imglib2.realtransform.TranslationGet; import net.imglib2.type.NativeType; import net.imglib2.type.numeric.RealType; @@ -56,14 +57,83 @@ public class NgffTransformations public static void main( final String[] args ) throws Exception { - // detect transformations - final String loc = "/home/john/Desktop/dfield.n5"; - final N5URI uri = new N5URI(loc); + +// final String p2pUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[1]"; +// final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( p2pUri ); +// final CoordinateTransform ct = pair.getA(); +// System.out.println( ct ); +// System.out.println( ct.getType() ); +// +// final N5Reader n5 = pair.getB(); +//// final RealTransform tform = ct.getTransform(n5); +//// System.out.println( tform ); +// +// +// final SequenceCoordinateTransform sct = (SequenceCoordinateTransform)ct; +// final AffineGet affine = sct.asAffine(3); +// System.out.println( affine.getRowPackedCopy()); + + + + final String dfUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[0]"; + final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( dfUri ); + final CoordinateTransform ct = pair.getA(); + System.out.println( ct ); + + final N5Reader n5 = pair.getB(); + final RealTransform tform = ct.getTransform(n5); + System.out.println( tform ); + + + + + +// final AffineTransform affine = new AffineTransform( 2 ); +// final Translation2D t = new Translation2D( new double[] { 5, 6 } ); +// System.out.println( Arrays.toString(affine.getRowPackedCopy() )); +// affine.preConcatenate(t); +// System.out.println( Arrays.toString(affine.getRowPackedCopy() )); + + + +// // detect transformations +// final String loc = "/home/john/Desktop/tforms.n5"; +// final N5URI uri = new N5URI(loc); + +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( loc ); +//// final RealTransform tform = findFieldTransformFirst( n5, "/dfield2d" ); +// final RealTransform tform = findFieldTransformStrict( n5, "/dfield2d", "boats.tif_dfield" ); + + +// // detect transformations +// final String loc = "/home/john/Desktop/tforms.n5"; +// final N5URI uri = new N5URI(loc); +// +// // dfield 2d path +// final String dfUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[0]"; +//// final String dfUri = "/home/john/Desktop/tforms.n5?/#coordinateTransformations[2]"; +//// final String dfPartUri = "/home/john/Desktop/tforms.n5"; +// +//// final RealTransform tform = open(dfUri); +//// System.out.println(tform); +// +// final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( dfUri ); +// final CoordinateTransform ct = pair.getA(); +// System.out.println( ct ); +// +// final RealTransform tform = ct.getTransform( pair.getB()); +// System.out.println( tform ); + + +// final String s = detectTransforms(dfUri); +// System.out.println( "full uri: " + s ); +// System.out.println("inferred full uri: " + detectTransforms(dfPartUri)); + // final CoordinateTransform[] cts = detectTransforms(loc); // System.out.println(Arrays.toString(cts)); - System.out.println(detectTransforms(loc)); +// System.out.println(detectTransforms(loc)); // System.out.println( uri ); // System.out.println( uri.getURI() ); @@ -234,6 +304,57 @@ public static InvertibleRealTransform openInvertible(final String url) { return null; } + public static RealTransform findFieldTransformFirst(final N5Reader n5, final String group) { + + final String normGrp = N5URI.normalizeGroupPath(group); + System.out.println( "nnrmGrp: " + normGrp ); + + final CoordinateTransform[] transforms = n5.getAttribute(group, CoordinateTransform.KEY, CoordinateTransform[].class); + if (transforms == null) + return null; + + if( transforms.length == 1 ) + { + + } + + boolean found = false; + for (final CoordinateTransform ct : transforms) { + System.out.println(ct); + final String nrmInput = N5URI.normalizeGroupPath(ct.getInput()); + System.out.println( "nrmInput: " + nrmInput ); + if (nrmInput.equals(normGrp)) { + found = true; + System.out.println( "found: " + ct ); + } + + } + + return null; + } + + public static RealTransform findFieldTransformStrict(final N5Reader n5, final String group, final String output ) { + + final String normGrp = N5URI.normalizeGroupPath(group); + System.out.println( "nnrmGrp: " + normGrp ); + + final CoordinateTransform[] transforms = n5.getAttribute(group, CoordinateTransform.KEY, CoordinateTransform[].class); + if (transforms == null) + return null; + + final boolean found = false; + for (final CoordinateTransform ct : transforms) { + System.out.println(ct); + final String nrmInput = N5URI.normalizeGroupPath(ct.getInput()); + System.out.println( "nrmInput: " + nrmInput ); + if (nrmInput.equals(normGrp) && ct.getOutput().equals(output) ) { + System.out.println( "found: " + ct ); + return ct.getTransform(n5); + } + } + return null; + } + /** * Finds a candidate transformation in the n5 attributes at the given url and returns the * complete URI for that transformation if found, otherwise null. @@ -244,32 +365,50 @@ public static InvertibleRealTransform openInvertible(final String url) { public static String detectTransforms( final String url ) { // detect transformations - N5URI uri; + final N5URI uri; try { uri = new N5URI(url); } catch (final URISyntaxException e) { return null; } - final String grp = ( uri.getGroupPath() != null ) ? uri.getGroupPath() : ""; - final String attr = ( uri.getAttributePath() != null && !uri.getAttributePath().equals("/")) ? uri.getAttributePath() : "coordinateTransformations"; +// final String grp = ( uri.getGroupPath() != null ) ? uri.getGroupPath() : ""; +// final String attr = ( uri.getAttributePath() != null && !uri.getAttributePath().equals("/")) ? uri.getAttributePath() : "coordinateTransformations[0]"; - final N5Reader n5; - try { + if( isValidTransformUri( url )) + return url; - n5 = new N5Factory().gsonBuilder(gsonBuilder()).openReader(uri.getContainerPath()); - final CoordinateTransform[] cts = n5.getAttribute(grp, attr, CoordinateTransform[].class); + if (!uri.getAttributePath().equals("coordinateTransformations[0]")) { - if (cts != null && cts.length > 0) - try { - return N5URI.from(uri.getContainerPath(), grp, "coordinateTransformations[0]").toString(); - } catch (final URISyntaxException e) {} + String defaultUri; + try { + defaultUri = N5URI.from(uri.getContainerPath(), uri.getGroupPath(), "coordinateTransformations[0]").toString(); + if( isValidTransformUri( defaultUri )) + return defaultUri; + } catch (final URISyntaxException e) { } + } + +// final N5Reader n5 = new N5Factory().gsonBuilder(gsonBuilder()).openReader(uri.getContainerPath()); +// final CoordinateTransform[] cts = n5.getAttribute(grp, attr, CoordinateTransform[].class); +// +// if (cts != null && cts.length > 0) +// try { +// return N5URI.from(uri.getContainerPath(), grp, "coordinateTransformations[0]").toString(); +// } catch (final URISyntaxException e) {} - } catch (final N5Exception e) {} return null; } + private static boolean isValidTransformUri(final String uri) { + + final Pair, N5Reader> out = openTransformN5(uri); + if (out != null && out.getA() != null) + return true; + + return false; + } + public static Pair,N5Reader> openTransformN5( final String url ) { try @@ -284,16 +423,19 @@ public static Pair,N5Reader> openTransformN5( final Strin { final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( loc ); final String dataset = n5url.getGroupPath() != null ? n5url.getGroupPath() : "/"; - final String attribute = n5url.getAttributePath() != null ? n5url.getAttributePath() : "coordinateTransformations/[0]"; + final String attribute = n5url.getAttributePath(); +// final String attribute = n5url.getAttributePath() != null ? n5url.getAttributePath() : "coordinateTransformations[0]"; final CoordinateTransform ct = n5.getAttribute(dataset, attribute, CoordinateTransform.class); - final CoordinateTransform nct = CoordinateTransform.create(ct); - return new ValuePair<>( nct, n5 ); + return new ValuePair<>( ct, n5 ); + +// final CoordinateTransform nct = CoordinateTransform.create(ct); +// return new ValuePair<>( nct, n5 ); } } - catch ( URISyntaxException | N5Exception e ) + catch ( URISyntaxException | N5Exception | ClassCastException e ) { - e.printStackTrace(); +// e.printStackTrace(); return null; } } @@ -313,16 +455,13 @@ public static CoordinateTransform openJson( final String url ) final Gson gson = gsonBuilder().create(); final JsonElement elem = gson.fromJson( string, JsonElement.class ); -// System.out.println( elem ); // final CoordinateTransformation ct = gson.fromJson( elem.getAsJsonArray().get( 0 ), CoordinateTransformation.class ); final CoordinateTransform ct = gson.fromJson( elem, CoordinateTransform.class ); -// System.out.println( ct ); final CoordinateTransform< ? > nct = CoordinateTransform.create( ct ); return nct; // final RealTransform tform = nct.getTransform( null ); -// System.out.println( tform ); // // return tform; } @@ -383,6 +522,10 @@ public static void addCoordinateTransformations( final N5Writer n5, final String System.arraycopy(cts, 0, ctsOut, 0, cts.length); ctsOut[ ctsOut.length - 1 ] = transform; } + + if( !n5.exists(groupPath)) + n5.createGroup(groupPath); + n5.setAttribute(groupPath, CoordinateTransform.KEY, ctsOut); } @@ -488,7 +631,7 @@ private static double[] prepend(double val, double[] array) { public static CoordinateSystem createVectorFieldCoordinateSystem(final String name, final CoordinateSystem input) { final Axis[] vecAxes = new Axis[input.getAxes().length + 1]; - vecAxes[0] = new Axis("d", "displacement", null, true); + vecAxes[0] = new Axis("displacement", "d", null, true); for (int i = 1; i < vecAxes.length; i++) vecAxes[i] = input.getAxes()[i - 1]; diff --git a/src/main/java/net/imglib2/realtransform/InvertibleWrapped2DIntermediate3D.java b/src/main/java/net/imglib2/realtransform/InvertibleWrapped2DIntermediate3D.java new file mode 100644 index 00000000..04a7cb0c --- /dev/null +++ b/src/main/java/net/imglib2/realtransform/InvertibleWrapped2DIntermediate3D.java @@ -0,0 +1,108 @@ +/*- + * #%L + * BigWarp plugin for Fiji. + * %% + * Copyright (C) 2015 - 2022 Howard Hughes Medical Institute. + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package net.imglib2.realtransform; + +import net.imglib2.RealLocalizable; +import net.imglib2.RealPositionable; + +public class InvertibleWrapped2DIntermediate3D implements InvertibleRealTransform +{ + public InvertibleRealTransform transform; + + public double[] tmp; + + public InvertibleWrapped2DIntermediate3D( final InvertibleRealTransform transform ) + { + this.transform = transform; + tmp = new double[ 3 ]; + } + + @Override + public int numSourceDimensions() + { + return 2; + } + + @Override + public int numTargetDimensions() + { + return 2; + } + + public InvertibleRealTransform getTransform() + { + return transform; + } + + @Override + public void apply(double[] source, double[] target) + { + tmp[ 0 ] = target[ 0 ]; + tmp[ 1 ] = target[ 1 ]; + transform.apply( tmp, tmp ); + source[ 0 ] = tmp[ 0 ]; + source[ 1 ] = tmp[ 1 ]; + } + + @Override + public void apply(RealLocalizable source, RealPositionable target) + { + tmp[ 0 ] = source.getDoublePosition( 0 ); + tmp[ 1 ] = source.getDoublePosition( 1 ); + transform.apply( tmp, tmp ); + target.setPosition( tmp[ 0 ], 0 ); + target.setPosition( tmp[ 1 ], 1 ); + } + + @Override + public void applyInverse( double[] source, double[] target ) + { + tmp[ 0 ] = target[ 0 ]; + tmp[ 1 ] = target[ 1 ]; + transform.applyInverse( tmp, tmp ); + source[ 0 ] = tmp[ 0 ]; + source[ 1 ] = tmp[ 1 ]; + } + + @Override + public void applyInverse( RealPositionable source, RealLocalizable target ) + { + tmp[ 0 ] = target.getDoublePosition( 0 ); + tmp[ 1 ] = target.getDoublePosition( 1 ); + transform.applyInverse( tmp, tmp ); + source.setPosition( tmp[ 0 ], 0 ); + source.setPosition( tmp[ 1 ], 1 ); + } + + @Override + public InvertibleWrapped2DIntermediate3D copy() + { + return new InvertibleWrapped2DIntermediate3D( transform.copy() ); + } + + @Override + public InvertibleRealTransform inverse() + { + return new InvertibleWrapped2DIntermediate3D( transform.inverse() ); + } + +} diff --git a/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java index a550ca70..f9391f1c 100644 --- a/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java +++ b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java @@ -12,7 +12,7 @@ *

* Given a {@link RealRandomAccessible} "lambda", and two transformations "a", and "b", implements the transformation * lambda * a(x) + (1-lambda) * b(x) for a point x. - * + * * @author John Bogovic * * @param lambda's type @@ -44,7 +44,7 @@ public SpatiallyInterpolatedRealTransform(RealTransform a, RealTransform b, Real this.lambda = lambda; lambdaAccess = lambda.realRandomAccess(); - int nd = a.numTargetDimensions(); + final int nd = a.numTargetDimensions(); arrA = new double[nd]; arrB = new double[nd]; pa = RealPoint.wrap(arrA); @@ -70,13 +70,13 @@ public void apply(double[] source, double[] target) { b.apply(source, arrB); // lambdaAccess.setPosition(source); - for( int i = 0; i < source.length; i++ ) + for( int i = 0; i < numSourceDimensions(); i++ ) lambdaAccess.setPosition( source[ i ], i ); final double am = lambdaAccess.get().getRealDouble(); final double bm = (1 - am); - for (int i = 0; i < target.length; i++) + for (int i = 0; i < numTargetDimensions(); i++) target[i] = am * arrA[i] + bm * arrB[i]; } @@ -87,10 +87,10 @@ public void apply(RealLocalizable source, RealPositionable target) { b.apply(source, pb); lambdaAccess.setPosition(source); - double am = lambdaAccess.get().getRealDouble(); - double bm = (1 - am); + final double am = lambdaAccess.get().getRealDouble(); + final double bm = (1 - am); - for (int i = 0; i < target.numDimensions(); i++) + for (int i = 0; i < numTargetDimensions(); i++) target.setPosition(am * pa.getDoublePosition(i) + bm * pb.getDoublePosition(i), i); } From c0cfff549a2e9e68dade0ac3c566d15c8b760eb6 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 28 Sep 2023 14:21:59 -0400 Subject: [PATCH 228/282] fix: deserialize transformation type --- src/main/java/bigwarp/BigWarp.java | 4 +++- src/main/java/bigwarp/transforms/io/TransformWriterJson.java | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index a7f84c8f..c3707c4f 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3468,7 +3468,9 @@ public void mouseReleased( final MouseEvent e ) public void setTransformType( final String type ) { - bwTransform.setTransformType( type ); + updateTransformTypePanel(type); + updateTransformTypeDialog(type); + bwTransform.setTransformType(type); this.restimateTransformation(); } diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index ac73e5a7..4c95b0ba 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -115,6 +115,9 @@ public static void read( final BigWarp< ? > bw, final JsonObject json ) } } + if( json.has( "type" )) + bw.setTransformType(json.get("type").getAsString()); + } } From 01da73bd1be894a51fecd344b98cafbee7506290 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 28 Sep 2023 14:26:32 -0400 Subject: [PATCH 229/282] feat: serialize source transformations --- src/main/java/bdv/gui/BigWarpInitDialog.java | 29 ++++++++++++------- .../sourceList/BigWarpSourceTableModel.java | 9 ++++++ src/main/java/bigwarp/BigWarpInit.java | 11 +++---- src/main/java/bigwarp/BigwarpSettings.java | 26 +++++++++++++++-- .../transforms/io/TransformWriterJson.java | 4 ++- .../BigWarpTransformedSourcesTest.java | 10 +++---- .../java/bigwarp/dfield/DfieldExportTest.java | 17 +++++------ 7 files changed, 72 insertions(+), 34 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index d39e8f82..a634da04 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -189,7 +189,7 @@ public static void main( final String[] args ) throws IOException createAndShow(); } - public static void runBigWarp( final String projectLandmarkPath, final String[] images, final String[] moving, final String[] transforms ) + public static BigWarp runBigWarp( final String projectLandmarkPath, final String[] images, final String[] moving, final String[] transforms ) { final BigWarpData< T > data = BigWarpInit.initData(); final boolean haveProjectLandmarkArg = projectLandmarkPath != null && !projectLandmarkPath.isEmpty(); @@ -210,13 +210,19 @@ public static void runBigWarp( final String projectLandmarkPath, final Strin { final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, images[ i ], id, moving[ i ].equals( "true" ) ); - final String transformUrl = transforms[ i ]; RealTransform transform = null; - if( transformUrl!= null && !transformUrl.isEmpty() ) - transform = NgffTransformations.open( transformUrl ); + final String transformUrl; + if( transforms != null && transforms.length > i ) + { + transformUrl = transforms[ i ]; + if( transformUrl!= null && !transformUrl.isEmpty() ) + transform = NgffTransformations.open( transformUrl ); + } + else + transformUrl = null; // add performs a null check on transform - BigWarpInit.add( data, infos, transform ); + BigWarpInit.add( data, infos, transform, transformUrl == null ? null : () -> transformUrl ); id += infos.size(); } @@ -235,10 +241,12 @@ public static void runBigWarp( final String projectLandmarkPath, final Strin } } - BigWarp bw; + BigWarp bw = null; try { + bwOpts.is2D(BigWarp.detectNumDims( data.sources ) == 2); data.applyTransformations(); + bw = new BigWarp<>( data, bwOpts, new ProgressWriterIJ() ); if( haveProject ) bw.loadSettings( projectLandmarkPath, true ); @@ -258,6 +266,7 @@ else if( haveLandmarks ) e.printStackTrace(); } + return bw; } public void runBigWarp() @@ -288,7 +297,7 @@ public void runBigWarp() // strip off prefix if present final ImagePlus imp = WindowManager.getImage( tableRow.srcName.replaceAll( "^"+ImageJPrefix, "" ) ); final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, imp, id, 0, tableRow.moving ); - BigWarpInit.add( data, infos, tableRow.getTransform() ); + BigWarpInit.add( data, infos, tableRow.getTransform(), tableRow.getTransformUri() ); id += infos.size(); } else if( tableRow.type.equals( SourceType.DATASET )) @@ -297,16 +306,16 @@ else if( tableRow.type.equals( SourceType.DATASET )) .filter( x -> x.getSource().equals( tableRow.srcName ) ) .findFirst().get(); final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, dataset, id, tableRow.moving ); - BigWarpInit.add( data, infos, tableRow.getTransform() ); + BigWarpInit.add( data, infos, tableRow.getTransform(), tableRow.getTransformUri() ); id += infos.size(); } else { - // TODO deal with exceptions + // deal with exceptions differently? try { final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, tableRow.srcName, id, tableRow.moving ); - BigWarpInit.add( data, infos, tableRow.getTransform() ); + BigWarpInit.add( data, infos, tableRow.getTransform(), tableRow.getTransformUri() ); id += infos.size(); } catch ( final URISyntaxException e ) diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index a794d0b5..b8395721 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import javax.swing.DefaultCellEditor; import javax.swing.JButton; @@ -238,6 +239,14 @@ public RealTransform getTransform() return transform; } + + public Supplier getTransformUri() + { + if( transformUrl!= null && !transformUrl.isEmpty() ) + return () -> transformUrl; + + return null; + } } protected static class RemoveRowButton extends JButton { diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 216a312b..4305c44c 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -32,6 +32,7 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.N5URI; @@ -307,16 +308,16 @@ public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > s return add( bwdata, source, sourceInfo ); } - public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > source, SourceInfo sourceInfo, RealTransform transform ) + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, Source< T > source, SourceInfo sourceInfo, RealTransform transform, Supplier transformUriSupplier ) { final LinkedHashMap< Source< T >, SourceInfo > sourceToInfo = new LinkedHashMap<>(); sourceToInfo.put( source, sourceInfo ); - return add( bwdata, sourceToInfo, transform ); + return add( bwdata, sourceToInfo, transform, transformUriSupplier ); } public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap< Source< T >, SourceInfo > sources ) { - add( bwdata, sources, null ); + add( bwdata, sources, null, null ); return bwdata; } @@ -338,7 +339,7 @@ public static < T > BigWarpData< T > add( BigWarpData bwdata, Source< T > src, i return bwdata; } - public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap< Source< T >, SourceInfo > sources, RealTransform transform ) + public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap< Source< T >, SourceInfo > sources, RealTransform transform, Supplier transformUriSupplier ) { sources.forEach( ( source, info ) -> { addSourceToListsGenericType( source, info.getId(), bwdata.converterSetups, bwdata.sources ); @@ -347,7 +348,7 @@ public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap if ( transform != null ) { - info.setTransform( transform ); + info.setTransform( transform, transformUriSupplier ); } bwdata.sourceInfos.put( info.getId(), info ); } ); diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 2db2e39d..4690abea 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -18,6 +18,7 @@ import bigwarp.landmarks.LandmarkTableModel; import bigwarp.source.SourceInfo; import bigwarp.transforms.BigWarpTransform; +import bigwarp.transforms.NgffTransformations; import bigwarp.transforms.io.TransformWriterJson; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -40,6 +41,7 @@ import java.util.stream.Collectors; import mpicbg.spim.data.SpimDataException; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.RealTransform; import net.imglib2.type.numeric.ARGBType; import org.scijava.listeners.Listeners; @@ -59,7 +61,7 @@ public class BigwarpSettings extends TypeAdapter< BigwarpSettings > private final BigWarpTransform transform; - private final Map< Integer, SourceInfo> sourceInfos; + private final Map sourceInfos; BigWarpViewerPanel viewerP; @@ -215,6 +217,11 @@ public void write( final JsonWriter out, final Map< Integer, SourceInfo > value out.name( "name" ).value( sourceInfo.getName() ); } out.name( "isMoving" ).value( sourceInfo.isMoving() ); + + final String transformUri = sourceInfo.getTransformUri(); + if( transformUri != null ) + out.name( "transform" ).value( transformUri ); + out.endObject(); } out.endObject(); @@ -230,6 +237,7 @@ public Map< Integer, SourceInfo > read( final JsonReader in ) throws IOException final int id = Integer.parseInt( in.nextName() ); in.beginObject(); String uri = null; + String transformUri = null; String name = null; Boolean isMoving = null; while ( in.hasNext() ) @@ -246,6 +254,9 @@ public Map< Integer, SourceInfo > read( final JsonReader in ) throws IOException case "isMoving": isMoving = in.nextBoolean(); break; + case "transform": + transformUri = in.nextString(); + break; } } /* Only add if we either are told to override (in which case remove previous) or don't have. */ @@ -262,14 +273,20 @@ public Map< Integer, SourceInfo > read( final JsonReader in ) throws IOException final LinkedHashMap< Source< T >, SourceInfo > sources; try { - //TODO Transform sources = BigWarpInit.createSources( bigwarp.data, uri, id, isMoving ); } catch ( URISyntaxException | SpimDataException e ) { throw new RuntimeException( e ); } - BigWarpInit.add( bigwarp.data, sources ); + + RealTransform transform = null; + final String tformUri = transformUri; + if( transformUri != null ) + transform = NgffTransformations.open(transformUri); + + BigWarpInit.add( bigwarp.data, sources, transform, () -> tformUri ); + if ( targetIdx >= 0 ) { /* move the source and converterSetup to the correct idx */ @@ -283,7 +300,10 @@ public Map< Integer, SourceInfo > read( final JsonReader in ) throws IOException in.endObject(); } in.endObject(); + + bigwarp.data.applyTransformations(); bigwarp.initialize(); + return bigwarp.data.sourceInfos; } } diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index 4c95b0ba..353c0f20 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -80,10 +80,12 @@ public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransf public static void read( final BigWarp< ? > bw, final JsonObject json ) { + if( json.has( "landmarks" )) { final int nd = json.get("landmarks").getAsJsonObject().get("numDimensions").getAsInt(); - if( bw.numDimensions() != nd ) + final boolean nonEmpty = json.get("landmarks").getAsJsonObject().get("active").getAsJsonArray().size() > 0; + if( bw.numDimensions() != nd && nonEmpty ) bw.changeDimensionality(nd == 2); bw.getLandmarkPanel().getTableModel().fromJson( json ); diff --git a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java index ad687787..107a0c3b 100644 --- a/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java +++ b/src/test/java/bigwarp/BigWarpTransformedSourcesTest.java @@ -11,7 +11,7 @@ public class BigWarpTransformedSourcesTest public static void main( String[] args ) throws SpimDataException { - BigWarpData< ? > data = createData(); + final BigWarpData< ? > data = createData(); data.applyTransformations(); final BigWarp bw = new BigWarp<>( data, new ProgressWriterConsole()); @@ -28,17 +28,17 @@ public static BigWarpData createData() // final ImagePlus mr = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif"); // final ImagePlus t1 = IJ.openImage("/groups/saalfeld/home/bogovicj/tmp/t1-head.tif"); - AffineTransform3D translation0 = new AffineTransform3D(); + final AffineTransform3D translation0 = new AffineTransform3D(); translation0.translate( -50, -50, -10 ); - AffineTransform3D translation = new AffineTransform3D(); + final AffineTransform3D translation = new AffineTransform3D(); translation.translate( -100, -150, -50 ); int id = 0; final BigWarpData< T > data = BigWarpInit.initData(); - BigWarpInit.add( data, BigWarpInit.createSources( data, mr, id++, 0, true ), translation0 ); + BigWarpInit.add( data, BigWarpInit.createSources( data, mr, id++, 0, true ), translation0, null); BigWarpInit.add( data, BigWarpInit.createSources( data, t1, id++, 0, false )); - BigWarpInit.add( data, BigWarpInit.createSources( data, t1, id++, 0, false ), translation); + BigWarpInit.add( data, BigWarpInit.createSources( data, t1, id++, 0, false ), translation, null); return data; } diff --git a/src/test/java/bigwarp/dfield/DfieldExportTest.java b/src/test/java/bigwarp/dfield/DfieldExportTest.java index b744e66b..8e863e65 100644 --- a/src/test/java/bigwarp/dfield/DfieldExportTest.java +++ b/src/test/java/bigwarp/dfield/DfieldExportTest.java @@ -19,13 +19,11 @@ import bigwarp.transforms.BigWarpTransform; import ij.ImagePlus; import net.imglib2.FinalRealInterval; -import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealPoint; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.img.imageplus.ImagePlusImgs; import net.imglib2.iterator.RealIntervalIterator; -import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.DisplacementFieldTransform; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.RealTransform; @@ -33,7 +31,6 @@ import net.imglib2.realtransform.Scale3D; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.util.Intervals; import net.imglib2.util.Util; import net.imglib2.view.Views; @@ -46,7 +43,7 @@ public class DfieldExportTest @Before public void setup() { - ImagePlus imp = ImagePlusImgs.bytes( 64, 64, 16 ).getImagePlus(); + final ImagePlus imp = ImagePlusImgs.bytes( 64, 64, 16 ).getImagePlus(); data = makeData( imp, null ); dataWithTransform = makeData( imp, new Scale3D( 0.5, 0.5, 0.5 )); @@ -55,7 +52,7 @@ public void setup() { ltm.load( new File( "src/test/resources/mr_landmarks_p2p2p4-111.csv" )); } - catch ( IOException e ) + catch ( final IOException e ) { e.printStackTrace(); fail(); @@ -68,7 +65,7 @@ private static < T extends RealType< T > > BigWarpData< T > makeData( ImagePlus final boolean isMoving = true; final BigWarpData data = BigWarpInit.initData(); final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, imp, id, 0, isMoving ); - BigWarpInit.add( data, infos, tform ); + BigWarpInit.add( data, infos, tform, null ); return data; } @@ -87,7 +84,7 @@ public void dfieldExportTest() final double[] offset = new double[] { 0, 0, 0 }; final int nThreads = 1; - final FinalRealInterval testItvl = new FinalRealInterval( + final FinalRealInterval testItvl = new FinalRealInterval( new double[]{ 3.6, 3.6, 1.6 }, new double[]{ 32.0, 40.0, 9.6 }); @@ -127,7 +124,7 @@ public void dfieldIgnoreAffineExportTest() final double[] offset = new double[] { 0, 0, 0 }; final int nThreads = 1; - final FinalRealInterval testItvl = new FinalRealInterval( + final FinalRealInterval testItvl = new FinalRealInterval( new double[]{ 3.6, 3.6, 1.6 }, new double[]{ 32.0, 40.0, 9.6 }); @@ -161,11 +158,11 @@ public void dfieldConcatExportTest() final double[] offset = new double[] { 0, 0, 0 }; final int nThreads = 1; - final FinalRealInterval testItvl = new FinalRealInterval( + final FinalRealInterval testItvl = new FinalRealInterval( new double[]{ 3.6, 3.6, 1.6 }, new double[]{ 32.0, 40.0, 9.6 }); - // flattened + // flattened final ImagePlus dfieldImpFlat = BigWarpToDeformationFieldPlugIn.toImagePlus( dataWithTransform, ltm, bwTransform, ignoreAffine, true, inverse, virtual, From 4207ef39f5503354c43b6a61327b351be55b7a52 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 28 Sep 2023 16:50:46 -0400 Subject: [PATCH 230/282] feat!: change BigWarpSourceTableModel.setTransform * rm duplicate --- .../gui/sourceList/BigWarpSourceTableModel.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java index b8395721..3890f08a 100644 --- a/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java +++ b/src/main/java/bdv/gui/sourceList/BigWarpSourceTableModel.java @@ -119,13 +119,12 @@ public void setValueAt(Object value, int row, int col) else if( col == imageColIdx ) sources.get( row ).srcName = (String)value; else if( col == transformColIdx ) - setTransform( (String)value, row ); + setTransform( row, (String)value); } - protected void setTransform(String value, int row) - { - if (transformChangedCallback != null) - { + public void setTransform(final int row, final String value) { + + if (transformChangedCallback != null) { final String res = transformChangedCallback.apply(value); if (res != null) sources.get(row).transformUrl = res; @@ -142,11 +141,6 @@ public void add( String srcName, boolean moving, SourceType type ) sources.add( new SourceRow( srcName, moving, "", type )); } - public void setTransform( int i, String transform ) - { - sources.get( i ).transformUrl = transform; - } - public void add( String srcName, boolean moving ) { add( srcName, moving, SourceType.URL ); From 3334c4d02da17d440b5fcba3958f4d89589c137b Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 28 Sep 2023 16:52:36 -0400 Subject: [PATCH 231/282] fix: transform serialization, especially linear --- .../ij/BigWarpToDeformationFieldPlugIn.java | 45 +++++++---- src/main/java/bigwarp/BigWarp.java | 2 +- src/main/java/bigwarp/BigWarpData.java | 78 +++++++++++++------ src/main/java/bigwarp/source/SourceInfo.java | 13 +++- .../transforms/NgffTransformations.java | 9 +-- src/main/java/bigwarp/util/BigWarpUtils.java | 30 ++++++- 6 files changed, 130 insertions(+), 47 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 59794100..e71f2125 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -301,7 +301,7 @@ else if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { if( !bwTransform.isNonlinear() ) // is linear { - writeAffineN5(params.n5Base, params.n5Dataset, "input", "output", bwTransform ); + writeAffineN5(params.n5Base, params.n5Dataset, data, bwTransform ); } else if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { @@ -537,10 +537,14 @@ protected static InvertibleRealTransform getTransformation( final BigWarpData public static void writeAffineN5( final String n5BasePath, final String n5Dataset, - final String input, - final String output, + final BigWarpData data, final BigWarpTransform bwTransform ) { + final String mvgSpaceName = data != null && data.numMovingSources() > 0 ? data.getMovingSource( 0 ).getSpimSource().getName() : "moving"; + final String tgtSpaceName = data != null && data.numTargetSources() > 0 ? data.getTargetSource( 0 ).getSpimSource().getName() : "target"; + final String input= mvgSpaceName; + final String output= tgtSpaceName; + CoordinateTransform ct = null; final InvertibleCoordinateTransform tform = bwTransform.getCoordinateTransform(); switch( bwTransform.getTransformType()) { @@ -554,14 +558,16 @@ else if (tform instanceof TranslationModel3D) double[] simparams; if (tform instanceof SimilarityModel2D) { - simparams = new double[ 6 ]; - ((SimilarityModel2D)tform).toArray(simparams); + simparams = bwTransform.toImglib2((SimilarityModel2D)tform).inverse().getRowPackedCopy(); +// simparams = new double[ 6 ]; +// ((SimilarityModel2D)tform).toArray(simparams); ct = new AffineCoordinateTransform("translation transformation", input, output, simparams); } else if (tform instanceof SimilarityModel3D) { - simparams = new double[ 12 ]; - ((SimilarityModel3D)tform).toArray(simparams); + simparams = bwTransform.toImglib2((SimilarityModel3D)tform).inverse().getRowPackedCopy(); +// simparams = new double[ 12 ]; +// ((SimilarityModel3D)tform).toArray(simparams); ct = new AffineCoordinateTransform("translation transformation", input, output, simparams); } break; @@ -569,14 +575,16 @@ else if (tform instanceof SimilarityModel3D) double[] rotparams; if (tform instanceof RigidModel2D) { - rotparams = new double[ 6 ]; - ((RigidModel2D)tform).toArray(rotparams); + rotparams = bwTransform.toImglib2((RigidModel2D)tform).inverse().getRowPackedCopy(); +// rotparams = new double[ 6 ]; +// ((RigidModel2D)tform).toArray(rotparams); ct = new AffineCoordinateTransform("translation transformation", input, output, rotparams); } else if (tform instanceof RigidModel3D) { - rotparams = new double[ 12 ]; - ((RigidModel3D)tform).toArray(rotparams); + rotparams = bwTransform.toImglib2((RigidModel3D)tform).inverse().getRowPackedCopy(); +// rotparams = new double[ 12 ]; +// ((RigidModel3D)tform).toArray(rotparams); ct = new AffineCoordinateTransform("translation transformation", input, output, rotparams); } break; @@ -584,14 +592,16 @@ else if (tform instanceof RigidModel3D) double[] affparams; if (tform instanceof AffineModel2D) { - affparams = new double[ 6 ]; - ((AffineModel2D)tform).toArray(affparams); + affparams = bwTransform.toImglib2((AffineModel2D)tform).inverse().getRowPackedCopy(); +// affparams = new double[ 6 ]; +// ((AffineModel2D)tform).toArray(affparams); ct = new AffineCoordinateTransform("translation transformation", input, output, affparams); } else if (tform instanceof AffineModel3D) { - affparams = new double[ 12 ]; - ((AffineModel3D)tform).toArray(affparams); + affparams = bwTransform.toImglib2((AffineModel3D)tform).inverse().getRowPackedCopy(); +// affparams = new double[ 12 ]; +// ((AffineModel3D)tform).toArray(affparams); ct = new AffineCoordinateTransform("translation transformation", input, output, affparams); } break; @@ -600,10 +610,15 @@ else if (tform instanceof AffineModel3D) if( ct == null ) return; + + final String dataset = (n5Dataset == null) ? "" : n5Dataset; final N5Factory factory = new N5Factory().gsonBuilder( NgffTransformations.gsonBuilder() ); final N5Writer n5 = factory.openWriter( n5BasePath ); NgffTransformations.addCoordinateTransformations(n5, dataset, ct); + + // also add to root + NgffTransformations.addCoordinateTransformations(n5, "", ct); } public static void writeN5( diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index c3707c4f..1f7926be 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2297,7 +2297,7 @@ public void importTransformMaskSource( final String uri ) { LinkedHashMap, SourceInfo> infos; try { infos = BigWarpInit.createSources(data, uri, TRANSFORM_MASK_SOURCE_ID, false); - BigWarpInit.add( data, infos, null ); + BigWarpInit.add( data, infos, null, null ); infos.entrySet().stream().map( e -> { return e.getKey(); }).findFirst().ifPresent( x -> { transformMask = (Source>)x; diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index a3271f27..bee5d0a1 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -1,6 +1,8 @@ package bigwarp; import bigwarp.source.SourceInfo; +import bigwarp.util.BigWarpUtils; + import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -336,8 +338,53 @@ public Source applyFixedTransform( final Source src, final RealTransfo tform = new Wrapped2DTransformAs3D( transform ); } + // TODO using a TransformedSource like the below wasn't working correctly + // investigate later + +// if( transform instanceof AffineGet ) +// { +// // if transform is a 2D affine, turn it into a 3D transform +// +// // can use TransformedSource +// final AffineTransform3D affine3d; +// if( transform instanceof AffineTransform3D ) +// affine3d = ( AffineTransform3D ) transform; +// else +// { +// affine3d = new AffineTransform3D(); +// final AffineGet transformTo3D = BigWarpUtils.toAffine3D((AffineGet)transform); +// System.out.println( transformTo3D ); +// affine3d.preConcatenate( transformTo3D ); +// System.out.println( affine3d ); +// } +// +// // could perhaps try to be clever if its a warped source (?), maybe later +// TransformedSource tsrc; +// if ( src instanceof TransformedSource ) +// { +// tsrc = ( TransformedSource ) ( src ); +// } +// else +// { +// tsrc = new TransformedSource( src ); +// } +// tsrc.setFixedTransform( affine3d ); +// return ( Source< T > ) tsrc; +// } +// else +// { +// // need to use WarpedSource +// final WarpedSource wsrc = new WarpedSource( src, src.getName() ); +// wsrc.updateTransform( tform ); +// wsrc.setIsTransformed( true ); +// return ( Source< T > ) wsrc; +// } + + if( transform instanceof AffineGet ) { + // if transform is a 2D affine, turn it into a 3D transform + // can use TransformedSource final AffineTransform3D affine3d; if( transform instanceof AffineTransform3D ) @@ -345,30 +392,17 @@ public Source applyFixedTransform( final Source src, final RealTransfo else { affine3d = new AffineTransform3D(); - affine3d.preConcatenate( ( AffineGet ) transform ); - } - - // could perhaps try to be clever if its a warped source (?), maybe later - TransformedSource tsrc; - if ( src instanceof TransformedSource ) - { - tsrc = ( TransformedSource ) ( src ); + final AffineGet transformTo3D = BigWarpUtils.toAffine3D((AffineGet)transform); + affine3d.preConcatenate( transformTo3D ); } - else - { - tsrc = new TransformedSource( src ); - } - tsrc.setFixedTransform( affine3d ); - return ( Source< T > ) tsrc; - } - else - { - // need to use WarpedSource - final WarpedSource wsrc = new WarpedSource( src, src.getName() ); - wsrc.updateTransform( tform ); - wsrc.setIsTransformed( true ); - return ( Source< T > ) wsrc; + tform = affine3d.inverse(); } + + // need to use WarpedSource + final WarpedSource wsrc = new WarpedSource( src, src.getName() ); + wsrc.updateTransform( tform ); + wsrc.setIsTransformed( true ); + return ( Source< T > ) wsrc; } /** diff --git a/src/main/java/bigwarp/source/SourceInfo.java b/src/main/java/bigwarp/source/SourceInfo.java index 295839fe..ebc63408 100644 --- a/src/main/java/bigwarp/source/SourceInfo.java +++ b/src/main/java/bigwarp/source/SourceInfo.java @@ -20,6 +20,8 @@ public class SourceInfo private RealTransform transform; + private Supplier transformUriSupplier; + boolean serializable = false; public SourceInfo( final int id, final boolean moving ) @@ -103,9 +105,10 @@ public boolean isMoving() return moving; } - public void setTransform( final RealTransform transform ) + public void setTransform( final RealTransform transform, Supplier transformUriSupplier ) { this.transform = transform; + this.transformUriSupplier = transformUriSupplier; } public RealTransform getTransform() @@ -113,6 +116,14 @@ public RealTransform getTransform() return transform; } + public String getTransformUri() + { + if( transformUriSupplier != null ) + return transformUriSupplier.get(); + else + return null; + } + public SourceAndConverter< ? > getSourceAndConverter() { return sourceAndConverter; diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index 4217e180..bb341695 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -558,11 +558,7 @@ public static final & RealType> DisplacementFieldCoo { N5Utils.save(dfield, n5Writer, dataset, vecBlkSz, compression, exec); } - catch ( final InterruptedException e ) - { - e.printStackTrace(); - } - catch ( final ExecutionException e ) + catch ( final InterruptedException | ExecutionException e ) { e.printStackTrace(); } @@ -576,7 +572,8 @@ public static final & RealType> DisplacementFieldCoo createTransformation( "", spacing, offset, dataset, cs[0] ) }; n5Writer.setAttribute(dataset, CoordinateTransform.KEY, ct ); - return new DisplacementFieldCoordinateTransform( "", dataset, "linear" ); + return new DisplacementFieldCoordinateTransform( "", dataset, "linear", + inputCoordinates.getName(), outputCoordinates.getName() ); } diff --git a/src/main/java/bigwarp/util/BigWarpUtils.java b/src/main/java/bigwarp/util/BigWarpUtils.java index fe15a580..4079cbd9 100644 --- a/src/main/java/bigwarp/util/BigWarpUtils.java +++ b/src/main/java/bigwarp/util/BigWarpUtils.java @@ -29,6 +29,7 @@ import bdv.viewer.ViewerPanel; import bdv.viewer.ViewerState; import net.imglib2.Interval; +import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.util.LinAlgHelpers; @@ -268,16 +269,41 @@ public static String parse( String arg, String start, String end ) return arg.substring( startIdx, endIdx ); } + /** + * Return a 3D {@link AffineGet} from a lower-dimensional (1D or 2D) AffineGet. + * The input instance is returned if it is 3D. + * + * @param affine the input affine. + * @return the 3D affine + */ + public static AffineGet toAffine3D( final AffineGet affine ) + { + if( affine.numSourceDimensions() == 3) + return affine; + + final AffineTransform3D out = new AffineTransform3D(); + final int N = affine.numSourceDimensions(); + for (int i = 0; i < N; i++) + for (int j = 0; j < N; j++) + out.set(affine.get(i, j), i, j); + + // translation part + for (int i = 0; i < N; i++) + out.set(affine.get(i, N+1), i, 3); + + return out; + } + // /** // * Computes the angle of rotation between the two input quaternions, // * returning the result in degrees. Assumes the inputs are unit quaternions. -// * +// * // * @param q1 first quaternion // * @param q2 second quaternion // * @return the angle in degrees // */ // public static double quaternionAngleD( double[] q1, double q2 ) // { -// +// // } } From 4b8f0adef9697f268fa104d5df733f5e845c9c72 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 28 Sep 2023 16:53:12 -0400 Subject: [PATCH 232/282] chore: more cleaning --- src/main/java/bdv/gui/BigWarpInitDialog.java | 6 ------ src/main/java/bigwarp/BigWarpActions.java | 1 - src/main/java/bigwarp/BigWarpData.java | 2 +- src/main/java/bigwarp/BigWarpInit.java | 1 - src/main/java/bigwarp/util/BigWarpUtils.java | 18 +++++++++--------- 5 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index a634da04..9dad75bf 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -748,12 +748,6 @@ public void initializeImagePlusSources() } } - public void fillTableFromProject() - { - // TODO implement me - System.out.println( "implement me" ); - } - public static BigWarpInitDialog createAndShow() { return createAndShow( null ); diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 18caa5f1..d7f3f62c 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -923,7 +923,6 @@ public SaveProjectAction( final BigWarp< ? > bw ) @Override public void actionPerformed( final ActionEvent e ) { - System.out.println("action save project"); bw.saveProject(); } } diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index bee5d0a1..e07b380d 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -309,7 +309,7 @@ public static < T > SourceAndConverter< T > inheritConverter( final Source sr } else { - System.out.println( "Inherit Converter needs to handle volatile"); + System.err.println( "Inherit Converter can't handle volatile"); // inheritConverter( src, sac ); return null; // return new SourceAndConverter< T >( src, sac.getConverter(), wrapSourceAsTransformed( src, name + "_vol", ndims ) ); diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 4305c44c..fd79bcbb 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -239,7 +239,6 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > * instaed, and pass output to * {@link #add(BigWarpData, LinkedHashMap, RealTransform)} */ - @SuppressWarnings( { "rawtypes" } ) @Deprecated public static < T > int add( BigWarpData< T > bwdata, ImagePlus ip, int setupId, int numTimepoints, boolean isMoving ) { diff --git a/src/main/java/bigwarp/util/BigWarpUtils.java b/src/main/java/bigwarp/util/BigWarpUtils.java index 4079cbd9..3cffd7d1 100644 --- a/src/main/java/bigwarp/util/BigWarpUtils.java +++ b/src/main/java/bigwarp/util/BigWarpUtils.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -72,12 +72,12 @@ public static void ensurePositiveDeterminant( final AffineTransform3D xfm ) if( det( xfm ) < 0 ) flipX( xfm ); } - + public static double det( final AffineTransform3D xfm ) { return LinAlgHelpers.det3x3( - xfm.get(0, 0), xfm.get(0, 1), xfm.get(0, 2), - xfm.get(1, 0), xfm.get(1, 1), xfm.get(1, 2), + xfm.get(0, 0), xfm.get(0, 1), xfm.get(0, 2), + xfm.get(1, 0), xfm.get(1, 1), xfm.get(1, 2), xfm.get(2, 0), xfm.get(2, 1), xfm.get(2, 2) ); } @@ -190,7 +190,7 @@ public static AffineTransform3D initTransform( final int viewerWidth, final int /** * Computes the angle of rotation between the two input quaternions, * returning the result in radians. Assumes the inputs are unit quaternions. - * + * * @param q1 first quaternion * @param q2 second quaternion * @return the angle in radians @@ -203,7 +203,7 @@ public static double quaternionAngle( double[] q1, double[] q2 ) return Math.acos( 2 * dot * dot - 1); } - + // public static double angleBetween( final AffineTransform3D xfm1, final AffineTransform3D xfm2 ) // { // double[][] tmpMat = new double[ 3 ][ 4 ]; @@ -212,7 +212,7 @@ public static double quaternionAngle( double[] q1, double[] q2 ) // // xfm1.toMatrix( tmpMat ); // LinAlgHelpers.qu -// +// // normalize( q1 ); // normalize( q2 ); // @@ -252,7 +252,7 @@ public static HashMap parseMacroArguments( String input, String k arguments = arguments.substring( i + 1 ).trim(); if( arguments.length() == 0 ) done = true; - else + else arguments = arguments.substring( 1 ).trim(); // remove comma } From c38356b40717252be38e267be2fcffde8f6fdc65 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 28 Sep 2023 16:55:20 -0400 Subject: [PATCH 233/282] feat: greatly improve H5/N5/Zarr import of transforms from dialog * add transform metadata, parser, and tree renderer --- src/main/java/bdv/gui/BigWarpInitDialog.java | 30 +++++++- .../metadata/N5TransformMetadata.java | 20 +++++ .../metadata/N5TransformMetadataParser.java | 27 +++++++ .../metadata/N5TransformTreeCellRenderer.java | 76 +++++++++++++++++++ 4 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 src/main/java/bigwarp/transforms/metadata/N5TransformMetadata.java create mode 100644 src/main/java/bigwarp/transforms/metadata/N5TransformMetadataParser.java create mode 100644 src/main/java/bigwarp/transforms/metadata/N5TransformTreeCellRenderer.java diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 9dad75bf..82b465db 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -52,6 +52,8 @@ import bigwarp.BigWarpInit; import bigwarp.source.SourceInfo; import bigwarp.transforms.NgffTransformations; +import bigwarp.transforms.metadata.N5TransformMetadataParser; +import bigwarp.transforms.metadata.N5TransformTreeCellRenderer; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; @@ -83,7 +85,7 @@ public class BigWarpInitDialog extends JFrame private BigWarpSourceTableModel sourceTableModel; private JComboBox imagePlusDropdown; private JButton addImageButton, addPathButton, addTransformButton; - private DatasetSelectorDialog selectionDialog; + private DatasetSelectorDialog selectionDialog, transformSelectionDialog; private String lastOpenedContainer = ""; private String lastBrowsePath = null; @@ -507,7 +509,10 @@ public JPanel createContent() panel.add( addN5TransformButton, cn5 ); addN5TransformButton.addActionListener( e -> { - selectionDialog.run( this::n5DialogTransformCallback ); + if (sourceTable.getSelectedRow() < 0) + IJ.showMessage("Please highlight the row you would like to transform."); + else + transformSelectionDialog.run(this::n5DialogTransformCallback); }); // source list @@ -582,7 +587,7 @@ public void buildN5SelectionDialog() exec = Executors.newFixedThreadPool( Prefs.getThreads() ); selectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), - lastOpenedContainer, new N5MetadataParser[] {}, // no + lastOpenedContainer, new N5MetadataParser[] {}, N5Importer.PARSERS ); selectionDialog.setLoaderExecutor( exec ); @@ -605,6 +610,23 @@ public void buildN5SelectionDialog() selectionDialog.setVirtualOption( true ); selectionDialog.setCropOption( true ); + + + // transform + + final N5MetadataParser[] tformParsers = new N5MetadataParser[]{ new N5TransformMetadataParser() }; + + transformSelectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), + lastOpenedContainer, new N5MetadataParser[] {}, + tformParsers ); + + transformSelectionDialog.setLoaderExecutor( exec ); + transformSelectionDialog.setTreeRenderer( new N5TransformTreeCellRenderer( true ) ); + transformSelectionDialog.setContainerPathUpdateCallback( x -> { + if ( x != null ) + lastOpenedContainer = x; + } ); + } public void n5DialogCallback( final DataSelection selection ) @@ -618,7 +640,7 @@ public void n5DialogCallback( final DataSelection selection ) public void n5DialogTransformCallback( final DataSelection selection ) { - final String n5RootPath = selectionDialog.getN5RootPath(); + final String n5RootPath = transformSelectionDialog.getN5RootPath(); final int i = sourceTable.getSelectedRow(); if( selection.metadata.size() > 0 ) sourceTableModel.setTransform(i, n5RootPath + "?" + selection.metadata.get(0).getPath() ); diff --git a/src/main/java/bigwarp/transforms/metadata/N5TransformMetadata.java b/src/main/java/bigwarp/transforms/metadata/N5TransformMetadata.java new file mode 100644 index 00000000..b36d5a1d --- /dev/null +++ b/src/main/java/bigwarp/transforms/metadata/N5TransformMetadata.java @@ -0,0 +1,20 @@ +package bigwarp.transforms.metadata; + +import org.janelia.saalfeldlab.n5.universe.metadata.AbstractN5Metadata; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; + +public class N5TransformMetadata extends AbstractN5Metadata { + + private CoordinateTransform[] transforms; + + public N5TransformMetadata(String path, CoordinateTransform[] transforms) { + super(path); + this.transforms = transforms; + } + + public CoordinateTransform[] getTransforms() + { + return transforms; + } + +} diff --git a/src/main/java/bigwarp/transforms/metadata/N5TransformMetadataParser.java b/src/main/java/bigwarp/transforms/metadata/N5TransformMetadataParser.java new file mode 100644 index 00000000..cfbfc10f --- /dev/null +++ b/src/main/java/bigwarp/transforms/metadata/N5TransformMetadataParser.java @@ -0,0 +1,27 @@ +package bigwarp.transforms.metadata; + +import java.util.Optional; + +import org.janelia.saalfeldlab.n5.N5Reader; +import org.janelia.saalfeldlab.n5.universe.N5Factory; +import org.janelia.saalfeldlab.n5.universe.N5TreeNode; +import org.janelia.saalfeldlab.n5.universe.metadata.N5MetadataParser; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; + +import bigwarp.transforms.NgffTransformations; + +public class N5TransformMetadataParser implements N5MetadataParser { + + @Override + public Optional parseMetadata(N5Reader n5, N5TreeNode node) { + + final N5Reader n5Tform = new N5Factory().gsonBuilder( NgffTransformations.gsonBuilder() ).openReader( n5.getURI().toString() ); + final CoordinateTransform[] cts = n5Tform.getAttribute(node.getPath(), "coordinateTransformations", CoordinateTransform[].class); + + if( cts != null ) + return Optional.of( new N5TransformMetadata(node.getPath(), cts)); + else + return Optional.empty(); + } + +} diff --git a/src/main/java/bigwarp/transforms/metadata/N5TransformTreeCellRenderer.java b/src/main/java/bigwarp/transforms/metadata/N5TransformTreeCellRenderer.java new file mode 100644 index 00000000..8132da1b --- /dev/null +++ b/src/main/java/bigwarp/transforms/metadata/N5TransformTreeCellRenderer.java @@ -0,0 +1,76 @@ +package bigwarp.transforms.metadata; + +import java.awt.Component; + +import javax.swing.JTree; + +import org.janelia.saalfeldlab.n5.ui.N5DatasetTreeCellRenderer; +import org.janelia.saalfeldlab.n5.ui.N5SwingTreeNode; +import org.janelia.saalfeldlab.n5.universe.N5TreeNode; +import org.janelia.saalfeldlab.n5.universe.metadata.N5Metadata; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; + +public class N5TransformTreeCellRenderer extends N5DatasetTreeCellRenderer { + + private static final long serialVersionUID = 9198333318002035941L; + + public N5TransformTreeCellRenderer(boolean showConversionWarning) { + + super(showConversionWarning); + } + + @Override + public String getParameterString(final N5TreeNode node) { + + final N5Metadata meta = node.getMetadata(); + if (meta == null || !(meta instanceof N5TransformMetadata)) + return ""; + + final CoordinateTransform[] tforms = ((N5TransformMetadata)node.getMetadata()).getTransforms(); + + if (tforms != null) { + final String suffix = tforms.length > 1 ? " ..." : ""; + final String first = tforms.length > 0 ? String.format("\"%s\" (%s)", tforms[0].getName(), tforms[0].getType()) : ""; + + return String.format(" (%d) [%s%s]", tforms.length, first, suffix); + } else + return ""; + + } + + @Override + public Component getTreeCellRendererComponent( final JTree tree, final Object value, + final boolean sel, final boolean exp, final boolean leaf, final int row, final boolean hasFocus ) + { + + super.getTreeCellRendererComponent( tree, value, sel, exp, leaf, row, hasFocus ); + + N5SwingTreeNode node; + if ( value instanceof N5SwingTreeNode ) + { + node = ( ( N5SwingTreeNode ) value ); + if ( node.getMetadata() != null ) + { + + final String memStr = memString( node ); + final String memSizeString = memStr.isEmpty() ? "" : " (" + memStr + ")"; + final String name = node.getParent() == null ? rootName : node.getNodeName(); + + setText( String.join( "", new String[]{ + "", + String.format(nameFormat, name), + getParameterString( node ), + memSizeString, + "" + })); + } + else + { + setText(node.getParent() == null ? rootName : node.getNodeName()); + } + } + return this; + } + +} + From 45b7bc70cc2665da624e955df94e8ff59fbf6428 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 29 Sep 2023 11:35:39 -0400 Subject: [PATCH 234/282] chore: update n5 versions --- pom.xml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 57f36e61..e7733804 100644 --- a/pom.xml +++ b/pom.xml @@ -128,11 +128,12 @@ sign,deploy-to-scijava - 3.0.0 - 3.2.4 - 2.0.0 + 3.0.2 + 3.2.6 + 2.0.1 7.0.0 1.1.1-SNAPSHOT + 1.0.1 10.4.8 @@ -329,5 +330,9 @@ xmlunit 1.5 + + org.janelia.saalfeldlab + n5-zarr + From 10d29aa41cf74f1957699697139b21531595b6e3 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 29 Sep 2023 11:36:04 -0400 Subject: [PATCH 235/282] fix: BigWarpInit be more permissive with n5 source uris --- src/main/java/bigwarp/BigWarpInit.java | 58 ++++++++++++++++++-------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index fd79bcbb..67b8905e 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -470,29 +470,46 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina final URI encodedUri = N5URI.encodeAsUri( uri ); final LinkedHashMap< Source< T >, SourceInfo > sourceStateMap = new LinkedHashMap<>(); - if ( encodedUri.isOpaque() ) + final boolean possibleN5 = encodedUri.getPath().contains(".n5") || + encodedUri.getPath().contains(".zarr") || + encodedUri.getPath().contains(".h5") || + encodedUri.getPath().contains(".hdf") || + encodedUri.getPath().contains(".hdf5"); + + if ( encodedUri.isOpaque() || possibleN5 ) { - final N5URI n5URL = new N5URI( encodedUri.getSchemeSpecificPart() ); - final String firstScheme = encodedUri.getScheme().toLowerCase(); final N5Reader n5reader; - switch ( firstScheme ) + final N5URI n5URL = new N5URI( encodedUri.getSchemeSpecificPart() ); + final String firstScheme = encodedUri.getScheme(); + if( firstScheme != null ) { - case "n5": - n5reader = new N5Factory().openReader( n5URL.getContainerPath() ); - break; - case "zarr": - n5reader = new N5ZarrReader( n5URL.getContainerPath() ); - break; - case "h5": - case "hdf5": - case "hdf": - n5reader = new N5HDF5Reader( n5URL.getContainerPath() ); - break; - default: - throw new URISyntaxException( firstScheme, "Unsupported Top Level Protocol" ); + switch ( firstScheme.toLowerCase() ) + { + case "n5": + n5reader = new N5Factory().openReader( n5URL.getContainerPath() ); + break; + case "zarr": + n5reader = new N5ZarrReader( n5URL.getContainerPath() ); + break; + case "h5": + case "hdf5": + case "hdf": + n5reader = new N5HDF5Reader( n5URL.getContainerPath() ); + break; + default: + throw new URISyntaxException( firstScheme, "Unsupported Top Level Protocol" ); + } } + else { + // give it a try anyway + n5reader = new N5Factory().openReader(n5URL.getContainerPath()); + if( n5reader == null ) + throw new URISyntaxException( n5URL.toString(), " not valid N5 container." ); + } + final Source< T > source = loadN5Source( n5reader, n5URL.getGroupPath() ); + sourceStateMap.put( source, new SourceInfo( setupId, isMoving, n5URL.getGroupPath() ) ); } else @@ -504,7 +521,9 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina final N5Reader n5reader = new N5Factory().openReader( containerWithoutN5Scheme ); final String group = n5URL.getGroupPath(); final Source< T > source = loadN5Source( n5reader, group ); - sourceStateMap.put( source, new SourceInfo( setupId, isMoving, group ) ); + + if( source != null ) + sourceStateMap.put( source, new SourceInfo( setupId, isMoving, group ) ); } catch ( final Exception ignored ) {} @@ -678,6 +697,9 @@ public static < T, M extends N5Metadata > Source< T > openAsSource( final N5Read { final RandomAccessibleInterval imageRaw; final RandomAccessibleInterval image; + if( meta == null ) + return null; + try { if ( isVolatile ) From 6e20014d95aeab7f3952a236249217f7004abe14 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 29 Sep 2023 11:36:26 -0400 Subject: [PATCH 236/282] test/fix: expected values for serialization tests --- src/test/resources/bigwarp/url/transformTest.zarr/.zgroup | 1 + src/test/resources/settings/expected.json | 3 +-- src/test/resources/settings/expected_with_dfield.json | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/test/resources/bigwarp/url/transformTest.zarr/.zgroup b/src/test/resources/bigwarp/url/transformTest.zarr/.zgroup index e69de29b..0c3ab975 100644 --- a/src/test/resources/bigwarp/url/transformTest.zarr/.zgroup +++ b/src/test/resources/bigwarp/url/transformTest.zarr/.zgroup @@ -0,0 +1 @@ +{"zarr_format":2} diff --git a/src/test/resources/settings/expected.json b/src/test/resources/settings/expected.json index 4313d54b..72ca0598 100644 --- a/src/test/resources/settings/expected.json +++ b/src/test/resources/settings/expected.json @@ -158,7 +158,6 @@ }, "Transform": { "type": "Thin Plate Spline", - "maskInterpolationType": "NONE", "landmarks": { "type": "BigWarpLandmarks", "numDimensions": 3, @@ -232,4 +231,4 @@ ] } } -} \ No newline at end of file +} diff --git a/src/test/resources/settings/expected_with_dfield.json b/src/test/resources/settings/expected_with_dfield.json index 6dcb7741..fd231465 100644 --- a/src/test/resources/settings/expected_with_dfield.json +++ b/src/test/resources/settings/expected_with_dfield.json @@ -154,7 +154,6 @@ }, "Transform": { "type": "Thin Plate Spline", - "maskInterpolationType": "NONE", "landmarks": { "type": "BigWarpLandmarks", "numDimensions": 3, @@ -228,4 +227,4 @@ ] } } -} \ No newline at end of file +} From 15c4f8217f9cfac469671c12a255e07bbb178d89 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 29 Sep 2023 11:56:30 -0400 Subject: [PATCH 237/282] fix: whoops didn't need BigWarpInit change --- src/main/java/bigwarp/BigWarpInit.java | 51 +++++++++----------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index 67b8905e..f6ef72cf 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -470,46 +470,29 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina final URI encodedUri = N5URI.encodeAsUri( uri ); final LinkedHashMap< Source< T >, SourceInfo > sourceStateMap = new LinkedHashMap<>(); - final boolean possibleN5 = encodedUri.getPath().contains(".n5") || - encodedUri.getPath().contains(".zarr") || - encodedUri.getPath().contains(".h5") || - encodedUri.getPath().contains(".hdf") || - encodedUri.getPath().contains(".hdf5"); - - if ( encodedUri.isOpaque() || possibleN5 ) + if ( encodedUri.isOpaque() ) { - final N5Reader n5reader; final N5URI n5URL = new N5URI( encodedUri.getSchemeSpecificPart() ); - final String firstScheme = encodedUri.getScheme(); - if( firstScheme != null ) + final String firstScheme = encodedUri.getScheme().toLowerCase(); + final N5Reader n5reader; + switch ( firstScheme.toLowerCase() ) { - switch ( firstScheme.toLowerCase() ) - { - case "n5": - n5reader = new N5Factory().openReader( n5URL.getContainerPath() ); - break; - case "zarr": - n5reader = new N5ZarrReader( n5URL.getContainerPath() ); - break; - case "h5": - case "hdf5": - case "hdf": - n5reader = new N5HDF5Reader( n5URL.getContainerPath() ); - break; - default: - throw new URISyntaxException( firstScheme, "Unsupported Top Level Protocol" ); - } - } - else { - // give it a try anyway - n5reader = new N5Factory().openReader(n5URL.getContainerPath()); - if( n5reader == null ) - throw new URISyntaxException( n5URL.toString(), " not valid N5 container." ); + case "n5": + n5reader = new N5Factory().openReader( n5URL.getContainerPath() ); + break; + case "zarr": + n5reader = new N5ZarrReader( n5URL.getContainerPath() ); + break; + case "h5": + case "hdf5": + case "hdf": + n5reader = new N5HDF5Reader( n5URL.getContainerPath() ); + break; + default: + throw new URISyntaxException( firstScheme, "Unsupported Top Level Protocol" ); } - final Source< T > source = loadN5Source( n5reader, n5URL.getGroupPath() ); - sourceStateMap.put( source, new SourceInfo( setupId, isMoving, n5URL.getGroupPath() ) ); } else From 1dbbf2b8187a0ee8f11ecd6ea30b7cf8d5378edd Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 29 Sep 2023 13:43:48 -0400 Subject: [PATCH 238/282] fix: bw dialog DatasetService issues --- src/main/java/bdv/gui/BigWarpInitDialog.java | 57 ++++++++++---------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 82b465db..eb839140 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -10,6 +10,7 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -653,22 +654,22 @@ protected void addImage() if ( !imageJOpen && datasetService == null) return; - if( datasetService != null ) - { - final String title = (String)(imagePlusDropdown.getSelectedItem()); - addDataset( title, false ); - } - else - { - final String title = (String)(imagePlusDropdown.getSelectedItem()); - addImagePlus( title ); - } + final String title = (String)(imagePlusDropdown.getSelectedItem()); + if (!addDataset(title, false)) + addImagePlus(title); + this.repaint(); } - protected void addDataset( final String datasetSource, final boolean moving ) + protected boolean addDataset( final String datasetSource, final boolean moving ) { - sourceTableModel.addDataset( datasetSource, moving ); + if( datasetService.getDatasets().stream().filter( x -> x.getSource().equals(datasetSource)).count() > 0 ) + { + sourceTableModel.addDataset( datasetSource, moving ); + return true; + } + else + return false; } protected void addImagePlus( final String title ) @@ -718,29 +719,31 @@ protected void updateImagePlusDropdown() if( !imageJOpen && datasetService == null ) return; - final String[] titles; + // add both images from dataset service and ij1 window manager but avoid duplicates + final ArrayList titleList = new ArrayList<>(); if( datasetService != null ) { - int i = 0; - titles = new String[ datasetService.getDatasets().size() ]; + final int i = 0; for( final Dataset d : datasetService.getDatasets() ) - titles[i++] = d.getSource(); + titleList.add(d.getSource()); } - else - { - // don't need any open windows if we're using N5 - final int[] ids = WindowManager.getIDList(); - // Find any open images - final int N = ids == null ? 0 : ids.length; + // don't need any open windows if we're using N5 + final int[] ids = WindowManager.getIDList(); - titles = new String[ N ]; - for ( int i = 0; i < N; ++i ) - { - titles[ i ] = ( WindowManager.getImage( ids[ i ] )).getTitle(); - } + // Find any open images + final int N = ids == null ? 0 : ids.length; + for ( int i = 0; i < N; ++i ) + { + final String t = ( WindowManager.getImage( ids[ i ] )).getTitle(); + if( !titleList.contains(t)) + titleList.add(t); } + final String[] titles = new String[titleList.size()]; + for (int i = 0; i < titleList.size(); i++) + titles[i] = titleList.get(i); + imagePlusDropdown.setModel( new DefaultComboBoxModel<>( titles )); } From a766b066591d731efd16a43d9a3c595a2807e82f Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 29 Sep 2023 16:45:28 -0400 Subject: [PATCH 239/282] fix: EDT exception on loading --- src/main/java/bigwarp/BigWarp.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 1f7926be..f402064f 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -4082,19 +4082,16 @@ public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSourc final BigwarpSettings settings = getSettings(); settings.setOverwriteSources( overwriteSources ); - try { - SwingUtilities.invokeAndWait( () -> { + Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override + public void run() { try { settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); - } catch (final IOException e) { + } catch (final Exception e) { e.printStackTrace(); } - }); - } catch (final InvocationTargetException e) { - e.printStackTrace(); - } catch (final InterruptedException e) { - e.printStackTrace(); - } + } + }); activeSourcesDialogP.update(); activeSourcesDialogQ.update(); From 5159fa6500e721d95689b79820f2ae29e11e2581 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 14:04:49 -0400 Subject: [PATCH 240/282] fix: selection of transform from n5 containers --- src/main/java/bdv/gui/BigWarpInitDialog.java | 53 +++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index eb839140..4bfb48f3 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -25,9 +25,14 @@ import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; +import javax.swing.JTree; import javax.swing.Timer; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; import org.janelia.saalfeldlab.n5.ij.N5Importer; import org.janelia.saalfeldlab.n5.ij.N5Importer.N5BasePathFun; @@ -35,6 +40,8 @@ import org.janelia.saalfeldlab.n5.ui.DataSelection; import org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog; import org.janelia.saalfeldlab.n5.ui.N5DatasetTreeCellRenderer; +import org.janelia.saalfeldlab.n5.ui.N5SwingTreeNode; +import org.janelia.saalfeldlab.n5.universe.metadata.N5DatasetMetadata; import org.janelia.saalfeldlab.n5.universe.metadata.N5Metadata; import org.janelia.saalfeldlab.n5.universe.metadata.N5MetadataParser; import org.janelia.saalfeldlab.n5.universe.metadata.canonical.CanonicalDatasetMetadata; @@ -53,6 +60,7 @@ import bigwarp.BigWarpInit; import bigwarp.source.SourceInfo; import bigwarp.transforms.NgffTransformations; +import bigwarp.transforms.metadata.N5TransformMetadata; import bigwarp.transforms.metadata.N5TransformMetadataParser; import bigwarp.transforms.metadata.N5TransformTreeCellRenderer; import ij.IJ; @@ -513,7 +521,17 @@ public JPanel createContent() if (sourceTable.getSelectedRow() < 0) IJ.showMessage("Please highlight the row you would like to transform."); else + { transformSelectionDialog.run(this::n5DialogTransformCallback); + + // remove any existing selection listeners + final JTree tree = transformSelectionDialog.getJTree(); + for ( final TreeSelectionListener l : tree.getTreeSelectionListeners()) + tree.removeTreeSelectionListener(l); + + // add a new listener for transform metadata + tree.addTreeSelectionListener(new N5TransformTreeSelectionListener(tree.getSelectionModel())); + } }); // source list @@ -618,8 +636,7 @@ public void buildN5SelectionDialog() final N5MetadataParser[] tformParsers = new N5MetadataParser[]{ new N5TransformMetadataParser() }; transformSelectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), - lastOpenedContainer, new N5MetadataParser[] {}, - tformParsers ); + lastOpenedContainer, new N5MetadataParser[] {}, tformParsers ); transformSelectionDialog.setLoaderExecutor( exec ); transformSelectionDialog.setTreeRenderer( new N5TransformTreeCellRenderer( true ) ); @@ -1020,4 +1037,36 @@ public static void runMacro( final String args ) // } } + /** + * Removes selected nodes that do not have transformation metadata. + */ + public static class N5TransformTreeSelectionListener implements TreeSelectionListener { + + private TreeSelectionModel selectionModel; + + public N5TransformTreeSelectionListener(final TreeSelectionModel selectionModel) { + + this.selectionModel = selectionModel; + } + + @Override + public void valueChanged(final TreeSelectionEvent sel) { + + int i = 0; + for (final TreePath path : sel.getPaths()) { + if (!sel.isAddedPath(i)) + continue; + + final Object last = path.getLastPathComponent(); + if (last instanceof N5SwingTreeNode) { + final N5SwingTreeNode node = ((N5SwingTreeNode)last); + if (node.getMetadata() == null || !(node.getMetadata() instanceof N5TransformMetadata)) { + selectionModel.removeSelectionPath(path); + } + } + i++; + } + } + } + } From c9f4cd35a347f046c91a35773de708830bf6056e Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 14:05:16 -0400 Subject: [PATCH 241/282] feat: add WarpedSource.getOriginalName --- src/main/java/bdv/img/WarpedSource.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/bdv/img/WarpedSource.java b/src/main/java/bdv/img/WarpedSource.java index cc4900f0..cf5862db 100644 --- a/src/main/java/bdv/img/WarpedSource.java +++ b/src/main/java/bdv/img/WarpedSource.java @@ -228,6 +228,11 @@ public String getName() return source.getName() + "_" + name; } + public String getOriginalName() + { + return getWrappedSource().getName(); + } + @Override public VoxelDimensions getVoxelDimensions() { From fd3e5b7e486f7f0156fe2cc39b92541066ddb143 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 14:05:42 -0400 Subject: [PATCH 242/282] fix: input and output names form exported transformations --- .../ij/BigWarpToDeformationFieldPlugIn.java | 34 ++++++++++++++++--- .../transforms/NgffTransformations.java | 2 +- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index e71f2125..4f72affd 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -55,6 +55,8 @@ import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.TranslationCoordinateTransform; import bdv.gui.ExportDisplacementFieldFrame; +import bdv.img.WarpedSource; +import bdv.viewer.Source; import bigwarp.BigWarp; import bigwarp.BigWarpData; import bigwarp.BigWarpExporter; @@ -686,8 +688,8 @@ public static void writeN5( { final String dataset = ( n5Dataset == null || n5Dataset.isEmpty() ) ? N5DisplacementField.FORWARD_ATTR : n5Dataset; - final String mvgSpaceName = data != null && data.numMovingSources() > 0 ? data.getMovingSource( 0 ).getSpimSource().getName() : "moving"; - final String tgtSpaceName = data != null && data.numTargetSources() > 0 ? data.getTargetSource( 0 ).getSpimSource().getName() : "target"; + final String mvgSpaceName = getMovingName(data); + final String tgtSpaceName = getTargetName(data); final String inputSpace; final String outputSpace; if( inverse ) @@ -738,7 +740,7 @@ public static void writeN5( final RealTransformSequence totalNoAffine = new RealTransformSequence(); totalNoAffine.add( transform ); totalNoAffine.add( affine.inverse() ); - dfield = DisplacementFieldTransform.createDisplacementField( totalNoAffine, new FinalInterval( dims ), spacing ); + dfield = DisplacementFieldTransform.createDisplacementField( totalNoAffine, new FinalInterval( dims ), spacing, offset ); if( format.equals( ExportDisplacementFieldFrame.FMT_SLICER )) { @@ -758,7 +760,7 @@ public static void writeN5( } else { - dfield = DisplacementFieldTransform.createDisplacementField( transform, new FinalInterval( dims ), spacing ); + dfield = DisplacementFieldTransform.createDisplacementField( transform, new FinalInterval( dims ), spacing, offset ); if( format.equals( ExportDisplacementFieldFrame.FMT_SLICER )) { @@ -778,6 +780,30 @@ public static void writeN5( n5.close(); } + private static String getMovingName( final BigWarpData data ) { + if( data != null && data.numMovingSources() > 0 ) + { + final Source src = data.getMovingSource( 0 ).getSpimSource(); + if( src instanceof WarpedSource ) + return ((WarpedSource)src).getOriginalName(); + else + return src.getName(); + } + return "moving"; + } + + private static String getTargetName( final BigWarpData data ) { + if( data != null && data.numTargetSources() > 0 ) + { + final Source src = data.getTargetSource( 0 ).getSpimSource(); + if( src instanceof WarpedSource ) + return ((WarpedSource)src).getOriginalName(); + else + return src.getName(); + } + return "target"; + } + private static int[] fillBlockSize(final int[] blockSize, final int N) { if( blockSize.length >= N ) diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index bb341695..0b6f2244 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -563,7 +563,7 @@ public static final & RealType> DisplacementFieldCoo e.printStackTrace(); } - final String vecFieldCsName = inputCoordinates.getName() + "_dfield"; + final String vecFieldCsName = inputCoordinates.getName(); final CoordinateSystem[] cs = new CoordinateSystem[] { createVectorFieldCoordinateSystem( vecFieldCsName, inputCoordinates ) }; n5Writer.setAttribute(dataset, CoordinateSystem.KEY, cs); From 802c257370771a75f263c125caf65ab393503d58 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 14:08:52 -0400 Subject: [PATCH 243/282] fix: target image resolution as default for dfield export --- src/main/java/bdv/gui/ExportDisplacementFieldFrame.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index d06200d7..2a28066c 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -30,6 +30,7 @@ import com.formdev.flatlaf.util.UIScale; +import bdv.ij.ApplyBigwarpPlugin; import bdv.ij.BigWarpToDeformationFieldPlugIn; import bdv.ij.BigWarpToDeformationFieldPlugIn.DeformationFieldExportParameters; import bdv.viewer.Source; @@ -293,6 +294,10 @@ public void createContent() fovPanel.updateFieldsFromReference(); else fovPanel.updateFieldsFromImageJReference(); + + // set default resolution to target image resolution + final double[] res = ApplyBigwarpPlugin.getResolution( data, ApplyBigwarpPlugin.TARGET, null ); + fovPanel.setSpacing(res); } addDefaultN5DatasetAction(); From 4400199d0bb347f9effc2a172ee22439434d24a7 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 14:32:04 -0400 Subject: [PATCH 244/282] fix: catch errors with empty landmark table --- src/main/java/bigwarp/BigWarp.java | 6 ++++++ src/main/java/bigwarp/BigWarpActions.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index f402064f..0bd5df43 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1947,6 +1947,12 @@ public void warpToLandmark( int row, BigWarpViewerPanel viewer ) return; } + if ( BigWarp.this.landmarkModel.getRowCount() < 1 ) + { + message.showMessage( "No landmarks found." ); + return; + } + int offset = 0; final int ndims = landmarkModel.getNumdims(); double[] pt = null; diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index d7f3f62c..9ad3acb5 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -1028,6 +1028,12 @@ public WarpToNextAction( final BigWarp< ? > bw, boolean fwd ) @Override public void actionPerformed( ActionEvent e ) { + if ( bw.landmarkModel.getRowCount() < 1 ) + { + bw.message.showMessage( "No landmarks found." ); + return; + } + final int[] selectedRows = bw.getLandmarkPanel().getJTable().getSelectedRows(); int row = 0; From 683d48423cdd05217af6f1246c6ef80feb71cbee Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 14:38:05 -0400 Subject: [PATCH 245/282] allow undo/redo from landmark mode --- src/main/java/bigwarp/BigWarpActions.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 9ad3acb5..367cff81 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -383,12 +383,6 @@ public UndoRedoAction( final String name, BigWarp< ? > bw ) @Override public void actionPerformed( ActionEvent e ) { - if( bw.isInLandmarkMode() ) - { - bw.message.showMessage( "Undo/Redo not allowed in landmark mode" ); - return; - } - // I would love for this check to work instead of using a try-catch // bug it doesn't seem to be consistent // if( isRedo && manager.canRedo() ){ From 66800cc056cf7600ebedd2d28de4a0188540f00c Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 15:31:20 -0400 Subject: [PATCH 246/282] fix: AOOBE when setting resolution of 2D fov panel --- src/main/java/bdv/ij/ApplyBigwarpPlugin.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java index 348d1494..875d0f57 100644 --- a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java +++ b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java @@ -199,7 +199,7 @@ public static double[] getResolution( final Source< ? > spimSource = bwData.getTargetSource(0 ).getSpimSource(); return getResolution( spimSource, resolutionOption, resolutionSpec ); } - else if( resolutionOption.equals( MOVING )) + else if( resolutionOption.equals( MOVING ) ) { if( bwData.numTargetSources() <= 0 ) return null; @@ -339,8 +339,9 @@ public static Interval getPixelInterval( { final double[] inputres = resolutionFromSource( source ); + final int N = outputResolution.length <= rai.numDimensions() ? outputResolution.length : rai.numDimensions(); final long[] max = new long[ rai.numDimensions() ]; - for( int d = 0; d < rai.numDimensions(); d++ ) + for( int d = 0; d < N; d++ ) { max[ d ] = (long)Math.ceil( ( inputres[ d ] * rai.dimension( d )) / outputResolution[ d ]); } From 898111738a1fa8de73cafb0ee91c62dda6c3e019 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 15:31:39 -0400 Subject: [PATCH 247/282] fix: intermittent exception on startup --- src/main/java/bigwarp/BigWarp.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 0bd5df43..124704bf 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1736,9 +1736,10 @@ protected int selectedLandmark( final double[] pt, final boolean isMoving ) */ protected int selectedLandmark( final double[] pt, final boolean isMoving, final boolean selectInTable ) { - logger.trace( "clicked: " + XfmUtils.printArray( pt ) ); + // this gets called on startup for some reason, so put this check in + if( landmarkModel == null ) + return -1; - // TODO selectedLandmark final int N = landmarkModel.getRowCount(); // a point will be selected if you click inside the spot ( with a 5 pixel buffer ) From 5e9dfbf91732be95dde670c4fd7693828b94c51a Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 16:15:56 -0400 Subject: [PATCH 248/282] fix: BigWarpInit.runBigWarp with arguments serializes imported transforms --- src/main/java/bdv/gui/BigWarpInitDialog.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 4bfb48f3..6480116d 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -222,18 +222,26 @@ public static BigWarp runBigWarp( final String projectLandmarkPath, final final LinkedHashMap< Source< T >, SourceInfo > infos = BigWarpInit.createSources( data, images[ i ], id, moving[ i ].equals( "true" ) ); RealTransform transform = null; - final String transformUrl; + final Supplier transformSupplier; if( transforms != null && transforms.length > i ) { - transformUrl = transforms[ i ]; + final String transformUrl = transforms[ i ]; if( transformUrl!= null && !transformUrl.isEmpty() ) + { transform = NgffTransformations.open( transformUrl ); + transformSupplier = () -> transformUrl; + } + else { + transformSupplier = null; + } } else - transformUrl = null; + { + transformSupplier = null; + } // add performs a null check on transform - BigWarpInit.add( data, infos, transform, transformUrl == null ? null : () -> transformUrl ); + BigWarpInit.add( data, infos, transform, transformSupplier ); id += infos.size(); } From dadaf456599869fcae61cdfd99caa98c71dfb4ed Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 2 Oct 2023 16:16:15 -0400 Subject: [PATCH 249/282] chore: less logging --- src/main/java/bigwarp/BigWarp.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 124704bf..1e72d045 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1644,12 +1644,9 @@ public static void updateRowSelection( LandmarkTableModel landmarkModel, JTable table, boolean isMoving, int lastRowEdited ) { - logger.trace( "updateRowSelection " ); - final int i = landmarkModel.getNextRow( isMoving ); if ( i < table.getRowCount() ) { - logger.trace( " landmarkTable ( updateRowSelection ) selecting row " + i ); table.setRowSelectionInterval( i, i ); } else if( lastRowEdited >= 0 && lastRowEdited < table.getRowCount() ) table.setRowSelectionInterval( lastRowEdited, lastRowEdited ); @@ -1762,9 +1759,6 @@ protected int selectedLandmark( final double[] pt, final boolean isMoving, final int bestIdx = -1; double smallestDist = Double.MAX_VALUE; - logger.trace( " selectedLandmarkHelper dist scale: " + scale ); - logger.trace( " selectedLandmarkHelper radsq: " + radsq ); - for ( int n = 0; n < N; n++ ) { final Double[] lmpt; @@ -1788,7 +1782,6 @@ else if( isMoving && isMovingDisplayTransformed() ) } dist *= ( scale * scale ); - logger.trace( " dist squared of lm index : " + n + " is " + dist ); if ( dist < radsq && dist < smallestDist ) { smallestDist = dist; @@ -1806,7 +1799,6 @@ else if( isMoving && isMovingDisplayTransformed() ) landmarkTable.setEditingRow( bestIdx ); landmarkFrame.repaint(); } - logger.trace( "selectedLandmark: " + bestIdx ); return bestIdx; } @@ -2065,7 +2057,6 @@ public boolean toggleMovingImageDisplay() // points to estimate a reasonable transformation. // return early if an re-estimation did not occur final boolean success = restimateTransformation(); - logger.trace( "toggleMovingImageDisplay, success: " + success ); if ( !success ) { message.showMessage( "Require at least 4 points to estimate a transformation" ); @@ -3256,7 +3247,6 @@ public void mouseDragged( final MouseEvent e ) thisViewer.doUpdateOnDrag() && BigWarp.this.landmarkModel.isActive( selectedPointIndex ) ) { - logger.trace("Drag resolve"); solverThread.requestResolve( isMoving, selectedPointIndex, ptarrayLoc ); } else @@ -3265,7 +3255,6 @@ public void mouseDragged( final MouseEvent e ) // the undoable action is added on mouseRelease if( isMoving && isMovingDisplayTransformed() ) { - logger.trace("Drag moving transformed"); // The moving image: // Update the warped point during the drag even if there is a corresponding fixed image point // Do this so the point sticks on the mouse @@ -3277,7 +3266,6 @@ public void mouseDragged( final MouseEvent e ) } else { - logger.trace("Drag default"); // The fixed image BigWarp.this.landmarkModel.pointEdit( selectedPointIndex, ptarrayLoc, false, isMoving, false, false, currentTransform ); thisViewer.requestRepaint(); From b0dacfb6a72d4a7011aec3b870fe89cfb7a3c264 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 11:24:16 -0400 Subject: [PATCH 250/282] fix: behavior of fov panel --- .../bdv/gui/ExportDisplacementFieldFrame.java | 9 +- src/main/java/bdv/gui/FieldOfViewPanel.java | 119 +++++++++++------- .../bdv/gui/ImprovedFormattedTextField.java | 55 ++++++-- 3 files changed, 124 insertions(+), 59 deletions(-) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index 2a28066c..273d5fe8 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -291,13 +291,14 @@ public void createContent() if( isNonlinear ) { if( data != null ) + { + // set default resolution to target image resolution + final double[] res = ApplyBigwarpPlugin.getResolution( data, ApplyBigwarpPlugin.TARGET, null ); + fovPanel.setSpacing(res); fovPanel.updateFieldsFromReference(); + } else fovPanel.updateFieldsFromImageJReference(); - - // set default resolution to target image resolution - final double[] res = ApplyBigwarpPlugin.getResolution( data, ApplyBigwarpPlugin.TARGET, null ); - fovPanel.setSpacing(res); } addDefaultN5DatasetAction(); diff --git a/src/main/java/bdv/gui/FieldOfViewPanel.java b/src/main/java/bdv/gui/FieldOfViewPanel.java index d63c0322..60e49e72 100644 --- a/src/main/java/bdv/gui/FieldOfViewPanel.java +++ b/src/main/java/bdv/gui/FieldOfViewPanel.java @@ -6,12 +6,14 @@ import java.awt.Insets; import java.text.DecimalFormat; import java.text.NumberFormat; +import java.util.Arrays; import java.util.List; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -105,12 +107,17 @@ public double[] getMin() return min; } + /** + * Sets the minimum value, does not trigger callbacks. + * + * @param newMin the new min val + */ public void setMin( final double[] newMin ) { final int N = newMin.length > min.length ? min.length : newMin.length; for ( int i = 0; i < N; i++ ) { - minFields[ i ].setValue( new Double( newMin[ i ] ) ); + minFields[ i ].setValue( new Double( newMin[ i ] ), false ); min[ i ] = newMin[ i ]; } } @@ -120,12 +127,17 @@ public double[] getSpacing() return spacing; } + /** + * Sets the spacing, does not trigger callbacks + * + * @param newSpacing the new spacing + */ public void setSpacing( final double[] newSpacing ) { final int N = newSpacing.length > spacing.length ? spacing.length : newSpacing.length; for ( int i = 0; i < N; i++ ) { - spacingFields[ i ].setValue( new Double( newSpacing[ i ] ) ); + spacingFields[ i ].setValue( new Double( newSpacing[ i ] ), false ); spacing[ i ] = newSpacing[ i ]; } } @@ -140,12 +152,17 @@ public long[] getPixelSize() return pixSize; } + /** + * Sets the pixel size, does not trigger callbacks. + * + * @param newSize the new discrete image size (in pixels) + */ public void setPixelSize( final long[] newSize ) { final int N = newSize.length > pixSize.length ? pixSize.length : newSize.length; for ( int i = 0; i < N; i++ ) { - pixelFields[ i ].setValue( new Long( newSize[ i ])); + pixelFields[i].setValue( new Long(newSize[i]), false ); pixSize[ i ] = newSize[ i ]; } } @@ -168,7 +185,7 @@ private void updateSizeLabel() public void create() { - setLayout(new GridBagLayout()); + setLayout(new GridBagLayout()); final GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; @@ -206,7 +223,7 @@ else if( IJ.getInstance() != null ) { add( new JLabel( "reference:" ), gbc ); - String[] impTitles = getImagePlusTitles(); + final String[] impTitles = getImagePlusTitles(); int numImp = 0; if( impTitles != null ) numImp = impTitles.length; @@ -258,10 +275,10 @@ public void removeUpdate( DocumentEvent e ) }); add( unitField, gbc ); - final JLabel minLabel = new JLabel( "min" ); + final JLabel minLabel = new JLabel( String.format("min (%s)", unit )); sizeLabel = new JLabel( String.format( "size (%s)", unit ) ); - final JLabel spacingLabel = new JLabel( "spacing" ); - final JLabel pixelLabel = new JLabel( "size (pixels)" ); + final JLabel spacingLabel = new JLabel( String.format( "spacing (%s/px)", unit )); + final JLabel pixelLabel = new JLabel( "size (px)" ); gbc.gridy++; gbc.gridx = 1; @@ -284,11 +301,11 @@ public void removeUpdate( DocumentEvent e ) gbc.gridy++; add( yLabel, gbc ); - + if( ndims >= 3 ) { gbc.gridy++; - JLabel zLabel = new JLabel("z"); + final JLabel zLabel = new JLabel("z"); add( zLabel, gbc ); } @@ -306,87 +323,103 @@ public void removeUpdate( DocumentEvent e ) final int textWidthScaled = UIScale.scale( textFieldWidth ); final int textHeight = UIScale.scale( 20 ); final Dimension textFieldSize = new Dimension( textWidthScaled, textHeight ); - final DecimalFormat decimalFormat = new DecimalFormat(); + final DecimalFormat decimalFormat = new DecimalFormat(); decimalFormat.setMaximumFractionDigits( 8 ); // add fields for( int i = 0; i < ndims; i++ ) { - final int idx = i; gbc.gridy = i + j; gbc.gridx = 1; minFields[ i ] = new ImprovedFormattedTextField( decimalFormat ); minFields[ i ].setPreferredSize( textFieldSize ); minFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); - minFields[ i ].setValue( new Double( initMin[i]) ); - minFields[ i ].addActionListener( a -> - { - min[ idx ] = Double.parseDouble( minFields[ idx ].getText() ); - }); + minFields[ i ].setValueNoCallback( new Double( initMin[i]) ); add( minFields[ i ], gbc ); gbc.gridx = 2; sizeFields[ i ] = new ImprovedFormattedTextField( decimalFormat ); sizeFields[ i ].setPreferredSize( textFieldSize ); sizeFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); - sizeFields[ i ].setValue( new Double( initSpacing[ i ] * initPixsize[ i ] ) ); - sizeFields[ i ].addActionListener( a -> - { - size[ idx ] = Double.parseDouble( sizeFields[ idx ].getText() ); - updatePixelsFromSize( idx ); - }); + sizeFields[ i ].setValueNoCallback( new Double( initSpacing[ i ] * initPixsize[ i ] ) ); add( sizeFields[ i ], gbc ); gbc.gridx = 3; spacingFields[ i ] = new ImprovedFormattedTextField( decimalFormat ); spacingFields[ i ].setPreferredSize( textFieldSize ); spacingFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); - spacingFields[ i ].setValue( new Double( initSpacing[ i ] ) ); - spacingFields[ i ].addActionListener( a -> - { - spacing[ idx ] = Double.parseDouble( spacingFields[ idx ].getText() ); - updatePixelsFromSpacing( idx ); - }); + spacingFields[ i ].setValueNoCallback( new Double( initSpacing[ i ] ) ); add( spacingFields[ i ], gbc ); gbc.gridx = 4; - pixelFields[ i ] = new ImprovedFormattedTextField( NumberFormat.getIntegerInstance() ); + pixelFields[ i ] = new ImprovedFormattedTextField( NumberFormat.getIntegerInstance()); pixelFields[ i ].setPreferredSize( textFieldSize ); pixelFields[ i ].setHorizontalAlignment( JTextField.RIGHT ); - pixelFields[ i ].setValue( new Long( initPixsize[ i ] ) ); - pixelFields[ i ].addActionListener( a -> - { - pixSize[ idx ] = Long.parseLong( pixelFields[ idx ].getText() ); - updateSpacingFromPixels( idx ); - }); + pixelFields[ i ].setValueNoCallback( new Long( initPixsize[ i ] ) ); add( pixelFields[ i ], gbc ); + + // set callbacks for fields + // what fields update others when modified + final int idx = i; + minFields[ i ].setCallback( () -> { +// System.out.println("min callback"); + try { + min[ idx ] = Double.parseDouble( minFields[ idx ].getText() ); + } catch (final NumberFormatException e) {} + }); + + sizeFields[ i ].setCallback( () -> { +// System.out.println("size callback"); + try { + size[ idx ] = Double.parseDouble( sizeFields[ idx ].getText() ); + updatePixelsFromSize( idx ); + } catch (final NumberFormatException e) {} + }); + + spacingFields[ i ].setCallback( () -> { +// System.out.println("spacing callback"); + try { + spacing[ idx ] = Double.parseDouble( spacingFields[ idx ].getText() ); +// updatePixelsFromSpacing( idx ); + updateSize( idx ); + } catch (final NumberFormatException e) {} + }); + + pixelFields[ i ].setCallback( () -> { +// System.out.println("pix sz callback"); + try { + pixSize[ idx ] = Long.parseLong( pixelFields[ idx ].getText() ); + updateSize( idx ); + } catch (final NumberFormatException e) {} +// updateSpacingFromPixels( idx ); // an alternative update + }); } } protected void updatePixelsFromSize( int i ) { pixSize[ i ] = ( long ) Math.ceil( size[ i ] / spacing[ i ] ); - pixelFields[ i ].setValue( new Double( pixSize[ i ] ) ); + SwingUtilities.invokeLater( () -> { pixelFields[ i ].setValueNoCallback( new Double( pixSize[ i ] ) ); }); } protected void updatePixelsFromSpacing( int i ) { pixSize[ i ] = ( long ) Math.floor( size[ i ] / spacing[ i ] ); - pixelFields[ i ].setValue( new Long( pixSize[ i ] ) ); + SwingUtilities.invokeLater( () -> { pixelFields[ i ].setValueNoCallback( new Long( pixSize[ i ] ) ); }); } protected void updateSpacingFromPixels( int i ) { spacing[ i ] = size[ i ] / pixSize[ i ]; - spacingFields[ i ].setValue( new Double( spacing[ i ] ) ); + SwingUtilities.invokeLater( () -> { spacingFields[ i ].setValueNoCallback( new Double( spacing[ i ] ) ); }); } protected void updateSize( int i ) { size[ i ] = spacing[ i ] * pixSize[ i ]; - sizeFields[ i ].setValue( new Double( size[ i ] ) ); + SwingUtilities.invokeLater( () -> { sizeFields[ i ].setValueNoCallback( new Double( size[ i ] ) ); }); } protected void updateFieldsFromReference() @@ -434,19 +467,19 @@ protected void updateFieldsFromImageJReference() if( IJ.getInstance() != null ) { final ImagePlus refImp = WindowManager.getImage( (String)referenceComboBox.getSelectedItem() ); - setSpacing( new double[] { + setSpacing( new double[] { refImp.getCalibration().pixelWidth, refImp.getCalibration().pixelHeight, refImp.getCalibration().pixelDepth, }); - setMin( new double[] { + setMin( new double[] { refImp.getCalibration().xOrigin, refImp.getCalibration().yOrigin, refImp.getCalibration().zOrigin, }); - setPixelSize( new long[] { + setPixelSize( new long[] { refImp.getWidth(), refImp.getHeight(), refImp.getNSlices() diff --git a/src/main/java/bdv/gui/ImprovedFormattedTextField.java b/src/main/java/bdv/gui/ImprovedFormattedTextField.java index 29226ad0..790338ee 100644 --- a/src/main/java/bdv/gui/ImprovedFormattedTextField.java +++ b/src/main/java/bdv/gui/ImprovedFormattedTextField.java @@ -21,7 +21,7 @@ * Extension of {@code JFormattedTextField} which solves some of the usability * issues *

- * + * *

* from * https://stackoverflow.com/questions/1313390/is-there-any-way-to-accept-only-numeric-values-in-a-jtextfield?answertab=scoredesc#tab-top @@ -35,6 +35,10 @@ public class ImprovedFormattedTextField extends JFormattedTextField private Color fBackground, fForeground; + private Runnable updateCallback; + + private boolean runCallback = true; + /** * Create a new {@code ImprovedFormattedTextField} instance which will use * {@code aFormat} for the validation of the user input. @@ -71,6 +75,11 @@ public ImprovedFormattedTextField( Format aFormat, Object aValue ) setValue( aValue ); } + public void setCallback(final Runnable updateCallback) { + + this.updateCallback = updateCallback; + } + private void updateBackgroundOnEachUpdate() { getDocument().addDocumentListener( new DocumentListener() @@ -79,18 +88,24 @@ private void updateBackgroundOnEachUpdate() public void insertUpdate( DocumentEvent e ) { updateBackground(); + if( runCallback && updateCallback != null ) + updateCallback.run(); } @Override public void removeUpdate( DocumentEvent e ) { updateBackground(); + if( runCallback && updateCallback != null ) + updateCallback.run(); } @Override public void changedUpdate( DocumentEvent e ) { updateBackground(); + if( runCallback && updateCallback != null ) + updateCallback.run(); } } ); } @@ -101,7 +116,7 @@ public void changedUpdate( DocumentEvent e ) */ private void updateBackground() { - boolean valid = validContent(); + final boolean valid = validContent(); if ( ERROR_BACKGROUND_COLOR != null ) { setBackground( valid ? fBackground : ERROR_BACKGROUND_COLOR ); @@ -122,7 +137,7 @@ public void updateUI() private boolean validContent() { - AbstractFormatter formatter = getFormatter(); + final AbstractFormatter formatter = getFormatter(); if ( formatter != null ) { try @@ -130,7 +145,7 @@ private boolean validContent() formatter.stringToValue( getText() ); return true; } - catch ( ParseException e ) + catch ( final ParseException e ) { return false; } @@ -138,20 +153,19 @@ private boolean validContent() return true; } - @Override - public void setValue( Object value ) + public void setValue( Object value, boolean callback ) { boolean validValue = true; // before setting the value, parse it by using the format try { - AbstractFormatter formatter = getFormatter(); + final AbstractFormatter formatter = getFormatter(); if ( formatter != null ) { formatter.valueToString( value ); } } - catch ( ParseException e ) + catch ( final ParseException e ) { validValue = false; updateBackground(); @@ -159,12 +173,29 @@ public void setValue( Object value ) // only set the value when valid if ( validValue ) { - int old_caret_position = getCaretPosition(); + final int old_caret_position = getCaretPosition(); + + // TODO synchronize? + final boolean before = runCallback; + runCallback = callback; super.setValue( value ); + runCallback = before; + setCaretPosition( Math.min( old_caret_position, getText().length() ) ); } } + public void setValueNoCallback( Object value ) + { + setValue( value, false ); + } + + @Override + public void setValue( Object value ) + { + setValue( value, true ); + } + @Override protected boolean processKeyBinding( KeyStroke ks, KeyEvent e, int condition, boolean pressed ) { @@ -253,11 +284,11 @@ public AttributedCharacterIterator formatToCharacterIterator( Object obj ) @Override public Object parseObject( String source, ParsePosition pos ) { - int initialIndex = pos.getIndex(); - Object result = fDelegate.parseObject( source, pos ); + final int initialIndex = pos.getIndex(); + final Object result = fDelegate.parseObject( source, pos ); if ( result != null && pos.getIndex() < source.length() ) { - int errorIndex = pos.getIndex(); + final int errorIndex = pos.getIndex(); pos.setIndex( initialIndex ); pos.setErrorIndex( errorIndex ); return null; From 5d713b36a959d528239deeafc99d14fe4d1f6c17 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 11:24:39 -0400 Subject: [PATCH 251/282] fix: (again) intermittent AIOOB on startup --- src/main/java/bigwarp/BigWarp.java | 67 ++++++++++++++++-------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 1e72d045..c2c2972e 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1737,8 +1737,6 @@ protected int selectedLandmark( final double[] pt, final boolean isMoving, final if( landmarkModel == null ) return -1; - final int N = landmarkModel.getRowCount(); - // a point will be selected if you click inside the spot ( with a 5 pixel buffer ) double radsq = ( viewerSettings.getSpotSize() * viewerSettings.getSpotSize() ) + 5 ; final AffineTransform3D viewerXfm = new AffineTransform3D(); @@ -1759,45 +1757,50 @@ protected int selectedLandmark( final double[] pt, final boolean isMoving, final int bestIdx = -1; double smallestDist = Double.MAX_VALUE; - for ( int n = 0; n < N; n++ ) + synchronized( landmarkModel ) { - final Double[] lmpt; - if( isMoving && landmarkModel.isWarped( n ) && isMovingDisplayTransformed() ) - { - lmpt = landmarkModel.getWarpedPoints().get( n ); - } - else if( isMoving && isMovingDisplayTransformed() ) + final int N = landmarkModel.getRowCount(); + for ( int n = 0; n < N; n++ ) { - lmpt = landmarkModel.getPoints( false ).get( n ); - } - else - { - lmpt = landmarkModel.getPoints( isMoving ).get( n ); - } + final Double[] lmpt; + if( isMoving && landmarkModel.isWarped( n ) && isMovingDisplayTransformed() ) + { + lmpt = landmarkModel.getWarpedPoints().get( n ); + } + else if( isMoving && isMovingDisplayTransformed() ) + { + lmpt = landmarkModel.getPoints( false ).get( n ); + } + else + { + lmpt = landmarkModel.getPoints( isMoving ).get( n ); + } - dist = 0.0; - for ( int i = 0; i < landmarkModel.getNumdims(); i++ ) - { - dist += ( pt[ i ] - lmpt[ i ] ) * ( pt[ i ] - lmpt[ i ] ); - } + dist = 0.0; + for ( int i = 0; i < landmarkModel.getNumdims(); i++ ) + { + dist += ( pt[ i ] - lmpt[ i ] ) * ( pt[ i ] - lmpt[ i ] ); + } - dist *= ( scale * scale ); - if ( dist < radsq && dist < smallestDist ) - { - smallestDist = dist; - bestIdx = n; + dist *= ( scale * scale ); + if ( dist < radsq && dist < smallestDist ) + { + smallestDist = dist; + bestIdx = n; + } } - } - if ( selectInTable && landmarkFrame.isVisible() ) - { - if( landmarkTable.isEditing()) + if ( selectInTable && landmarkFrame.isVisible() ) { - landmarkTable.getCellEditor().stopCellEditing(); + if( landmarkTable.isEditing()) + { + landmarkTable.getCellEditor().stopCellEditing(); + } + + landmarkTable.setEditingRow( bestIdx ); + landmarkFrame.repaint(); } - landmarkTable.setEditingRow( bestIdx ); - landmarkFrame.repaint(); } return bestIdx; } From ea7e41295de1560b66ceb1865e51747e37cbe800 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 11:26:12 -0400 Subject: [PATCH 252/282] chore: clean and code style --- .../java/bigwarp/BigWarpARGBExporter.java | 52 ++-- src/main/java/bigwarp/BigWarpExporter.java | 276 +++++++++--------- .../java/bigwarp/BigWarpRealExporter.java | 64 ++-- 3 files changed, 188 insertions(+), 204 deletions(-) diff --git a/src/main/java/bigwarp/BigWarpARGBExporter.java b/src/main/java/bigwarp/BigWarpARGBExporter.java index f653abe6..2de86dc0 100644 --- a/src/main/java/bigwarp/BigWarpARGBExporter.java +++ b/src/main/java/bigwarp/BigWarpARGBExporter.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -55,17 +55,6 @@ public class BigWarpARGBExporter extends BigWarpExporter private Interpolation interp; -// public BigWarpARGBExporter( -// final List< SourceAndConverter< ARGBType >> sources, -// final List< ConverterSetup > convSetups, -// final int[] movingSourceIndexList, -// final int[] targetSourceIndexList, -// final Interpolation interp, -// final ProgressWriter progress ) -// { -// super( sources, convSetups, movingSourceIndexList, targetSourceIndexList, interp, progress ); -// } - public BigWarpARGBExporter( BigWarpData bwData, final List< ConverterSetup > convSetups, @@ -77,7 +66,7 @@ public BigWarpARGBExporter( /** * Returns true if moving image sources are all of the same type. - * + * * @param sources the sources * @param movingSourceIndexList list of indexes for moving sources * @return true if all moving sources are of the same type @@ -86,15 +75,15 @@ public static boolean isTypeListFullyConsistent( ArrayList< SourceAndConverter< { for ( int i = 0; i < movingSourceIndexList.length; i++ ) { - int idx = movingSourceIndexList[ i ]; - Object type = sources.get( idx ).getSpimSource().getType(); + final int idx = movingSourceIndexList[ i ]; + final Object type = sources.get( idx ).getSpimSource().getType(); if ( !type.getClass().equals( ARGBType.class ) ) return false; } return true; } - + @Override public boolean isRGB() { @@ -104,12 +93,12 @@ public boolean isRGB() @Override public RandomAccessibleInterval< ARGBType > exportRai() { - ArrayList< RandomAccessibleInterval< ARGBType > > raiList = new ArrayList< RandomAccessibleInterval< ARGBType > >(); + final ArrayList< RandomAccessibleInterval< ARGBType > > raiList = new ArrayList< RandomAccessibleInterval< ARGBType > >(); buildTotalRenderTransform(); final int numChannels = bwData.numMovingSources(); - VoxelDimensions voxdim = new FinalVoxelDimensions( unit, + final VoxelDimensions voxdim = new FinalVoxelDimensions( unit, resolutionTransform.get( 0, 0 ), resolutionTransform.get( 1, 1 ), resolutionTransform.get( 2, 2 )); @@ -119,22 +108,23 @@ public RandomAccessibleInterval< ARGBType > exportRai() final RealRandomAccessible< ARGBType > raiRaw = ( RealRandomAccessible< ARGBType > )bwData.getMovingSource( i ).getSpimSource().getInterpolatedSource( 0, 0, interp ); // apply the transformations - final AffineRandomAccessible< ARGBType, AffineGet > rai = RealViews.affine( + final AffineRandomAccessible< ARGBType, AffineGet > rai = RealViews.affine( raiRaw, pixelRenderToPhysical.inverse() ); raiList.add( Views.interval( Views.raster( rai ), outputInterval ) ); } - RandomAccessibleInterval< ARGBType > raiStack = Views.stack( raiList ); + final RandomAccessibleInterval< ARGBType > raiStack = Views.stack( raiList ); return raiStack; } + @Override public ImagePlus export() { buildTotalRenderTransform(); final int numChannels = bwData.numMovingSources(); - VoxelDimensions voxdim = new FinalVoxelDimensions( unit, + final VoxelDimensions voxdim = new FinalVoxelDimensions( unit, resolutionTransform.get( 0, 0 ), resolutionTransform.get( 1, 1 ), resolutionTransform.get( 2, 2 )); @@ -161,9 +151,9 @@ else if( nThreads == 1 ) dimensions[ 0 ] = outputInterval.dimension( 0 ); // x dimensions[ 1 ] = outputInterval.dimension( 1 ); // y dimensions[ 2 ] = numChannels; // c - dimensions[ 3 ] = outputInterval.dimension( 2 ); // z - FinalInterval destIntervalPerm = new FinalInterval( dimensions ); - RandomAccessibleInterval< ARGBType > img = copyToImageStack( + dimensions[ 3 ] = outputInterval.dimension( 2 ); // z + final FinalInterval destIntervalPerm = new FinalInterval( dimensions ); + final RandomAccessibleInterval< ARGBType > img = copyToImageStack( raiStack, destIntervalPerm, factory, nThreads ); ip = ((ImagePlusImg)img).getImagePlus(); @@ -174,9 +164,9 @@ else if ( outputInterval.numDimensions() == 2 ) dimensions[ 0 ] = outputInterval.dimension( 0 ); // x dimensions[ 1 ] = outputInterval.dimension( 1 ); // y dimensions[ 2 ] = numChannels; // c - dimensions[ 3 ] = 1; // z - FinalInterval destIntervalPerm = new FinalInterval( dimensions ); - RandomAccessibleInterval< ARGBType > img = copyToImageStack( + dimensions[ 3 ] = 1; // z + final FinalInterval destIntervalPerm = new FinalInterval( dimensions ); + final RandomAccessibleInterval< ARGBType > img = copyToImageStack( Views.addDimension( Views.extendMirrorDouble( raiStack )), destIntervalPerm, factory, nThreads ); ip = ((ImagePlusImg)img).getImagePlus(); @@ -187,7 +177,7 @@ else if ( outputInterval.numDimensions() == 2 ) ip.getCalibration().pixelHeight = voxdim.dimension( 1 ); ip.getCalibration().pixelDepth = voxdim.dimension( 2 ); ip.getCalibration().setUnit( voxdim.unit() ); - + if( offsetTransform != null ) { ip.getCalibration().xOrigin = offsetTransform.get( 0, 3 ); @@ -204,7 +194,7 @@ public static ImagePlus copyToImageStack( final RandomAccessible< ARGBType > rai { // A bit of hacking to make slices the 4th dimension and channels the 3rd // since that's how ImagePlusImgFactory does it - MixedTransformView< ARGBType > raip = Views.permute( rai, 2, 3 ); + final MixedTransformView< ARGBType > raip = Views.permute( rai, 2, 3 ); final long[] dimensions = new long[ itvl.numDimensions() ]; for( int d = 0; d < itvl.numDimensions(); d++ ) @@ -221,7 +211,7 @@ else if( d == 3 ) final ImagePlusImgFactory< ARGBType > factory = new ImagePlusImgFactory< ARGBType >( new ARGBType() ); final ImagePlusImg< ARGBType, ? > target = factory.create( dimensions ); - long[] dims = new long[ target.numDimensions() ]; + final long[] dims = new long[ target.numDimensions() ]; target.dimensions( dims ); double k = 0; diff --git a/src/main/java/bigwarp/BigWarpExporter.java b/src/main/java/bigwarp/BigWarpExporter.java index 759b4032..226f8e26 100644 --- a/src/main/java/bigwarp/BigWarpExporter.java +++ b/src/main/java/bigwarp/BigWarpExporter.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -74,25 +74,20 @@ public abstract class BigWarpExporter { final protected List< SourceAndConverter< T >> sources; - private List< ConverterSetup > convSetups; - private List< ImagePlus > outputList; -// final protected int[] movingSourceIndexList; -// -// final protected int[] targetSourceIndexList; protected final BigWarpData bwData; - + protected AffineTransform3D pixelRenderToPhysical; - + protected AffineTransform3D resolutionTransform; - + protected AffineTransform3D offsetTransform; - + protected Interval outputInterval; protected Interpolation interp; - + protected boolean isVirtual = false; protected int nThreads = 1; @@ -137,7 +132,7 @@ public enum ParallelizationPolicy { // { // WarpedSource ws = (WarpedSource)( sac.getSpimSource() ); // WarpedSource wsCopy = new WarpedSource<>( ws.getWrappedSource(), ws.getName() ) ; -// +// // if( ws.getTransform() != null ) // { // wsCopy.updateTransform( ws.getTransform().copy() ); @@ -147,7 +142,7 @@ public enum ParallelizationPolicy { // } // else // srcCopy = src; -// +// // SourceAndConverter copy = new SourceAndConverter<>( srcCopy, sac.getConverter() ); // sources.add( copy ); // } @@ -161,7 +156,7 @@ public enum ParallelizationPolicy { // this.progress = progress; // // this.setInterp( interp ); -// +// // pixelRenderToPhysical = new AffineTransform3D(); // resolutionTransform = new AffineTransform3D(); // offsetTransform = new AffineTransform3D(); @@ -170,7 +165,7 @@ public enum ParallelizationPolicy { // unit = sources.get( targetSourceIndexList[ 0 ] ).getSpimSource().getVoxelDimensions().unit(); // } catch( Exception e ) {} // } - + public BigWarpExporter( BigWarpData bwData, final List< ConverterSetup > convSetups, @@ -179,16 +174,15 @@ public BigWarpExporter( { this.bwData = bwData; this.sources = new ArrayList>(); - this.convSetups = convSetups; - for( SourceAndConverter sac : bwData.sources ) + for( final SourceAndConverter sac : bwData.sources ) { Source srcCopy = null; - Source src = sac.getSpimSource(); + final Source src = sac.getSpimSource(); if( src instanceof WarpedSource ) { - WarpedSource ws = (WarpedSource)( sac.getSpimSource() ); - WarpedSource wsCopy = new WarpedSource<>( ws.getWrappedSource(), ws.getName() ) ; - + final WarpedSource ws = (WarpedSource)( sac.getSpimSource() ); + final WarpedSource wsCopy = new WarpedSource<>( ws.getWrappedSource(), ws.getName() ) ; + if( ws.getTransform() != null ) { wsCopy.updateTransform( ws.getTransform().copy() ); @@ -198,8 +192,8 @@ public BigWarpExporter( } else srcCopy = src; - - SourceAndConverter copy = new SourceAndConverter<>( srcCopy, sac.getConverter() ); + + final SourceAndConverter copy = new SourceAndConverter<>( srcCopy, sac.getConverter() ); sources.add( copy ); } @@ -209,14 +203,14 @@ public BigWarpExporter( this.progress = progress; this.setInterp( interp ); - + pixelRenderToPhysical = new AffineTransform3D(); resolutionTransform = new AffineTransform3D(); offsetTransform = new AffineTransform3D(); try { unit = bwData.getTargetSource( 0 ).getSpimSource().getVoxelDimensions().unit(); - } catch( Exception e ) {} + } catch( final Exception e ) {} } public abstract RandomAccessibleInterval exportRai(); @@ -249,7 +243,7 @@ public void setInterp( Interpolation interp ) { this.interp = interp; } - + public void setVirtual( final boolean isVirtual ) { this.isVirtual = isVirtual; @@ -275,10 +269,10 @@ public void setRenderResolution( double... res ) for( int i = 0; i < res.length; i++ ) resolutionTransform.set( res[ i ], i, i ); } - + /** * Set the offset of the output field of view in pixels. - * + * * @param offset the offset in pixel units. */ public void setOffset( double... offset ) @@ -289,8 +283,8 @@ public void setOffset( double... offset ) /** * Generate the transform from output pixel space to physical space. - * - * Call this after setRenderResolution and setOffset. + * + * Call this after setRenderResolution and setOffset. */ public void buildTotalRenderTransform() { @@ -309,13 +303,13 @@ public RandomAccessibleInterval exportSource( SourceAndConverter src ) final RealRandomAccessible< T > raiRaw = src.getSpimSource().getInterpolatedSource( 0, 0, interp ); // apply the transformations - final AffineRandomAccessible< T, AffineGet > rai = RealViews.affine( + final AffineRandomAccessible< T, AffineGet > rai = RealViews.affine( raiRaw, pixelRenderToPhysical.inverse() ); - return Views.interval( Views.raster( rai ), outputInterval ); + return Views.interval( Views.raster( rai ), outputInterval ); } - public static void updateBrightnessContrast( + public static void updateBrightnessContrast( final ImagePlus imp, final List convSetups, final int[] indexList ) @@ -324,25 +318,25 @@ public static void updateBrightnessContrast( for( int i = 0; i < indexList.length; i++ ) { - ConverterSetup setup = convSetups.get( indexList[ i ] ); - double rngmin = setup.getDisplayRangeMin(); - double rngmax = setup.getDisplayRangeMax(); + final ConverterSetup setup = convSetups.get( indexList[ i ] ); + final double rngmin = setup.getDisplayRangeMin(); + final double rngmax = setup.getDisplayRangeMax(); imp.setC( i + 1 ); // ImagePlus.setC is one-indexed imp.setDisplayRange( rngmin, rngmax ); imp.updateAndDraw(); } } - - public static void updateBrightnessContrast( + + public static void updateBrightnessContrast( final ImagePlus imp, final List convSetups) { for( int i = 0; i < convSetups.size(); i++ ) { final ConverterSetup setup = convSetups.get( i ); - double rngmin = setup.getDisplayRangeMin(); - double rngmax = setup.getDisplayRangeMax(); + final double rngmin = setup.getDisplayRangeMin(); + final double rngmax = setup.getDisplayRangeMax(); imp.setC( i + 1 ); // ImagePlus.setC is one-indexed imp.setDisplayRange( rngmin, rngmax ); @@ -350,7 +344,7 @@ public static void updateBrightnessContrast( } } - public static void updateBrightnessContrast( + public static void updateBrightnessContrast( final ImagePlus imp, final BigWarpData bwdata, final int[] indexList ) @@ -359,9 +353,9 @@ public static void updateBrightnessContrast( for( int i = 0; i < indexList.length; i++ ) { - ConverterSetup setup = bwdata.converterSetups.get( indexList[ i ] ); - double rngmin = setup.getDisplayRangeMin(); - double rngmax = setup.getDisplayRangeMax(); + final ConverterSetup setup = bwdata.converterSetups.get( indexList[ i ] ); + final double rngmin = setup.getDisplayRangeMin(); + final double rngmax = setup.getDisplayRangeMax(); imp.setC( i + 1 ); // ImagePlus.setC is one-indexed imp.setDisplayRange( rngmin, rngmax ); @@ -371,32 +365,32 @@ public static void updateBrightnessContrast( public FinalInterval destinationIntervalFromLandmarks( ArrayList pts, boolean isMoving ) { - int nd = pts.get( 0 ).length; - long[] min = new long[ nd ]; - long[] max = new long[ nd ]; + final int nd = pts.get( 0 ).length; + final long[] min = new long[ nd ]; + final long[] max = new long[ nd ]; Arrays.fill( min, Long.MAX_VALUE ); Arrays.fill( max, Long.MIN_VALUE ); - for( Double[] pt : pts ) + for( final Double[] pt : pts ) { for( int d = 0; d < nd; d++ ) { if( pt[ d ] > max [ d ] ) max[ d ] = (long)Math.ceil( pt[ d ]); - + if( pt[ d ] < min [ d ] ) min[ d ] = (long)Math.floor( pt[ d ]); } } return new FinalInterval( min, max ); } - + public static FinalInterval getSubInterval( Interval interval, int d, long start, long end ) { - int nd = interval.numDimensions(); - long[] min = new long[ nd ]; - long[] max = new long[ nd ]; + final int nd = interval.numDimensions(); + final long[] min = new long[ nd ]; + final long[] max = new long[ nd ]; for( int i = 0; i < nd; i++ ) { if( i == d ) @@ -413,20 +407,20 @@ public static FinalInterval getSubInterval( Interval interval, int d, long start return new FinalInterval( min, max ); } - public < T extends NumericType > RandomAccessibleInterval copyToImageStack( + public < T extends NumericType > RandomAccessibleInterval copyToImageStack( final RandomAccessible< T > raible, final Interval itvl, final ImgFactory factory, final int nThreads ) { - Img< T > target = factory.create( itvl ); + final Img< T > target = factory.create( itvl ); if( policy == ParallelizationPolicy.ITER ) return copyToImageStackIterOrder( raible, itvl, target, nThreads, progress ); else return copyToImageStackBySlice( raible, itvl, target, nThreads, progress ); } - public static < T extends NumericType > RandomAccessibleInterval copyToImageStackBySlice( + public static < T extends NumericType > RandomAccessibleInterval copyToImageStackBySlice( final RandomAccessible< T > raible, final Interval itvl, final ImgFactory factory, @@ -434,11 +428,11 @@ public static < T extends NumericType > RandomAccessibleInterval copyToIma final ProgressWriter progress ) { // create the image plus image - Img< T > target = factory.create( itvl ); + final Img< T > target = factory.create( itvl ); return copyToImageStackBySlice( raible, itvl, target, nThreads, progress ); } - public static < T extends NumericType > RandomAccessibleInterval copyToImageStackBySlice( + public static < T extends NumericType > RandomAccessibleInterval copyToImageStackBySlice( final RandomAccessible< T > ra, final Interval itvl, final RandomAccessibleInterval target, @@ -446,10 +440,10 @@ public static < T extends NumericType > RandomAccessibleInterval copyToIma final ProgressWriter progress ) { // TODO I wish I didn't have to do this inside this method - MixedTransformView< T > raible = Views.permute( ra, 2, 3 ); + final MixedTransformView< T > raible = Views.permute( ra, 2, 3 ); // what dimension should we split across? - int nd = raible.numDimensions(); + final int nd = raible.numDimensions(); int tmp = nd - 1; while( tmp >= 0 ) { @@ -461,8 +455,8 @@ public static < T extends NumericType > RandomAccessibleInterval copyToIma final int dim2split = tmp; final long[] splitPoints = new long[ nThreads + 1 ]; - long N = target.dimension( dim2split ); - long del = ( long )( N / nThreads ); + final long N = target.dimension( dim2split ); + final long del = ( long )( N / nThreads ); splitPoints[ 0 ] = 0; splitPoints[ nThreads ] = target.dimension( dim2split ); for( int i = 1; i < nThreads; i++ ) @@ -470,9 +464,9 @@ public static < T extends NumericType > RandomAccessibleInterval copyToIma splitPoints[ i ] = splitPoints[ i - 1 ] + del; } - ExecutorService threadPool = Executors.newFixedThreadPool( nThreads ); + final ExecutorService threadPool = Executors.newFixedThreadPool( nThreads ); - LinkedList> jobs = new LinkedList>(); + final LinkedList> jobs = new LinkedList>(); for( int i = 0; i < nThreads; i++ ) { final long start = splitPoints[ i ]; @@ -487,7 +481,7 @@ public Boolean call() { final FinalInterval subItvl = getSubInterval( target, dim2split, start, end ); final IntervalView< T > subTgt = Views.interval( target, subItvl ); - long N = Intervals.numElements(subTgt); + final long N = Intervals.numElements(subTgt); final Cursor< T > c = subTgt.cursor(); final RandomAccess< T > ra = raible.randomAccess(); long j = 0; @@ -499,14 +493,14 @@ public Boolean call() if( start == 0 && j % 100000 == 0 ) { - double ratio = 1.0 * j / N; - progress.setProgress( ratio ); + final double ratio = 1.0 * j / N; + progress.setProgress( ratio ); } j++; } return true; } - catch( Exception e ) + catch( final Exception e ) { e.printStackTrace(); } @@ -520,7 +514,7 @@ public Boolean call() threadPool.shutdown(); // wait for all jobs to finish } - catch ( InterruptedException e1 ) + catch ( final InterruptedException e1 ) { e1.printStackTrace(); } @@ -529,7 +523,7 @@ public Boolean call() return target; } - public static < T extends NumericType > RandomAccessibleInterval copyToImageStackIterOrder( + public static < T extends NumericType > RandomAccessibleInterval copyToImageStackIterOrder( final RandomAccessible< T > raible, final Interval itvl, final ImgFactory factory, @@ -537,11 +531,11 @@ public static < T extends NumericType > RandomAccessibleInterval copyToIma final ProgressWriter progress ) { // create the image plus image - Img< T > target = factory.create( itvl ); + final Img< T > target = factory.create( itvl ); return copyToImageStackIterOrder( raible, itvl, target, nThreads, progress ); } - public static < T extends NumericType > RandomAccessibleInterval copyToImageStackIterOrder( + public static < T extends NumericType > RandomAccessibleInterval copyToImageStackIterOrder( final RandomAccessible< T > ra, final Interval itvl, final RandomAccessibleInterval target, @@ -551,11 +545,11 @@ public static < T extends NumericType > RandomAccessibleInterval copyToIma progress.setProgress(0.0); // TODO I wish I didn't have to do this inside this method.. // Maybe I don't have to, and should do it where I call this instead? - MixedTransformView< T > raible = Views.permute( ra, 2, 3 ); + final MixedTransformView< T > raible = Views.permute( ra, 2, 3 ); - ExecutorService threadPool = Executors.newFixedThreadPool( nThreads ); + final ExecutorService threadPool = Executors.newFixedThreadPool( nThreads ); - LinkedList> jobs = new LinkedList>(); + final LinkedList> jobs = new LinkedList>(); for( int i = 0; i < nThreads; i++ ) { @@ -567,10 +561,10 @@ public Boolean call() { try { - IterableInterval it = Views.flatIterable( target ); + final IterableInterval it = Views.flatIterable( target ); final RandomAccess< T > access = raible.randomAccess(); - long N = it.size(); + final long N = it.size(); final Cursor< T > c = it.cursor(); c.jumpFwd( 1 + offset ); for( long j = offset; j < N; j += nThreads ) @@ -578,17 +572,17 @@ public Boolean call() access.setPosition( c ); c.get().set( access.get() ); c.jumpFwd( nThreads ); - + if( offset == 0 && j % (nThreads * 100000) == 0 ) { - double ratio = 1.0 * j / N; - progress.setProgress( ratio ); + final double ratio = 1.0 * j / N; + progress.setProgress( ratio ); } } return true; } - catch( Exception e ) + catch( final Exception e ) { e.printStackTrace(); } @@ -602,7 +596,7 @@ public Boolean call() threadPool.shutdown(); // wait for all jobs to finish } - catch ( InterruptedException e1 ) + catch ( final InterruptedException e1 ) { e1.printStackTrace(); } @@ -610,80 +604,80 @@ public Boolean call() progress.setProgress(1.0); return target; } - + public static FinalInterval transformRealInterval( RealTransform xfm, RealInterval interval ) { - int nd = interval.numDimensions(); - double[] pt = new double[ nd ]; - double[] ptxfm = new double[ nd ]; + final int nd = interval.numDimensions(); + final double[] pt = new double[ nd ]; + final double[] ptxfm = new double[ nd ]; - long[] min = new long[ nd ]; - long[] max = new long[ nd ]; + final long[] min = new long[ nd ]; + final long[] max = new long[ nd ]; - // transform min + // transform min for( int d = 0; d < nd; d++ ) pt[ d ] = interval.realMin( d ); - + xfm.apply( pt, ptxfm ); copyToLongFloor( ptxfm, min ); // transform max - + for( int d = 0; d < nd; d++ ) { pt[ d ] = interval.realMax( d ); } - + xfm.apply( pt, ptxfm ); copyToLongCeil( ptxfm, max ); - + return new FinalInterval( min, max ); } - + public static FinalInterval transformIntervalMinMax( RealTransform xfm, Interval interval ) { - int nd = interval.numDimensions(); - double[] pt = new double[ nd ]; - double[] ptxfm = new double[ nd ]; + final int nd = interval.numDimensions(); + final double[] pt = new double[ nd ]; + final double[] ptxfm = new double[ nd ]; - long[] min = new long[ nd ]; - long[] max = new long[ nd ]; + final long[] min = new long[ nd ]; + final long[] max = new long[ nd ]; - // transform min + // transform min for( int d = 0; d < nd; d++ ) pt[ d ] = interval.min( d ); - + xfm.apply( pt, ptxfm ); copyToLongFloor( ptxfm, min ); // transform max - + for( int d = 0; d < nd; d++ ) { pt[ d ] = interval.max( d ); } - + xfm.apply( pt, ptxfm ); copyToLongCeil( ptxfm, max ); - + return new FinalInterval( min, max ); } /** * Only works for 2D or 3D. - * + * * @param affine variable in which to store the result - * @param xfm the transform + * @param xfm the transform * @param interval the interval */ public static void estimateAffineFromCorners( AffineTransform3D affine, RealTransform xfm, Interval interval ) { - if( xfm == null ) + if( xfm == null ) return; - int nd = interval.numDimensions(); + final int nd = interval.numDimensions(); int N; Model model; if ( nd == 2 ) @@ -696,21 +690,21 @@ public static void estimateAffineFromCorners( AffineTransform3D affine, RealTran N = 8; model = new AffineModel3D(); } - - double[][] mvgPts = new double[ nd ][ N ]; - double[][] tgtPts = new double[ nd ][ N ]; - double[] w = new double[ N ]; + final double[][] mvgPts = new double[ nd ][ N ]; + final double[][] tgtPts = new double[ nd ][ N ]; + + final double[] w = new double[ N ]; Arrays.fill( w, 1.0 ); - double[] pt = new double[ nd ]; - double[] ptxfm = new double[ nd ]; + final double[] pt = new double[ nd ]; + final double[] ptxfm = new double[ nd ]; - long[] unitInterval = new long[ nd ]; + final long[] unitInterval = new long[ nd ]; Arrays.fill( unitInterval, 2 ); - + int i = 0; - IntervalIterator it = new IntervalIterator( unitInterval ); + final IntervalIterator it = new IntervalIterator( unitInterval ); while( it.hasNext() ) { it.fwd(); @@ -729,7 +723,7 @@ public static void estimateAffineFromCorners( AffineTransform3D affine, RealTran mvgPts[ d ][ i ] = pt[ d ]; tgtPts[ d ][ i ] = ptxfm[ d ]; } - + i++; } @@ -737,46 +731,46 @@ public static void estimateAffineFromCorners( AffineTransform3D affine, RealTran { model.fit( mvgPts, tgtPts, w ); } - catch ( Exception e ) + catch ( final Exception e ) { affine.identity(); return; } - + if ( nd == 2 ) { - double[] mat = new double[ 6 ]; + final double[] mat = new double[ 6 ]; ((AffineModel2D)model).toArray( mat ); affine.set( mat ); } else { - double[] mat = new double[ 12 ]; + final double[] mat = new double[ 12 ]; ((AffineModel3D)model).getMatrix( mat ); affine.set( mat ); } } - + public static FinalInterval estimateBounds( RealTransform xfm, Interval interval ) { if( xfm == null ) - return new FinalInterval( + return new FinalInterval( Intervals.minAsLongArray(interval), Intervals.maxAsLongArray(interval) ); - int nd = interval.numDimensions(); - double[] pt = new double[ nd ]; - double[] ptxfm = new double[ nd ]; + final int nd = interval.numDimensions(); + final double[] pt = new double[ nd ]; + final double[] ptxfm = new double[ nd ]; - long[] min = new long[ nd ]; - long[] max = new long[ nd ]; + final long[] min = new long[ nd ]; + final long[] max = new long[ nd ]; Arrays.fill( min, Long.MAX_VALUE ); Arrays.fill( max, Long.MIN_VALUE ); - long[] unitInterval = new long[ nd ]; + final long[] unitInterval = new long[ nd ]; Arrays.fill( unitInterval, 2 ); - - IntervalIterator it = new IntervalIterator( unitInterval ); + + final IntervalIterator it = new IntervalIterator( unitInterval ); while( it.hasNext() ) { it.fwd(); @@ -792,12 +786,12 @@ public static FinalInterval estimateBounds( RealTransform xfm, Interval interval for( int d = 0; d < nd; d++ ) { - long lo = (long)Math.floor( ptxfm[d] ); - long hi = (long)Math.ceil( ptxfm[d] ); - + final long lo = (long)Math.floor( ptxfm[d] ); + final long hi = (long)Math.ceil( ptxfm[d] ); + if( lo < min[ d ]) min[ d ] = lo; - + if( hi > max[ d ]) max[ d ] = hi; } @@ -831,7 +825,7 @@ public ImagePlus exportAsynch( final boolean wait, final boolean show ) { exportThread.join(); } - catch ( InterruptedException e ) + catch ( final InterruptedException e ) { e.printStackTrace(); } @@ -883,7 +877,7 @@ public void run() try{ IJ.save( exporter.result, exporter.exportPath ); } - catch( Exception e ) + catch( final Exception e ) { IJ.showMessage( "Failed to write : " + exporter.exportPath ); } @@ -905,12 +899,12 @@ public static BigWarpExporter getExporter( final Interpolation interp, final ProgressWriter progressWriter ) { - List movingSourceIndexList = bwData.getMovingSourceIndices(); + final List movingSourceIndexList = bwData.getMovingSourceIndices(); //TODO Caleb: Consider a method that just takes a list of all moving sources if ( BigWarpRealExporter.isTypeListFullyConsistent( transformedSources, movingSourceIndexList ) ) { - Object baseType = transformedSources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getType(); + final Object baseType = transformedSources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getType(); if( baseType instanceof RealType ) return new BigWarpRealExporter( bwData, bwData.converterSetups, interp, (RealType)baseType, progressWriter); else if ( ARGBType.class.isInstance( baseType ) ) diff --git a/src/main/java/bigwarp/BigWarpRealExporter.java b/src/main/java/bigwarp/BigWarpRealExporter.java index 7a67c01a..a264c3e1 100644 --- a/src/main/java/bigwarp/BigWarpRealExporter.java +++ b/src/main/java/bigwarp/BigWarpRealExporter.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -82,7 +82,7 @@ public BigWarpRealExporter( /** * Returns true if moving image sources are all of the same type. - * + * * @param sources the sources * @param the type * @param movingSourceIndexList list of indexes for moving sources @@ -90,12 +90,12 @@ public BigWarpRealExporter( */ public static boolean isTypeListFullyConsistent( List< SourceAndConverter< T >> sources, int[] movingSourceIndexList ) { - Object baseType = sources.get( movingSourceIndexList[ 0 ] ).getSpimSource().getType(); + final Object baseType = sources.get( movingSourceIndexList[ 0 ] ).getSpimSource().getType(); for ( int i = 1; i < movingSourceIndexList.length; i++ ) { - int idx = movingSourceIndexList[ i ]; - Object type = sources.get( idx ).getSpimSource().getType(); + final int idx = movingSourceIndexList[ i ]; + final Object type = sources.get( idx ).getSpimSource().getType(); if ( !baseType.getClass().equals( type.getClass() ) ) return false; @@ -103,10 +103,10 @@ public static boolean isTypeListFullyConsistent( List< SourceAndConverter< T return true; } - + /** * Returns true if moving image sources are all of the same type. - * + * * @param sources the sources * @param the type * @param movingSourceIndexList list of indexes for moving sources @@ -114,12 +114,12 @@ public static boolean isTypeListFullyConsistent( List< SourceAndConverter< T */ public static boolean isTypeListFullyConsistent( List< SourceAndConverter< T >> sources, List movingSourceIndexList ) { - Object baseType = sources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getType(); + final Object baseType = sources.get( movingSourceIndexList.get( 0 ) ).getSpimSource().getType(); for ( int i = 1; i < movingSourceIndexList.size(); i++ ) { - int idx = movingSourceIndexList.get( i ); - Object type = sources.get( idx ).getSpimSource().getType(); + final int idx = movingSourceIndexList.get( i ); + final Object type = sources.get( idx ).getSpimSource().getType(); if ( !baseType.getClass().equals( type.getClass() ) ) return false; @@ -127,45 +127,45 @@ public static boolean isTypeListFullyConsistent( List< SourceAndConverter< T return true; } - + @Override public RandomAccessibleInterval< T > exportRai() { - System.out.println( "RealExporter.exportRai"); - ArrayList< RandomAccessibleInterval< T > > raiList = new ArrayList< RandomAccessibleInterval< T > >(); + final ArrayList< RandomAccessibleInterval< T > > raiList = new ArrayList< RandomAccessibleInterval< T > >(); buildTotalRenderTransform(); final int numChannels = bwData.numMovingSources(); for ( int i = 0; i < numChannels; i++ ) { - SourceAndConverter< T > msrcTmp = bwData.getMovingSource( i ); + final SourceAndConverter< T > msrcTmp = bwData.getMovingSource( i ); final RealRandomAccessible< T > raiRaw = ( RealRandomAccessible< T > ) bwData.getMovingSource( i ).getSpimSource().getInterpolatedSource( 0, 0, interp ); // apply the transformations - final AffineRandomAccessible< T, AffineGet > rai = RealViews.affine( + final AffineRandomAccessible< T, AffineGet > rai = RealViews.affine( raiRaw, pixelRenderToPhysical.inverse() ); - + raiList.add( Views.interval( Views.raster( rai ), outputInterval ) ); } - RandomAccessibleInterval< T > raiStack = Views.stack( raiList ); + final RandomAccessibleInterval< T > raiStack = Views.stack( raiList ); return raiStack; } - + @Override public boolean isRGB() { return false; } + @Override @SuppressWarnings("unchecked") public ImagePlus export() { final int numChannels = bwData.numMovingSources(); - RandomAccessibleInterval< T > raiStack = exportRai(); - - VoxelDimensions voxdim = new FinalVoxelDimensions( unit, + final RandomAccessibleInterval< T > raiStack = exportRai(); + + final VoxelDimensions voxdim = new FinalVoxelDimensions( unit, resolutionTransform.get( 0, 0 ), resolutionTransform.get( 1, 1 ), resolutionTransform.get( 2, 2 )); @@ -195,9 +195,9 @@ else if( nThreads == 1 ) dimensions[ 0 ] = outputInterval.dimension( 0 ); // x dimensions[ 1 ] = outputInterval.dimension( 1 ); // y dimensions[ 2 ] = numChannels; // c - dimensions[ 3 ] = outputInterval.dimension( 2 ); // z - FinalInterval destIntervalPerm = new FinalInterval( dimensions ); - RandomAccessibleInterval< T > img = copyToImageStack( + dimensions[ 3 ] = outputInterval.dimension( 2 ); // z + final FinalInterval destIntervalPerm = new FinalInterval( dimensions ); + final RandomAccessibleInterval< T > img = copyToImageStack( raiStack, destIntervalPerm, factory, nThreads ); ip = ((ImagePlusImg)img).getImagePlus(); @@ -208,9 +208,9 @@ else if ( outputInterval.numDimensions() == 2 ) dimensions[ 0 ] = outputInterval.dimension( 0 ); // x dimensions[ 1 ] = outputInterval.dimension( 1 ); // y dimensions[ 2 ] = numChannels; // c - dimensions[ 3 ] = 1; // z - FinalInterval destIntervalPerm = new FinalInterval( dimensions ); - RandomAccessibleInterval< T > img = copyToImageStack( + dimensions[ 3 ] = 1; // z + final FinalInterval destIntervalPerm = new FinalInterval( dimensions ); + final RandomAccessibleInterval< T > img = copyToImageStack( Views.addDimension( Views.extendMirrorDouble( raiStack )), destIntervalPerm, factory, nThreads ); ip = ((ImagePlusImg)img).getImagePlus(); @@ -221,14 +221,14 @@ else if ( outputInterval.numDimensions() == 2 ) ip.getCalibration().pixelHeight = voxdim.dimension( 1 ); ip.getCalibration().pixelDepth = voxdim.dimension( 2 ); ip.getCalibration().setUnit( voxdim.unit() ); - + if( offsetTransform != null ) { ip.getCalibration().xOrigin = offsetTransform.get( 0, 3 ); ip.getCalibration().yOrigin = offsetTransform.get( 1, 3 ); ip.getCalibration().zOrigin = offsetTransform.get( 2, 3 ); } - + // ip.setTitle( sources.get( movingSourceIndexList[ 0 ]).getSpimSource().getName() + nameSuffix ); ip.setTitle( bwData.getMovingSource( 0 ).getSpimSource().getName() + nameSuffix ); @@ -262,10 +262,10 @@ else if ( d == 3 && itvl.numDimensions() > 3 ) final ImagePlusImgFactory< T > factory = new ImagePlusImgFactory< T >( t ); final ImagePlusImg< T, ? > target = factory.create( dimensions ); - long[] dims = new long[ target.numDimensions() ]; + final long[] dims = new long[ target.numDimensions() ]; target.dimensions( dims ); - long N = Intervals.numElements(itvl); + final long N = Intervals.numElements(itvl); final Cursor< T > c = target.cursor(); final RandomAccess< T > ra = raip.randomAccess(); double k = 0; From 173a5681e7b4ee33e7ae67f2ab95df80e2bc5faf Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 13:11:44 -0400 Subject: [PATCH 253/282] fix: undo EDT change to save. other issues arose --- src/main/java/bigwarp/BigWarp.java | 66 ++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index c2c2972e..c317590a 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3995,16 +3995,38 @@ protected void loadSettingsOrProject( final File f ) { settingsFile = fileChooser.getSelectedFile(); - Executors.newSingleThreadExecutor().execute(new Runnable() { - @Override - public void run() { - try { - loadSettings(settingsFile.getCanonicalPath(), true); - } catch (final Exception e) { - e.printStackTrace(); - } - } - }); + try { + loadSettings(settingsFile.getCanonicalPath(), true); + } catch (IOException | JDOMException e) { + e.printStackTrace(); + } + +// try { +// SwingUtilities.invokeAndWait( () -> { +// try { +// loadSettings(settingsFile.getCanonicalPath(), true); +// } catch (final IOException e) { +// e.printStackTrace(); +// } catch (final JDOMException e) { +// e.printStackTrace(); +// } +// }); +// } catch (final Exception e) { +// e.printStackTrace(); +// } + + + // TODO I may need this +// Executors.newSingleThreadExecutor().execute(new Runnable() { +// @Override +// public void run() { +// try { +// loadSettings(settingsFile.getCanonicalPath(), true); +// } catch (final Exception e) { +// e.printStackTrace(); +// } +// } +// }); } } @@ -4079,17 +4101,19 @@ public void loadSettings( final String jsonOrXmlFilename, boolean overwriteSourc { final BigwarpSettings settings = getSettings(); settings.setOverwriteSources( overwriteSources ); - - Executors.newSingleThreadExecutor().execute(new Runnable() { - @Override - public void run() { - try { - settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); - } catch (final Exception e) { - e.printStackTrace(); - } - } - }); + settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); + + // TODO I may need this +// Executors.newSingleThreadExecutor().execute(new Runnable() { +// @Override +// public void run() { +// try { +// settings.read( new JsonReader( new FileReader( jsonOrXmlFilename ) ) ); +// } catch (final Exception e) { +// e.printStackTrace(); +// } +// } +// }); activeSourcesDialogP.update(); activeSourcesDialogQ.update(); From 9319848b3d820c2f6af74380b1a460d346161749 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 13:11:57 -0400 Subject: [PATCH 254/282] fix: interp transform NPE when lambda null --- .../realtransform/SpatiallyInterpolatedRealTransform.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java index f9391f1c..a25ca558 100644 --- a/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java +++ b/src/main/java/net/imglib2/realtransform/SpatiallyInterpolatedRealTransform.java @@ -42,7 +42,9 @@ public SpatiallyInterpolatedRealTransform(RealTransform a, RealTransform b, Real this.a = a; this.b = b; this.lambda = lambda; - lambdaAccess = lambda.realRandomAccess(); + + if( lambda != null ) + lambdaAccess = lambda.realRandomAccess(); final int nd = a.numTargetDimensions(); arrA = new double[nd]; From 19aca625933cbff5cf4e81532873cdb16a8a9cdc Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 14:48:33 -0400 Subject: [PATCH 255/282] fix: activation of warp vis sources --- src/main/java/bigwarp/BigWarp.java | 79 +++++++++++++++++-------- src/main/java/bigwarp/WarpVisFrame.java | 10 ++-- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index c317590a..d042d91a 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2601,15 +2601,8 @@ else if ( both ) jacDetSource = addJacobianDeterminantSource( ndims, data, "Jacobian determinant" ); synchronizeSources(); } - state.setSourceActive( data.getSourceInfo( JACDET_SOURCE_ID ).getSourceAndConverter(), true ); + showSourceFused( viewerFrame, JACDET_SOURCE_ID ); - if ( warpMagSource != null ) - state.setSourceActive( data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(), false ); - - if ( gridSource != null ) - state.setSourceActive( data.getSourceInfo( GRID_SOURCE_ID ).getSourceAndConverter(), false ); - - state.setDisplayMode( DisplayMode.FUSED ); viewerFrame.getViewerPanel().showMessage( "Displaying Jacobian Determinant" ); break; } @@ -2622,13 +2615,7 @@ else if ( both ) warpMagSource = addWarpMagnitudeSource( data, ndims == 2, "Warp magnitude" ); synchronizeSources(); } - state.setSourceActive( data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(), true ); - - if ( jacDetSource != null ) - state.setSourceActive( data.getSourceInfo( JACDET_SOURCE_ID ).getSourceAndConverter(), false ); - - if ( gridSource != null ) - state.setSourceActive( data.getSourceInfo( GRID_SOURCE_ID ).getSourceAndConverter(), false ); + showSourceFused( viewerFrame, WARPMAG_SOURCE_ID ); // estimate the max warp // final WarpMagnitudeSource< ? > wmSrc = ( ( WarpMagnitudeSource< ? > ) sources.get( warpMagSourceIndex ).getSpimSource() ); @@ -2637,7 +2624,7 @@ else if ( both ) // set the slider // ( ( RealARGBColorConverter< FloatType > ) ( sources.get( warpMagSourceIndex ).getConverter() ) ).setMax( maxval ); - state.setDisplayMode( DisplayMode.FUSED ); + viewerFrame.getViewerPanel().showMessage( "Displaying Warp Magnitude" ); break; } @@ -2650,15 +2637,8 @@ else if ( both ) synchronizeSources(); data.getConverterSetup( GRID_SOURCE_ID ).setDisplayRange( 0, 512 ); } - state.setSourceActive( data.getSourceInfo( GRID_SOURCE_ID ).getSourceAndConverter(), true ); - - if ( warpMagSource != null ) - state.setSourceActive( data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(), false ); - - if ( jacDetSource != null ) - state.setSourceActive( data.getSourceInfo( JACDET_SOURCE_ID ).getSourceAndConverter(), false ); + showSourceFused( viewerFrame, GRID_SOURCE_ID ); - state.setDisplayMode( DisplayMode.FUSED ); viewerFrame.getViewerPanel().showMessage( "Displaying Warp Grid" ); break; } @@ -2692,7 +2672,7 @@ else if ( viewerFrameQ.isActive() ) return; } - if ( landmarkModel.getTransform() == null ) + if( getBwTransform().getTransformation() == null ) { message.showMessage( "No warp - estimate warp first." ); return; @@ -2702,6 +2682,7 @@ else if ( viewerFrameQ.isActive() ) // TODO consider remembering whether fused was on before displaying warpmag // so that its still on or off after we turn it off + final SourceAndConverter< ? > wmSac = data.getSourceInfo( WARPMAG_SOURCE_ID ).getSourceAndConverter(); if ( state.isSourceActive( wmSac ) ) // warp mag is visible, turn it off { @@ -2728,6 +2709,53 @@ else if ( viewerFrameQ.isActive() ) viewerFrame.getViewerPanel().requestRepaint(); } + private void showSourceFused(BigWarpViewerFrame viewerFrame, int sourceId) { + + if (viewerFrame == null) { + if (viewerFrameP.isActive()) { + viewerFrame = viewerFrameP; + } else if (viewerFrameQ.isActive()) { + viewerFrame = viewerFrameQ; + } else + return; + } + + if (getBwTransform().getTransformation() == null) { + message.showMessage("No warp - estimate warp first."); + return; + } + + final SourceAndConverter< ? > newSrc = data.getSourceInfo( sourceId ).getSourceAndConverter(); + + final ViewerState state = viewerFrame.getViewerPanel().state(); + if (!state.getDisplayMode().equals(DisplayMode.FUSED)) { + final SourceAndConverter currentSource = state.getCurrentSource(); + for( final SourceAndConverter src : state.getSources()) + state.setSourceActive(src, src == currentSource || src == newSrc ); + } + else { + + final SourceInfo warpMagSrcInfo = data.getSourceInfo( WARPMAG_SOURCE_ID ); + final SourceInfo gridSrcInfo = data.getSourceInfo( GRID_SOURCE_ID ); + final SourceInfo jacDetSrcInfo = data.getSourceInfo( JACDET_SOURCE_ID ); + + // un-dispolay all the warp vis sources + if (warpMagSrcInfo != null) + state.setSourceActive(warpMagSrcInfo.getSourceAndConverter(), false); + + if (gridSrcInfo != null) + state.setSourceActive(gridSrcInfo.getSourceAndConverter(), false); + + if (jacDetSrcInfo != null) + state.setSourceActive(jacDetSrcInfo.getSourceAndConverter(), false); + + // activate the requested one + state.setSourceActive(newSrc, true); + } + + state.setDisplayMode(DisplayMode.FUSED); + } + private void setTransformationMovingSourceOnly( final InvertibleRealTransform transform ) { this.currentTransform = transform; @@ -4015,7 +4043,6 @@ protected void loadSettingsOrProject( final File f ) // e.printStackTrace(); // } - // TODO I may need this // Executors.newSingleThreadExecutor().execute(new Runnable() { // @Override diff --git a/src/main/java/bigwarp/WarpVisFrame.java b/src/main/java/bigwarp/WarpVisFrame.java index 1b1b96d5..31f22df6 100644 --- a/src/main/java/bigwarp/WarpVisFrame.java +++ b/src/main/java/bigwarp/WarpVisFrame.java @@ -494,10 +494,10 @@ public void stateChanged( ChangeEvent e ) public void addListeners() { - final MyChangeListener mylistener = new MyChangeListener(); - setWarpVisOffButton.addChangeListener( mylistener ); - setWarpGridButton.addChangeListener( mylistener ); - setWarpMagButton.addChangeListener( mylistener ); + final VisOptUiListener visOptListener = new VisOptUiListener(); + setWarpVisOffButton.addChangeListener( visOptListener ); + setWarpGridButton.addChangeListener( visOptListener ); + setWarpMagButton.addChangeListener( visOptListener ); gridSpacingSlider.addChangeListener( new ChangeListener() { @@ -522,7 +522,7 @@ public void stateChanged( ChangeEvent e ) }); } - public class MyChangeListener implements ChangeListener + private class VisOptUiListener implements ChangeListener { @Override public void stateChanged( ChangeEvent e ) From 4825a24f7dac0fa16a157080070d4d0d23d6a9b9 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 14:48:44 -0400 Subject: [PATCH 256/282] fix: suppress error --- .../java/bigwarp/transforms/io/TransformWriterJson.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java index 353c0f20..302ab48c 100644 --- a/src/main/java/bigwarp/transforms/io/TransformWriterJson.java +++ b/src/main/java/bigwarp/transforms/io/TransformWriterJson.java @@ -50,11 +50,7 @@ public static void read( final File f, final BigWarp bw ) read( bw, json ); - } catch ( final IOException e ) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } + } catch ( final IOException e ) { } } public static JsonObject write(LandmarkTableModel ltm, BigWarpTransform bwTransform) { From 7bc2caa7e7257ea13f4700306ba1683f85d059c5 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 18:08:35 -0400 Subject: [PATCH 257/282] fix: export inverse affines * to be consistent with dfields --- .../ij/BigWarpToDeformationFieldPlugIn.java | 45 ++++++++----------- src/main/java/bigwarp/BigWarpData.java | 1 - 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 4f72affd..db041566 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -475,7 +475,7 @@ else if ( nd == 3 ) * @param ignoreAffine whether the output should include the affine part of the transformation * @return the transformation */ - protected static InvertibleRealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concatPreTransforms, + public static InvertibleRealTransform getTransformation( final BigWarpData data, final BigWarpTransform transform, final boolean concatPreTransforms, final boolean ignoreAffine ) { final InvertibleRealTransform tps = transform.getTransformation( false ); @@ -536,6 +536,8 @@ protected static InvertibleRealTransform getTransformation( final BigWarpData return startingTransform; } + + public static void writeAffineN5( final String n5BasePath, final String n5Dataset, @@ -546,65 +548,54 @@ public static void writeAffineN5( final String tgtSpaceName = data != null && data.numTargetSources() > 0 ? data.getTargetSource( 0 ).getSpimSource().getName() : "target"; final String input= mvgSpaceName; final String output= tgtSpaceName; + final String name = input + " to " + output; CoordinateTransform ct = null; final InvertibleCoordinateTransform tform = bwTransform.getCoordinateTransform(); switch( bwTransform.getTransformType()) { case BigWarpTransform.TRANSLATION: if (tform instanceof TranslationModel2D) - ct = new TranslationCoordinateTransform("translation transformation", input, output, ((TranslationModel2D)tform).getTranslation()); + ct = new TranslationCoordinateTransform(name, input, output, ((TranslationModel2D)tform).createInverse().getTranslation()); else if (tform instanceof TranslationModel3D) - ct = new TranslationCoordinateTransform("translation transformation", input, output, ((TranslationModel3D)tform).getTranslation()); + ct = new TranslationCoordinateTransform(name, input, output, ((TranslationModel3D)tform).createInverse().getTranslation()); break; case BigWarpTransform.SIMILARITY: double[] simparams; if (tform instanceof SimilarityModel2D) { - simparams = bwTransform.toImglib2((SimilarityModel2D)tform).inverse().getRowPackedCopy(); -// simparams = new double[ 6 ]; -// ((SimilarityModel2D)tform).toArray(simparams); - ct = new AffineCoordinateTransform("translation transformation", input, output, simparams); + simparams = bwTransform.toImglib2((SimilarityModel2D)tform).getRowPackedCopy(); + ct = new AffineCoordinateTransform(name, input, output, simparams); } else if (tform instanceof SimilarityModel3D) { - simparams = bwTransform.toImglib2((SimilarityModel3D)tform).inverse().getRowPackedCopy(); -// simparams = new double[ 12 ]; -// ((SimilarityModel3D)tform).toArray(simparams); - ct = new AffineCoordinateTransform("translation transformation", input, output, simparams); + simparams = bwTransform.toImglib2((SimilarityModel3D)tform).getRowPackedCopy(); + ct = new AffineCoordinateTransform(name, input, output, simparams); } break; case BigWarpTransform.ROTATION: double[] rotparams; if (tform instanceof RigidModel2D) { - rotparams = bwTransform.toImglib2((RigidModel2D)tform).inverse().getRowPackedCopy(); -// rotparams = new double[ 6 ]; -// ((RigidModel2D)tform).toArray(rotparams); - ct = new AffineCoordinateTransform("translation transformation", input, output, rotparams); + rotparams = bwTransform.toImglib2((RigidModel2D)tform).getRowPackedCopy(); + ct = new AffineCoordinateTransform(name, input, output, rotparams); } else if (tform instanceof RigidModel3D) { - rotparams = bwTransform.toImglib2((RigidModel3D)tform).inverse().getRowPackedCopy(); -// rotparams = new double[ 12 ]; -// ((RigidModel3D)tform).toArray(rotparams); - ct = new AffineCoordinateTransform("translation transformation", input, output, rotparams); + rotparams = bwTransform.toImglib2((RigidModel3D)tform).getRowPackedCopy(); + ct = new AffineCoordinateTransform(name, input, output, rotparams); } break; case BigWarpTransform.AFFINE: double[] affparams; if (tform instanceof AffineModel2D) { - affparams = bwTransform.toImglib2((AffineModel2D)tform).inverse().getRowPackedCopy(); -// affparams = new double[ 6 ]; -// ((AffineModel2D)tform).toArray(affparams); - ct = new AffineCoordinateTransform("translation transformation", input, output, affparams); + affparams = bwTransform.toImglib2((AffineModel2D)tform).getRowPackedCopy(); + ct = new AffineCoordinateTransform(name, input, output, affparams); } else if (tform instanceof AffineModel3D) { - affparams = bwTransform.toImglib2((AffineModel3D)tform).inverse().getRowPackedCopy(); -// affparams = new double[ 12 ]; -// ((AffineModel3D)tform).toArray(affparams); - ct = new AffineCoordinateTransform("translation transformation", input, output, affparams); + affparams = bwTransform.toImglib2((AffineModel3D)tform).getRowPackedCopy(); + ct = new AffineCoordinateTransform(name, input, output, affparams); } break; } diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index e07b380d..c55aac5a 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -395,7 +395,6 @@ public Source applyFixedTransform( final Source src, final RealTransfo final AffineGet transformTo3D = BigWarpUtils.toAffine3D((AffineGet)transform); affine3d.preConcatenate( transformTo3D ); } - tform = affine3d.inverse(); } // need to use WarpedSource From d24d02230e2def89a00e4e49ca179a3f34adb42e Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Tue, 3 Oct 2023 18:10:05 -0400 Subject: [PATCH 258/282] fix: export of split affine-dfield * and rename dialog "export transformation" --- src/main/java/bdv/gui/ExportDisplacementFieldFrame.java | 2 +- src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java | 7 ++----- src/main/java/bigwarp/BigWarp.java | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index 273d5fe8..6203b449 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -120,7 +120,7 @@ public ExportDisplacementFieldFrame( BigWarp bw ) public ExportDisplacementFieldFrame( BigWarpData data, BigWarpTransform bwTransform, LandmarkTableModel ltm ) { - super( "Export displacement field" ); + super( "Export transformation" ); initialPath = ""; imageJOpen = IJ.getInstance() != null; diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index db041566..6635a89d 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -727,11 +727,8 @@ public static void writeN5( final AffineGet affine = bwXfm.affinePartOfTps(); final AffineCoordinateTransform ngffAffine = new AffineCoordinateTransform( affine.getRowPackedCopy() ); - // displacement field (with the affine removed) - final RealTransformSequence totalNoAffine = new RealTransformSequence(); - totalNoAffine.add( transform ); - totalNoAffine.add( affine.inverse() ); - dfield = DisplacementFieldTransform.createDisplacementField( totalNoAffine, new FinalInterval( dims ), spacing, offset ); + // the variable transform has the affine part removed here + dfield = DisplacementFieldTransform.createDisplacementField( transform, new FinalInterval( dims ), spacing, offset ); if( format.equals( ExportDisplacementFieldFrame.FMT_SLICER )) { diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index d042d91a..019cc552 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -1087,7 +1087,7 @@ protected void setUpViewerMenu( final BigWarpViewerFrame vframe ) fileMenu.add( exportToImagePlus ); final JMenuItem exportWarpField = new JMenuItem( actionMap.get( BigWarpActions.EXPORT_WARP )); - exportWarpField.setText( "Export warp field" ); + exportWarpField.setText( "Export transformation" ); fileMenu.add( exportWarpField ); } From 5755fbec1452e3f51d34dbb23cdfff00beb3e29f Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 5 Oct 2023 13:27:46 -0400 Subject: [PATCH 259/282] fix: export of translation transforms --- src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 6635a89d..a1d1199d 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -555,9 +555,9 @@ public static void writeAffineN5( switch( bwTransform.getTransformType()) { case BigWarpTransform.TRANSLATION: if (tform instanceof TranslationModel2D) - ct = new TranslationCoordinateTransform(name, input, output, ((TranslationModel2D)tform).createInverse().getTranslation()); + ct = new TranslationCoordinateTransform(name, input, output, ((TranslationModel2D)tform).getTranslation()); else if (tform instanceof TranslationModel3D) - ct = new TranslationCoordinateTransform(name, input, output, ((TranslationModel3D)tform).createInverse().getTranslation()); + ct = new TranslationCoordinateTransform(name, input, output, ((TranslationModel3D)tform).getTranslation()); break; case BigWarpTransform.SIMILARITY: double[] simparams; From c69ec6deb1949001ef885a51cebbcf52e56744da Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 5 Oct 2023 13:28:26 -0400 Subject: [PATCH 260/282] fix: export of sequence transforms * when a fixed transform has been imported --- .../ij/BigWarpToDeformationFieldPlugIn.java | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index a1d1199d..826ed62f 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -51,6 +51,7 @@ import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.AffineCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.DisplacementFieldCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.ReferencedCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.SequenceCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.TranslationCoordinateTransform; @@ -657,6 +658,7 @@ public static void writeN5( writeN5( n5BasePath, n5Dataset, ltm, bwTransform, data, dims, spacing, offset, unit, spatialBlockSize, compression, nThreads, format, false, flatten, inverse, invTolerance, invMaxIters ); } + @SuppressWarnings("rawtypes") public static void writeN5( final String n5BasePath, final String n5Dataset, @@ -720,6 +722,24 @@ public static void writeN5( final N5Factory factory = new N5Factory().gsonBuilder( NgffTransformations.gsonBuilder() ); final N5Writer n5 = factory.openWriter( n5BasePath ); + + // TODO generalize + // get first transformUri for a moving source + ReferencedCoordinateTransform refCt = null; + if( !flatten ) + { + for ( final Entry e : data.sourceInfos.entrySet() ) + { + final SourceInfo i = e.getValue(); + if( i.isMoving() && i.getTransformUri() != null && !i.getTransformUri().isEmpty()) + { + refCt = new ReferencedCoordinateTransform( i.getTransformUri() ); + break; + } + } + } + + final RandomAccessibleInterval< DoubleType > dfield; if( splitAffine ) { @@ -739,9 +759,12 @@ public static void writeN5( else { final DisplacementFieldCoordinateTransform dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); + + // the transform sequence needs to have a reference to whatever transform was imported, if requested + final CoordinateTransform[] ctList = refCt == null ? new CoordinateTransform[]{ dfieldTform, ngffAffine } : new CoordinateTransform[]{ dfieldTform, ngffAffine, refCt }; + // the total transform - final SequenceCoordinateTransform totalTform = new SequenceCoordinateTransform( inputSpace, outputSpace, - new CoordinateTransform[]{ dfieldTform, ngffAffine }); + final SequenceCoordinateTransform totalTform = new SequenceCoordinateTransform( inputSpace, outputSpace, ctList ); NgffTransformations.addCoordinateTransformations( n5, "/", totalTform ); } @@ -760,7 +783,15 @@ public static void writeN5( } else { - final DisplacementFieldCoordinateTransform ngffTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); + final DisplacementFieldCoordinateTransform dfieldTform = NgffTransformations.save( n5, dataset, dfield, inputSpace, outputSpace, spacing, offset, unit, blockSize, compression, nThreads ); + + final CoordinateTransform ngffTform; + if( refCt == null ) + ngffTform = dfieldTform; + else + ngffTform = new SequenceCoordinateTransform( refCt.getInput(), dfieldTform.getOutput(), new CoordinateTransform[]{ dfieldTform, refCt }); + + NgffTransformations.addCoordinateTransformations( n5, "/", ngffTform ); } } From 32da0db363b7d23914d0c8d585f64ee98b3371f5 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 5 Oct 2023 13:28:55 -0400 Subject: [PATCH 261/282] fix: exporting image with moving(warped) fov with no transform --- src/main/java/bdv/ij/ApplyBigwarpPlugin.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java index 875d0f57..99ab6bc3 100644 --- a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java +++ b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java @@ -350,6 +350,13 @@ public static Interval getPixelInterval( } else if( fieldOfViewOption.equals( MOVING_WARPED )) { + final FinalInterval interval = new FinalInterval( + Intervals.minAsLongArray( rai ), + Intervals.maxAsLongArray( rai )); + + if( transform == null ) + return interval; + final double[] movingRes = resolutionFromSource( source ); final int ndims = transform.numSourceDimensions(); final AffineTransform movingPixelToPhysical = new AffineTransform( ndims ); @@ -369,10 +376,6 @@ else if( fieldOfViewOption.equals( MOVING_WARPED )) seq.add( transform.inverse() ); seq.add( outputResolution2Pixel.inverse() ); - final FinalInterval interval = new FinalInterval( - Intervals.minAsLongArray( rai ), - Intervals.maxAsLongArray( rai )); - return bboxEst.estimatePixelInterval(seq, interval); // return BigWarpExporter.estimateBounds( seq, interval ); } From 37c7447cc39c3180859986879d2cbf777d0455c5 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 5 Oct 2023 13:30:10 -0400 Subject: [PATCH 262/282] fix(ui): remove "slicer"-style transform export option from ui --- src/main/java/bdv/gui/ExportDisplacementFieldFrame.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java index 6203b449..ddb00f12 100644 --- a/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java +++ b/src/main/java/bdv/gui/ExportDisplacementFieldFrame.java @@ -412,7 +412,8 @@ public JPanel basicPanel() ctxt.gridx = 3; panel.add( new JLabel( "Format:" ), ctxt ); gbcCheck.gridx = 4; - formatComboBox = new JComboBox< String >( new String[] { FMT_NGFF, FMT_SLICER } ); +// formatComboBox = new JComboBox< String >( new String[] { FMT_NGFF, FMT_SLICER } ); + formatComboBox = new JComboBox< String >( new String[] { FMT_NGFF } ); panel.add( formatComboBox, gbcCheck ); ctxt.gridx = 5; From a56e48e72927b36722f4d1ecac3d8031fbb3130c Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 5 Oct 2023 14:45:16 -0400 Subject: [PATCH 263/282] fix: warped source bounding box estimation * and issue with multiscale --- src/main/java/bdv/img/WarpedSource.java | 86 ++++++++++++------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/src/main/java/bdv/img/WarpedSource.java b/src/main/java/bdv/img/WarpedSource.java index cf5862db..972eddb1 100644 --- a/src/main/java/bdv/img/WarpedSource.java +++ b/src/main/java/bdv/img/WarpedSource.java @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -28,16 +28,17 @@ import bdv.viewer.SourceAndConverter; import bdv.viewer.render.DefaultMipmapOrdering; import bdv.viewer.render.MipmapOrdering; -import bigwarp.BigWarpExporter; import mpicbg.spim.data.sequence.VoxelDimensions; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealRandomAccessible; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.BoundingBoxEstimation; +import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.RealTransformRealRandomAccessible; -import net.imglib2.realtransform.RealViews; +import net.imglib2.realtransform.RealTransformSequence; +import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.view.Views; public class WarpedSource < T > implements Source< T >, MipmapOrdering @@ -64,10 +65,12 @@ public static < T > SourceAndConverter< T > wrap( final SourceAndConverter< T > */ private final MipmapOrdering sourceMipmapOrdering; - private RealTransform xfm; + private InvertibleRealTransform xfm; + + private Interval[] boundingIntervalsPerLevel; private boolean isTransformed; - + private final Supplier< Boolean > boundingBoxCullingSupplier; private BoundingBoxEstimation bboxEst; @@ -84,10 +87,11 @@ public WarpedSource( final Source< T > source, final String name, this.name = name; this.isTransformed = false; this.boundingBoxCullingSupplier = doBoundingBoxCulling; - bboxEst = new BoundingBoxEstimation( BoundingBoxEstimation.Method.FACES, 5 ); - this.xfm = null; + bboxEst = new BoundingBoxEstimation( BoundingBoxEstimation.Method.FACES, 5 ); + boundingIntervalsPerLevel = new Interval[source.getNumMipmapLevels()]; + sourceMipmapOrdering = MipmapOrdering.class.isInstance( source ) ? ( MipmapOrdering ) source : new DefaultMipmapOrdering( source ); } @@ -97,7 +101,7 @@ public boolean isPresent( final int t ) { return source.isPresent( t ); } - + @Override public boolean doBoundingBoxCulling() { @@ -109,14 +113,27 @@ public boolean doBoundingBoxCulling() public void updateTransform( RealTransform xfm ) { - this.xfm = xfm; + if( xfm instanceof InvertibleRealTransform ) + this.xfm = (InvertibleRealTransform)xfm; + else + this.xfm = new WrappedIterativeInvertibleRealTransform<>(xfm); + + updateBoundingIntervals(); + } + + protected void updateBoundingIntervals() + { + for( int i = 0; i < getNumMipmapLevels(); i++ ) + { + boundingIntervalsPerLevel[i] = estimateBoundingInterval(0, i); + } } - + public void setIsTransformed( boolean isTransformed ) { this.isTransformed = isTransformed; } - + public void setBoundingBoxEstimator( final BoundingBoxEstimation bboxEst ) { this.bboxEst = bboxEst; @@ -139,7 +156,7 @@ public RandomAccessibleInterval< T > getSource( final int t, final int level ) { return Views.interval( Views.raster( getInterpolatedSource( t, level, Interpolation.NEARESTNEIGHBOR ) ), - estimateBoundingInterval( t, level )); + boundingIntervalsPerLevel[level] ); } return source.getSource( t, level ); } @@ -152,9 +169,9 @@ private Interval estimateBoundingInterval( final int t, final int level ) } else { - // getSource can be called by multiple threads, so need ensure application of + // getSource can be called by multiple threads, so need ensure application of // the transform is thread safe here by copying - return bboxEst.estimatePixelInterval( xfm.copy(), source.getSource( t, level ) ); + return bboxEst.estimatePixelInterval( xfm.copy().inverse(), source.getSource( t, level ) ); } } @@ -162,43 +179,22 @@ private Interval estimateBoundingInterval( final int t, final int level ) public RealRandomAccessible< T > getInterpolatedSource( final int t, final int level, final Interpolation method ) { -// RealRandomAccessible realSrc = source.getInterpolatedSource( t, level, method ); -// if( isTransformed && xfm != null ) -// { -// final AffineTransform3D transform = new AffineTransform3D(); -// source.getSourceTransform( t, level, transform ); -// -// RealTransformSequence totalTransform = new RealTransformSequence(); -//// totalTransform.add( transform ); -//// totalTransform.add( xfm ); -//// totalTransform.add( transform.inverse() ); -// -// totalTransform.add( transform.inverse() ); -// totalTransform.add( xfm ); -// totalTransform.add( transform ); -// -// return new RealTransformRealRandomAccessible< T, RealTransform >( realSrc, xfm ); -// } -// else -// { -// return realSrc; -// } - - final RealRandomAccessible< T > sourceRealAccessible = source.getInterpolatedSource( t, level, method ); - if( isTransformed ) + final RealRandomAccessible realSrc = source.getInterpolatedSource( t, level, method ); + if( isTransformed && xfm != null ) { final AffineTransform3D transform = new AffineTransform3D(); source.getSourceTransform( t, level, transform ); - final RealRandomAccessible< T > srcRaTransformed = RealViews.affineReal( source.getInterpolatedSource( t, level, method ), transform ); - if( xfm == null ) - return srcRaTransformed; - else - return new RealTransformRealRandomAccessible< T, RealTransform >( srcRaTransformed, xfm); + final RealTransformSequence totalTransform = new RealTransformSequence(); + totalTransform.add( transform.inverse() ); + totalTransform.add( xfm ); + totalTransform.add( transform ); + + return new RealTransformRealRandomAccessible< T, RealTransform >( realSrc, xfm ); } else { - return sourceRealAccessible; + return realSrc; } } From 2de1723e7d90b4b0576a968218c3ae29ad664fc9 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 5 Oct 2023 14:45:37 -0400 Subject: [PATCH 264/282] chore: n5 deps --- pom.xml | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index e7733804..8a2c0f90 100644 --- a/pom.xml +++ b/pom.xml @@ -129,10 +129,13 @@ sign,deploy-to-scijava 3.0.2 - 3.2.6 + 3.2.6-SNAPSHOT 2.0.1 + 4.0.1 + 4.0.0 7.0.0 1.1.1-SNAPSHOT + 5.3.1 1.0.1 10.4.8 @@ -246,6 +249,22 @@ org.janelia.saalfeldlab n5-imglib2 + + org.janelia.saalfeldlab + n5-aws-s3 + + + org.janelia.saalfeldlab + n5-google-cloud + + + org.janelia.saalfeldlab + n5-viewer_fiji + + + org.janelia.saalfeldlab + n5-zarr + org.janelia.saalfeldlab n5-universe @@ -330,9 +349,6 @@ xmlunit 1.5 - - org.janelia.saalfeldlab - n5-zarr - + From 0cab41ed8dd70cd90c03629f277111d68403ff80 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 5 Oct 2023 14:46:44 -0400 Subject: [PATCH 265/282] chore: bump imglib2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a2c0f90..f1022070 100644 --- a/pom.xml +++ b/pom.xml @@ -118,7 +118,7 @@ BigWarp plugin for Fiji. **/resources/*.xml - 6.0.0 + 6.2.0 4.0.1 1.48 From ab4d0c873a037cb6268d6b10f9d81ec9d8ca4a8a Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Thu, 5 Oct 2023 14:54:44 -0400 Subject: [PATCH 266/282] chore: cleanup, move main methods to test classes --- src/main/java/bdv/gui/BigWarpInitDialog.java | 81 ++-- src/main/java/bdv/ij/BigWarpCommand.java | 31 +- src/main/java/bigwarp/BigWarpInit.java | 5 - .../transforms/NgffTransformations.java | 275 ++------------ src/test/java/bigwarp/NgffTransformTests.java | 345 ++++++++++++++++++ src/test/java/bigwarp/StartupTests.java | 121 ++++++ 6 files changed, 558 insertions(+), 300 deletions(-) create mode 100644 src/test/java/bigwarp/NgffTransformTests.java create mode 100644 src/test/java/bigwarp/StartupTests.java diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 6480116d..316a8815 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -15,6 +15,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; +import java.util.function.Supplier; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; @@ -34,17 +35,22 @@ import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; -import org.janelia.saalfeldlab.n5.ij.N5Importer; +import org.janelia.saalfeldlab.n5.bdv.N5ViewerTreeCellRenderer; import org.janelia.saalfeldlab.n5.ij.N5Importer.N5BasePathFun; import org.janelia.saalfeldlab.n5.ij.N5Importer.N5ViewerReaderFun; +import org.janelia.saalfeldlab.n5.metadata.N5ViewerMultichannelMetadata; +import org.janelia.saalfeldlab.n5.metadata.imagej.ImagePlusLegacyMetadataParser; import org.janelia.saalfeldlab.n5.ui.DataSelection; import org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog; -import org.janelia.saalfeldlab.n5.ui.N5DatasetTreeCellRenderer; import org.janelia.saalfeldlab.n5.ui.N5SwingTreeNode; -import org.janelia.saalfeldlab.n5.universe.metadata.N5DatasetMetadata; +import org.janelia.saalfeldlab.n5.universe.metadata.N5CosemMetadataParser; +import org.janelia.saalfeldlab.n5.universe.metadata.N5CosemMultiScaleMetadata; +import org.janelia.saalfeldlab.n5.universe.metadata.N5GenericSingleScaleMetadataParser; import org.janelia.saalfeldlab.n5.universe.metadata.N5Metadata; import org.janelia.saalfeldlab.n5.universe.metadata.N5MetadataParser; -import org.janelia.saalfeldlab.n5.universe.metadata.canonical.CanonicalDatasetMetadata; +import org.janelia.saalfeldlab.n5.universe.metadata.N5SingleScaleMetadataParser; +import org.janelia.saalfeldlab.n5.universe.metadata.N5ViewerMultiscaleMetadataParser; +import org.janelia.saalfeldlab.n5.universe.metadata.canonical.CanonicalMetadataParser; import org.jdom2.JDOMException; import com.formdev.flatlaf.util.UIScale; @@ -64,7 +70,6 @@ import bigwarp.transforms.metadata.N5TransformMetadataParser; import bigwarp.transforms.metadata.N5TransformTreeCellRenderer; import ij.IJ; -import ij.ImageJ; import ij.ImagePlus; import ij.Macro; import ij.Prefs; @@ -123,9 +128,23 @@ public class BigWarpInitDialog extends JFrame private boolean initialRecorderState; - public BigWarpInitDialog() - { - } + + public static final N5MetadataParser[] n5Parsers = new N5MetadataParser[]{ + new N5CosemMetadataParser(), + new N5SingleScaleMetadataParser(), + new CanonicalMetadataParser(), + new ImagePlusLegacyMetadataParser(), + new N5GenericSingleScaleMetadataParser() + }; + + public static final N5MetadataParser[] n5vGroupParsers = new N5MetadataParser[]{ +// new org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.OmeNgffMetadataParser(), +// new org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v03.OmeNgffMetadataParser(), // TODO test later + new N5CosemMultiScaleMetadata.CosemMultiScaleParser(), + new N5ViewerMultiscaleMetadataParser(), + new CanonicalMetadataParser(), + new N5ViewerMultichannelMetadata.N5ViewerMultichannelMetadataParser() + }; public BigWarpInitDialog( final String title ) { @@ -168,38 +187,12 @@ public BigWarpInitDialog( final String title, final DatasetService datasetServic }; } + public void setInitialRecorderState( final boolean initialRecorderState ) { this.initialRecorderState = initialRecorderState; } - public static void main( final String[] args ) throws IOException - { -// ImageJ ij2 = new ImageJ(); -// ij2.ui().showUI(); - -// ImageJ ij = new ImageJ(); -// -// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); -// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); -// -// IJ.openImage( "/home/john/tmp/boats.tif" ).show(); -// IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); -// -// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); -// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); - - new ImageJ(); -// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); -// String macroOptions = "images=imagej://mri-stack.tif,imagej://mri-stack.tif moving=true,false transforms=,"; -// runMacro( macroOptions ); - -// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); - IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); - - createAndShow(); - } - public static BigWarp runBigWarp( final String projectLandmarkPath, final String[] images, final String[] moving, final String[] transforms ) { final BigWarpData< T > data = BigWarpInit.initData(); @@ -614,15 +607,12 @@ public void buildN5SelectionDialog() exec = Executors.newFixedThreadPool( Prefs.getThreads() ); selectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), - lastOpenedContainer, new N5MetadataParser[] {}, - N5Importer.PARSERS ); + lastOpenedContainer, + n5vGroupParsers, + n5Parsers); selectionDialog.setLoaderExecutor( exec ); - selectionDialog.setTreeRenderer( new N5DatasetTreeCellRenderer( true ) ); - - // restrict canonical metadata to those with spatial metadata, but - // without multiscale - selectionDialog.getTranslationPanel().setFilter( x -> ( x instanceof CanonicalDatasetMetadata ) ); + selectionDialog.setTreeRenderer(new N5ViewerTreeCellRenderer(false)); selectionDialog.setContainerPathUpdateCallback( x -> { if ( x != null ) @@ -635,8 +625,8 @@ public void buildN5SelectionDialog() // Recorder.record = initialRecorderState; // } ); - selectionDialog.setVirtualOption( true ); - selectionDialog.setCropOption( true ); + selectionDialog.setVirtualOption( false ); + selectionDialog.setCropOption( false ); // transform @@ -748,7 +738,6 @@ protected void updateImagePlusDropdown() final ArrayList titleList = new ArrayList<>(); if( datasetService != null ) { - final int i = 0; for( final Dataset d : datasetService.getDatasets() ) titleList.add(d.getSource()); } @@ -1007,7 +996,7 @@ public static void runMacro( final String args ) return; } // TODO fix transforms - runBigWarp( null, images, moving, null ); + runBigWarp( null, images, moving, transforms ); } // System.out.println( "BigWarpInitDialog runMacro"); diff --git a/src/main/java/bdv/ij/BigWarpCommand.java b/src/main/java/bdv/ij/BigWarpCommand.java index 6dab575c..6fe1a074 100644 --- a/src/main/java/bdv/ij/BigWarpCommand.java +++ b/src/main/java/bdv/ij/BigWarpCommand.java @@ -10,7 +10,9 @@ import ij.Macro; import ij.plugin.PlugIn; import ij.plugin.frame.Recorder; +import net.imagej.Dataset; import net.imagej.DatasetService; +import net.imagej.ImageJ; @Plugin(type = Command.class, menuPath = "Plugins>BigDataViewer>Big Warp Command" ) public class BigWarpCommand implements Command, PlugIn @@ -40,6 +42,13 @@ public void run( String args ) BigWarpInitDialog.runMacro( macroOptions ); else { +// if( datasetService != null ) +// { +// System.out.println( "dset service exists"); +// for( final Dataset d : datasetService.getDatasets() ) +// System.out.println( d.getName()); +// } + final BigWarpInitDialog dialog = BigWarpInitDialog.createAndShow( datasetService ); // dialog sets recorder to its initial state on cancel or execution dialog.setInitialRecorderState( initialRecorderState ); @@ -64,19 +73,23 @@ public static void main( String[] a ) throws IOException // System.out.println( moving ); // System.out.println( transforms ); -// ImageJ ij2 = new ImageJ(); -// ij2.ui().showUI(); -// -//// Object im1 = ij2.io().open( "/home/john/tmp/mri-stack.tif" ); -//// Object im2 = ij2.io().open( "/home/john/tmp/t1-head.tif" ); -// -// Object im1 = ij2.io().open( "/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif" ); -// Object im2 = ij2.io().open( "/groups/saalfeld/home/bogovicj/tmp/t1-head.tif" ); -// + final ImageJ ij2 = new ImageJ(); + ij2.ui().showUI(); + +// final Object im1 = ij2.io().open( "/home/john/tmp/mri-stack.tif" ); +// final Object im2 = ij2.io().open( "/home/john/tmp/t1-head.tif" ); +//// +//// Object im1 = ij2.io().open( "/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif" ); +//// Object im2 = ij2.io().open( "/groups/saalfeld/home/bogovicj/tmp/t1-head.tif" ); +//// // ij2.ui().show( im1 ); // ij2.ui().show( im2 ); + final Object im1 = ij2.io().open( "/home/john/tmp/boats.tif" ); + ij2.ui().show( im1 ); + + // String args = "images=[a, b, c], isMoving=[true, true, false], transforms=[,,]"; // // String imagesList = null; diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index f6ef72cf..a1db7bdf 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -930,9 +930,6 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source final int[] movingSourceIndices = ImagePlusLoader.range( 0, numMovingSources ); final int[] targetSourceIndices = ImagePlusLoader.range( numMovingSources, numTargetSources ); -// List movingSourceIndices = IntStream.range( 0, numMovingSources ).collect( Collectors.toList()); -// List targetSourceIndices = IntStream.range( numMovingSources, numTargetSources + numMovingSources ) -// .collect( Collectors.toList()); /* Load the second source */ BigWarpInit.initSetups( spimDataQ, converterSetups, sources ); @@ -1082,8 +1079,6 @@ public static < T > BigWarpData< T > createBigWarpDataFromXML( final String xmlF */ public static < T > BigWarpData< T > createBigWarpDataFromImages( final ImagePlus impP, final ImagePlus impQ ) { -// return createBigWarpData( new ImagePlusLoader( impP ), new ImagePlusLoader( impQ ), null ); - int id = 0; final BigWarpData< T > bwdata = BigWarpInit.initData(); final LinkedHashMap< Source< T >, SourceInfo > mvgSrcs = BigWarpInit.createSources( bwdata, impP, id, 0, true ); diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index 0b6f2244..77aad0c6 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -6,7 +6,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; @@ -30,6 +29,7 @@ import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.DisplacementFieldCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.IdentityCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.InvertibleCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.ReferencedCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.ScaleCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.SequenceCoordinateTransform; import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.TranslationCoordinateTransform; @@ -40,11 +40,9 @@ import net.imglib2.RandomAccessibleInterval; import net.imglib2.realtransform.AffineGet; -import net.imglib2.realtransform.AffineTransform; import net.imglib2.realtransform.InvertibleRealTransform; import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.ScaleGet; -import net.imglib2.realtransform.Translation2D; import net.imglib2.realtransform.TranslationGet; import net.imglib2.type.NativeType; import net.imglib2.type.numeric.RealType; @@ -55,231 +53,6 @@ public class NgffTransformations { - public static void main( final String[] args ) throws Exception - { - -// final String p2pUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[1]"; -// final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( p2pUri ); -// final CoordinateTransform ct = pair.getA(); -// System.out.println( ct ); -// System.out.println( ct.getType() ); -// -// final N5Reader n5 = pair.getB(); -//// final RealTransform tform = ct.getTransform(n5); -//// System.out.println( tform ); -// -// -// final SequenceCoordinateTransform sct = (SequenceCoordinateTransform)ct; -// final AffineGet affine = sct.asAffine(3); -// System.out.println( affine.getRowPackedCopy()); - - - - final String dfUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[0]"; - final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( dfUri ); - final CoordinateTransform ct = pair.getA(); - System.out.println( ct ); - - final N5Reader n5 = pair.getB(); - final RealTransform tform = ct.getTransform(n5); - System.out.println( tform ); - - - - - -// final AffineTransform affine = new AffineTransform( 2 ); -// final Translation2D t = new Translation2D( new double[] { 5, 6 } ); -// System.out.println( Arrays.toString(affine.getRowPackedCopy() )); -// affine.preConcatenate(t); -// System.out.println( Arrays.toString(affine.getRowPackedCopy() )); - - - -// // detect transformations -// final String loc = "/home/john/Desktop/tforms.n5"; -// final N5URI uri = new N5URI(loc); - -// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( loc ); -//// final RealTransform tform = findFieldTransformFirst( n5, "/dfield2d" ); -// final RealTransform tform = findFieldTransformStrict( n5, "/dfield2d", "boats.tif_dfield" ); - - -// // detect transformations -// final String loc = "/home/john/Desktop/tforms.n5"; -// final N5URI uri = new N5URI(loc); -// -// // dfield 2d path -// final String dfUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[0]"; -//// final String dfUri = "/home/john/Desktop/tforms.n5?/#coordinateTransformations[2]"; -//// final String dfPartUri = "/home/john/Desktop/tforms.n5"; -// -//// final RealTransform tform = open(dfUri); -//// System.out.println(tform); -// -// final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( dfUri ); -// final CoordinateTransform ct = pair.getA(); -// System.out.println( ct ); -// -// final RealTransform tform = ct.getTransform( pair.getB()); -// System.out.println( tform ); - - -// final String s = detectTransforms(dfUri); -// System.out.println( "full uri: " + s ); -// System.out.println("inferred full uri: " + detectTransforms(dfPartUri)); - - -// final CoordinateTransform[] cts = detectTransforms(loc); -// System.out.println(Arrays.toString(cts)); - -// System.out.println(detectTransforms(loc)); - -// System.out.println( uri ); -// System.out.println( uri.getURI() ); -// -// final String grp = ( uri.getGroupPath() != null ) ? uri.getGroupPath() : ""; -// System.out.println( grp ); -// -// final String attr = ( uri.getAttributePath() != null ) ? uri.getAttributePath() : ""; -// System.out.println( attr ); - -// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( uri.getContainerPath() ); -// final JsonObject json = n5.getAttribute(grp, attr, JsonObject.class); -// final String ver = n5.getAttribute(grp, "n5", String.class); -// final JsonElement jcts = n5.getAttribute(grp, "coordinateTransformations", JsonElement.class); -// final JsonElement jct = n5.getAttribute(grp, "coordinateTransformations[0]", JsonElement.class); -// final CoordinateTransform ct = n5.getAttribute(grp, "coordinateTransformations[0]", CoordinateTransform.class); -// final CoordinateTransform[] cts = n5.getAttribute(grp, "coordinateTransformations", CoordinateTransform[].class); - -// System.out.println(""); -// System.out.println(json); -// System.out.println(""); -// System.out.println(ver); -// System.out.println(""); -// System.out.println(jcts); -// System.out.println(""); -// System.out.println(jct); -// System.out.println(""); -// System.out.println(ct); -// System.out.println(ct.getType()); -// System.out.println(""); -// System.out.println(Arrays.toString(cts)); - - -// openTransformN5( url ); - - - // full -// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5?/#/coordinateTransformations[0]"; - - // no dataset -// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5#/coordinateTransformations[0]"; - - // no dataset no attribute -// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; -// -// final N5URI url = new N5URI( bijPath ); -// System.out.println( url.getGroupPath()); -// System.out.println( url.getAttributePath()); -// -// final Pair< NgffCoordinateTransformation< ? >, N5Reader > bijN5 = openTransformN5( bijPath ); -// System.out.println( bijN5.getA() ); -// final InvertibleRealTransform bij = openInvertible( bijPath ); -// System.out.println( bij ); - - -// final String path = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; -// final N5URL url = new N5URL( path ); -// System.out.println( url.getAttribute() ); -// System.out.println( url.getDataset()); - - -// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5?/#/coordinateTransformations[0]"; -// final N5URL url = new N5URL( bijPath ); -// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( url.getLocation() ); -// final CoordinateTransformation ct = n5.getAttribute( url.getDataset(), url.getAttribute(), CoordinateTransformation.class ); -// System.out.println( ct ); -// -// final NgffCoordinateTransformation< ? > nct = NgffCoordinateTransformation.create( ct ); -// RealTransform tform = nct.getTransform( n5 ); -// System.out.println( tform ); - - - - -// final String basePath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; -// final String csPath = "?dfield#coordinateSystems/[0]"; -// final String namePath = "?dfield#coordinateSystems/[0]/name"; -// final String dimPath = "?dfield#/dimensions"; -// -// final N5URL baseUrl = new N5URL( basePath ); -// final N5URL nameUrl = baseUrl.getRelative( namePath ); -// final N5URL csUrl = baseUrl.getRelative( csPath ); -// final N5URL dimUrl = baseUrl.getRelative( dimPath ); -// -// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( baseUrl.getLocation() ); -// final String name = n5.getAttribute( nameUrl.getDataset(), nameUrl.getAttribute(), String.class ); -// final CoordinateSystem cs = n5.getAttribute( csUrl.getDataset(), csUrl.getAttribute(), CoordinateSystem.class ); -// final long[] dims = n5.getAttribute( dimUrl.getDataset(), dimUrl.getAttribute(), long[].class ); -// -// System.out.println( name ); -// System.out.println( cs ); -// System.out.println( cs.getAxes()[0].getName() ); -// System.out.println( Arrays.toString( dims ) ); - - - - -//// final String path = "/home/john/projects/ngff/dfieldTest/dfield.n5"; -// final String path = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; -// -// final String dataset = "/"; -//// final String dataset = "coordinateTransformations"; -//// final String dataset = "/dfield"; -// -// final N5FSReader n5 = new N5FSReader( path, gsonBuilder() ); -// -//// RealTransform dfieldTform = open( n5, dataset ); -//// System.out.println( dfieldTform ); -// -//// RealTransform dfieldTform = open( n5, dataset ); -//// System.out.println( dfieldTform ); -// -// TransformGraph g = openGraph( n5, dataset ); -// g.printSummary(); -// RealTransform fwdXfm = g.path( "jrc18F", "fcwb" ).get().totalTransform( n5, g ); -// RealTransform invXfm = g.path( "fcwb", "jrc18F" ).get().totalTransform( n5, g ); -// System.out.println( fwdXfm ); -// System.out.println( invXfm ); - - -// ArrayImg< IntType, IntArray > img = ArrayImgs.ints( 2, 3, 4, 5 ); -// -// int[] p = vectorAxisLastNgff( n5, dataset ); -// System.out.println( Arrays.toString( p )); -// System.out.println( "" ); -// -// IntervalView< IntType > imgP = N5DisplacementField.permute( img, p ); -// System.out.println( Intervals.toString( imgP )); - - -// try -// { -//// AffineGet p2p = N5DisplacementField.openPixelToPhysicalNgff( n5, "transform", true ); -//// System.out.println( p2p ); -// -//// int[] indexes = new int[] {1, 2, 3 }; -//// AffineGet sp2p = TransformUtils.subAffine( p2p, indexes ); -//// System.out.println( sp2p ); -// } -// catch ( Exception e ) -// { -// e.printStackTrace(); -// } - - } - @SuppressWarnings("unchecked") public static < T extends RealTransform> T open( final N5Reader n5, final String dataset, final String input, final String output ) { @@ -426,18 +199,33 @@ public static Pair,N5Reader> openTransformN5( final Strin final String attribute = n5url.getAttributePath(); // final String attribute = n5url.getAttributePath() != null ? n5url.getAttributePath() : "coordinateTransformations[0]"; - final CoordinateTransform ct = n5.getAttribute(dataset, attribute, CoordinateTransform.class); - return new ValuePair<>( ct, n5 ); + try { + final CoordinateTransform ct = n5.getAttribute(dataset, attribute, CoordinateTransform.class); + return new ValuePair<>( ct, n5 ); + } catch( N5Exception | ClassCastException e ) {} + + try { + return openReference( url, n5, dataset, attribute ); // try to open a reference + } catch( N5Exception | ClassCastException e ) {} // final CoordinateTransform nct = CoordinateTransform.create(ct); // return new ValuePair<>( nct, n5 ); } } - catch ( URISyntaxException | N5Exception | ClassCastException e ) - { -// e.printStackTrace(); + catch ( final URISyntaxException e ) { } + + return null; + } + + public static Pair,N5Reader> openReference( final String url, final N5Reader n5, final String dataset, final String attribute) { + + final ReferencedCoordinateTransform ref = n5.getAttribute(dataset, attribute, ReferencedCoordinateTransform.class); + if( ref == null ) return null; - } + else if( url != null && url.equals( ref.getUrl() )) + return null; // avoid self-reference + else + return openTransformN5( ref.getUrl()); } public static CoordinateTransform openJson( final String url ) @@ -458,12 +246,19 @@ public static CoordinateTransform openJson( final String url ) // final CoordinateTransformation ct = gson.fromJson( elem.getAsJsonArray().get( 0 ), CoordinateTransformation.class ); final CoordinateTransform ct = gson.fromJson( elem, CoordinateTransform.class ); - - final CoordinateTransform< ? > nct = CoordinateTransform.create( ct ); - return nct; -// final RealTransform tform = nct.getTransform( null ); -// -// return tform; + if( ct != null ) + { + final CoordinateTransform< ? > nct = CoordinateTransform.create( ct ); + return nct; + } else if( elem.isJsonObject()) { + // TODO figure out what should be returned here + final String refUrl = elem.getAsJsonObject().get("url").getAsString(); + if( url.equals( refUrl )) + return null; //avoid self-reference + else + return openTransformN5( refUrl ).getA(); + } + return null; } public static void save( final String jsonFile, final CoordinateTransform transform ) diff --git a/src/test/java/bigwarp/NgffTransformTests.java b/src/test/java/bigwarp/NgffTransformTests.java new file mode 100644 index 00000000..b4e94e51 --- /dev/null +++ b/src/test/java/bigwarp/NgffTransformTests.java @@ -0,0 +1,345 @@ +package bigwarp; + +import java.util.Arrays; + +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.Common; + +import net.imglib2.realtransform.RealTransform; + +public class NgffTransformTests { + + public static void main( final String[] args ) throws Exception + { +// final String url = "/home/john/projects/bigwarp/projects/jrc18-rot.zarr?/#coordinateTransformations[1]"; +// final Pair, N5Reader> ctN5 = Common.openTransformN5(url); +// System.out.println( ctN5.getA() ); +// +// final RealTransform tf = ctN5.getA().getTransform(ctN5.getB()); +// System.out.println( tf ); + +// final String dfUrl = "/home/john/projects/bigwarp/projects/jrc18-rot.zarr?/#coordinateTransformations[0]"; +// final Pair, N5Reader> ctN5 = Common.openTransformN5(dfUrl); +// System.out.println( ctN5.getA() ); +// +// final RealTransform df1 = ctN5.getA().getTransform(ctN5.getB()); +// System.out.println( df1 ); + + final String tuneUrl = "/home/john/projects/bigwarp/projects/jrc18-rot.zarr?/#coordinateTransformations[2]"; + final RealTransform tune = Common.open(tuneUrl); + + final double[] p = new double[] { 308, 122, 91 }; +// final double[] p = new double[] { 292, 116, 92 }; + final double[] q1 = new double[] { 0, 0, 0}; + final double[] q2 = new double[] { 0, 0, 0}; + + +// df1.apply(p, q1); +// System.out.println( Arrays.toString(p) ); +// System.out.println( Arrays.toString(q1) ); +// + tune.apply(p, q2); + System.out.println( " " ); + System.out.println( Arrays.toString(p) ); + System.out.println( Arrays.toString(q2) ); + + +// final String loc = "/home/john/projects/bigwarp/projects/jrc18-rot.zarr"; +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( loc ); +// final String dataset = ""; +// final String attribute = "coordinateTransformations[1]"; +// +// final CoordinateTransform ct = n5.getAttribute(dataset, attribute, CoordinateTransform.class); +// System.out.println( ct ); + + + +// final String urlRef = "/home/john/projects/bigwarp/projects/jrc18.zarr?/#coordinateTransformations[5]"; +// final RealTransform tform = open( urlRef ); +// System.out.println( tform ); + + +// final String lmPath = "/home/john/Desktop/bw-rot-landmarks.csv"; +// final LandmarkTableModel ltm = new LandmarkTableModel(3); +// ltm.load(new File( lmPath )); +// +// final BigWarpTransform bwTform = new BigWarpTransform(ltm); +// +// final InvertibleRealTransform tform = bwTform.getTransformation(); +// +// // tform is deformation then affine +// +// final InvertibleRealTransform tf = BigWarpToDeformationFieldPlugIn.getTransformation(null, bwTform, false, true); +// System.out.println( tf ); +// +// final AffineGet affineTps = bwTform.affinePartOfTps(); +// System.out.println( affineTps ); +// +// +// final double[] p = new double[] { 150, 200, 75 }; +// final double[] q1 = new double[] { 0, 0, 0}; +// final double[] q2 = new double[] { 0, 0, 0}; + + + // this part behaves as expected +// tform.apply(p, q1); +// System.out.println( " " ); +// System.out.println( "true: " + Arrays.toString(q1)); +// +// +// final RealTransformSequence seq = new RealTransformSequence(); +// seq.add( tf ); +// seq.add( affineTps ); +// seq.apply(p, q2); +// +// System.out.println( " " ); +// System.out.println( "othr: " + Arrays.toString(q2)); + + +// final Pair, N5Reader> ctN5 = NgffTransformations.openTransformN5("/home/john/projects/bigwarp/projects/jrc18-rot.zarr?/#coordinateTransformations[4]"); +// final RealTransform df = ctN5.getA().getTransform(ctN5.getB()); +// +// +// System.out.println( " " ); +// System.out.println( " " ); +// System.out.println( ctN5.getA().getName() ); +// +// tf.apply(p, q1); +// System.out.println( " " ); +// System.out.println( "true: " + Arrays.toString(q1)); +// +// df.apply(p, q2); +// System.out.println( " " ); +// System.out.println( "df : " + Arrays.toString(q2)); + + +//// final String jrc18DfTgt = "/home/john/projects/bigwarp/projects/bw_jrc18Down_tforms.n5?#coordinateTransformations[6]"; +// final String jrc18DfTgt = "/home/john/projects/bigwarp/projects/bw_jrc18Down_tforms.n5?#coordinateTransformations[0]"; +//// final RealTransform tform = open(jrc18DfTgt); +// +// final Pair, N5Reader> ctN5 = openTransformN5(jrc18DfTgt); +// final CoordinateTransform ct = ctN5.getA(); +// final N5Reader n5 = ctN5.getB(); +// +// System.out.println("ct: " + ct + " " + ct.getType()); +// +// final RealTransform tform = ct.getTransform( n5 ); + + +// final String p2pUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[1]"; +// final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( p2pUri ); +// final CoordinateTransform ct = pair.getA(); +// System.out.println( ct ); +// System.out.println( ct.getType() ); +// +// final N5Reader n5 = pair.getB(); +//// final RealTransform tform = ct.getTransform(n5); +//// System.out.println( tform ); +// +// +// final SequenceCoordinateTransform sct = (SequenceCoordinateTransform)ct; +// final AffineGet affine = sct.asAffine(3); +// System.out.println( affine.getRowPackedCopy()); + +// final String dfUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[0]"; +// final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( dfUri ); +// final CoordinateTransform ct = pair.getA(); +// System.out.println( ct ); +// +// final N5Reader n5 = pair.getB(); +// final RealTransform tform = ct.getTransform(n5); +// System.out.println( tform ); + + +// final AffineTransform affine = new AffineTransform( 2 ); +// final Translation2D t = new Translation2D( new double[] { 5, 6 } ); +// System.out.println( Arrays.toString(affine.getRowPackedCopy() )); +// affine.preConcatenate(t); +// System.out.println( Arrays.toString(affine.getRowPackedCopy() )); + + + +// // detect transformations +// final String loc = "/home/john/Desktop/tforms.n5"; +// final N5URI uri = new N5URI(loc); + +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( loc ); +//// final RealTransform tform = findFieldTransformFirst( n5, "/dfield2d" ); +// final RealTransform tform = findFieldTransformStrict( n5, "/dfield2d", "boats.tif_dfield" ); + + +// // detect transformations +// final String loc = "/home/john/Desktop/tforms.n5"; +// final N5URI uri = new N5URI(loc); +// +// // dfield 2d path +// final String dfUri = "/home/john/Desktop/tforms.n5?/dfield2d#coordinateTransformations[0]"; +//// final String dfUri = "/home/john/Desktop/tforms.n5?/#coordinateTransformations[2]"; +//// final String dfPartUri = "/home/john/Desktop/tforms.n5"; +// +//// final RealTransform tform = open(dfUri); +//// System.out.println(tform); +// +// final Pair< CoordinateTransform< ? >, N5Reader > pair = openTransformN5( dfUri ); +// final CoordinateTransform ct = pair.getA(); +// System.out.println( ct ); +// +// final RealTransform tform = ct.getTransform( pair.getB()); +// System.out.println( tform ); + + +// final String s = detectTransforms(dfUri); +// System.out.println( "full uri: " + s ); +// System.out.println("inferred full uri: " + detectTransforms(dfPartUri)); + + +// final CoordinateTransform[] cts = detectTransforms(loc); +// System.out.println(Arrays.toString(cts)); + +// System.out.println(detectTransforms(loc)); + +// System.out.println( uri ); +// System.out.println( uri.getURI() ); +// +// final String grp = ( uri.getGroupPath() != null ) ? uri.getGroupPath() : ""; +// System.out.println( grp ); +// +// final String attr = ( uri.getAttributePath() != null ) ? uri.getAttributePath() : ""; +// System.out.println( attr ); + +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( uri.getContainerPath() ); +// final JsonObject json = n5.getAttribute(grp, attr, JsonObject.class); +// final String ver = n5.getAttribute(grp, "n5", String.class); +// final JsonElement jcts = n5.getAttribute(grp, "coordinateTransformations", JsonElement.class); +// final JsonElement jct = n5.getAttribute(grp, "coordinateTransformations[0]", JsonElement.class); +// final CoordinateTransform ct = n5.getAttribute(grp, "coordinateTransformations[0]", CoordinateTransform.class); +// final CoordinateTransform[] cts = n5.getAttribute(grp, "coordinateTransformations", CoordinateTransform[].class); + +// System.out.println(""); +// System.out.println(json); +// System.out.println(""); +// System.out.println(ver); +// System.out.println(""); +// System.out.println(jcts); +// System.out.println(""); +// System.out.println(jct); +// System.out.println(""); +// System.out.println(ct); +// System.out.println(ct.getType()); +// System.out.println(""); +// System.out.println(Arrays.toString(cts)); + + +// openTransformN5( url ); + + + // full +// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5?/#/coordinateTransformations[0]"; + + // no dataset +// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5#/coordinateTransformations[0]"; + + // no dataset no attribute +// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; +// +// final N5URI url = new N5URI( bijPath ); +// System.out.println( url.getGroupPath()); +// System.out.println( url.getAttributePath()); +// +// final Pair< NgffCoordinateTransformation< ? >, N5Reader > bijN5 = openTransformN5( bijPath ); +// System.out.println( bijN5.getA() ); +// final InvertibleRealTransform bij = openInvertible( bijPath ); +// System.out.println( bij ); + + +// final String path = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; +// final N5URL url = new N5URL( path ); +// System.out.println( url.getAttribute() ); +// System.out.println( url.getDataset()); + + +// final String bijPath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5?/#/coordinateTransformations[0]"; +// final N5URL url = new N5URL( bijPath ); +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( url.getLocation() ); +// final CoordinateTransformation ct = n5.getAttribute( url.getDataset(), url.getAttribute(), CoordinateTransformation.class ); +// System.out.println( ct ); +// +// final NgffCoordinateTransformation< ? > nct = NgffCoordinateTransformation.create( ct ); +// RealTransform tform = nct.getTransform( n5 ); +// System.out.println( tform ); + + + + +// final String basePath = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; +// final String csPath = "?dfield#coordinateSystems/[0]"; +// final String namePath = "?dfield#coordinateSystems/[0]/name"; +// final String dimPath = "?dfield#/dimensions"; +// +// final N5URL baseUrl = new N5URL( basePath ); +// final N5URL nameUrl = baseUrl.getRelative( namePath ); +// final N5URL csUrl = baseUrl.getRelative( csPath ); +// final N5URL dimUrl = baseUrl.getRelative( dimPath ); +// +// final N5Reader n5 = new N5Factory().gsonBuilder( gsonBuilder() ).openReader( baseUrl.getLocation() ); +// final String name = n5.getAttribute( nameUrl.getDataset(), nameUrl.getAttribute(), String.class ); +// final CoordinateSystem cs = n5.getAttribute( csUrl.getDataset(), csUrl.getAttribute(), CoordinateSystem.class ); +// final long[] dims = n5.getAttribute( dimUrl.getDataset(), dimUrl.getAttribute(), long[].class ); +// +// System.out.println( name ); +// System.out.println( cs ); +// System.out.println( cs.getAxes()[0].getName() ); +// System.out.println( Arrays.toString( dims ) ); + + + + +//// final String path = "/home/john/projects/ngff/dfieldTest/dfield.n5"; +// final String path = "/home/john/projects/ngff/dfieldTest/jrc18_example.n5"; +// +// final String dataset = "/"; +//// final String dataset = "coordinateTransformations"; +//// final String dataset = "/dfield"; +// +// final N5FSReader n5 = new N5FSReader( path, gsonBuilder() ); +// +//// RealTransform dfieldTform = open( n5, dataset ); +//// System.out.println( dfieldTform ); +// +//// RealTransform dfieldTform = open( n5, dataset ); +//// System.out.println( dfieldTform ); +// +// TransformGraph g = openGraph( n5, dataset ); +// g.printSummary(); +// RealTransform fwdXfm = g.path( "jrc18F", "fcwb" ).get().totalTransform( n5, g ); +// RealTransform invXfm = g.path( "fcwb", "jrc18F" ).get().totalTransform( n5, g ); +// System.out.println( fwdXfm ); +// System.out.println( invXfm ); + + +// ArrayImg< IntType, IntArray > img = ArrayImgs.ints( 2, 3, 4, 5 ); +// +// int[] p = vectorAxisLastNgff( n5, dataset ); +// System.out.println( Arrays.toString( p )); +// System.out.println( "" ); +// +// IntervalView< IntType > imgP = N5DisplacementField.permute( img, p ); +// System.out.println( Intervals.toString( imgP )); + + +// try +// { +//// AffineGet p2p = N5DisplacementField.openPixelToPhysicalNgff( n5, "transform", true ); +//// System.out.println( p2p ); +// +//// int[] indexes = new int[] {1, 2, 3 }; +//// AffineGet sp2p = TransformUtils.subAffine( p2p, indexes ); +//// System.out.println( sp2p ); +// } +// catch ( Exception e ) +// { +// e.printStackTrace(); +// } + + } + +} diff --git a/src/test/java/bigwarp/StartupTests.java b/src/test/java/bigwarp/StartupTests.java new file mode 100644 index 00000000..f7ff5ce3 --- /dev/null +++ b/src/test/java/bigwarp/StartupTests.java @@ -0,0 +1,121 @@ +package bigwarp; + +import java.io.IOException; + +import bdv.gui.BigWarpInitDialog; +import ij.ImageJ; + +public class StartupTests { + + public static void main( final String[] args ) throws IOException + { +// ImageJ ij2 = new ImageJ(); +// ij2.ui().showUI(); + + final ImageJ ij = new ImageJ(); +// +// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boatsBlur.tif" ).show(); +// IJ.openImage( "/groups/saalfeld/home/bogovicj/tmp/boats.tif" ).show(); +// +// IJ.openImage( "/home/john/tmp/boats.tif" ).show(); +// IJ.openImage( "/home/john/tmp/boatsBlur.tif" ).show(); + +// IJ.createImage("", ImageJPrefix, DEFAULT_OUTER_PAD, DEFAULT_MID_PAD, DEFAULT_BUTTON_PAD) +// IJ.createImage("a", 32, 32, 8, 8).show(); + +// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); +// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); + +// new ImageJ(); +// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); +// String macroOptions = "images=imagej://mri-stack.tif,imagej://mri-stack.tif moving=true,false transforms=,"; +// runMacro( macroOptions ); + +// IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); +// IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); + +// final String proj = "/home/john/Desktop/bw-boats.json"; + final String proj = "/home/john/Desktop/bw-boats-affine2d.json"; +// final String proj = "/home/john/Desktop/bw-boats-tlation.json"; +// final String proj = "/home/john/Desktop/bw-boats-tlationImported-fineTune.json"; + +// final String proj = "/home/john/Desktop/bw-boats-affine2d-imported.json"; +// final String proj = "/home/john/Desktop/bigwarp-nomask-project.json"; +// final String proj = "/home/john/Desktop/bigwarp-affine2d.json"; +// final String proj = "/home/john/Desktop/bigwarp-vmask-project.json"; +// final String proj = "/home/john/Desktop/bigwarp-mask-project.json"; +// final String proj = "/home/john/Desktop/bigwarp-mask51k-project.json"; +// final String proj = "/home/john/Desktop/bigwarp-maskn5a-project.json"; +// final String proj = "/home/john/Desktop/bigwarp-project.json"; +// final String proj = "/home/john/Desktop/t1-bigwarp-project.json"; +// final String proj = "/home/john/Desktop/inf-bw.json"; + +// final String proj = "/home/john/projects/bigwarp/projects/bw_jrc18Down.json"; +// final String proj = "/home/john/projects/bigwarp/projects/bw_jrc18Down-vmask.json"; +// final String proj = "/home/john/Desktop/bw-jrc18-rot.json"; +// final String proj = "/home/john/Desktop/bw-jrc18-rot-maskTune.json"; + + final String boats = "/home/john/tmp/boats.tif"; + final String jrc18 = "/home/john/Documents/teaching/emboBioImage2023_registration/sampleImages/jrc18_down.nrrd"; +// final String jrc18Df2 = "/home/john/projects/bigwarp/projects/bw_jrc18Down_tforms.n5?#coordinateTransformations[3]"; +// final String jrc18Df5 = "/home/john/projects/bigwarp/projects/bw_jrc18Down_tforms.n5?#coordinateTransformations[5]"; +// final String jrc18DfTgt = "/home/john/projects/bigwarp/projects/bw_jrc18Down_tforms.n5?#coordinateTransformations[0]"; + + final String boatsTlationDf = "/home/john/projects/bigwarp/projects/boats-chain.zarr?/#coordinateTransformations[1]"; + final String boatsAffine = "/home/john/projects/bigwarp/projects/boats-chain.zarr?/#coordinateTransformations[2]"; + +// final String jrc18DfMvgWrp = "/home/john/projects/bigwarp/projects/bw_jrc18Down_tforms.n5?#coordinateTransformations[2]"; +// final String jrc18DfTgt = "/home/john/projects/bigwarp/projects/jrc18.zarr?/#coordinateTransformations[0]"; + + final String jrc18RotDfTgt = "/home/john/projects/bigwarp/projects/jrc18-rot.zarr?/#coordinateTransformations[0]"; + final String jrc18RotTotSeq = "/home/john/projects/bigwarp/projects/jrc18-rot.zarr?/#coordinateTransformations[1]"; + final String jrc18RotPartial = "/home/john/projects/bigwarp/projects/jrc18-rot.zarr?/#coordinateTransformations[2]"; + final String jrc18RotTotSeqRev = "/home/john/projects/bigwarp/projects/jrc18-rot.zarr?/#coordinateTransformations[3]"; + +// final String jrc18DfAffine = "/home/john/projects/bigwarp/projects/jrc18.zarr?/#coordinateTransformations[3]"; + +// runBigWarp(null, new String[] {boats, boats}, new String[] {"true", "false" }, new String[]{}); +// runBigWarp(proj, new String[] {boats, boats}, new String[] {"true", "false" }, null); +// runBigWarp(null, new String[] {boats, boats}, new String[] {"true", "false" }, new String[]{"/home/john/Desktop/tforms.n5?aff2d#coordinateTransformations[0]", null}); +// runBigWarp(null, new String[] {boats, boats}, new String[] {"true", "false" }, new String[]{"/home/john/projects/bigwarp/projects/boats-chain.zarr?/#coordinateTransformations[0]", null}); +// runBigWarp(null, new String[] {boats, boats}, new String[] {"true", "false" }, new String[]{boatsAffine, null}); +// runBigWarp(null, new String[] {boats}, new String[] {"true"}, new String[]{boatsAffine}); + +// runBigWarp(null, new String[] {boats, boats}, new String[] {"true", "false" }, new String[]{"/home/john/projects/bigwarp/projects/boats.n5?/#coordinateTransformations[0]", null}); +// runBigWarp(null, new String[] {boats, boats}, new String[] {"true", "false" }, new String[]{"/home/john/projects/bigwarp/projects/boats.zarr?/#coordinateTransformations[0]", null}); +// runBigWarp(null, new String[] {boats, boats}, new String[] {"true", "false" }, new String[]{"/home/john/projects/bigwarp/projects/boats.zarr?/#coordinateTransformations[2]", null}); + +// runBigWarp(null, new String[] {jrc18, jrc18}, new String[] {"true", "false" }, new String[]{ jrc18RotTotSeqRev, null }); + +// runBigWarp(proj, new String[] {}, new String[] {}, null); + + BigWarpInitDialog.createAndShow(); + + + // below this are from BigWarpCommand + +// String images = Macro.getValue(options, "images", ""); +// String moving = Macro.getValue(options, "moving", ""); +// String transforms = Macro.getValue(options, "transforms", ""); +// System.out.println( images ); +// System.out.println( moving ); +// System.out.println( transforms ); + +// final ImageJ ij2 = new ImageJ(); +// ij2.ui().showUI(); + +// final Object im1 = ij2.io().open( "/home/john/tmp/mri-stack.tif" ); +// final Object im2 = ij2.io().open( "/home/john/tmp/t1-head.tif" ); +//// Object im1 = ij2.io().open( "/groups/saalfeld/home/bogovicj/tmp/mri-stack.tif" ); +//// Object im2 = ij2.io().open( "/groups/saalfeld/home/bogovicj/tmp/t1-head.tif" ); +// ij2.ui().show( im1 ); +// ij2.ui().show( im2 ); +// final Object im1 = ij2.io().open( "/home/john/tmp/boats.tif" ); +// ij2.ui().show( im1 ); +// String args = "images=[a, b, c], isMoving=[true, true, false], transforms=[,,]"; +// String imagesList = null; +// String isMovingList = null; +// String transformsList = null; + + } +} From 7fc04c420e7df2222f6d2143567d7e146b61563d Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 09:27:52 -0400 Subject: [PATCH 267/282] fix: n5 selection dialog now works when called repeatedly --- src/main/java/bdv/gui/BigWarpInitDialog.java | 124 +++++++++++-------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index 316a8815..a8fa4222 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -79,6 +79,7 @@ import net.imagej.Dataset; import net.imagej.DatasetService; import net.imglib2.realtransform.RealTransform; +import net.imglib2.type.NativeType; public class BigWarpInitDialog extends JFrame { @@ -129,22 +130,6 @@ public class BigWarpInitDialog extends JFrame private boolean initialRecorderState; - public static final N5MetadataParser[] n5Parsers = new N5MetadataParser[]{ - new N5CosemMetadataParser(), - new N5SingleScaleMetadataParser(), - new CanonicalMetadataParser(), - new ImagePlusLegacyMetadataParser(), - new N5GenericSingleScaleMetadataParser() - }; - - public static final N5MetadataParser[] n5vGroupParsers = new N5MetadataParser[]{ -// new org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.OmeNgffMetadataParser(), -// new org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v03.OmeNgffMetadataParser(), // TODO test later - new N5CosemMultiScaleMetadata.CosemMultiScaleParser(), - new N5ViewerMultiscaleMetadataParser(), - new CanonicalMetadataParser(), - new N5ViewerMultichannelMetadata.N5ViewerMultichannelMetadataParser() - }; public BigWarpInitDialog( final String title ) { @@ -193,7 +178,7 @@ public void setInitialRecorderState( final boolean initialRecorderState ) this.initialRecorderState = initialRecorderState; } - public static BigWarp runBigWarp( final String projectLandmarkPath, final String[] images, final String[] moving, final String[] transforms ) + public static < T extends NativeType > BigWarp runBigWarp( final String projectLandmarkPath, final String[] images, final String[] moving, final String[] transforms ) { final BigWarpData< T > data = BigWarpInit.initData(); final boolean haveProjectLandmarkArg = projectLandmarkPath != null && !projectLandmarkPath.isEmpty(); @@ -281,7 +266,7 @@ else if( haveLandmarks ) return bw; } - public void runBigWarp() + public > void runBigWarp() { if (Recorder.record) { @@ -492,6 +477,29 @@ public JPanel createContent() panel.add( addN5Button, cn5 ); addN5Button.addActionListener( e -> { + + selectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), + lastOpenedContainer, + BigWarpInit.GROUP_PARSERS, + BigWarpInit.PARSERS); + + selectionDialog.setLoaderExecutor( exec ); + selectionDialog.setTreeRenderer(new N5ViewerTreeCellRenderer(false)); + + selectionDialog.setContainerPathUpdateCallback( x -> { + if ( x != null ) + lastOpenedContainer = x; + } ); + + // figure this out +// selectionDialog.setCancelCallback( x -> { +// // set back recorder state if canceled +// Recorder.record = initialRecorderState; +// } ); + + selectionDialog.setVirtualOption( false ); + selectionDialog.setCropOption( false ); + selectionDialog.run( this::n5DialogCallback ); }); @@ -523,6 +531,19 @@ public JPanel createContent() IJ.showMessage("Please highlight the row you would like to transform."); else { + + final N5MetadataParser[] tformParsers = new N5MetadataParser[]{ new N5TransformMetadataParser() }; + + transformSelectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), + lastOpenedContainer, new N5MetadataParser[] {}, tformParsers ); + + transformSelectionDialog.setLoaderExecutor( exec ); + transformSelectionDialog.setTreeRenderer( new N5TransformTreeCellRenderer( true ) ); + transformSelectionDialog.setContainerPathUpdateCallback( x -> { + if ( x != null ) + lastOpenedContainer = x; + } ); + transformSelectionDialog.run(this::n5DialogTransformCallback); // remove any existing selection listeners @@ -606,42 +627,47 @@ public void buildN5SelectionDialog() { exec = Executors.newFixedThreadPool( Prefs.getThreads() ); - selectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), - lastOpenedContainer, - n5vGroupParsers, - n5Parsers); - - selectionDialog.setLoaderExecutor( exec ); - selectionDialog.setTreeRenderer(new N5ViewerTreeCellRenderer(false)); - selectionDialog.setContainerPathUpdateCallback( x -> { - if ( x != null ) - lastOpenedContainer = x; - } ); + /* + * The Dialogs need to be created anew by the action listener + */ - // figure this out -// selectionDialog.setCancelCallback( x -> { -// // set back recorder state if canceled -// Recorder.record = initialRecorderState; +// selectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), +// lastOpenedContainer, +// n5vGroupParsers, +// n5Parsers); +// +// selectionDialog.setLoaderExecutor( exec ); +// selectionDialog.setTreeRenderer(new N5ViewerTreeCellRenderer(false)); +// +// selectionDialog.setContainerPathUpdateCallback( x -> { +// if ( x != null ) +// lastOpenedContainer = x; // } ); +// +// // figure this out +//// selectionDialog.setCancelCallback( x -> { +//// // set back recorder state if canceled +//// Recorder.record = initialRecorderState; +//// } ); +// +// selectionDialog.setVirtualOption( false ); +// selectionDialog.setCropOption( false ); - selectionDialog.setVirtualOption( false ); - selectionDialog.setCropOption( false ); - - - // transform - - final N5MetadataParser[] tformParsers = new N5MetadataParser[]{ new N5TransformMetadataParser() }; - - transformSelectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), - lastOpenedContainer, new N5MetadataParser[] {}, tformParsers ); - transformSelectionDialog.setLoaderExecutor( exec ); - transformSelectionDialog.setTreeRenderer( new N5TransformTreeCellRenderer( true ) ); - transformSelectionDialog.setContainerPathUpdateCallback( x -> { - if ( x != null ) - lastOpenedContainer = x; - } ); +// // transform +// +// final N5MetadataParser[] tformParsers = new N5MetadataParser[]{ new N5TransformMetadataParser() }; +// +// transformSelectionDialog = new DatasetSelectorDialog( new N5ViewerReaderFun(), new N5BasePathFun(), +// lastOpenedContainer, new N5MetadataParser[] {}, tformParsers ); +// +// transformSelectionDialog.setLoaderExecutor( exec ); +// transformSelectionDialog.setTreeRenderer( new N5TransformTreeCellRenderer( true ) ); +// transformSelectionDialog.setContainerPathUpdateCallback( x -> { +// if ( x != null ) +// lastOpenedContainer = x; +// } ); } From 140a4f29fcd0dd1b3566adc9b7553c9c98a581e9 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 09:28:22 -0400 Subject: [PATCH 268/282] fix: warped source back to orig impl * add RealTransformedSource --- .../java/bdv/img/RealTransformedSource.java | 266 ++++++++++++++++++ src/main/java/bdv/img/WarpedSource.java | 13 +- 2 files changed, 273 insertions(+), 6 deletions(-) create mode 100644 src/main/java/bdv/img/RealTransformedSource.java diff --git a/src/main/java/bdv/img/RealTransformedSource.java b/src/main/java/bdv/img/RealTransformedSource.java new file mode 100644 index 00000000..1701f84c --- /dev/null +++ b/src/main/java/bdv/img/RealTransformedSource.java @@ -0,0 +1,266 @@ +/*- + * #%L + * BigWarp plugin for Fiji. + * %% + * Copyright (C) 2015 - 2022 Howard Hughes Medical Institute. + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package bdv.img; + +import java.util.function.Supplier; + +import bdv.viewer.Interpolation; +import bdv.viewer.Source; +import bdv.viewer.SourceAndConverter; +import bdv.viewer.render.DefaultMipmapOrdering; +import bdv.viewer.render.MipmapOrdering; +import mpicbg.spim.data.sequence.VoxelDimensions; +import net.imglib2.Interval; +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.RealRandomAccessible; +import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.realtransform.BoundingBoxEstimation; +import net.imglib2.realtransform.InvertibleRealTransform; +import net.imglib2.realtransform.RealTransform; +import net.imglib2.realtransform.RealTransformRealRandomAccessible; +import net.imglib2.realtransform.RealTransformSequence; +import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; +import net.imglib2.view.Views; + +public class RealTransformedSource < T > implements Source< T >, MipmapOrdering +{ + + public static < T > SourceAndConverter< T > wrap( final SourceAndConverter< T > wrap, final String name, int ndims ) + { + return new SourceAndConverter< T >( + new RealTransformedSource< T >( wrap.getSpimSource(), name ), + wrap.getConverter(), + wrap.asVolatile() == null ? null : wrap( wrap.asVolatile(), name, ndims ) ); + } + + /** + * The wrapped {@link Source}. + */ + private final Source< T > source; + + private final String name; + + /** + * This is either the {@link #source} itself, if it implements + * {@link MipmapOrdering}, or a {@link DefaultMipmapOrdering}. + */ + private final MipmapOrdering sourceMipmapOrdering; + + private InvertibleRealTransform xfm; + + private Interval[] boundingIntervalsPerLevel; + + private boolean isTransformed; + + private final Supplier< Boolean > boundingBoxCullingSupplier; + + private BoundingBoxEstimation bboxEst; + + public RealTransformedSource( final Source< T > source, final String name ) + { + this( source, name, null ); + } + + public RealTransformedSource( final Source< T > source, final String name, + final Supplier< Boolean > doBoundingBoxCulling ) + { + this.source = source; + this.name = name; + this.isTransformed = false; + this.boundingBoxCullingSupplier = doBoundingBoxCulling; + this.xfm = null; + + bboxEst = new BoundingBoxEstimation( BoundingBoxEstimation.Method.FACES, 5 ); + boundingIntervalsPerLevel = new Interval[source.getNumMipmapLevels()]; + + sourceMipmapOrdering = MipmapOrdering.class.isInstance( source ) ? + ( MipmapOrdering ) source : new DefaultMipmapOrdering( source ); + } + + @Override + public boolean isPresent( final int t ) + { + return source.isPresent( t ); + } + + @Override + public boolean doBoundingBoxCulling() + { + if( boundingBoxCullingSupplier != null ) + return boundingBoxCullingSupplier.get(); + else + return ( !isTransformed ) && ( source.doBoundingBoxCulling() ); + } + + public void updateTransform( RealTransform xfm ) + { + if( xfm instanceof InvertibleRealTransform ) + this.xfm = (InvertibleRealTransform)xfm; + else + this.xfm = new WrappedIterativeInvertibleRealTransform<>(xfm); + + updateBoundingIntervals(); + } + + protected void updateBoundingIntervals() + { + for( int i = 0; i < getNumMipmapLevels(); i++ ) + { + boundingIntervalsPerLevel[i] = estimateBoundingInterval(0, i); + } + } + + public void setIsTransformed( boolean isTransformed ) + { + this.isTransformed = isTransformed; + } + + public void setBoundingBoxEstimator( final BoundingBoxEstimation bboxEst ) + { + this.bboxEst = bboxEst; + } + + public boolean isTransformed( ) + { + return isTransformed; + } + + public Source< T > getWrappedSource() + { + return source; + } + + @Override + public RandomAccessibleInterval< T > getSource( final int t, final int level ) + { +// if( isTransformed ) +// { +// return Views.interval( +// Views.raster( getInterpolatedSource( t, level, Interpolation.NEARESTNEIGHBOR ) ), +// boundingIntervalsPerLevel[level] ); +// } +// return source.getSource( t, level ); + + if( isTransformed ) + { + final RealTransformRealRandomAccessible interpSrc = (RealTransformRealRandomAccessible)getInterpolatedSource( t, level, Interpolation.NEARESTNEIGHBOR ); + + final AffineTransform3D transform = new AffineTransform3D(); + source.getSourceTransform( t, level, transform ); + final RealTransformSequence totalInverseTransform = new RealTransformSequence(); + totalInverseTransform.add( transform.inverse() ); + totalInverseTransform.add( transform.inverse() ); + totalInverseTransform.add( transform ); + + return Views.interval( Views.raster(interpSrc), boundingIntervalsPerLevel[level] ); + } + else + return source.getSource( t, level ); + } + + private Interval estimateBoundingInterval( final int t, final int level ) + { + if( xfm == null ) + { + return source.getSource( t, level ); + } + else + { + // getSource can be called by multiple threads, so need ensure application of + // the transform is thread safe here by copying + return bboxEst.estimatePixelInterval( xfm.copy().inverse(), source.getSource( t, level ) ); + } + } + + @Override + public RealRandomAccessible< T > getInterpolatedSource( final int t, final int level, final Interpolation method ) + { + + final RealRandomAccessible realSrc = source.getInterpolatedSource( t, level, method ); + if( isTransformed && xfm != null ) + { + final AffineTransform3D transform = new AffineTransform3D(); + source.getSourceTransform( t, level, transform ); + + final RealTransformSequence totalTransform = new RealTransformSequence(); + totalTransform.add( transform.inverse() ); + totalTransform.add( xfm ); + totalTransform.add( transform ); + + return new RealTransformRealRandomAccessible< T, RealTransform >( realSrc, xfm ); + } + else + { + return realSrc; + } + } + + @Override + public synchronized void getSourceTransform( final int t, final int level, final AffineTransform3D transform ) + { + if( isTransformed ) + transform.identity(); + else + source.getSourceTransform( t, level, transform ); + } + + public RealTransform getTransform() + { + return xfm; + } + + @Override + public T getType() + { + return source.getType(); + } + + @Override + public String getName() + { + return source.getName() + "_" + name; + } + + public String getOriginalName() + { + return getWrappedSource().getName(); + } + + @Override + public VoxelDimensions getVoxelDimensions() + { + return source.getVoxelDimensions(); + } + + @Override + public int getNumMipmapLevels() + { + return source.getNumMipmapLevels(); + } + + @Override + public synchronized MipmapHints getMipmapHints( final AffineTransform3D screenTransform, final int timepoint, final int previousTimepoint ) + { + return sourceMipmapOrdering.getMipmapHints( screenTransform, timepoint, previousTimepoint ); + } + +} diff --git a/src/main/java/bdv/img/WarpedSource.java b/src/main/java/bdv/img/WarpedSource.java index 972eddb1..296d804d 100644 --- a/src/main/java/bdv/img/WarpedSource.java +++ b/src/main/java/bdv/img/WarpedSource.java @@ -38,6 +38,7 @@ import net.imglib2.realtransform.RealTransform; import net.imglib2.realtransform.RealTransformRealRandomAccessible; import net.imglib2.realtransform.RealTransformSequence; +import net.imglib2.realtransform.RealViews; import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform; import net.imglib2.view.Views; @@ -157,6 +158,7 @@ public RandomAccessibleInterval< T > getSource( final int t, final int level ) return Views.interval( Views.raster( getInterpolatedSource( t, level, Interpolation.NEARESTNEIGHBOR ) ), boundingIntervalsPerLevel[level] ); + } return source.getSource( t, level ); } @@ -184,13 +186,12 @@ public RealRandomAccessible< T > getInterpolatedSource( final int t, final int l { final AffineTransform3D transform = new AffineTransform3D(); source.getSourceTransform( t, level, transform ); + final RealRandomAccessible< T > srcRaTransformed = RealViews.affineReal( source.getInterpolatedSource( t, level, method ), transform ); - final RealTransformSequence totalTransform = new RealTransformSequence(); - totalTransform.add( transform.inverse() ); - totalTransform.add( xfm ); - totalTransform.add( transform ); - - return new RealTransformRealRandomAccessible< T, RealTransform >( realSrc, xfm ); + if( xfm == null ) + return srcRaTransformed; + else + return new RealTransformRealRandomAccessible< T, RealTransform >( srcRaTransformed, xfm); } else { From 9010c47e15f9ae18e833ed12d846ffbb3176cb40 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 09:29:51 -0400 Subject: [PATCH 269/282] fix: open n5 sources as volatile --- src/main/java/bigwarp/BigWarp.java | 2 +- src/main/java/bigwarp/BigWarpInit.java | 74 ++++++++++++++------ src/main/java/bigwarp/BigwarpSettings.java | 5 +- src/test/java/bigwarp/BigWarpTestUtils.java | 29 ++++---- src/test/java/bigwarp/SerializationTest.java | 28 ++++---- src/test/java/bigwarp/StartupTests.java | 8 +-- src/test/java/bigwarp/url/UrlParseTest.java | 7 +- 7 files changed, 93 insertions(+), 60 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 7c94b1d3..7fb824c0 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3177,7 +3177,7 @@ public static void main( final String[] args ) final ProgressWriterIJ progress = new ProgressWriterIJ(); BigWarp bw; - BigWarpData bwdata; + BigWarpData bwdata; if ( fnP.endsWith( "xml" ) && fnQ.endsWith( "xml" ) ) { bwdata = BigWarpInit.createBigWarpDataFromXML( fnP, fnQ ); diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index a1db7bdf..e60fe6a9 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -38,6 +38,7 @@ import org.janelia.saalfeldlab.n5.N5URI; import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader; import org.janelia.saalfeldlab.n5.imglib2.N5Utils; +import org.janelia.saalfeldlab.n5.metadata.N5ViewerMultichannelMetadata; import org.janelia.saalfeldlab.n5.metadata.imagej.ImagePlusLegacyMetadataParser; import org.janelia.saalfeldlab.n5.metadata.imagej.N5ImagePlusMetadata; import org.janelia.saalfeldlab.n5.universe.N5DatasetDiscoverer; @@ -56,6 +57,7 @@ import org.janelia.saalfeldlab.n5.zarr.N5ZarrReader; import bdv.BigDataViewer; +import bdv.cache.SharedQueue; import bdv.img.BwRandomAccessibleIntervalSource; import bdv.img.RenamableSource; import bdv.spimdata.SpimDataMinimal; @@ -65,6 +67,7 @@ import bdv.tools.transformation.TransformedSource; import bdv.util.RandomAccessibleIntervalMipmapSource; import bdv.util.RandomAccessibleIntervalSource; +import bdv.util.volatiles.VolatileViews; import bdv.viewer.Source; import bdv.viewer.SourceAndConverter; import bigwarp.loader.ImagePlusLoader; @@ -88,12 +91,16 @@ import net.imagej.axis.Axes; import net.imagej.axis.CalibratedAxis; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.cache.img.CachedCellImg; +import net.imglib2.cache.volatiles.CacheHints; +import net.imglib2.cache.volatiles.LoadingStrategy; import net.imglib2.converter.Converter; import net.imglib2.converter.Converters; import net.imglib2.display.RealARGBColorConverter; import net.imglib2.display.ScaledARGBConverter; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.RealTransform; +import net.imglib2.type.NativeType; import net.imglib2.type.numeric.ARGBType; import net.imglib2.type.numeric.NumericType; import net.imglib2.type.numeric.RealType; @@ -106,6 +113,24 @@ public class BigWarpInit { + + public static final N5MetadataParser[] PARSERS = new N5MetadataParser[]{ + new N5CosemMetadataParser(), + new N5SingleScaleMetadataParser(), + new CanonicalMetadataParser(), + new ImagePlusLegacyMetadataParser(), + new N5GenericSingleScaleMetadataParser() + }; + + public static final N5MetadataParser[] GROUP_PARSERS = new N5MetadataParser[]{ +// new org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.OmeNgffMetadataParser(), +// new org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v03.OmeNgffMetadataParser(), // TODO test later + new N5CosemMultiScaleMetadata.CosemMultiScaleParser(), + new N5ViewerMultiscaleMetadataParser(), + new CanonicalMetadataParser(), + new N5ViewerMultichannelMetadata.N5ViewerMultichannelMetadataParser() + }; + private static String createSetupName( final BasicViewSetup setup ) { if ( setup.hasName() ) @@ -467,7 +492,7 @@ private static String schemeSpecificPartWithoutQuery( URI uri ) public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( final BigWarpData< T > bwData, String uri, int setupId, boolean isMoving ) throws URISyntaxException, IOException, SpimDataException { - + final SharedQueue sharedQueue = new SharedQueue(Math.max(1, Runtime.getRuntime().availableProcessors() / 2)); final URI encodedUri = N5URI.encodeAsUri( uri ); final LinkedHashMap< Source< T >, SourceInfo > sourceStateMap = new LinkedHashMap<>(); if ( encodedUri.isOpaque() ) @@ -492,7 +517,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina throw new URISyntaxException( firstScheme, "Unsupported Top Level Protocol" ); } - final Source< T > source = loadN5Source( n5reader, n5URL.getGroupPath() ); + final Source< T > source = (Source)loadN5Source( n5reader, n5URL.getGroupPath(), sharedQueue ); sourceStateMap.put( source, new SourceInfo( setupId, isMoving, n5URL.getGroupPath() ) ); } else @@ -503,7 +528,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fina final String containerWithoutN5Scheme = n5URL.getContainerPath().replaceFirst( "^n5://", "" ); final N5Reader n5reader = new N5Factory().openReader( containerWithoutN5Scheme ); final String group = n5URL.getGroupPath(); - final Source< T > source = loadN5Source( n5reader, group ); + final Source< T > source = (Source)loadN5Source( n5reader, group, sharedQueue ); if( source != null ) sourceStateMap.put( source, new SourceInfo( setupId, isMoving, group ) ); @@ -559,7 +584,7 @@ else if ( new File( uri ).isDirectory() ) /** * @return * - * @Deprecated Use output froom + * @Deprecated Use output from * {@link #createSources(BigWarpData, boolean, int, String, String)} * and add with * {@link #add(BigWarpData, LinkedHashMap, RealTransform)} @@ -579,8 +604,9 @@ public static < T > Map< Source< T >, SourceInfo > createSources( final BigWarpD return createSources( bwdata, isMoving, setupId, rootPath, dataset, null ); } - private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( final BigWarpData< T > bwdata, final boolean isMoving, final int setupId, final String rootPath, final String dataset, final AtomicReference< SpimData > returnMovingSpimData ) + private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( final BigWarpData< T > bwdata, final boolean isMoving, final int setupId, final String rootPath, final String dataset, final AtomicReference< SpimData > returnMovingSpimData ) { + final SharedQueue sharedQueue = new SharedQueue(Math.max(1, Runtime.getRuntime().availableProcessors() / 2)); if ( rootPath.endsWith( "xml" ) ) { SpimData spimData; @@ -623,7 +649,7 @@ private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fin else { final LinkedHashMap< Source< T >, SourceInfo > map = new LinkedHashMap<>(); - final Source< T > source = loadN5Source( rootPath, dataset ); + final Source< T > source = (Source)loadN5Source( rootPath, dataset, sharedQueue ); final SourceInfo info = new SourceInfo( setupId, isMoving, dataset, () -> rootPath + "$" + dataset ); info.setSerializable( true ); map.put( source, info ); @@ -632,7 +658,7 @@ private static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( fin } - public static < T > Source< T > loadN5Source( final String n5Root, final String n5Dataset ) + public static < T extends NativeType > Source< T > loadN5Source( final String n5Root, final String n5Dataset, final SharedQueue queue ) { final N5Reader n5; try @@ -643,16 +669,11 @@ public static < T > Source< T > loadN5Source( final String n5Root, final String e.printStackTrace(); return null; } - return loadN5Source( n5, n5Dataset ); + return loadN5Source( n5, n5Dataset, queue ); } - public static < T > Source< T > loadN5Source( final N5Reader n5, final String n5Dataset ) + public static < T extends NativeType> Source< T > loadN5Source( final N5Reader n5, final String n5Dataset, final SharedQueue queue ) { - final N5MetadataParser< ? >[] PARSERS = new N5MetadataParser[] { new ImagePlusLegacyMetadataParser(), new N5CosemMetadataParser(), new N5SingleScaleMetadataParser(), new CanonicalMetadataParser(), new N5GenericSingleScaleMetadataParser() - }; - - final N5MetadataParser< ? >[] GROUP_PARSERS = new N5MetadataParser[] { new N5CosemMultiScaleMetadata.CosemMultiScaleParser(), new N5ViewerMultiscaleMetadataParser(), new CanonicalMetadataParser(), - }; N5Metadata meta = null; try @@ -667,16 +688,16 @@ public static < T > Source< T > loadN5Source( final N5Reader n5, final String n5 if ( meta instanceof MultiscaleMetadata ) { - return openAsSourceMulti( n5, ( MultiscaleMetadata< ? > ) meta, true ); + return openAsSourceMulti( n5, ( MultiscaleMetadata< ? > ) meta, queue, true ); } else { - return openAsSource( n5, meta, true ); + return openAsSource( n5, meta, queue, true ); } } @SuppressWarnings( { "unchecked", "rawtypes" } ) - public static < T, M extends N5Metadata > Source< T > openAsSource( final N5Reader n5, final M meta, final boolean isVolatile ) + public static < T extends NativeType, M extends N5Metadata > Source< T > openAsSource( final N5Reader n5, final M meta, final SharedQueue sharedQueue, final boolean isVolatile ) { final RandomAccessibleInterval imageRaw; final RandomAccessibleInterval image; @@ -686,7 +707,10 @@ public static < T, M extends N5Metadata > Source< T > openAsSource( final N5Read try { if ( isVolatile ) - imageRaw = to3d( N5Utils.openVolatile( n5, meta.getPath() ) ); + { + final CachedCellImg rai = N5Utils.openVolatile( n5, meta.getPath() ); + imageRaw = to3d( VolatileViews.wrapAsVolatile( rai, sharedQueue, new CacheHints(LoadingStrategy.VOLATILE, 0, true)) ); + } else imageRaw = to3d( N5Utils.open( n5, meta.getPath() ) ); @@ -716,7 +740,7 @@ public static < T, M extends N5Metadata > Source< T > openAsSource( final N5Read return null; } - public static < T > Source< T > openAsSourceMulti( final N5Reader n5, final MultiscaleMetadata< ? > multiMeta, final boolean isVolatile ) + public static < T extends NativeType > Source< T > openAsSourceMulti( final N5Reader n5, final MultiscaleMetadata< ? > multiMeta, final SharedQueue sharedQueue, final boolean isVolatile ) { final String[] paths = multiMeta.getPaths(); final AffineTransform3D[] transforms = multiMeta.spatialTransforms3d(); @@ -725,12 +749,16 @@ public static < T > Source< T > openAsSourceMulti( final N5Reader n5, final Mult @SuppressWarnings( "rawtypes" ) final RandomAccessibleInterval[] images = new RandomAccessibleInterval[ paths.length ]; final double[][] mipmapScales = new double[ images.length ][ 3 ]; + final CacheHints cacheHints = new CacheHints(LoadingStrategy.VOLATILE, 0, true); for ( int s = 0; s < images.length; ++s ) { try { if ( isVolatile ) - images[ s ] = to3d( N5Utils.openVolatile( n5, paths[ s ] ) ); + { + final CachedCellImg rai = N5Utils.openVolatile( n5, paths[ s ] ); + images[ s ] = to3d( VolatileViews.wrapAsVolatile( rai, sharedQueue, cacheHints) ); + } else images[ s ] = to3d( N5Utils.open( n5, paths[ s ] ) ); } @@ -1039,7 +1067,7 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source * fixed source XML * @return BigWarpData */ - public static < T > BigWarpData< T > createBigWarpDataFromXML( final String xmlFilenameP, final String xmlFilenameQ ) + public static < T extends NativeType > BigWarpData< T > createBigWarpDataFromXML( final String xmlFilenameP, final String xmlFilenameQ ) { // return createBigWarpData( new XMLLoader( xmlFilenameP ), new XMLLoader( xmlFilenameQ ), null ); final BigWarpData< T > bwdata = BigWarpInit.initData(); @@ -1142,7 +1170,7 @@ public static < T > BigWarpData< T > createBigWarpDataFromImages( final ImagePlu * fixed source ImagePlus * @return BigWarpData */ - public static < T > BigWarpData< T > createBigWarpDataFromXMLImagePlus( final String xmlFilenameP, final ImagePlus impQ ) + public static < T extends NativeType > BigWarpData< T > createBigWarpDataFromXMLImagePlus( final String xmlFilenameP, final ImagePlus impQ ) { final BigWarpData< T > bwdata = BigWarpInit.initData(); try @@ -1194,7 +1222,7 @@ public static < T > BigWarpData< T > createBigWarpDataFromXMLImagePlus( final St * fixed source XML * @return BigWarpData */ - public static < T > BigWarpData< T > createBigWarpDataFromImagePlusXML( final ImagePlus impP, final String xmlFilenameQ ) + public static < T extends NativeType > BigWarpData< T > createBigWarpDataFromImagePlusXML( final ImagePlus impP, final String xmlFilenameQ ) { // return createBigWarpData( new ImagePlusLoader( impP ), new XMLLoader( xmlFilenameQ ) ); final BigWarpData< T > bwdata = BigWarpInit.initData(); diff --git a/src/main/java/bigwarp/BigwarpSettings.java b/src/main/java/bigwarp/BigwarpSettings.java index 4690abea..2bca5232 100644 --- a/src/main/java/bigwarp/BigwarpSettings.java +++ b/src/main/java/bigwarp/BigwarpSettings.java @@ -42,6 +42,7 @@ import mpicbg.spim.data.SpimDataException; import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.realtransform.RealTransform; +import net.imglib2.type.NativeType; import net.imglib2.type.numeric.ARGBType; import org.scijava.listeners.Listeners; @@ -143,7 +144,7 @@ public BigwarpSettings read( final JsonReader in ) throws IOException final JsonObject json = JsonParser.parseReader(in).getAsJsonObject(); if( json.has("Sources")) { - new BigWarpSourcesAdapter<>( bigWarp, overwriteSources ).fromJsonTree(json.get("Sources")); + new BigWarpSourcesAdapter( bigWarp, overwriteSources ).fromJsonTree(json.get("Sources")); final boolean is2D = BigWarp.detectNumDims(bigWarp.getSources()) == 2; if (is2D != bigWarp.options.values.is2D()) { bigWarp.changeDimensionality( is2D ); @@ -172,7 +173,7 @@ public BigwarpSettings read( final JsonReader in ) throws IOException return this; } - public static class BigWarpSourcesAdapter< T > extends TypeAdapter< Map< Integer, SourceInfo > > + public static class BigWarpSourcesAdapter< T extends NativeType > extends TypeAdapter< Map< Integer, SourceInfo > > { private BigWarp< T > bigwarp; diff --git a/src/test/java/bigwarp/BigWarpTestUtils.java b/src/test/java/bigwarp/BigWarpTestUtils.java index 9c8a67cc..55157388 100644 --- a/src/test/java/bigwarp/BigWarpTestUtils.java +++ b/src/test/java/bigwarp/BigWarpTestUtils.java @@ -29,6 +29,7 @@ import net.imglib2.FinalInterval; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.position.FunctionRandomAccessible; +import net.imglib2.type.NativeType; import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.view.Views; import org.junit.Assert; @@ -53,7 +54,7 @@ public static String createTemp3DImage( String title, String format ) //noinspection ResultOfMethodCallIgnored tmpImgPath.toFile().delete(); } - catch ( IOException e ) + catch ( final IOException e ) { throw new RuntimeException( e ); } @@ -63,7 +64,7 @@ public static String createTemp3DImage( String title, String format ) private static String create3DImage( final Path tmpImgPath ) throws IOException { - ImagePlus img3d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 4, NewImage.FILL_RAMP ); + final ImagePlus img3d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 4, NewImage.FILL_RAMP ); IJ.save( img3d, tmpImgPath.toFile().getCanonicalPath() ); tmpImgPath.toFile().deleteOnExit(); return tmpImgPath.toString(); @@ -81,7 +82,7 @@ public static String createTemp3DImage( Path imagePath ) { return create3DImage( imagePath ); } - catch ( Exception e ) + catch ( final Exception e ) { //noinspection ResultOfMethodCallIgnored imagePath.toFile().delete(); @@ -91,7 +92,7 @@ public static String createTemp3DImage( Path imagePath ) private static String create2DImage( final Path tmpImgPath ) throws IOException { - ImagePlus img2d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 1, NewImage.FILL_RAMP ); + final ImagePlus img2d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 1, NewImage.FILL_RAMP ); IJ.save( img2d, tmpImgPath.toFile().getCanonicalPath() ); tmpImgPath.toFile().deleteOnExit(); return tmpImgPath.toString(); @@ -115,7 +116,7 @@ public static String createTemp2DImage( String title, String format ) tmpImg.toFile().delete(); return create2DImage( tmpImg); } - catch ( Exception e ) + catch ( final Exception e ) { if (tmpImg != null) { //noinspection ResultOfMethodCallIgnored @@ -144,7 +145,7 @@ public static String createTemp3DImageStack( String title ) StackWriter.save( img3d ,tmpStackDir.toString() + "/", "format=tiff"); return tmpStackDir.toString(); } - catch ( IOException e ) + catch ( final IOException e ) { throw new RuntimeException( e ); } @@ -154,11 +155,11 @@ public static void assertJsonDiff( final JsonElement expectedJson, final JsonEle { final Gson gson = new Gson(); //noinspection UnstableApiUsage - Type mapType = new TypeToken< Map< String, Object > >() + final Type mapType = new TypeToken< Map< String, Object > >() { }.getType(); - Map< String, Object > expectedMap = gson.fromJson( expectedJson, mapType ); - Map< String, Object > actualMap = gson.fromJson( actualJson, mapType ); + final Map< String, Object > expectedMap = gson.fromJson( expectedJson, mapType ); + final Map< String, Object > actualMap = gson.fromJson( actualJson, mapType ); final MapDifference< String, Object > difference = Maps.difference( expectedMap, actualMap ); if ( !difference.areEqual() ) { @@ -232,18 +233,18 @@ public static String prettyPrint( JsonObject json ) return new GsonBuilder().setPrettyPrinting().create().toJson( json ); } - static < T > BigWarp< T > createBigWarp(boolean... moving ) throws SpimDataException, URISyntaxException, IOException + static < T extends NativeType >BigWarp< T > createBigWarp(boolean... moving ) throws SpimDataException, URISyntaxException, IOException { return createBigWarp( null, moving ); } - static < T > BigWarp< T > createBigWarp(String sourcePath, boolean... moving ) throws SpimDataException, URISyntaxException, IOException + static < T extends NativeType > BigWarp< T > createBigWarp(String sourcePath, boolean... moving ) throws SpimDataException, URISyntaxException, IOException { final BigWarpData< T > data = BigWarpInit.initData(); if (sourcePath != null) { createTemp3DImage( Paths.get(sourcePath) ); } - + final String tmpPath = sourcePath != null ? sourcePath : createTemp3DImage( "img", "tif" ); for ( int i = 0; i < moving.length; i++ ) @@ -251,13 +252,13 @@ static < T > BigWarp< T > createBigWarp(String sourcePath, boolean... moving ) final LinkedHashMap< Source< T >, SourceInfo > sources = BigWarpInit.createSources( data, tmpPath, i, moving[ i ] ); BigWarpInit.add( data, sources ); } - BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); + final BigWarpViewerOptions opts = BigWarpViewerOptions.options( false ); return new BigWarp<>( data, opts, null ); } static ImagePlus generateImagePlus( final String title ) { - FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( + final FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>( 3, ( l, v ) -> v.setOne(), UnsignedByteType::new ); diff --git a/src/test/java/bigwarp/SerializationTest.java b/src/test/java/bigwarp/SerializationTest.java index a2bfb508..bdd60f24 100644 --- a/src/test/java/bigwarp/SerializationTest.java +++ b/src/test/java/bigwarp/SerializationTest.java @@ -33,6 +33,8 @@ import net.imglib2.FinalInterval; import net.imglib2.RealPoint; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.type.NativeType; + import org.custommonkey.xmlunit.XMLAssert; import org.custommonkey.xmlunit.XMLUnit; import org.jdom2.JDOMException; @@ -59,8 +61,8 @@ public void after() { @Test public void maskTest() { - PlateauSphericalMaskSource mask = PlateauSphericalMaskSource.build( new RealPoint( 3 ), new FinalInterval( 5, 10, 20 ) ); - Gson gson = BigwarpSettings.gson; + final PlateauSphericalMaskSource mask = PlateauSphericalMaskSource.build( new RealPoint( 3 ), new FinalInterval( 5, 10, 20 ) ); + final Gson gson = BigwarpSettings.gson; final JsonElement actual = gson.toJsonTree( mask.getRandomAccessible() ); final JsonObject expected = new JsonObject(); @@ -90,7 +92,7 @@ public void bookmarksTest() bookmarks.put( "translate", translate ); translate.translate( Math.random(), Math.random(), Math.random(), Math.random() ); - Gson gson = BigwarpSettings.gson; + final Gson gson = BigwarpSettings.gson; final JsonElement actual = gson.toJsonTree( bookmarks ); final JsonObject expected = new JsonObject(); @@ -230,9 +232,9 @@ public void viewerPanelTest() throws SpimDataException, IOException, URISyntaxEx } @Test - public void sourceFromFileTest() throws SpimDataException, URISyntaxException, IOException, JDOMException + public < T extends NativeType > void sourceFromFileTest() throws SpimDataException, URISyntaxException, IOException, JDOMException { - final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( "/tmp/img8270806677315563879.tif" ); + final BigWarp< T > bw = BigWarpTestUtils.createBigWarp( "/tmp/img8270806677315563879.tif" ); bw.loadSettings("src/test/resources/settings/expected.json"); // Grab the sources // Compare the ids, urls, isMoving status, and isActive @@ -249,7 +251,7 @@ public void sourceFromFileTest() throws SpimDataException, URISyntaxException, I } @Test - public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, IOException, JDOMException + public < T extends NativeType > void sourceFromImageJTest() throws SpimDataException, URISyntaxException, IOException, JDOMException { final ImagePlus img = BigWarpTestUtils.generateImagePlus( "generated image" ); img.setDisplayRange( 5, 15 ); @@ -266,7 +268,7 @@ public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, } }); - final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); + final BigWarp< T > bw = BigWarpTestUtils.createBigWarp( ); bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); // Grab the sources // Compare the ids, urls, isMoving status, and isActive @@ -285,7 +287,7 @@ public void sourceFromImageJTest() throws SpimDataException, URISyntaxException, assertExpectedSettingsToCurrent( xmlSourceSettings, bw ); } - private static void assertExpectedSettingsToCurrent( final Path expectedSettings, final BigWarp< Object > bw ) throws IOException + private static void assertExpectedSettingsToCurrent( final Path expectedSettings, final BigWarp< ? > bw ) throws IOException { /* Save the settings and compare with initial to test the deserialization */ final Path tempSettings = Files.createTempFile( "deserialization", ".json" ); @@ -297,7 +299,7 @@ private static void assertExpectedSettingsToCurrent( final Path expectedSettings } @Test - public void sourceFromXmlTest() throws SpimDataException, URISyntaxException, IOException, JDOMException + public < T extends NativeType > void sourceFromXmlTest() throws SpimDataException, URISyntaxException, IOException, JDOMException { final String xmlUri = "src/test/resources/mri-stack.xml"; final Path xmlSourceSettings = createNewSettingsWithReplacement( @@ -310,7 +312,7 @@ public void sourceFromXmlTest() throws SpimDataException, URISyntaxException, IO } }); - final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); + final BigWarp< T > bw = BigWarpTestUtils.createBigWarp( ); bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); // Grab the sources // Compare the ids, urls, isMoving status, and isActive @@ -331,7 +333,7 @@ public void sourceFromXmlTest() throws SpimDataException, URISyntaxException, IO } @Test - public void sourceFromN5Test() throws SpimDataException, URISyntaxException, IOException, JDOMException + public < T extends NativeType > void sourceFromN5Test() throws SpimDataException, URISyntaxException, IOException, JDOMException { final String n5Uri = "src/test/resources/bigwarp/url/transformTest.n5?img"; @@ -346,7 +348,7 @@ public void sourceFromN5Test() throws SpimDataException, URISyntaxException, IOE } ); - final BigWarp< Object > bw = BigWarpTestUtils.createBigWarp( ); + final BigWarp< T > bw = BigWarpTestUtils.createBigWarp( ); bw.loadSettings(xmlSourceSettings.toFile().getCanonicalPath()); // Grab the sources // Compare the ids, urls, isMoving status, and isActive @@ -410,7 +412,7 @@ public void repeatComparison() throws Exception @Test public void compareKnownXmlComparisonTest() throws SpimDataException, IOException, JDOMException, SAXException, URISyntaxException { - BigWarp< ? > bw = BigWarpTestUtils.createBigWarp( true, false, false, false ); + final BigWarp< ? > bw = BigWarpTestUtils.createBigWarp( true, false, false, false ); final String originalXmlSettings = "src/test/resources/settings/compareKnownXml.bigwarp.settings.xml"; bw.loadSettings( originalXmlSettings ); diff --git a/src/test/java/bigwarp/StartupTests.java b/src/test/java/bigwarp/StartupTests.java index f7ff5ce3..3767dcd1 100644 --- a/src/test/java/bigwarp/StartupTests.java +++ b/src/test/java/bigwarp/StartupTests.java @@ -34,8 +34,8 @@ public static void main( final String[] args ) throws IOException // IJ.openImage( "/home/john/tmp/t1-head.tif" ).show(); // IJ.openImage( "/home/john/tmp/mri-stack.tif" ).show(); -// final String proj = "/home/john/Desktop/bw-boats.json"; - final String proj = "/home/john/Desktop/bw-boats-affine2d.json"; + final String proj = "/home/john/Desktop/bw-boats.json"; +// final String proj = "/home/john/Desktop/bw-boats-affine2d.json"; // final String proj = "/home/john/Desktop/bw-boats-tlation.json"; // final String proj = "/home/john/Desktop/bw-boats-tlationImported-fineTune.json"; @@ -87,9 +87,9 @@ public static void main( final String[] args ) throws IOException // runBigWarp(null, new String[] {jrc18, jrc18}, new String[] {"true", "false" }, new String[]{ jrc18RotTotSeqRev, null }); -// runBigWarp(proj, new String[] {}, new String[] {}, null); + BigWarpInitDialog.runBigWarp(proj, new String[] {}, new String[] {}, null); - BigWarpInitDialog.createAndShow(); +// BigWarpInitDialog.createAndShow(); // below this are from BigWarpCommand diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index 41f0e24b..43582614 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -28,6 +28,7 @@ import bigwarp.BigWarpTestUtils; import bigwarp.source.SourceInfo; import mpicbg.spim.data.SpimDataException; +import net.imglib2.type.NativeType; public class UrlParseTest { @@ -134,7 +135,7 @@ public void testUrlTransforms() } @Test - public void n5FileUrlEquivalencyTest() throws IOException, SpimDataException, URISyntaxException + public < T extends NativeType > void n5FileUrlEquivalencyTest() throws IOException, SpimDataException, URISyntaxException { final String relativePath = "src/test/resources/bigwarp/url/transformTest.n5"; final String absolutePath = Paths.get( relativePath ).toAbsolutePath().toFile().getCanonicalPath(); @@ -155,7 +156,7 @@ public void n5FileUrlEquivalencyTest() throws IOException, SpimDataException, UR relativePath + "?img" }; - final BigWarpData< Object > data = BigWarpInit.initData(); + final BigWarpData data = BigWarpInit.initData(); final AtomicInteger id = new AtomicInteger( 1 ); for ( final String uri : variants ) { @@ -171,7 +172,7 @@ private Object loadTransformFromUrl( final String url ) return null; } - private < T > Source< ? > loadSourceFromUri( final String uri ) throws SpimDataException, URISyntaxException, IOException + private < T extends NativeType > Source< ? > loadSourceFromUri( final String uri ) throws SpimDataException, URISyntaxException, IOException { final BigWarpData< T > data = BigWarpInit.initData(); From b8e0ee63d604f84fd5d20941a99d100a59590ea7 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 09:30:49 -0400 Subject: [PATCH 270/282] fix: load/save bw project menu options --- src/main/java/bigwarp/BigWarpActions.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index fbc94a5d..2a9e13d2 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -64,8 +64,12 @@ public class BigWarpActions extends Actions // General options public static final String CLOSE_DIALOG = "close dialog window"; public static final String[] CLOSE_DIALOG_KEYS = new String[] { NOT_MAPPED }; + public static final String LOAD_PROJECT = "load project"; + public static final String[] LOAD_PROJECT_KEYS = new String[]{ "ctrl shift O" }; + public static final String SAVE_PROJECT = "save project"; + public static final String[] SAVE_PROJECT_KEYS = new String[]{ "ctrl shift S" }; public static final String EXPAND_CARDS = "expand and focus cards panel"; public static final String[] EXPAND_CARDS_KEYS = new String[] { "P" }; @@ -297,6 +301,9 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) { descriptions.add( CLOSE_DIALOG, CLOSE_DIALOG_KEYS, "Close bigwarp." ); + descriptions.add( SAVE_PROJECT, SAVE_PROJECT_KEYS, "Save a bigwarp project." ); + descriptions.add( LOAD_PROJECT, LOAD_PROJECT_KEYS, "Load a bigwarp project." ); + descriptions.add( TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS, "Toggle landmark mode." ); descriptions.add( TOGGLE_MOVING_IMAGE_DISPLAY, TOGGLE_MOVING_IMAGE_DISPLAY_KEYS, "Toggle landmark mode." ); @@ -368,6 +375,9 @@ public TableDescriptions() @Override public void getCommandDescriptions( final CommandDescriptions descriptions ) { + descriptions.add( SAVE_PROJECT, SAVE_PROJECT_KEYS, "Save a bigwarp project." ); + descriptions.add( LOAD_PROJECT, LOAD_PROJECT_KEYS, "Load a bigwarp project." ); + descriptions.add( CLEAR_MOVING, CLEAR_MOVING_KEYS, "Clears moving landmark under the mouse cursor." ); descriptions.add( CLEAR_FIXED, CLEAR_FIXED_KEYS, "Clears fixed landmark under the mouse cursor." ); descriptions.add( CLEAR_SELECTED_MOVING, CLEAR_SELECTED_MOVING_KEYS, "Clears moving landmark for currently selected row." ); @@ -412,6 +422,9 @@ public static void installViewerActions( final InputActionBindings inputActionBindings = bwFrame.getKeybindings(); actions.install( inputActionBindings, "bw" ); + actions.runnableAction( bw::saveProject, SAVE_PROJECT, SAVE_PROJECT_KEYS ); + actions.runnableAction( bw::loadProject, LOAD_PROJECT, LOAD_PROJECT_KEYS ); + actions.runnableAction( () -> { bw.getBwTransform().transformToString(); }, PRINT_TRANSFORM, PRINT_TRANSFORM_KEYS); actions.runnableAction( bw::toggleInLandmarkMode, TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS); actions.runnableAction( bw::toggleMovingImageDisplay, TOGGLE_MOVING_IMAGE_DISPLAY, TOGGLE_MOVING_IMAGE_DISPLAY_KEYS ); @@ -486,6 +499,9 @@ public static void installTableActions( { actions.install( inputActionBindings, "bw-table" ); + actions.runnableAction( bw::saveProject, SAVE_PROJECT, SAVE_PROJECT_KEYS ); + actions.runnableAction( bw::loadProject, LOAD_PROJECT, LOAD_PROJECT_KEYS ); + // unmapped actions.runnableAction( () -> { bw.getBwTransform().transformToString(); }, PRINT_TRANSFORM, PRINT_TRANSFORM_KEYS); actions.runnableAction( bw::toggleInLandmarkMode, TOGGLE_LANDMARK_MODE, TOGGLE_LANDMARK_MODE_KEYS); @@ -662,7 +678,6 @@ public static ActionMap createActionMapViewer( final BigWarp< ? > bw ) public static InputMap createInputMap( final KeyStrokeAdder.Factory keyProperties ) { - System.out.println( "create input map" ); final InputMap inputMap = new InputMap(); final KeyStrokeAdder map = keyProperties.keyStrokeAdder( inputMap ); From 69d97e3dc04f6533e72fe67e9d04da226e53447d Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 09:36:42 -0400 Subject: [PATCH 271/282] refactor: rename "warp" to "jump" to landmarks --- src/main/java/bigwarp/BigWarp.java | 34 +++++----- src/main/java/bigwarp/BigWarpActions.java | 80 +++++++++++------------ 2 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 7fb824c0..49c86eb8 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2032,7 +2032,7 @@ else if ( viewerFrameQ.isActive() ) * * @param inc the increment */ - public void warpToLandmarkRelative( int inc ) + public void jumpToLandmarkRelative( int inc ) { final int[] selectedRows = getLandmarkPanel().getJTable().getSelectedRows(); @@ -2053,33 +2053,35 @@ else if( row < 0 ) if( getViewerFrameP().isActive() ) { - warpToLandmark( row, getViewerFrameP().getViewerPanel() ); + jumpToLandmark( row, getViewerFrameP().getViewerPanel() ); } else { - warpToLandmark( row, getViewerFrameQ().getViewerPanel() ); + jumpToLandmark( row, getViewerFrameQ().getViewerPanel() ); } } - public void warpToNextLandmark() + public void jumpToNextLandmark() { - warpToLandmarkRelative( 1 ); + System.out.println("warp to next"); + jumpToLandmarkRelative( 1 ); } - public void warpToPrevLandmark() + public void jumpToPrevLandmark() { - warpToLandmarkRelative( -1 ); + System.out.println("warp to prev"); + jumpToLandmarkRelative( -1 ); } - public void warpToNearestLandmark() + public void jumpToNearestLandmark() { if( getViewerFrameP().isActive() ) - warpToNearest( getViewerFrameP().getViewerPanel() ); + jumpToNearestLandmark( getViewerFrameP().getViewerPanel() ); else - warpToNearest( getViewerFrameQ().getViewerPanel() ); + jumpToNearestLandmark( getViewerFrameQ().getViewerPanel() ); } - public void warpToNearest( BigWarpViewerPanel viewer ) + public void jumpToNearestLandmark( BigWarpViewerPanel viewer ) { if ( inLandmarkMode ) { @@ -2089,10 +2091,10 @@ public void warpToNearest( BigWarpViewerPanel viewer ) final RealPoint mousePt = new RealPoint( 3 ); // need 3d point even for 2d images viewer.getGlobalMouseCoordinates( mousePt ); - warpToLandmark( landmarkModel.getIndexNearestTo( mousePt, viewer.getIsMoving() ), viewer ); + jumpToLandmark( landmarkModel.getIndexNearestTo( mousePt, viewer.getIsMoving() ), viewer ); } - public void warpToSelectedLandmark() + public void jumpToSelectedLandmark() { final int[] selectedRows = getLandmarkPanel().getJTable().getSelectedRows(); @@ -2101,12 +2103,12 @@ public void warpToSelectedLandmark() row = selectedRows[ 0 ]; if( getViewerFrameP().isActive() ) - warpToLandmark( row, getViewerFrameP().getViewerPanel() ); + jumpToLandmark( row, getViewerFrameP().getViewerPanel() ); else - warpToLandmark( row, getViewerFrameQ().getViewerPanel() ); + jumpToLandmark( row, getViewerFrameQ().getViewerPanel() ); } - public void warpToLandmark( int row, BigWarpViewerPanel viewer ) + public void jumpToLandmark( int row, BigWarpViewerPanel viewer ) { if( inLandmarkMode ) { diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 2a9e13d2..83a76790 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -152,17 +152,17 @@ public class BigWarpActions extends Actions public static final String ALIGN_ACTIVE_TO_OTHER = String.format( ALIGN_VIEW_TRANSFORMS, AlignViewerPanelAction.TYPE.ACTIVE_TO_OTHER ); public static final String[] ALIGN_ACTIVE_TO_OTHER_KEYS = new String[] { "W" }; - public static final String WARP_TO_SELECTED_POINT = "center on selected landmark"; - public static final String[] WARP_TO_SELECTED_POINT_KEYS = new String[]{ "D" }; + public static final String JUMP_TO_SELECTED_POINT = "center on selected landmark"; + public static final String[] JUMP_TO_SELECTED_POINT_KEYS = new String[]{ "D" }; - public static final String WARP_TO_NEXT_POINT = "center on next landmark"; - public static final String[] WARP_TO_NEXT_POINT_KEYS = new String[]{ "ctrl D"}; + public static final String JUMP_TO_NEXT_POINT = "center on next landmark"; + public static final String[] JUMP_TO_NEXT_POINT_KEYS = new String[]{ "ctrl D"}; - public static final String WARP_TO_PREV_POINT = "center on prev landmark"; - public static final String[] WARP_TO_PREV_POINT_KEYS = new String[]{ "ctrl shift D"}; + public static final String JUMP_TO_PREV_POINT = "center on prev landmark"; + public static final String[] JUMP_TO_PREV_POINT_KEYS = new String[]{ "ctrl shift D"}; - public static final String WARP_TO_NEAREST_POINT = "center on nearest landmark"; - public static final String[] WARP_TO_NEAREST_POINT_KEYS = new String[]{ "E" }; + public static final String JUMP_TO_NEAREST_POINT = "center on nearest landmark"; + public static final String[] JUMP_TO_NEAREST_POINT_KEYS = new String[]{ "E" }; // landmark options public static final String LOAD_LANDMARKS = "load landmarks"; @@ -324,10 +324,10 @@ public void getCommandDescriptions( final CommandDescriptions descriptions ) descriptions.add( RESET_VIEWER, RESET_VIEWER_KEYS, "Resets the view to the view on startup." ); descriptions.add( ALIGN_OTHER_TO_ACTIVE, ALIGN_OTHER_TO_ACTIVE_KEYS, "Sets the view of the non-active viewer to match the active viewer." ); descriptions.add( ALIGN_ACTIVE_TO_OTHER, ALIGN_ACTIVE_TO_OTHER_KEYS, "Sets the view of the active viewer to match the non-active viewer." ); - descriptions.add( WARP_TO_SELECTED_POINT, WARP_TO_SELECTED_POINT_KEYS, "Center the viewer on the selected landmark." ); - descriptions.add( WARP_TO_NEAREST_POINT, WARP_TO_NEAREST_POINT_KEYS, "Center the viewer on the nearest landmark." ); - descriptions.add( WARP_TO_NEXT_POINT, WARP_TO_NEXT_POINT_KEYS, "Center the viewer on the next landmark." ); - descriptions.add( WARP_TO_PREV_POINT, WARP_TO_PREV_POINT_KEYS, "Center the viewer on the previous landmark." ); + descriptions.add( JUMP_TO_SELECTED_POINT, JUMP_TO_SELECTED_POINT_KEYS, "Center the viewer on the selected landmark." ); + descriptions.add( JUMP_TO_NEAREST_POINT, JUMP_TO_NEAREST_POINT_KEYS, "Center the viewer on the nearest landmark." ); + descriptions.add( JUMP_TO_NEXT_POINT, JUMP_TO_NEXT_POINT_KEYS, "Center the viewer on the next landmark." ); + descriptions.add( JUMP_TO_PREV_POINT, JUMP_TO_PREV_POINT_KEYS, "Center the viewer on the previous landmark." ); // cards descriptions.add( EXPAND_CARDS, EXPAND_CARDS_KEYS, "Expand and focus the BigDataViewer card panel" ); @@ -436,10 +436,10 @@ public static void installViewerActions( actions.runnableAction( bw::resetView, RESET_VIEWER, RESET_VIEWER_KEYS); actions.runnableAction( bw::matchOtherViewerPanelToActive, ALIGN_OTHER_TO_ACTIVE, ALIGN_OTHER_TO_ACTIVE_KEYS ); actions.runnableAction( bw::matchActiveViewerPanelToOther, ALIGN_ACTIVE_TO_OTHER, ALIGN_ACTIVE_TO_OTHER_KEYS ); - actions.runnableAction( bw::warpToSelectedLandmark, WARP_TO_SELECTED_POINT, WARP_TO_SELECTED_POINT_KEYS ); - actions.runnableAction( bw::warpToNearestLandmark, WARP_TO_NEAREST_POINT, WARP_TO_NEAREST_POINT_KEYS ); - actions.runnableAction( bw::warpToNextLandmark, WARP_TO_NEXT_POINT, WARP_TO_NEXT_POINT_KEYS ); - actions.runnableAction( bw::warpToPrevLandmark, WARP_TO_PREV_POINT, WARP_TO_PREV_POINT_KEYS ); + actions.runnableAction( bw::jumpToSelectedLandmark, JUMP_TO_SELECTED_POINT, JUMP_TO_SELECTED_POINT_KEYS ); + actions.runnableAction( bw::jumpToNearestLandmark, JUMP_TO_NEAREST_POINT, JUMP_TO_NEAREST_POINT_KEYS ); + actions.runnableAction( bw::jumpToNextLandmark, JUMP_TO_NEXT_POINT, JUMP_TO_NEXT_POINT_KEYS ); + actions.runnableAction( bw::jumpToPrevLandmark, JUMP_TO_PREV_POINT, JUMP_TO_PREV_POINT_KEYS ); // bookmarks actions.runnableAction( bw::goToBookmark, GO_TO_BOOKMARK, GO_TO_BOOKMARK_KEYS ); @@ -511,10 +511,10 @@ public static void installTableActions( actions.runnableAction( bw::resetView, RESET_VIEWER, NOT_MAPPED ); actions.runnableAction( bw::matchOtherViewerPanelToActive, ALIGN_OTHER_TO_ACTIVE, NOT_MAPPED ); actions.runnableAction( bw::matchActiveViewerPanelToOther, ALIGN_ACTIVE_TO_OTHER, NOT_MAPPED ); - actions.runnableAction( bw::warpToSelectedLandmark, WARP_TO_SELECTED_POINT, NOT_MAPPED ); - actions.runnableAction( bw::warpToNearestLandmark, WARP_TO_NEAREST_POINT, NOT_MAPPED ); - actions.runnableAction( bw::warpToNextLandmark, WARP_TO_NEXT_POINT, NOT_MAPPED ); - actions.runnableAction( bw::warpToPrevLandmark, WARP_TO_PREV_POINT, NOT_MAPPED ); + actions.runnableAction( bw::jumpToSelectedLandmark, JUMP_TO_SELECTED_POINT, NOT_MAPPED ); + actions.runnableAction( bw::jumpToNearestLandmark, JUMP_TO_NEAREST_POINT, NOT_MAPPED ); + actions.runnableAction( bw::jumpToNextLandmark, JUMP_TO_NEXT_POINT, NOT_MAPPED ); + actions.runnableAction( bw::jumpToPrevLandmark, JUMP_TO_PREV_POINT, NOT_MAPPED ); // bookmarks actions.runnableAction( bw::goToBookmark, GO_TO_BOOKMARK, NOT_MAPPED ); @@ -622,10 +622,10 @@ public static InputMap createInputMapViewer( final KeyStrokeAdder.Factory keyPro map.put( TOGGLE_MOVING_IMAGE_DISPLAY, "T" ); - map.put( WARP_TO_SELECTED_POINT, "D" ); - map.put( String.format( WARP_TO_NEXT_POINT, true), "ctrl D" ); - map.put( String.format( WARP_TO_NEXT_POINT, false), "ctrl shift D" ); - map.put( WARP_TO_NEAREST_POINT, "E" ); + map.put( JUMP_TO_SELECTED_POINT, "D" ); + map.put( String.format( JUMP_TO_NEXT_POINT, true), "ctrl D" ); + map.put( String.format( JUMP_TO_NEXT_POINT, false), "ctrl shift D" ); + map.put( JUMP_TO_NEAREST_POINT, "E" ); map.put( EXPORT_WARP, "ctrl W" ); map.put( EXPORT_AFFINE, "ctrl A" ); @@ -656,9 +656,9 @@ public static ActionMap createActionMapViewer( final BigWarp< ? > bw ) new AlignViewerPanelAction( bw, AlignViewerPanelAction.TYPE.ACTIVE_TO_OTHER ).put( actionMap ); new AlignViewerPanelAction( bw, AlignViewerPanelAction.TYPE.OTHER_TO_ACTIVE ).put( actionMap ); new WarpToSelectedAction( bw ).put( actionMap ); - new WarpToNextAction( bw, true ).put( actionMap ); - new WarpToNextAction( bw, false ).put( actionMap ); - new WarpToNearest( bw ).put( actionMap ); + new JumpToNextAction( bw, true ).put( actionMap ); + new JumpToNextAction( bw, false ).put( actionMap ); + new JumpToNearest( bw ).put( actionMap ); for( final GridSource.GRID_TYPE t : GridSource.GRID_TYPE.values()) new SetWarpVisGridTypeAction( String.format( WARPVISGRID, t.name()), bw, t ).put( actionMap ); @@ -1409,7 +1409,7 @@ public static class WarpToSelectedAction extends AbstractNamedAction public WarpToSelectedAction( final BigWarp< ? > bw ) { - super( WARP_TO_SELECTED_POINT ); + super( JUMP_TO_SELECTED_POINT ); this.bw = bw; } @@ -1423,20 +1423,20 @@ public void actionPerformed( ActionEvent e ) row = selectedRows[ 0 ]; if( bw.getViewerFrameP().isActive() ) - bw.warpToLandmark( row, bw.getViewerFrameP().getViewerPanel() ); + bw.jumpToLandmark( row, bw.getViewerFrameP().getViewerPanel() ); else - bw.warpToLandmark( row, bw.getViewerFrameQ().getViewerPanel() ); + bw.jumpToLandmark( row, bw.getViewerFrameQ().getViewerPanel() ); } private static final long serialVersionUID = 5233843444920094805L; } - public static class WarpToNearest extends AbstractNamedAction + public static class JumpToNearest extends AbstractNamedAction { final BigWarp< ? > bw; - public WarpToNearest( final BigWarp< ? > bw ) + public JumpToNearest( final BigWarp< ? > bw ) { - super( WARP_TO_NEAREST_POINT ); + super( JUMP_TO_NEAREST_POINT ); this.bw = bw; } @@ -1444,21 +1444,21 @@ public WarpToNearest( final BigWarp< ? > bw ) public void actionPerformed( ActionEvent e ) { if( bw.getViewerFrameP().isActive() ) - bw.warpToNearest( bw.getViewerFrameP().getViewerPanel() ); + bw.jumpToNearestLandmark( bw.getViewerFrameP().getViewerPanel() ); else - bw.warpToNearest( bw.getViewerFrameQ().getViewerPanel() ); + bw.jumpToNearestLandmark( bw.getViewerFrameQ().getViewerPanel() ); } private static final long serialVersionUID = 3244181492305479433L; } - public static class WarpToNextAction extends AbstractNamedAction + public static class JumpToNextAction extends AbstractNamedAction { final BigWarp< ? > bw; final int inc; - public WarpToNextAction( final BigWarp< ? > bw, boolean fwd ) + public JumpToNextAction( final BigWarp< ? > bw, boolean fwd ) { - super( String.format( WARP_TO_NEXT_POINT, fwd) ); + super( String.format( JUMP_TO_NEXT_POINT, fwd) ); this.bw = bw; if( fwd ) inc = 1; @@ -1494,11 +1494,11 @@ else if( row < 0 ) if( bw.getViewerFrameP().isActive() ) { - bw.warpToLandmark( row, bw.getViewerFrameP().getViewerPanel() ); + bw.jumpToLandmark( row, bw.getViewerFrameP().getViewerPanel() ); } else { - bw.warpToLandmark( row, bw.getViewerFrameQ().getViewerPanel() ); + bw.jumpToLandmark( row, bw.getViewerFrameQ().getViewerPanel() ); } } private static final long serialVersionUID = 8515568118251877405L; From a0c3496de3c210797ad3ae8635e8eaa403e61d71 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 09:42:38 -0400 Subject: [PATCH 272/282] chore: bump major version * n5-ij 3.2.6 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f1022070..5472fa07 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ sc.fiji bigwarp_fiji - 8.0.1-SNAPSHOT + 9.0.0-SNAPSHOT BigWarp plugin for Fiji A tool for manual pointwise deformable registration using bigdataviewer. @@ -129,7 +129,7 @@ sign,deploy-to-scijava 3.0.2 - 3.2.6-SNAPSHOT + 3.2.6 2.0.1 4.0.1 4.0.0 From aa3fe4e5a4dbe709081d4a8978bb9699bdc8cac7 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 16:46:25 -0400 Subject: [PATCH 273/282] chore/refactor: bump n5-universe 1.2.0 * n5 transform metadata classes now in new package --- pom.xml | 2 +- .../ij/BigWarpToDeformationFieldPlugIn.java | 12 +++++----- .../transforms/NgffTransformations.java | 24 +++++++++---------- .../metadata/N5TransformMetadata.java | 2 +- .../metadata/N5TransformMetadataParser.java | 2 +- .../metadata/N5TransformTreeCellRenderer.java | 2 +- src/test/java/bigwarp/NgffTransformTests.java | 2 +- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/pom.xml b/pom.xml index 5472fa07..a12e4470 100644 --- a/pom.xml +++ b/pom.xml @@ -134,7 +134,7 @@ 4.0.1 4.0.0 7.0.0 - 1.1.1-SNAPSHOT + 1.2.0 5.3.1 1.0.1 10.4.8 diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 826ed62f..96fa5072 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -48,12 +48,12 @@ import org.janelia.saalfeldlab.n5.ij.N5Exporter; import org.janelia.saalfeldlab.n5.imglib2.N5DisplacementField; import org.janelia.saalfeldlab.n5.universe.N5Factory; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.AffineCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.DisplacementFieldCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.ReferencedCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.SequenceCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.TranslationCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.AffineCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.CoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.DisplacementFieldCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.ReferencedCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.SequenceCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.TranslationCoordinateTransform; import bdv.gui.ExportDisplacementFieldFrame; import bdv.img.WarpedSource; diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java index 77aad0c6..2e386567 100644 --- a/src/main/java/bigwarp/transforms/NgffTransformations.java +++ b/src/main/java/bigwarp/transforms/NgffTransformations.java @@ -21,18 +21,18 @@ import org.janelia.saalfeldlab.n5.universe.N5Factory; import org.janelia.saalfeldlab.n5.universe.metadata.axes.Axis; import org.janelia.saalfeldlab.n5.universe.metadata.axes.CoordinateSystem; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.Common; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.graph.TransformGraph; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.AffineCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransformAdapter; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.DisplacementFieldCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.IdentityCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.InvertibleCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.ReferencedCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.ScaleCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.SequenceCoordinateTransform; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.TranslationCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.Common; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.graph.TransformGraph; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.AffineCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.CoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.CoordinateTransformAdapter; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.DisplacementFieldCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.IdentityCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.InvertibleCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.ReferencedCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.ScaleCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.SequenceCoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.TranslationCoordinateTransform; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/src/main/java/bigwarp/transforms/metadata/N5TransformMetadata.java b/src/main/java/bigwarp/transforms/metadata/N5TransformMetadata.java index b36d5a1d..65f1fc51 100644 --- a/src/main/java/bigwarp/transforms/metadata/N5TransformMetadata.java +++ b/src/main/java/bigwarp/transforms/metadata/N5TransformMetadata.java @@ -1,7 +1,7 @@ package bigwarp.transforms.metadata; import org.janelia.saalfeldlab.n5.universe.metadata.AbstractN5Metadata; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.CoordinateTransform; public class N5TransformMetadata extends AbstractN5Metadata { diff --git a/src/main/java/bigwarp/transforms/metadata/N5TransformMetadataParser.java b/src/main/java/bigwarp/transforms/metadata/N5TransformMetadataParser.java index cfbfc10f..1d40ba5d 100644 --- a/src/main/java/bigwarp/transforms/metadata/N5TransformMetadataParser.java +++ b/src/main/java/bigwarp/transforms/metadata/N5TransformMetadataParser.java @@ -6,7 +6,7 @@ import org.janelia.saalfeldlab.n5.universe.N5Factory; import org.janelia.saalfeldlab.n5.universe.N5TreeNode; import org.janelia.saalfeldlab.n5.universe.metadata.N5MetadataParser; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.CoordinateTransform; import bigwarp.transforms.NgffTransformations; diff --git a/src/main/java/bigwarp/transforms/metadata/N5TransformTreeCellRenderer.java b/src/main/java/bigwarp/transforms/metadata/N5TransformTreeCellRenderer.java index 8132da1b..cf4b7fd5 100644 --- a/src/main/java/bigwarp/transforms/metadata/N5TransformTreeCellRenderer.java +++ b/src/main/java/bigwarp/transforms/metadata/N5TransformTreeCellRenderer.java @@ -8,7 +8,7 @@ import org.janelia.saalfeldlab.n5.ui.N5SwingTreeNode; import org.janelia.saalfeldlab.n5.universe.N5TreeNode; import org.janelia.saalfeldlab.n5.universe.metadata.N5Metadata; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.transformations.CoordinateTransform; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.transformations.CoordinateTransform; public class N5TransformTreeCellRenderer extends N5DatasetTreeCellRenderer { diff --git a/src/test/java/bigwarp/NgffTransformTests.java b/src/test/java/bigwarp/NgffTransformTests.java index b4e94e51..a4d146d7 100644 --- a/src/test/java/bigwarp/NgffTransformTests.java +++ b/src/test/java/bigwarp/NgffTransformTests.java @@ -2,7 +2,7 @@ import java.util.Arrays; -import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.prototype.Common; +import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v05.Common; import net.imglib2.realtransform.RealTransform; From d01b3898859012a57533bb9e2b44a5978a5cc515 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 16:47:10 -0400 Subject: [PATCH 274/282] fix: jump-actions now call appropriate method in bigwarp class --- src/main/java/bigwarp/BigWarp.java | 2 - src/main/java/bigwarp/BigWarpActions.java | 56 +++-------------------- 2 files changed, 7 insertions(+), 51 deletions(-) diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index 49c86eb8..eb393e81 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -2063,13 +2063,11 @@ else if( row < 0 ) public void jumpToNextLandmark() { - System.out.println("warp to next"); jumpToLandmarkRelative( 1 ); } public void jumpToPrevLandmark() { - System.out.println("warp to prev"); jumpToLandmarkRelative( -1 ); } diff --git a/src/main/java/bigwarp/BigWarpActions.java b/src/main/java/bigwarp/BigWarpActions.java index 83a76790..54c559b2 100755 --- a/src/main/java/bigwarp/BigWarpActions.java +++ b/src/main/java/bigwarp/BigWarpActions.java @@ -655,7 +655,7 @@ public static ActionMap createActionMapViewer( final BigWarp< ? > bw ) new ResetActiveViewerAction( bw ).put( actionMap ); new AlignViewerPanelAction( bw, AlignViewerPanelAction.TYPE.ACTIVE_TO_OTHER ).put( actionMap ); new AlignViewerPanelAction( bw, AlignViewerPanelAction.TYPE.OTHER_TO_ACTIVE ).put( actionMap ); - new WarpToSelectedAction( bw ).put( actionMap ); + new JumpToSelectedAction( bw ).put( actionMap ); new JumpToNextAction( bw, true ).put( actionMap ); new JumpToNextAction( bw, false ).put( actionMap ); new JumpToNearest( bw ).put( actionMap ); @@ -1403,11 +1403,11 @@ public void actionPerformed( final ActionEvent e ) } } - public static class WarpToSelectedAction extends AbstractNamedAction + public static class JumpToSelectedAction extends AbstractNamedAction { final BigWarp< ? > bw; - public WarpToSelectedAction( final BigWarp< ? > bw ) + public JumpToSelectedAction( final BigWarp< ? > bw ) { super( JUMP_TO_SELECTED_POINT ); this.bw = bw; @@ -1416,16 +1416,7 @@ public WarpToSelectedAction( final BigWarp< ? > bw ) @Override public void actionPerformed( ActionEvent e ) { - final int[] selectedRows = bw.getLandmarkPanel().getJTable().getSelectedRows(); - - int row = 0; - if( selectedRows.length > 0 ) - row = selectedRows[ 0 ]; - - if( bw.getViewerFrameP().isActive() ) - bw.jumpToLandmark( row, bw.getViewerFrameP().getViewerPanel() ); - else - bw.jumpToLandmark( row, bw.getViewerFrameQ().getViewerPanel() ); + bw.jumpToSelectedLandmark(); } private static final long serialVersionUID = 5233843444920094805L; @@ -1443,10 +1434,7 @@ public JumpToNearest( final BigWarp< ? > bw ) @Override public void actionPerformed( ActionEvent e ) { - if( bw.getViewerFrameP().isActive() ) - bw.jumpToNearestLandmark( bw.getViewerFrameP().getViewerPanel() ); - else - bw.jumpToNearestLandmark( bw.getViewerFrameQ().getViewerPanel() ); + bw.jumpToNearestLandmark(); } private static final long serialVersionUID = 3244181492305479433L; } @@ -1458,7 +1446,7 @@ public static class JumpToNextAction extends AbstractNamedAction public JumpToNextAction( final BigWarp< ? > bw, boolean fwd ) { - super( String.format( JUMP_TO_NEXT_POINT, fwd) ); + super( fwd ? JUMP_TO_NEXT_POINT : JUMP_TO_PREV_POINT ); this.bw = bw; if( fwd ) inc = 1; @@ -1469,37 +1457,7 @@ public JumpToNextAction( final BigWarp< ? > bw, boolean fwd ) @Override public void actionPerformed( ActionEvent e ) { - if ( bw.landmarkModel.getRowCount() < 1 ) - { - bw.message.showMessage( "No landmarks found." ); - return; - } - - final int[] selectedRows = bw.getLandmarkPanel().getJTable().getSelectedRows(); - - int row = 0; - if( selectedRows.length > 0 ) - row = selectedRows[ selectedRows.length - 1 ]; - - row = row + inc; // increment to get the *next* row - - // wrap to start if necessary - if( row >= bw.getLandmarkPanel().getTableModel().getRowCount() ) - row = 0; - else if( row < 0 ) - row = bw.getLandmarkPanel().getTableModel().getRowCount() - 1; - - // select new row - bw.getLandmarkPanel().getJTable().setRowSelectionInterval( row, row ); - - if( bw.getViewerFrameP().isActive() ) - { - bw.jumpToLandmark( row, bw.getViewerFrameP().getViewerPanel() ); - } - else - { - bw.jumpToLandmark( row, bw.getViewerFrameQ().getViewerPanel() ); - } + bw.jumpToLandmarkRelative(inc); } private static final long serialVersionUID = 8515568118251877405L; } From 8c52686afa47687c33243fd7a652573dcc004add Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Fri, 6 Oct 2023 16:47:39 -0400 Subject: [PATCH 275/282] style: bwViewerPanel cleanup --- src/main/java/bdv/viewer/BigWarpViewerPanel.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index 63495cb5..ceb898d6 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -77,11 +77,13 @@ public class BigWarpViewerPanel extends ViewerPanel ViewerOptions options; + @SuppressWarnings("rawtypes") public BigWarpViewerPanel( final BigWarpData bwData , final BigWarpViewerSettings viewerSettings, final CacheControl cache, boolean isMoving ) { this( bwData, viewerSettings, cache, BigWarpViewerOptions.options(), isMoving ); } + @SuppressWarnings("unchecked") public BigWarpViewerPanel( final BigWarpData bwData, final BigWarpViewerSettings viewerSettings, final CacheControl cache, final BigWarpViewerOptions optional, boolean isMoving ) { // TODO compiler complains if the first argument is 'final BigWarpData bwData' @@ -97,7 +99,6 @@ public BigWarpViewerPanel( final BigWarpData bwData, final BigWarpViewerSettings overlay.paint( ( Graphics2D ) g ); } if ( dragOverlay != null ) { - //dragOverlay.setViewerState( state ); dragOverlay.paint( ( Graphics2D ) g ); } } ); @@ -213,14 +214,6 @@ public boolean isInFixedImageSpace() return true; else { - // final Source< ? > spimSource = bwData.getMovingSource( 0 ).getSpimSource(); - // final boolean isTransformed; - // if (spimSource instanceof WarpedSource) { - // isTransformed = ( ( WarpedSource< ? > ) spimSource ).isTransformed(); - // } else { - // isTransformed = false; - // } - // return !isMoving || isTransformed; return !isMoving || ( ( WarpedSource< ? > ) ( ( bwData.getMovingSource( 0 )).getSpimSource() ) ).isTransformed(); } } From dcaeab9298b82d75d4b28a0f43d4212706490156 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 9 Oct 2023 10:02:28 -0400 Subject: [PATCH 276/282] chore(ci): use xvfb --- .github/workflows/build-main.yml | 1 + .github/workflows/build-pr.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/build-main.yml b/.github/workflows/build-main.yml index 5ef56920..1653bc86 100644 --- a/.github/workflows/build-main.yml +++ b/.github/workflows/build-main.yml @@ -22,6 +22,7 @@ jobs: - name: Set up CI environment run: .github/setup.sh - name: Execute the build + uses: coactions/setup-xvfb@v1 run: .github/build.sh env: GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }} diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 925b5765..4b2c8473 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -20,4 +20,5 @@ jobs: - name: Set up CI environment run: .github/setup.sh - name: Execute the build + uses: coactions/setup-xvfb@v1 run: .github/build.sh From 1a2d63b427cdd7b876fd456b96c8f1195ea402cc Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 9 Oct 2023 10:08:13 -0400 Subject: [PATCH 277/282] chore(ci): gh action builds --- .github/workflows/build-main.yml | 3 ++- .github/workflows/build-pr.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-main.yml b/.github/workflows/build-main.yml index 1653bc86..884af70d 100644 --- a/.github/workflows/build-main.yml +++ b/.github/workflows/build-main.yml @@ -23,7 +23,8 @@ jobs: run: .github/setup.sh - name: Execute the build uses: coactions/setup-xvfb@v1 - run: .github/build.sh + with: + run: .github/build.sh env: GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 4b2c8473..f735d550 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -21,4 +21,5 @@ jobs: run: .github/setup.sh - name: Execute the build uses: coactions/setup-xvfb@v1 - run: .github/build.sh + with: + run: .github/build.sh From 536cfda508fd516734f682c25dc2b5faead13470 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 9 Oct 2023 11:59:43 -0400 Subject: [PATCH 278/282] chore(test): mvn test profiles * don't use xvfb * default profile does not run ui tests --- .github/workflows/build-main.yml | 4 +--- .github/workflows/build-pr.yml | 4 +--- pom.xml | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-main.yml b/.github/workflows/build-main.yml index 884af70d..5ef56920 100644 --- a/.github/workflows/build-main.yml +++ b/.github/workflows/build-main.yml @@ -22,9 +22,7 @@ jobs: - name: Set up CI environment run: .github/setup.sh - name: Execute the build - uses: coactions/setup-xvfb@v1 - with: - run: .github/build.sh + run: .github/build.sh env: GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index f735d550..925b5765 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -20,6 +20,4 @@ jobs: - name: Set up CI environment run: .github/setup.sh - name: Execute the build - uses: coactions/setup-xvfb@v1 - with: - run: .github/build.sh + run: .github/build.sh diff --git a/pom.xml b/pom.xml index a12e4470..c5897d9c 100644 --- a/pom.xml +++ b/pom.xml @@ -351,4 +351,38 @@ + + + + default + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/SerializationTest.java + + + + + + + + uiTests + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + From a4a8075dc1f481482f068d0c4e1828be945a7a90 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 9 Oct 2023 13:20:26 -0400 Subject: [PATCH 279/282] fix(test): url and dfield tests * avoid displaying result of dfield test * rm unused url parse tests --- .../ij/BigWarpToDeformationFieldPlugIn.java | 10 ++++--- src/test/java/bigwarp/url/UrlParseTest.java | 30 +++++++++---------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index 96fa5072..e67240b0 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -283,6 +283,7 @@ public static void runFromParameters( final DeformationFieldExportParameters par if ( params.size != null ) dims = params.size; + ImagePlus imp = null; if ( params.n5Base.isEmpty() ) { if( !bwTransform.isNonlinear() ) // is linear @@ -291,14 +292,16 @@ public static void runFromParameters( final DeformationFieldExportParameters par } else if ( params.inverseOption.equals( INVERSE_OPTIONS.BOTH.toString() ) ) { - toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), false, params.virtual, params.size, params.spacing, params.nThreads ); - toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), true, params.virtual, params.size, params.spacing, params.nThreads ); + imp = toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), false, params.virtual, params.size, params.spacing, params.nThreads ); + imp = toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), true, params.virtual, params.size, params.spacing, params.nThreads ); } else { final boolean inverse = params.inverseOption.equals( INVERSE_OPTIONS.INVERSE.toString() ); - toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), inverse, params.virtual, params.size, params.spacing, params.nThreads ); + imp = toImagePlus( data, ltm, bwTransform, params.ignoreAffine, params.flatten(), inverse, params.virtual, params.size, params.spacing, params.nThreads ); } + if( imp != null ) + imp.show(); } else { @@ -463,7 +466,6 @@ else if ( nd == 3 ) dfieldIp.getCalibration().zOrigin = offset[ 2 ]; } - dfieldIp.show(); return dfieldIp; } diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index 43582614..a54bbedc 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -117,22 +117,22 @@ public void testUrlSources() throws SpimDataException, URISyntaxException, IOExc } } - @Test - public void testUrlTransforms() - { - final String n5Path = new File( "src/test/resources/bigwarp/url/transformTest.n5" ).getAbsolutePath(); - - final String s0Url = n5Path + "?ant&transform=[0]"; - final String s0DefaultUrl = n5Path + "?ant&transform=[0]"; - +// @Test +// public void testUrlTransforms() +// { +// final String n5Path = new File( "src/test/resources/bigwarp/url/transformTest.n5" ).getAbsolutePath(); +// +// final String s0Url = n5Path + "?ant&transform=[0]"; +// final String s0DefaultUrl = n5Path + "?ant&transform=[0]"; +// // TODO when we're ready // final Object s0 = loadTransformFromUrl( s0Url ); // final Object s0Default = loadTransformFromUrl( s0DefaultUrl ); - +// // assertNotNull( s0 ); // assertNotNull( s0Default ); // assertEquals( s0, s0Default ); - } +// } @Test public < T extends NativeType > void n5FileUrlEquivalencyTest() throws IOException, SpimDataException, URISyntaxException @@ -166,11 +166,11 @@ public < T extends NativeType > void n5FileUrlEquivalencyTest() throws IOExce } } - private Object loadTransformFromUrl( final String url ) - { - // TODO Caleb will remove me and replace calls to me with something real - return null; - } +// private Object loadTransformFromUrl( final String url ) +// { +// // TODO Caleb will remove me and replace calls to me with something real +// return null; +// } private < T extends NativeType > Source< ? > loadSourceFromUri( final String uri ) throws SpimDataException, URISyntaxException, IOException { From 0cf39d566223249521fe1396bc3877e70e9a92a2 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 9 Oct 2023 13:47:10 -0400 Subject: [PATCH 280/282] test: try to avoid headless exception in UriParseTest * put test data in resources folder, don't generate every time * IJ.save seemed to be causing headless exception --- src/test/java/bigwarp/BigWarpTestUtils.java | 21 ++++++++++-------- src/test/java/bigwarp/url/UrlParseTest.java | 7 +++--- src/test/resources/testdata/img2d.png | Bin 0 -> 77 bytes src/test/resources/testdata/img3d.tif | Bin 0 -> 859 bytes .../testdata/imgDir/imgDir3d0000.tif | Bin 0 -> 224 bytes .../testdata/imgDir/imgDir3d0001.tif | Bin 0 -> 224 bytes .../testdata/imgDir/imgDir3d0002.tif | Bin 0 -> 224 bytes .../testdata/imgDir/imgDir3d0003.tif | Bin 0 -> 224 bytes 8 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 src/test/resources/testdata/img2d.png create mode 100644 src/test/resources/testdata/img3d.tif create mode 100644 src/test/resources/testdata/imgDir/imgDir3d0000.tif create mode 100644 src/test/resources/testdata/imgDir/imgDir3d0001.tif create mode 100644 src/test/resources/testdata/imgDir/imgDir3d0002.tif create mode 100644 src/test/resources/testdata/imgDir/imgDir3d0003.tif diff --git a/src/test/java/bigwarp/BigWarpTestUtils.java b/src/test/java/bigwarp/BigWarpTestUtils.java index 55157388..49e45de6 100644 --- a/src/test/java/bigwarp/BigWarpTestUtils.java +++ b/src/test/java/bigwarp/BigWarpTestUtils.java @@ -59,13 +59,15 @@ public static String createTemp3DImage( String title, String format ) throw new RuntimeException( e ); } - return createTemp3DImage( tmpImgPath ); + return createTemp3DImage( format, tmpImgPath ); } - private static String create3DImage( final Path tmpImgPath ) throws IOException + private static String create3DImage( final String format, final Path tmpImgPath ) throws IOException { final ImagePlus img3d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 4, NewImage.FILL_RAMP ); - IJ.save( img3d, tmpImgPath.toFile().getCanonicalPath() ); + System.out.println( tmpImgPath.toString()); + IJ.saveAs(img3d, format, tmpImgPath.toString()); + tmpImgPath.toFile().deleteOnExit(); return tmpImgPath.toString(); } @@ -76,11 +78,11 @@ private static String create3DImage( final Path tmpImgPath ) throws IOException * @param imagePath of the temporary image file * @return the path to the temporary image file */ - public static String createTemp3DImage( Path imagePath ) + public static String createTemp3DImage( final String format, Path imagePath ) { try { - return create3DImage( imagePath ); + return create3DImage( format, imagePath ); } catch ( final Exception e ) { @@ -90,10 +92,11 @@ public static String createTemp3DImage( Path imagePath ) } } - private static String create2DImage( final Path tmpImgPath ) throws IOException + private static String create2DImage( final String format, final Path tmpImgPath ) throws IOException { final ImagePlus img2d = NewImage.createByteImage( tmpImgPath.getFileName().toString(), 8, 8, 1, NewImage.FILL_RAMP ); - IJ.save( img2d, tmpImgPath.toFile().getCanonicalPath() ); + System.out.println( tmpImgPath.toString()); + IJ.saveAs(img2d, format, tmpImgPath.toString()); tmpImgPath.toFile().deleteOnExit(); return tmpImgPath.toString(); } @@ -114,7 +117,7 @@ public static String createTemp2DImage( String title, String format ) tmpImg = Files.createTempFile( title, "." + format ); //noinspection ResultOfMethodCallIgnored tmpImg.toFile().delete(); - return create2DImage( tmpImg); + return create2DImage( format, tmpImg ); } catch ( final Exception e ) { @@ -242,7 +245,7 @@ static < T extends NativeType > BigWarp< T > createBigWarp(String sourcePath, { final BigWarpData< T > data = BigWarpInit.initData(); if (sourcePath != null) { - createTemp3DImage( Paths.get(sourcePath) ); + createTemp3DImage( "tif", Paths.get(sourcePath) ); } final String tmpPath = sourcePath != null ? sourcePath : createTemp3DImage( "img", "tif" ); diff --git a/src/test/java/bigwarp/url/UrlParseTest.java b/src/test/java/bigwarp/url/UrlParseTest.java index a54bbedc..388a8e84 100644 --- a/src/test/java/bigwarp/url/UrlParseTest.java +++ b/src/test/java/bigwarp/url/UrlParseTest.java @@ -25,18 +25,17 @@ import bdv.viewer.Source; import bigwarp.BigWarpData; import bigwarp.BigWarpInit; -import bigwarp.BigWarpTestUtils; import bigwarp.source.SourceInfo; import mpicbg.spim.data.SpimDataException; import net.imglib2.type.NativeType; public class UrlParseTest { - public static final String TIFF_FILE_3D = BigWarpTestUtils.createTemp3DImage( "img3d", "tif" ); + public static final String TIFF_FILE_3D = "src/test/resources/testdata/img3d.tif"; - public static final String PNG_FILE_2D = BigWarpTestUtils.createTemp2DImage( "img2d", "png" ); + public static final String PNG_FILE_2D = "src/test/resources/testdata/img2d.png"; - public static final String TIFF_STACK_DIR = BigWarpTestUtils.createTemp3DImageStack( "imgDir3d" ); + public static final String TIFF_STACK_DIR = "src/test/resources/testdata/imgDir"; private Class< N5FSReader > n5Clazz; diff --git a/src/test/resources/testdata/img2d.png b/src/test/resources/testdata/img2d.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a05303e04a1283cc3290d3e607f6bf63380390 GIT binary patch literal 77 zcmeAS@N?(olHy`uVBq!ia0vp^93TuL7#^lP3xlE#$@;uPDOa24ldCW9F{`S}I5 zX^A<-say;U3JwVk3l2OOsWfdP?Jtp$=FUXx Date: Mon, 9 Oct 2023 14:52:31 -0400 Subject: [PATCH 281/282] feat: bwViewerFrame add getTriggerBindings --- src/main/java/bdv/gui/BigWarpViewerFrame.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index bd2a2afb..32c52598 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -230,6 +230,11 @@ public InputActionBindings getKeybindings() return keybindings; } + public TriggerBehaviourBindings getTriggerBindings() { + + return triggerbindings; + } + public void setTransformEnabled( final boolean enabled ) { viewer.setTransformEnabled( enabled ); From 76f766bcb6344c6aa46bc18969370857014bd054 Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 9 Oct 2023 14:52:50 -0400 Subject: [PATCH 282/282] doc: javadoc corrections and updates --- src/main/java/bdv/gui/BigWarpInitDialog.java | 5 +-- src/main/java/bdv/gui/BigWarpViewerFrame.java | 2 +- .../ij/BigWarpToDeformationFieldPlugIn.java | 8 ++-- .../java/bdv/viewer/BigWarpViewerPanel.java | 3 +- src/main/java/bigwarp/BigWarp.java | 7 ++-- src/main/java/bigwarp/BigWarpData.java | 2 +- src/main/java/bigwarp/BigWarpInit.java | 39 ++++++++++--------- .../bigwarp/landmarks/LandmarkTableModel.java | 7 ++-- ...teauSphericalMaskRealRandomAccessible.java | 22 +++++------ .../utility/geom/BoundingSphereRitter.java | 28 ++++++------- .../org/janelia/utility/geom/GeomUtils.java | 36 ++++++++--------- 11 files changed, 80 insertions(+), 79 deletions(-) diff --git a/src/main/java/bdv/gui/BigWarpInitDialog.java b/src/main/java/bdv/gui/BigWarpInitDialog.java index a8fa4222..72e7829c 100644 --- a/src/main/java/bdv/gui/BigWarpInitDialog.java +++ b/src/main/java/bdv/gui/BigWarpInitDialog.java @@ -788,10 +788,7 @@ protected void updateImagePlusDropdown() } /** - * Adds first two image plus images to the sourc list automatically. - * - * Make sure to call {@link updateImagePlusDropdown} before calling this - * method. + * Adds first two image plus images to the source list automatically. */ public void initializeImagePlusSources() { diff --git a/src/main/java/bdv/gui/BigWarpViewerFrame.java b/src/main/java/bdv/gui/BigWarpViewerFrame.java index 32c52598..e892e9cc 100644 --- a/src/main/java/bdv/gui/BigWarpViewerFrame.java +++ b/src/main/java/bdv/gui/BigWarpViewerFrame.java @@ -246,7 +246,7 @@ public void setTransformEnabled( final boolean enabled ) /** * Get {@code Behaviours} hook where TransformEventHandler behaviours are installed. - * This is installed in {@link #getTriggerbindings} with the id "transform". + * This is installed in {@link #getTriggerBindings} with the id "transform". * The hook can be used to update the keymap and install additional behaviours. */ public Behaviours getTransformBehaviours() diff --git a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java index e67240b0..1bceb401 100644 --- a/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java +++ b/src/main/java/bdv/ij/BigWarpToDeformationFieldPlugIn.java @@ -474,7 +474,7 @@ else if ( nd == 3 ) * * @param data the bigwarp data storing the fixed transformations * @param transform the current transformation - * @param concat concatenate the current with fixed transformation + * @param concatPreTransforms concatenate the current with fixed transformation * @param ignoreAffine whether the output should include the affine part of the transformation * @return the transformation */ @@ -857,9 +857,11 @@ private static RealTransform getTpsAffineToggle( final BigWarpTransform bwXfm, f } /** - * @param tps + * Get the affine part of a thin-plate spline transform. The affine will be 2D (3D) + * if the transformation is 2D (3D). * - * @return + * @param tps the {@link ThinPlateR2LogRSplineKernelTransform} instance + * @return the {@link AffineGet} instance. * * @deprecated Use {@link BigWarpTransform} method instead */ diff --git a/src/main/java/bdv/viewer/BigWarpViewerPanel.java b/src/main/java/bdv/viewer/BigWarpViewerPanel.java index ceb898d6..de353058 100644 --- a/src/main/java/bdv/viewer/BigWarpViewerPanel.java +++ b/src/main/java/bdv/viewer/BigWarpViewerPanel.java @@ -29,6 +29,7 @@ import bdv.viewer.animate.RotationAnimator; import bdv.viewer.animate.SimilarityTransformAnimator3D; import bdv.viewer.overlay.BigWarpMaskSphereOverlay; +import bigwarp.BigWarp; import bigwarp.BigWarpData; import bigwarp.source.SourceInfo; import bigwarp.util.Rotation2DHelpers; @@ -156,7 +157,7 @@ public void setHoveredIndex( int index ) * Makes the first group contain all the moving images and the second group * contain all the fixed images *

- * Deprecated. use {@link BigWarp#createMovingTargetGroup()} + * @deprecated use {@link BigWarp#createMovingTargetGroups} * * @return the number sources in the moving group */ diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java index eb393e81..e80ed662 100755 --- a/src/main/java/bigwarp/BigWarp.java +++ b/src/main/java/bigwarp/BigWarp.java @@ -3734,8 +3734,9 @@ public BoundingBoxEstimation getBoxEstimation() } /** - * Use getTps, getTpsBase, or getTransformation instead - * @return + * @deprecated Use getTps, getTpsBase, or getTransformation instead + * + * @return the {@link ThinPlateR2LogRSplineKernelTransform} iinnstance */ @Deprecated public ThinPlateR2LogRSplineKernelTransform getTransform() @@ -3980,7 +3981,7 @@ public File getBigwarpSettingsFolder() /** * Returns the {@link BigWarpAutoSaver}. * - * @return + * @return the {@link BigWarpAutoSaver} instance. */ public BigWarpAutoSaver getAutoSaver() { diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java index c55aac5a..1d5a3465 100644 --- a/src/main/java/bigwarp/BigWarpData.java +++ b/src/main/java/bigwarp/BigWarpData.java @@ -225,7 +225,7 @@ public boolean isMoving( SourceAndConverter sac ) { } /** - * @Deprecated only handled maintaing the moving lists, now a no-op + * @deprecated only handled maintaing the moving lists, now a no-op */ @Deprecated public void wrapUp() diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java index e60fe6a9..13144358 100644 --- a/src/main/java/bigwarp/BigWarpInit.java +++ b/src/main/java/bigwarp/BigWarpInit.java @@ -257,12 +257,12 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T > } /** - * @return + * Initialize BigWarp. * - * @Deprecated Use - * {@link #createSources(BigWarpData, ImagePlus, int, int, boolean)} - * instaed, and pass output to - * {@link #add(BigWarpData, LinkedHashMap, RealTransform)} + * @return the number of sources + * + * @deprecated Use {@code createSources(BigWarpData,ImagePlus,int,int,boolean)} instead, and pass output to + * {@code add(BigWarpData,LinkedHashMap)} */ @Deprecated public static < T > int add( BigWarpData< T > bwdata, ImagePlus ip, int setupId, int numTimepoints, boolean isMoving ) @@ -315,9 +315,11 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW } /** - * @return + * Initialize BigWarp. + * + * @return a {@link BigWarpData} instance * - * @Deprecated Use the output from one of the + * @deprecated Use the output from one of the * {{@link #createSources(BigWarpData, String, int, boolean)}} * to call {{@link #add(BigWarpData, LinkedHashMap)}} instead */ @@ -346,12 +348,13 @@ public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap } /** - * @return + * Initialize BigWarp. * - * @Deprecated Use the output from one of the - * {{@link #createSources(BigWarpData, String, int, boolean)}} - * to call - * {{@link #add(BigWarpData, LinkedHashMap, RealTransform)}} + * @return a {@link BigWarpData} instance + * + * @deprecated Use the output from one of the + * {{@code createSources(BigWarpData, String, int, boolean)}} + * to call {{@code add(BigWarpData, LinkedHashMap, RealTransform)}} * instead */ @SuppressWarnings( { "unchecked", "rawtypes" } ) @@ -582,13 +585,13 @@ else if ( new File( uri ).isDirectory() ) } /** - * @return + * Initialize BigWarp. + * + * @return a {@link SpimData} instance * - * @Deprecated Use output from - * {@link #createSources(BigWarpData, boolean, int, String, String)} - * and add with - * {@link #add(BigWarpData, LinkedHashMap, RealTransform)} - * instead. + * @deprecated Use output from + * {@code createSources(BigWarpData, boolean, int, String, String)} and add with + * {@code add(BigWarpData, LinkedHashMap, RealTransform)} instead. */ @Deprecated public static < T > SpimData addToData( final BigWarpData< T > bwdata, final boolean isMoving, final int setupId, final String rootPath, final String dataset ) diff --git a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java index 76f82674..37540aa1 100644 --- a/src/main/java/bigwarp/landmarks/LandmarkTableModel.java +++ b/src/main/java/bigwarp/landmarks/LandmarkTableModel.java @@ -1267,9 +1267,10 @@ public void loadCsv( File f, boolean invert ) throws IOException } /** - * Loads this table from a file - * @param f the file - * @param invert invert the moving and target point sets + * Loads this table from a file. + * + * @param invert if true, the moving and target point sets are inverted + * @param rows a list of strings containing rows of a csv file * @throws IOException an exception */ protected void loadCsvHelper( boolean invert, final List rows ) throws IOException diff --git a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java index 24abafb8..7f2f2aed 100644 --- a/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java +++ b/src/main/java/bigwarp/source/PlateauSphericalMaskRealRandomAccessible.java @@ -101,14 +101,14 @@ public void setOverlays( final List< BigWarpMaskSphereOverlay > overlays ) { public static void main( String[] args ) { - long S = 50; - double[] center = new double[] { S, S, S }; - RealPoint pt = RealPoint.wrap( center ); + final long S = 50; + final double[] center = new double[] { S, S, S }; + final RealPoint pt = RealPoint.wrap( center ); - PlateauSphericalMaskRealRandomAccessible img = new PlateauSphericalMaskRealRandomAccessible( pt ); + final PlateauSphericalMaskRealRandomAccessible img = new PlateauSphericalMaskRealRandomAccessible( pt ); img.setRadius( 10 ); img.setSigma( 10 ); - Interval interval = Intervals.createMinSize( 0, 0, 0, 2 * S, 2 * S, 2 * S ); + final Interval interval = Intervals.createMinSize( 0, 0, 0, 2 * S, 2 * S, 2 * S ); // //// BdvOptions options = BdvOptions.options().screenScales( new double[] { 1 } ); // BdvOptions options = BdvOptions.options(); @@ -127,7 +127,7 @@ public static void main( String[] args ) //// bdv.getBdvHandle().getViewerPanel().getDisplay().addMouseListener( ml ); // double x = 50; - RealRandomAccess< DoubleType > access = img.realRandomAccess(); + final RealRandomAccess< DoubleType > access = img.realRandomAccess(); access.setPosition( center ); while ( x < 100 ) { @@ -337,12 +337,12 @@ public void fromJson( JsonObject json ) } /** - * Re.turns the sigma that makes a Gaussian shape most like a cosine with period T. + * Returns the sigma that makes a Gaussian shape most like a cosine with period T. *

* see https://gist.github.com/bogovicj/d212b236868c76798edfd11150b2c9a0 * * @param T the cosine period - * @return + * @return the appropriate sigma */ public static double gaussSigma( double T ) { @@ -363,7 +363,7 @@ public GaussianFalloff( PlateauSphericalMaskRealRandomAccessible mask ) public void accept( RealLocalizable x, DoubleType v ) { v.setZero(); - double r2 = squaredDistance( x, mask.center ); + final double r2 = squaredDistance( x, mask.center ); if ( r2 <= mask.plateauR2 ) v.setOne(); else @@ -403,7 +403,7 @@ else if ( r >= mask.plateauR + mask.sigma ) // final double t = (r2 - plateauR2); // final double r = Math.sqrt( r2 ); final double t = ( r - mask.plateauR ); - double val = 0.5 + 0.5 * Math.cos( t * PI / mask.sigma ); + final double val = 0.5 + 0.5 * Math.cos( t * PI / mask.sigma ); v.set( val ); } } @@ -463,7 +463,7 @@ public void write( final JsonWriter out, final RealPoint value ) throws IOExcept public RealPoint read( final JsonReader in ) throws IOException { in.beginArray(); - ArrayList< Double > pos = new ArrayList<>(); + final ArrayList< Double > pos = new ArrayList<>(); while ( in.hasNext() ) { pos.add( in.nextDouble() ); diff --git a/src/main/java/org/janelia/utility/geom/BoundingSphereRitter.java b/src/main/java/org/janelia/utility/geom/BoundingSphereRitter.java index 17a21bfa..95ced48a 100644 --- a/src/main/java/org/janelia/utility/geom/BoundingSphereRitter.java +++ b/src/main/java/org/janelia/utility/geom/BoundingSphereRitter.java @@ -3,10 +3,10 @@ import java.util.List; /** - * Estimates the smallest sphere that bounds given points. + * Estimates the smallest sphere that bounds given points. *

- * Ritter, Jack (1990), "An efficient bounding sphere", in Glassner, Andrew S. (ed.), Graphics Gems, San Diego, CA, US: Academic Press Professional, Inc., pp. 301–303, - * + * Ritter, Jack (1990), "An efficient bounding sphere", in Glassner, Andrew S. (ed.), Graphics Gems, San Diego, CA, US: Academic Press Professional, Inc., pp. 301–303, + * * @author John Bogovic * */ @@ -14,9 +14,9 @@ public class BoundingSphereRitter { /** - * Returns an estimate of the smallest {@link ImmutableSphere} that contains the input points. - * - * @param points a collection of points + * Returns an estimate of the smallest {@link Sphere} that contains the input points. + * + * @param points a collection of points * @return the bounding sphere */ public static Sphere boundingSphere( final List points ) @@ -45,13 +45,13 @@ public static Sphere boundingSphere( final List points ) for ( int d = 0; d < nd; d++ ) center[d] = 0.5 * ( x[d] + y[d] ); - Sphere sph = new Sphere( center, Math.sqrt( maxSqrDist ) / 2 ); + final Sphere sph = new Sphere( center, Math.sqrt( maxSqrDist ) / 2 ); boolean allCovered = false; int k = 0; while( !allCovered && k < 5) { allCovered = false; - for( double[] p : points ) + for( final double[] p : points ) { allCovered |= updateSphere( sph, p ); } @@ -59,10 +59,10 @@ public static Sphere boundingSphere( final List points ) } return sph; } - + /** * return the point in point farthest from p - * + * * @param points a list of points * @param p a base point * @return the point farthest from p @@ -82,19 +82,19 @@ public static double[] furthestFrom( final List points, double[] p ) } return points.get( maxIndex ); } - + /** * Changes the value of the input sphere such that it contains the given point p. * Returns true if the sphere was modified. - * + * * @param sphere * @param p * @return true if the sphere was changed */ public static boolean updateSphere( final Sphere sphere, final double[] p ) { - double sqrDist = GeomUtils.squaredDistance( sphere.getCenterArray(), p ); - double r = sphere.getRadius(); + final double sqrDist = GeomUtils.squaredDistance( sphere.getCenterArray(), p ); + final double r = sphere.getRadius(); if ( sqrDist <= r*r ) { return false; diff --git a/src/main/java/org/janelia/utility/geom/GeomUtils.java b/src/main/java/org/janelia/utility/geom/GeomUtils.java index affef38d..2917be9f 100644 --- a/src/main/java/org/janelia/utility/geom/GeomUtils.java +++ b/src/main/java/org/janelia/utility/geom/GeomUtils.java @@ -10,10 +10,10 @@ import net.imglib2.util.ValuePair; public class GeomUtils { - + /** * Finds the parameters of the smallest hypersphere containing the points. - * + * * @param pts a list of points * @return a pair containing the center and the squared distance */ @@ -25,7 +25,7 @@ public static Pair smallestEnclosingSphere( List pt // find pair of points with the largest distance for( int i = 0; i < pts.size(); i++) for( int j = i+1; j < pts.size(); j++) { - double d = squaredDistance( pts.get( i ), pts.get( j )); + final double d = squaredDistance( pts.get( i ), pts.get( j )); if( d < maxSqrDist ) { maxSqrDist = d; @@ -33,11 +33,11 @@ public static Pair smallestEnclosingSphere( List pt q = pts.get( j ); } } - + final RealPoint center = new RealPoint( p.numDimensions()); for( int d = 0; d < p.numDimensions(); d++ ) { - center.setPosition( + center.setPosition( 0.5 * p.getDoublePosition(d) + 0.5 * q.getDoublePosition(d), d ); } @@ -63,7 +63,7 @@ final public static double squaredDistance( final RealLocalizable position1, fin } return dist; - } + } final public static double squaredDistance( final double[] position1, final double[] position2 ) { @@ -86,9 +86,9 @@ public static AffineTransform2D fromScalesAngle( double... p ) public static AffineTransform2D fromScalesAngle( double sx, double sy, double tht ) { - AffineTransform2D t = new AffineTransform2D(); - double cosTht = Math.cos( tht ); - double sinTht = Math.sin( tht ); + final AffineTransform2D t = new AffineTransform2D(); + final double cosTht = Math.cos( tht ); + final double sinTht = Math.sin( tht ); t.set( sx * cosTht, -sx * sinTht, 0.0, sy * sinTht, sy * cosTht, 0.0 ); @@ -102,7 +102,7 @@ public static AffineTransform2D fromScalesAngle( double sx, double sy, double th * tht : the angle * * @param t the transformations - * @return + * @return the scales and angle [sx, sy, tht] */ public static double[] scalesAngle( final AffineTransform2D t ) { @@ -119,12 +119,6 @@ public static double[] scalesAngle( final AffineTransform2D t ) final double sy = sd * mcd; final double tht = Math.atan2( -b, a ); return new double[] { sx, sy, tht }; - -// final double tht1 = Math.atan2( -b, a ); -// final double tht2 = Math.atan2( c, d ); -// System.out.println( "tht1 : " + tht1 ); -// System.out.println( "tht2 : " + tht2 ); -// return new double[] { sx, sy, tht1, tht2 }; } /** @@ -134,12 +128,14 @@ public static double[] scalesAngle( final AffineTransform2D t ) * tht : the angle * * @param t the transformations - * @return + * @return the scales and angle [sx, sy, tht] */ - public static double[] scalesAngle( final AffineTransform2D t, final double[] center ) + public static double[] scalesAngle( final AffineTransform2D t, final double[] center ) { - final double a = t.get( 0, 0 ); final double b = t.get( 0, 1 ); - final double c = t.get( 1, 0 ); final double d = t.get( 1, 1 ); + // TODO why does the center arg do nothing? + + final double a = t.get( 0, 0 ); final double b = t.get( 0, 1 ); + final double c = t.get( 1, 0 ); final double d = t.get( 1, 1 ); // don't allow flips // final double sa = a >= 0 ? 1 : -1;