diff --git a/pom.xml b/pom.xml
index fd6f1c07..11b9f280 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,11 +118,11 @@
BigWarp plugin for Fiji.
**/resources/*.xml
- 7.1.0
+ 7.1.1
4.0.3
0.15.0
1.0.0-beta-18
- 0.15.3
+ 0.16.0
10.6.0
1.0.0-beta-36
@@ -131,15 +131,11 @@
3.0.4
3.3.0
- 7.0.1
+ 7.0.2
4.2.1
- 1.1.1
- 2.2.0
4.1.1
- 1.3.5
1.6.0
- 4.2.1
- 6.1.1
+ 4.2.3
0.41
0.41
diff --git a/scripts/BigWarp_N5.groovy b/scripts/BigWarp_N5.groovy
index 1816e94a..07737986 100644
--- a/scripts/BigWarp_N5.groovy
+++ b/scripts/BigWarp_N5.groovy
@@ -154,7 +154,7 @@ def makeSources( String n5Base, String[] datasets )
source = new RandomAccessibleIntervalMipmapSource(
images,
- Util.getTypeFromInterval(images[0]),
+ images[0].getType(),
scales,
new mpicbg.spim.data.sequence.FinalVoxelDimensions( "pix", 1, 1, 1),
"source");
diff --git a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java
index e23b13a9..7052c03a 100644
--- a/src/main/java/bdv/ij/ApplyBigwarpPlugin.java
+++ b/src/main/java/bdv/ij/ApplyBigwarpPlugin.java
@@ -85,7 +85,7 @@
import net.imglib2.view.Views;
/**
- * Apply a bigwarp transform to a 2d or 3d ImagePlus
+ * Apply a Bigwarp transform to a 2d or 3d ImagePlus
*/
public class ApplyBigwarpPlugin implements PlugIn
{
@@ -97,7 +97,11 @@ public class ApplyBigwarpPlugin implements PlugIn
public static final String SPECIFIED_PHYSICAL = "Specified (physical units)";
public static final String SPECIFIED_PIXEL = "Specified (pixel units)";
public static final String LANDMARK_POINTS = "Landmark points";
+
+ @Deprecated
public static final String LANDMARK_POINT_CUBE_PHYSICAL = "Landmark point cube (physical units)";
+
+ @Deprecated
public static final String LANDMARK_POINT_CUBE_PIXEL = "Landmark point cube (pixel units)";
public static void main( final String[] args )
@@ -135,32 +139,6 @@ public static boolean validateInput(
return true;
}
- public static double[] getResolution(
- final Source< ? > source,
- final String resolutionOption,
- final double[] resolutionSpec )
- {
- if( ( source == null ) )
- {
- System.err.println("Requested target resolution but target image is missing.");
- return null;
- }
-
- final double[] res = resolutionFromSource( source );
-
- /*
- * Maybe the below will work in the future, but it does not right now
- * ( April 2021) in part because theres no way to set the VoxelDimensions for a
- * bdv.util.RandomAccessibleIntervalSource
- */
-// VoxelDimensions voxdims = source.getVoxelDimensions();
-// if( voxdims == null )
-// Arrays.fill( res, 1.0 );
-// else
-// voxdims.dimensions( res );
-
- return res;
- }
public static String getUnit( final BigWarpData> bwData,
final String resolutionOption )
@@ -390,6 +368,19 @@ else if( fieldOfViewOption.equals( UNION_TARGET_MOVING ))
return null;
}
+ public static double[] getResolution(
+ final Source< ? > source,
+ final String resolutionOption,
+ final double[] resolutionSpec )
+ {
+ if( ( source == null ) )
+ {
+ System.err.println("Requested target resolution but target image is missing.");
+ return null;
+ }
+ return resolutionFromSource( source );
+ }
+
public static double[] resolutionFromSource( final Source< ? > src )
{
final double[] res = new double[ 3 ];
@@ -503,7 +494,7 @@ public static List getPixelInterval(
out.add(new FinalInterval(min, max));
return out;
} else {
- System.out.println("Invalid fov spec, length : " + fovSpec.length);
+ System.err.println("Invalid fov spec, length : " + fovSpec.length);
return null;
}
} else if (fieldOfViewOption.equals(SPECIFIED_PHYSICAL)) {
@@ -527,14 +518,14 @@ public static List getPixelInterval(
final long[] max = new long[]{
(long)Math.floor((offsetSpec[0] + fovSpec[0]) / outputResolution[0]),
- (long)Math.floor((offsetSpec[0] + fovSpec[1]) / outputResolution[1]),
+ (long)Math.floor((offsetSpec[1] + fovSpec[1]) / outputResolution[1]),
(long)Math.floor((offsetSpec[2] + fovSpec[2]) / outputResolution[2])};
final ArrayList out = new ArrayList<>();
- out.add(new FinalInterval(min, max));
+ out.add(Intervals.zeroMin(new FinalInterval(min, max)));
return out;
} else {
- System.out.println("Invalid fov spec, length : " + fovSpec.length);
+ System.err.println("Invalid fov spec, length : " + fovSpec.length);
return null;
}
} else if (fieldOfViewOption.equals(LANDMARK_POINTS)) {
@@ -564,7 +555,6 @@ public static List getPixelInterval(
}
System.out.println("Estimated field of view using " + numPoints + " landmarks.");
-
// Make sure something naughty didn't happen
for (int d = 0; d < min.length; d++) {
if (min[d] == Long.MAX_VALUE) {
@@ -579,7 +569,7 @@ public static List getPixelInterval(
}
final ArrayList out = new ArrayList<>();
- out.add(new FinalInterval(min, max));
+ out.add(Intervals.zeroMin(new FinalInterval(min, max)));
return out;
} else if (fieldOfViewOption.equals(LANDMARK_POINT_CUBE_PHYSICAL)
|| fieldOfViewOption.equals(LANDMARK_POINT_CUBE_PIXEL)) {
@@ -667,14 +657,69 @@ public static List getMatchedPoints(
}
ptList.add( pt );
-
- System.out.println( "Using point with name : "
- + landmarks.getNames().get( i ) );
}
return ptList;
}
+ /**
+ * Get the offset in pixels given the output resolution and interval
+ *
+ * @param fieldOfViewOption the field of view option
+ * @param offsetSpec the offset specification
+ * @param ltm the {@link LandmarkTableModel}
+ * @param fieldOfViewPointFilter the landmark name filter for FOV estimation
+ * @param outputResolution the resolution of the output image
+ * @param targetSource the target source
+ * @return the offset in physical units
+ */
+ public static double[] getPhysicalOffset(
+ final String fieldOfViewOption,
+ final double[] offsetSpec,
+ final LandmarkTableModel ltm,
+ final String fieldOfViewPointFilter,
+ final double[] outputResolution,
+ final Source> targetSource )
+ {
+ final int nd = 3; // this okay even for 2D
+ final double[] offset = new double[ nd ];
+ if( fieldOfViewOption.equals( SPECIFIED_PIXEL ) )
+ {
+ System.arraycopy( offsetSpec, 0, offset, 0, offset.length );
+ return offset;
+ }
+ else if( fieldOfViewOption.equals( SPECIFIED_PHYSICAL ) )
+ {
+ for( int d = 0; d < nd; d++ ) {
+ offset[ d ] = offsetSpec[ d ] / outputResolution[ d ];
+ }
+ return offset;
+ }
+ else if( fieldOfViewOption.equals( LANDMARK_POINTS ) )
+ {
+ Arrays.fill(offset, Double.MAX_VALUE);
+ List pts = getMatchedPoints(ltm, fieldOfViewPointFilter);
+ for( int i = 0; i < pts.size(); i++ ) {
+ for( int d = 0; d < nd; d++ ) {
+ final double v = pts.get(i)[d];
+ offset[d] = v < offset[d] ? v : offset[d];
+ }
+ }
+ return offset;
+ }
+ else
+ {
+ final Interval outputInterval = targetSource.getSource(0, 0);
+ final AffineTransform3D tform = new AffineTransform3D();
+ targetSource.getSourceTransform(0, 0, tform);
+
+ // is using interval min overkill?
+ // or can I count on it always be at the origin?
+ tform.apply(outputInterval.minAsDoubleArray(), offset);
+ return offset;
+ }
+ }
+
/**
* Get the offset in pixels given the output resolution and interval
*
@@ -824,14 +869,87 @@ public static List apply(
final boolean wait,
final WriteDestinationOptions writeOpts) {
- final int numChannels = bwData.numMovingSources();
-
final InvertibleRealTransform invXfm = new BigWarpTransform( landmarks, tranformTypeOption ).getTransformation();
+ return apply(
+ bwData,
+ landmarks,
+ invXfm,
+ tranformTypeOption,
+ fieldOfViewOption,
+ fieldOfViewPointFilter,
+ bboxEst,
+ resolutionOption,
+ resolutionSpec,
+ fovSpec,
+ offsetSpec,
+ interp,
+ isVirtual,
+ nThreads,
+ wait,
+ writeOpts);
+ }
+
+ public static List apply(
+ final BigWarpData bwData,
+ final LandmarkTableModel landmarks,
+ final InvertibleRealTransform invXfm,
+ final String tranformTypeOption,
+ final String fieldOfViewOption,
+ final String fieldOfViewPointFilter,
+ final BoundingBoxEstimation bboxEst,
+ final String resolutionOption,
+ final double[] resolutionSpec,
+ final double[] fovSpec,
+ final double[] offsetSpec,
+ final Interpolation interp,
+ final boolean isVirtual,
+ final int nThreads,
+ final boolean wait,
+ final WriteDestinationOptions writeOpts) {
+
+ final boolean show = ( writeOpts == null || writeOpts.pathOrN5Root == null || writeOpts.pathOrN5Root.isEmpty());
+ return apply(bwData, landmarks, invXfm,
+ tranformTypeOption, fieldOfViewOption, fieldOfViewPointFilter, bboxEst,
+ resolutionOption, resolutionSpec, fovSpec, offsetSpec,
+ interp, isVirtual, nThreads, wait, writeOpts, show);
+ }
+
+ public static List apply(
+ final BigWarpData bwData,
+ final LandmarkTableModel landmarks,
+ final InvertibleRealTransform invXfm,
+ final String tranformTypeOption,
+ final String fieldOfViewOption,
+ final String fieldOfViewPointFilter,
+ final BoundingBoxEstimation bboxEst,
+ final String resolutionOption,
+ final double[] resolutionSpec,
+ final double[] fovSpec,
+ final double[] offsetSpec,
+ final Interpolation interp,
+ final boolean isVirtual,
+ final int nThreads,
+ final boolean wait,
+ final WriteDestinationOptions writeOpts,
+ final boolean show) {
+
+ final int numChannels = bwData.numMovingSources();
for ( int i = 0; i < numChannels; i++ )
{
final SourceAndConverter< T > movingSource = bwData.getMovingSource( i );
- ((WarpedSource>)(movingSource.getSpimSource())).updateTransform(invXfm);
- ((WarpedSource>)(movingSource.getSpimSource())).setIsTransformed(true);
+ final WarpedSource> ws = ((WarpedSource>)(movingSource.getSpimSource()));
+ if (ws.getTransform() == null) {
+ ws.updateTransform(invXfm);
+ ws.setIsTransformed(true);
+ }
+ }
+
+ Source> tgtSrc = null;
+ if (fieldOfViewOption.equals(TARGET) || resolutionOption.equals(TARGET)) {
+ if (bwData.numTargetSources() == 0)
+ throw new RuntimeException("Requested target field of view, but no target source exists.");
+ else
+ tgtSrc = bwData.getTargetSource(0).getSpimSource();
}
final ProgressWriter progressWriter = new ProgressWriterIJ();
@@ -839,7 +957,6 @@ public static List apply(
// Generate the properties needed to generate the transform from output pixel space
// to physical space
final double[] res = getResolution( bwData, resolutionOption, resolutionSpec );
-
final List outputIntervalList = getPixelInterval(bwData, landmarks, invXfm, fieldOfViewOption,
fieldOfViewPointFilter, bboxEst, fovSpec, offsetSpec, res);
@@ -847,7 +964,8 @@ public static List apply(
if( outputIntervalList.size() > 1 )
ApplyBigwarpPlugin.fillMatchedPointNames( matchedPtNames, landmarks, fieldOfViewPointFilter );
- final double[] offset = getPixelOffset( fieldOfViewOption, offsetSpec, res, outputIntervalList.get( 0 ) );
+ final double[] offset = getPhysicalOffset( fieldOfViewOption, offsetSpec, landmarks,
+ fieldOfViewPointFilter, res, tgtSrc );
if( writeOpts != null && writeOpts.n5Dataset != null && !writeOpts.n5Dataset.isEmpty())
{
@@ -858,15 +976,12 @@ public static List apply(
offset, res, unit,
progressWriter, writeOpts,
Executors.newFixedThreadPool(nThreads));
+
return null;
}
else
{
- final boolean show;
- if( writeOpts == null || writeOpts.pathOrN5Root == null || writeOpts.pathOrN5Root.isEmpty())
- show = true;
- else
- show = false;
+
return runExport( bwData, bwData.sources, fieldOfViewOption,
outputIntervalList, matchedPtNames, interp,
@@ -896,14 +1011,12 @@ public static List runExport(
int i = 0;
for( final Interval outputInterval : outputIntervalList )
{
- final double[] offset = ApplyBigwarpPlugin.getPixelOffset( fieldOfViewOption, offsetIn, resolution, outputIntervalList.get( i ) );
-
// need to declare the exporter in the loop since the actual work
// is done asynchronously, and changing variables in the loop would mess it up
final BigWarpExporter> exporter = BigWarpExporter.getExporter( data, sources, interp, progressWriter );
exporter.setOutputList( ipList );
exporter.setRenderResolution( resolution );
- exporter.setOffset( offset );
+ exporter.setOffset( offsetIn );
exporter.setVirtual( isVirtual );
exporter.setNumThreads( nThreads );
@@ -973,10 +1086,6 @@ public static & NumericType> void runN5Export(
final double[] offset = ApplyBigwarpPlugin.getPixelOffset( fieldOfViewOption, offsetArg, resolution,
outputInterval);
- System.out.println("resolution: " + Arrays.toString(resolution));
- System.out.println("offset : " + Arrays.toString(offset));
- System.out.println("interval : " + Intervals.toString(outputInterval));
-
// setup n5 parameters
final String dataset = writeOpts.n5Dataset;
final int[] blockSize = writeOpts.blockSize;
@@ -1087,11 +1196,11 @@ public static & NumericType> void runN5Export(
final ExecutorService exec )
{
- final int nd = BigWarp.detectNumDims( data.sources );
- final double[] resolution = limit(nd,resolutionArg);
+ final int nd = BigWarp.detectNumDims(data.sources);
+ final double[] resolution = limit(nd, resolutionArg);
- // pixel offset
- final double[] offsetPixel = ApplyBigwarpPlugin.getPixelOffset( fieldOfViewOption, offsetArg, resolution,
+ // physical offset
+ final double[] offsetPhysical = ApplyBigwarpPlugin.getPixelOffset(fieldOfViewOption, offsetArg, resolution,
outputInterval);
// setup n5 parameters
@@ -1130,13 +1239,6 @@ public static & NumericType> void runN5Export(
if( resolution.length > 2 )
resolutionTransform.set( resolution[ 2 ], 2, 2 );
- final double[] offsetPhysical = new double[resolution.length];
- offsetPhysical[0] = resolution[0] * offsetPixel[0];
- offsetPhysical[1] = resolution[1] * offsetPixel[1];
-
- if( resolution.length > 2 )
- offsetPhysical[2] = resolution[2] * offsetPixel[2];
-
final AffineTransform3D offsetTransform = new AffineTransform3D();
offsetTransform.set( offsetPhysical[ 0 ], 0, 3 );
offsetTransform.set( offsetPhysical[ 1 ], 1, 3 );
@@ -1153,7 +1255,7 @@ public static & NumericType> void runN5Export(
final BigWarpExporter> exporter = BigWarpExporter.getExporter( data,
sourceAndConverter, interp, progressWriter );
exporter.setRenderResolution( resolution );
- exporter.setOffset( offsetPixel );
+ exporter.setOffset( offsetPhysical );
exporter.setInterval(Intervals.zeroMin(outputInterval));
exporter.setSingleChannelNoStack(true);
final RandomAccessibleInterval imgExp = (RandomAccessibleInterval)exporter.exportRai((Source)sourceAndConverter.getSpimSource());
@@ -1166,7 +1268,6 @@ public static & NumericType> void runN5Export(
imgToWrite = img;
final String destDataset = dataset;
-
final OmeNgffMetadata metadata = OmeNgffMetadata.buildForWriting(nd, srcName, axes, new String[]{"s0"},
new double[][]{resolution}, new double[][]{offsetPhysical});
@@ -1185,7 +1286,6 @@ public static & NumericType> void runN5Export(
progressWriter.setProgress( 1.0 );
- System.out.println("done");
}
@Override
diff --git a/src/main/java/bigwarp/BigWarp.java b/src/main/java/bigwarp/BigWarp.java
index a547e6ca..8942eb9f 100755
--- a/src/main/java/bigwarp/BigWarp.java
+++ b/src/main/java/bigwarp/BigWarp.java
@@ -1431,8 +1431,6 @@ public void exportAsImagePlus( boolean virtual, String path )
ApplyBigwarpPlugin.MOVING_WARPED,
ApplyBigwarpPlugin.UNION_TARGET_MOVING,
ApplyBigwarpPlugin.LANDMARK_POINTS,
- ApplyBigwarpPlugin.LANDMARK_POINT_CUBE_PIXEL,
- ApplyBigwarpPlugin.LANDMARK_POINT_CUBE_PHYSICAL,
ApplyBigwarpPlugin.SPECIFIED_PIXEL,
ApplyBigwarpPlugin.SPECIFIED_PHYSICAL
},
@@ -1521,69 +1519,23 @@ public void exportAsImagePlus( boolean virtual, String path )
else
interp = Interpolation.NLINEAR;
- final double[] res = ApplyBigwarpPlugin.getResolution( this.data, resolutionOption, resolutionSpec );
-
- final List outputIntervalList = ApplyBigwarpPlugin.getPixelInterval( this.data,
- this.landmarkModel, this.currentTransform,
- fieldOfViewOption, fieldOfViewPointFilter, bboxOptions, fovSpec, offsetSpec, res );
-
- final List matchedPtNames = new ArrayList<>();
- if( outputIntervalList.size() > 1 )
- ApplyBigwarpPlugin.fillMatchedPointNames( matchedPtNames, getLandmarkPanel().getTableModel(), fieldOfViewPointFilter );
-
-
- // export has to be treated differently if we're doing fov's around
- // landmark centers (because multiple images can be exported this way )
- if( matchedPtNames.size() > 0 )
- {
- final BigwarpLandmarkSelectionPanel selection = new BigwarpLandmarkSelectionPanel<>(
- data, data.sources, fieldOfViewOption,
- outputIntervalList, matchedPtNames, interp,
- offsetSpec, res, isVirtual, nThreads,
- progressWriter );
- }
- else
- {
- if( writeOpts.n5Dataset != null && !writeOpts.n5Dataset.isEmpty())
- {
- @SuppressWarnings("rawtypes")
- final SourceAndConverter activeSource = getCurrentSourceInActiveViewer();
-
- final String unit = ApplyBigwarpPlugin.getUnit( data, resolutionOption );
- new Thread()
- {
- @SuppressWarnings("unchecked")
- @Override
- public void run()
- {
- progressWriter.setProgress( 0.01 );
- ApplyBigwarpPlugin.runN5Export( data, activeSource,
- fieldOfViewOption,
- outputIntervalList.get(0), interp,
- offsetSpec, res, unit,
- progressWriter, writeOpts,
- Executors.newFixedThreadPool( nThreads ));
-
- progressWriter.setProgress( 1.00 );
- }
- }.start();
- }
- else
- {
- // export
- final boolean show = ( writeOpts.pathOrN5Root == null || writeOpts.pathOrN5Root.isEmpty() );
- ApplyBigwarpPlugin.runExport( data, data.sources, fieldOfViewOption,
- outputIntervalList, matchedPtNames, interp,
- offsetSpec, res, isVirtual, nThreads,
- progressWriter, show, false, writeOpts );
- }
- }
- }
-
- private SourceAndConverter> getCurrentSourceInActiveViewer() {
-
- BigWarpViewerFrame activeFrame = viewerFrameP.isActive() ? viewerFrameP : viewerFrameQ;
- return activeFrame.getViewerPanel().state().getCurrentSource();
+ // TODO run n5 export in a separate thread?
+ ApplyBigwarpPlugin.apply(data,
+ landmarkModel,
+ this.currentTransform,
+ compressionString,
+ fieldOfViewOption,
+ fieldOfViewPointFilter,
+ bboxOptions,
+ resolutionOption,
+ resolutionSpec,
+ fovSpec,
+ offsetSpec,
+ interp,
+ isVirtual,
+ nThreads,
+ isVirtual,
+ writeOpts);
}
public void exportWarpField()
diff --git a/src/main/java/bigwarp/BigWarpARGBExporter.java b/src/main/java/bigwarp/BigWarpARGBExporter.java
index 2e623e7a..def7ecb2 100644
--- a/src/main/java/bigwarp/BigWarpARGBExporter.java
+++ b/src/main/java/bigwarp/BigWarpARGBExporter.java
@@ -101,7 +101,7 @@ public RandomAccessibleInterval< ARGBType > exportRai()
final int numChannels = bwData.numMovingSources();
for ( int i = 0; i < numChannels; i++ )
{
- final Source src = bwData.getMovingSource( i ).getSpimSource();
+ final Source src = bwData.getMovingSourceForExport( i ).getSpimSource();
raiList.add( (RandomAccessibleInterval)exportRai(src));
}
final RandomAccessibleInterval< ARGBType > raiStack = Views.stack( raiList );
@@ -117,6 +117,7 @@ public RandomAccessibleInterval> exportRai(Source> src) {
src.getSourceTransform(0, 0, srcXfm);
// in pixel space
+ @SuppressWarnings("unchecked")
final RealRandomAccessible raiRaw = (RealRandomAccessible)src.getInterpolatedSource(0, 0, interp);
// the transform from world to new pixel coordinates
diff --git a/src/main/java/bigwarp/BigWarpData.java b/src/main/java/bigwarp/BigWarpData.java
index 580d9767..a9aa1966 100644
--- a/src/main/java/bigwarp/BigWarpData.java
+++ b/src/main/java/bigwarp/BigWarpData.java
@@ -1,8 +1,5 @@
package bigwarp;
-import bigwarp.source.SourceInfo;
-import bigwarp.util.BigWarpUtils;
-
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -12,25 +9,26 @@
import java.util.function.Supplier;
import bdv.cache.CacheControl;
+import bdv.cache.SharedQueue;
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.source.SourceInfo;
+import bigwarp.util.BigWarpUtils;
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.Wrapped2DTransformAs3D;
-import net.imglib2.util.Intervals;
+import net.imglib2.realtransform.inverse.WrappedIterativeInvertibleRealTransform;
public class BigWarpData< T >
{
@@ -40,6 +38,10 @@ public class BigWarpData< T >
public final List< ConverterSetup > converterSetups;
public final CacheControl cache;
+
+ public boolean cacheFixedTransform = true;
+
+ private static SharedQueue sharedQueue;
public BigWarpData()
{
@@ -98,6 +100,14 @@ public BigWarpData( final List< SourceAndConverter< T > > sources, final List< C
else
this.cache = cache;
}
+
+ public static SharedQueue getSharedQueue() {
+
+ if (sharedQueue == null)
+ sharedQueue = new SharedQueue(Math.max(1, Runtime.getRuntime().availableProcessors() / 2));
+
+ return sharedQueue;
+ }
private static ArrayList listOf( int[] x )
{
@@ -132,6 +142,22 @@ public SourceAndConverter< T > getMovingSource( int i )
return null;
}
+ @SuppressWarnings("unchecked")
+ public SourceAndConverter getMovingSourceForExport(int i) {
+
+ int curIdx = 0;
+ for (final Map.Entry idToInfo : sourceInfos.entrySet()) {
+ final SourceInfo info = idToInfo.getValue();
+ if (info.isMoving()) {
+ if (curIdx == i) {
+ return info.sourceForExport() != null ? (SourceAndConverter)info.sourceForExport() : (SourceAndConverter)info.getSourceAndConverter();
+ }
+ curIdx++;
+ }
+ }
+ return null;
+ }
+
public int numTargetSources()
{
return sourceInfos.size() - numMovingSources();
@@ -150,6 +176,7 @@ public List< Integer > getMovingSourceIndices() {
return indices;
}
+ @SuppressWarnings("unchecked")
public SourceAndConverter< T > getTargetSource( int i )
{
int curIdx = 0;
@@ -325,7 +352,6 @@ public List> wrapSourcesAsTransformed()
{
final List< SourceAndConverter> wrappedSource = new ArrayList<>();
- int i = 0;
for ( final SourceInfo sourceInfo : sourceInfos.values() )
{
if ( sourceInfo.isMoving() )
@@ -337,7 +363,6 @@ public List> wrapSourcesAsTransformed()
{
wrappedSource.add( ( SourceAndConverter< T > ) sourceInfo.getSourceAndConverter() );
}
- i++;
}
return wrappedSource;
}
@@ -366,17 +391,30 @@ public void setTransformation(SourceInfo srcInfo, final RealTransform transform,
wrapMovingSources(srcInfo);
}
+ @SuppressWarnings({"unchecked", "rawtypes"})
public void applyTransformations() {
int i = 0;
- for (final SourceAndConverter sac : sources) {
+ for (final SourceAndConverter sac : sources) {
final SourceInfo info = getSourceInfo(sac);
final RealTransform transform = info.getTransform();
if (transform != null) {
- final SourceAndConverter newSac = inheritConverter(
+
+ SourceAndConverter sourceForExport = null;
+ SourceAndConverter newSac = inheritConverter(
applyFixedTransform(sac.getSpimSource(), transform),
sac);
+ if (cacheFixedTransform) {
+
+ sourceForExport = newSac;
+ final InvertibleRealTransform invTransform = transform instanceof InvertibleRealTransform ? (InvertibleRealTransform)transform
+ : new WrappedIterativeInvertibleRealTransform(transform);
+ newSac = BigWarpInit.cacheTransformedSource(sac, invTransform, getSharedQueue());
+ }
+
+ // will need to reload transformation on export if the transform is cached
+ info.setSourceForExport(sourceForExport);
info.setSourceAndConverter(newSac);
sources.set(i, newSac);
}
@@ -384,14 +422,30 @@ public void applyTransformations() {
}
}
+ @SuppressWarnings({"unchecked", "rawtypes"})
public void applyTransformation(final SourceInfo info, Source unWrappedSource) {
final RealTransform transform = info.getTransform();
- @SuppressWarnings("unchecked")
- final SourceAndConverter sac = (SourceAndConverter)info.getSourceAndConverter();
- final SourceAndConverter newSac = inheritConverter(
- transform != null ? applyFixedTransform(unWrappedSource, transform) : unWrappedSource,
+ if (transform == null)
+ return;
+
+ final SourceAndConverter sac = info.getSourceAndConverter();
+ SourceAndConverter> sourceForExport = null;
+ SourceAndConverter newSac = inheritConverter(
+ applyFixedTransform(sac.getSpimSource(), transform),
sac);
+
+ if (cacheFixedTransform) {
+
+ sourceForExport = newSac;
+ final InvertibleRealTransform invTransform = transform instanceof InvertibleRealTransform ? (InvertibleRealTransform)transform
+ : new WrappedIterativeInvertibleRealTransform(transform);
+ newSac = BigWarpInit.cacheTransformedSource(sac, invTransform, getSharedQueue());
+ }
+
+ // will need to reload transformation on export if the transform is
+ // cached
+ info.setSourceForExport(sourceForExport);
info.setSourceAndConverter(newSac);
sources.set(sources.indexOf(sac), newSac);
}
@@ -432,7 +486,7 @@ public void updateFixedTransform( final Source src, final RealTransform trans
if( !(src instanceof WarpedSource ))
return;
- WarpedSource> wsrc = (WarpedSource>)src;
+ final WarpedSource> wsrc = (WarpedSource>)src;
wsrc.updateTransform(tform);
}
@@ -461,43 +515,36 @@ public Source applyFixedTransform( final Source src, final RealTransfo
// TODO using a TransformedSource like the below wasn't working correctly
// investigate later
-// if( transform instanceof AffineGet )
-// {
+ // 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
-// {
+ // 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 );
+ // 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 );
+ // if (src instanceof TransformedSource) {
+ // tsrc = (TransformedSource)(src);
+ // } else {
+ // tsrc = new TransformedSource(src);
// }
-// tsrc.setFixedTransform( affine3d );
-// return ( Source< T > ) tsrc;
-// }
-// else
-// {
+ // tsrc.setFixedTransform(affine3d);
+ // return (Source)tsrc;
+ // } else {
// // need to use WarpedSource
-// final WarpedSource> wsrc = new WarpedSource( src, src.getName() );
-// wsrc.updateTransform( tform );
-// wsrc.setIsTransformed( true );
-// return ( Source< T > ) wsrc;
+ // final WarpedSource> wsrc = new WarpedSource(src, src.getName());
+ // wsrc.updateTransform(tform);
+ // wsrc.setIsTransformed(true);
+ // return (Source)wsrc;
// }
@@ -521,6 +568,7 @@ public Source applyFixedTransform( final Source src, final RealTransfo
final WarpedSource> wsrc = new WarpedSource( src, null );
wsrc.updateTransform( tform );
wsrc.setIsTransformed( true );
+
return ( Source< T > ) wsrc;
}
diff --git a/src/main/java/bigwarp/BigWarpExporter.java b/src/main/java/bigwarp/BigWarpExporter.java
index 640024e8..2e55b60e 100644
--- a/src/main/java/bigwarp/BigWarpExporter.java
+++ b/src/main/java/bigwarp/BigWarpExporter.java
@@ -116,7 +116,6 @@ public enum ParallelizationPolicy {
private String exportPath;
-
public BigWarpExporter(
BigWarpData bwData,
final List< ConverterSetup > convSetups,
@@ -232,7 +231,7 @@ public void setSingleChannelNoStack( boolean singleChannelNoStack )
}
/**
- * Set the offset of the output field of view in pixels.
+ * Set the offset of the output field of view in physical units.
*
* @param offset the offset in pixel units.
*/
@@ -250,8 +249,8 @@ public void setOffset( double... offset )
public void buildTotalRenderTransform()
{
pixelRenderToPhysical.identity();
- pixelRenderToPhysical.concatenate( resolutionTransform );
pixelRenderToPhysical.concatenate( offsetTransform );
+ pixelRenderToPhysical.concatenate( resolutionTransform );
}
public void setInterval( final Interval outputInterval )
@@ -259,6 +258,7 @@ public void setInterval( final Interval outputInterval )
this.outputInterval = outputInterval;
}
+ @SuppressWarnings("hiding")
public RandomAccessibleInterval exportSource( SourceAndConverter src )
{
final RealRandomAccessible< T > raiRaw = src.getSpimSource().getInterpolatedSource( 0, 0, interp );
@@ -582,13 +582,9 @@ public static FinalInterval transformRealInterval( RealTransform xfm, RealInterv
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 );
diff --git a/src/main/java/bigwarp/BigWarpInit.java b/src/main/java/bigwarp/BigWarpInit.java
index fa3db9b8..f03063f9 100644
--- a/src/main/java/bigwarp/BigWarpInit.java
+++ b/src/main/java/bigwarp/BigWarpInit.java
@@ -26,6 +26,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -72,6 +73,8 @@
import bdv.util.BdvOptions;
import bdv.util.RandomAccessibleIntervalMipmapSource;
import bdv.util.RandomAccessibleIntervalSource;
+import bdv.util.VolatileSource;
+import bdv.util.volatiles.VolatileTypeMatcher;
import bdv.util.volatiles.VolatileViews;
import bdv.viewer.Source;
import bdv.viewer.SourceAndConverter;
@@ -95,16 +98,31 @@
import net.imagej.Dataset;
import net.imagej.axis.Axes;
import net.imagej.axis.CalibratedAxis;
+import net.imglib2.Interval;
import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.RealInterval;
+import net.imglib2.Volatile;
import net.imglib2.cache.img.CachedCellImg;
+import net.imglib2.cache.img.CellLoader;
+import net.imglib2.cache.img.ReadOnlyCachedCellImgFactory;
+import net.imglib2.cache.img.ReadOnlyCachedCellImgOptions;
+import net.imglib2.cache.img.SingleCellArrayImg;
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.img.cell.AbstractCellImg;
+import net.imglib2.interpolation.randomaccess.ClampingNLinearInterpolatorFactory;
+import net.imglib2.outofbounds.OutOfBoundsConstantValueFactory;
import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.realtransform.BoundingBoxEstimation;
+import net.imglib2.realtransform.InvertibleRealTransform;
+import net.imglib2.realtransform.InvertibleRealTransformSequence;
import net.imglib2.realtransform.RealTransform;
+import net.imglib2.realtransform.RealTransformRandomAccessible;
+import net.imglib2.realtransform.Translation;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.ARGBType;
import net.imglib2.type.numeric.NumericType;
@@ -112,12 +130,11 @@
import net.imglib2.type.numeric.integer.UnsignedIntType;
import net.imglib2.type.volatiles.VolatileARGBType;
import net.imglib2.util.Util;
+import net.imglib2.view.ExtendedRandomAccessibleInterval;
import net.imglib2.view.IntervalView;
import net.imglib2.view.Views;
-public class BigWarpInit
-{
-
+public class BigWarpInit {
public static final N5MetadataParser>[] PARSERS = new N5MetadataParser[]{
new N5CosemMetadataParser(),
@@ -262,8 +279,8 @@ public static < T extends RealType< T > > void initSourceReal( final Source< T >
/**
* Add images from an {@link ImagePlus} as sources for BigWarp. Each channel will be added as its own source.
- *
- * @param the type
+ *
+ * @param the type
* @param bwdata the bigwarp data
* @param ip an ImagePlus
* @param setupId id
@@ -326,7 +343,17 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW
/**
* Initialize BigWarp.
- *
+ *
+ * @param bwdata
+ * a BigWarpData instance
+ * @param src
+ * the Source to add
+ * @param setupId
+ * the id to assign to the source
+ * @param numTimepoints
+ * number of time points this source has
+ * @param isMoving
+ * true if this is a moving source
* @return a {@link BigWarpData} instance
*
* @deprecated Use the output from one of the
@@ -360,11 +387,23 @@ public static < T > BigWarpData< T > add( BigWarpData< T > bwdata, LinkedHashMap
/**
* Initialize BigWarp.
*
+ * @param bwdata
+ * a BigWarpData instance
+ * @param src
+ * the Source to add
+ * @param setupId
+ * the id to assign to the source
+ * @param numTimepoints
+ * number of time points this source has
+ * @param isMoving
+ * true if this is a moving source
+ * @param transform
+ * a fixed transform to apply to this source
* @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)}}
+ * {{@code createSources(BigWarpData, String, int, boolean)}} to
+ * call {{@code add(BigWarpData, LinkedHashMap, RealTransform)}}
* instead
*/
@SuppressWarnings( { "unchecked", "rawtypes" } )
@@ -430,7 +469,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW
final IntervalView> channel = hasZ ? channelRaw : Views.addDimension( channelRaw, 0, 0 );
@SuppressWarnings( "unchecked" )
- final RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( channel, Util.getTypeFromInterval( data ), res, data.getName() );
+ final RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( channel, data.getType(), res, data.getName() );
final SourceInfo info = new SourceInfo( baseId + c, isMoving, data.getName(), () -> data.getSource() );
info.setSerializable( first );
@@ -445,7 +484,7 @@ public static < T > LinkedHashMap< Source< T >, SourceInfo > createSources( BigW
final RandomAccessibleInterval> img = hasZ ? data : Views.addDimension( data, 0, 0 );
@SuppressWarnings( "unchecked" )
- final RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( img, Util.getTypeFromInterval( data ), res, data.getName() );
+ final RandomAccessibleIntervalSource source = new RandomAccessibleIntervalSource( img, data.getType(), res, data.getName() );
final SourceInfo info = new SourceInfo( baseId, isMoving, data.getName(), () -> data.getSource() );
info.setSerializable( true );
@@ -505,7 +544,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 SharedQueue sharedQueue = BigWarpData.getSharedQueue();
final URI encodedUri = N5URI.encodeAsUri( uri.trim() );
final LinkedHashMap< Source< T >, SourceInfo > sourceStateMap = new LinkedHashMap<>();
if ( encodedUri.isOpaque() )
@@ -595,11 +634,17 @@ else if ( new File( uri ).isDirectory() )
}
/**
- * Initialize BigWarp.
+ * Add a source to thet given {@link BigWarpData} instance using the N5 api
*
+ * @param the type
+ * @param bwdata the BigWarpData instance
+ * @param isMoving true if this source is moving
+ * @param setupId the id to assign to this source
+ * @param rootPath the root path to the container
+ * @param dataset the path to the dataset relative to the container root
* @return a {@link SpimData} instance
- *
- * @deprecated Use output from
+ *
+ * * @deprecated Use output from
* {@code createSources(BigWarpData, boolean, int, String, String)} and add with
* {@code add(BigWarpData, LinkedHashMap, RealTransform)} instead.
*/
@@ -727,7 +772,7 @@ public static < T extends NativeType, M extends N5Metadata > Source< T > open
else
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 && imageRaw.getType() instanceof UnsignedIntType )
{
image = toColor( imageRaw );
}
@@ -740,10 +785,10 @@ public static < T extends NativeType, M extends N5Metadata > Source< T > open
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 ) image.getType(), srcXfm, meta.getPath(), voxelDims );
}
else
- return new BwRandomAccessibleIntervalSource( image, ( NumericType ) Util.getTypeFromInterval( image ), new AffineTransform3D(), meta.getPath() );
+ return new BwRandomAccessibleIntervalSource( image, ( NumericType ) image.getType(), new AffineTransform3D(), meta.getPath() );
}
catch ( final RuntimeException e )
{
@@ -755,18 +800,19 @@ public static < T extends NativeType, M extends N5Metadata > Source< T > open
public static < T extends NativeType & NumericType> Source< T > openN5V( final N5Reader n5, final MultiscaleMetadata< ? > multiMeta, final SharedQueue sharedQueue )
{
- List> sources = new ArrayList<>();
- List converterSetups = new ArrayList<>();
+ final List> sources = new ArrayList<>();
+ final List converterSetups = new ArrayList<>();
try {
N5Viewer.buildN5Sources(n5, new DataSelection(n5, Collections.singletonList(multiMeta)), sharedQueue, converterSetups, sources, BdvOptions.options());
if( sources.size() > 0 )
return (Source)sources.get(0).getSpimSource();
- } catch (IOException e) { }
+ } catch (final IOException e) { }
return null;
}
- public static < T extends NativeType > Source< T > openAsSourceMulti( final N5Reader n5, final MultiscaleMetadata< ? > multiMeta, final SharedQueue sharedQueue, final boolean isVolatile )
+ @SuppressWarnings("unchecked")
+ public static < T extends NumericType & 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();
@@ -798,10 +844,7 @@ public static < T extends NativeType > Source< T > openAsSourceMulti( final N
mipmapScales[ s ][ 2 ] = transforms[ s ].get( 2, 2 );
}
- @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" );
-
- return source;
+ return new RandomAccessibleIntervalMipmapSource( images, (T)images[ 0 ].getType(), mipmapScales, new mpicbg.spim.data.sequence.FinalVoxelDimensions( unit, mipmapScales[ 0 ] ), new AffineTransform3D(), multiMeta.getPaths()[ 0 ] + "_group" );
}
private static RandomAccessibleInterval< ? > to3d( RandomAccessibleInterval< ? > img )
@@ -824,12 +867,9 @@ public void convert( UnsignedIntType input, ARGBType output )
}, new ARGBType() );
}
- @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 );
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static BigWarpData initData() {
+
return new BigWarpData();
}
@@ -929,36 +969,153 @@ private static < T extends NumericType< T > > void addSourceToListsNumericType(
}
}
- public static ArrayList< SourceAndConverter< ? > > wrapSourcesAsRenamable( final List< SourceAndConverter< ? > > sources, final String[] names )
- {
- final ArrayList< SourceAndConverter< ? > > wrappedSource = new ArrayList< SourceAndConverter< ? > >();
+ public static ArrayList> wrapSourcesAsRenamable(final List> sources,
+ final String[] names) {
+
+ final ArrayList> wrappedSource = new ArrayList>();
int i = 0;
- for ( final SourceAndConverter< ? > sac : sources )
- {
- final SourceAndConverter< ? > renamableSource = wrapSourceAsRenamable( sac );
- if ( names != null )
- {
- ( ( RenamableSource< ? > ) renamableSource.getSpimSource() ).setName( names[ i ] );
+ for (final SourceAndConverter> sac : sources) {
+ final SourceAndConverter> renamableSource = wrapSourceAsRenamable(sac);
+ if (names != null) {
+ ((RenamableSource>)renamableSource.getSpimSource()).setName(names[i]);
}
- wrappedSource.add( renamableSource );
+ wrappedSource.add(renamableSource);
i++;
}
return wrappedSource;
}
- private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final SourceAndConverter< T > src )
- {
- if ( src.asVolatile() == null )
- {
- return new SourceAndConverter< T >( new RenamableSource< T >( src.getSpimSource() ), src.getConverter(), null );
+ private static SourceAndConverter wrapSourceAsRenamable(final SourceAndConverter src) {
+
+ if (src.asVolatile() == null) {
+ return new SourceAndConverter(new RenamableSource(src.getSpimSource()), src.getConverter(), null);
+ } else {
+ return new SourceAndConverter(new RenamableSource(src.getSpimSource()), src.getConverter(),
+ src.asVolatile());
}
- else
- {
- return new SourceAndConverter< T >( new RenamableSource< T >( src.getSpimSource() ), src.getConverter(), src.asVolatile() );
+ }
+
+ @SuppressWarnings("unchecked")
+ public static & NativeType, V extends Volatile & NumericType> SourceAndConverter cacheTransformedSource(
+ final SourceAndConverter sac,
+ final InvertibleRealTransform transform,
+ SharedQueue sharedQueue) {
+
+ final Source src = sac.getSpimSource();
+ final int nd = src.getSource(0, 0).numDimensions();
+ final int N = src.getNumMipmapLevels();
+
+ final T type = src.getType();
+ final V vtype = (V)VolatileTypeMatcher.getVolatileTypeForType(type);
+
+ final int[] defaultCellDimensions = new int[nd];
+ Arrays.fill(defaultCellDimensions, 64);
+
+ // TODO handle time?
+ final RandomAccessibleInterval[] mipmaps = new RandomAccessibleInterval[N];
+ final RandomAccessibleInterval>[] vmipmaps = new RandomAccessibleInterval[N];
+ final AffineTransform3D[] sourceTransforms = new AffineTransform3D[N];
+ for (int i = 0; i < src.getNumMipmapLevels(); i++) {
+
+ final RandomAccessibleInterval img = src.getSource(0, i);
+
+ final AffineTransform3D origScaleTform = new AffineTransform3D();
+ src.getSourceTransform(0, i, origScaleTform);
+
+ // build the inverse transform: from transformed pixel coordinates
+ // to original pixel coordinates "through" physical coordinates
+ InvertibleRealTransformSequence tformToPhysicalSpace = new InvertibleRealTransformSequence();
+ tformToPhysicalSpace.add(origScaleTform);
+ tformToPhysicalSpace.add(transform.copy());
+ tformToPhysicalSpace.add(origScaleTform.inverse());
+
+ // compute the bounding box in physical coordinates
+ final BoundingBoxEstimation bbox = new BoundingBoxEstimation();
+ final RealInterval targetInterval = bbox.estimateInterval(tformToPhysicalSpace.inverse(), img);
+ final Interval pixelInterval = BoundingBoxEstimation.containingInterval(targetInterval);
+
+ // update the source transform to take into account any change in bounding box
+ final AffineTransform3D newSourceTform = origScaleTform.copy();
+ final Translation tlation = new Translation(targetInterval.minAsDoubleArray());
+ newSourceTform.concatenate(tlation.inverse());
+ sourceTransforms[i] = newSourceTform;
+
+ InvertibleRealTransformSequence tformToPixelSpace = new InvertibleRealTransformSequence();
+ tformToPixelSpace.add(origScaleTform);
+ tformToPixelSpace.add(transform.copy());
+ tformToPixelSpace.add(newSourceTform.inverse());
+
+ final RandomAccessibleInterval raiTform = transform( img, pixelInterval, tformToPixelSpace);
+ final ReadOnlyCachedCellImgFactory cacheFactory = new ReadOnlyCachedCellImgFactory(
+ new ReadOnlyCachedCellImgOptions()
+ .volatileAccesses(true)
+ .cellDimensions(getCellDimensionsOrDefault(img, defaultCellDimensions)));
+
+ final CellLoader copier = new CellLoader() {
+ @Override
+ public void load(SingleCellArrayImg cell) throws Exception {
+
+ Views.flatIterable(Views.interval(Views.pair(raiTform, cell), cell)).forEach(
+ pair -> pair.getB().set(pair.getA()));
+ }
+ };
+
+ final RandomAccessibleInterval cachedTransformedMipmap = cacheFactory.create(
+ raiTform.dimensionsAsLongArray(),
+ type.copy(),
+ copier);
+ mipmaps[i] = cachedTransformedMipmap;
+
+ final int priority = N - 1 - i;
+ final CacheHints cacheHints = new CacheHints(LoadingStrategy.BUDGETED, priority, false);
+ vmipmaps[i] = VolatileViews.wrapAsVolatile(cachedTransformedMipmap, sharedQueue, cacheHints);
+ }
+
+ final RandomAccessibleIntervalMipmapSource cachedTransformedSource =
+ new RandomAccessibleIntervalMipmapSource(
+ mipmaps,
+ type,
+ sourceTransforms,
+ src.getVoxelDimensions(),
+ src.getName(),
+ src.doBoundingBoxCulling());
+
+ final Source vsrc = new VolatileSource(cachedTransformedSource, vtype, sharedQueue);
+ final SourceAndConverter vsac = new SourceAndConverter(vsrc, BigDataViewer.createConverterToARGB(vtype));
+ return new SourceAndConverter(cachedTransformedSource, BigDataViewer.createConverterToARGB(type), vsac);
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static int[] getCellDimensionsOrDefault(final RandomAccessibleInterval> img,
+ final int[] defaultDimensions) {
+
+ // TODO need to unwrap views
+ if (img instanceof AbstractCellImg) {
+ return ((AbstractCellImg)img).getCellGrid().getCellDimensions();
+ } else {
+ return defaultDimensions;
}
}
+ private static & NativeType> RandomAccessibleInterval transform(
+ final RandomAccessibleInterval img,
+ final Interval targetInterval,
+ final RealTransform transform) {
+
+ final T background = img.getType().copy();
+ background.setZero();
+
+ return Views.interval(
+ new RealTransformRandomAccessible<>(
+ Views.interpolate(
+ new ExtendedRandomAccessibleInterval<>(img,
+ new OutOfBoundsConstantValueFactory<>(background)),
+ new ClampingNLinearInterpolatorFactory<>()),
+ transform),
+ targetInterval);
+ }
+
/**
* Create {@link BigWarpData} from two {@link AbstractSpimData}.
*
@@ -1086,16 +1243,16 @@ private static < T > SourceAndConverter< T > wrapSourceAsRenamable( final Source
/**
* Create {@link BigWarpData} from two XML files.
- *
+ *
+ * @param the type
* @param xmlFilenameP
* moving source XML
* @param xmlFilenameQ
* fixed source XML
- * @return BigWarpData
+ * @return a BigWarpData instance
*/
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();
try
{
@@ -1125,6 +1282,7 @@ public static < T extends NativeType > BigWarpData< T > createBigWarpDataFrom
/**
* Create {@link BigWarpData} from two {@link ImagePlus ImagePluses}.
*
+ * @param the type
* @param impP
* moving source ImagePlus
* @param impQ
@@ -1138,7 +1296,9 @@ public static < T > BigWarpData< T > createBigWarpDataFromImages( final ImagePlu
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 ) );
+
+ if (impQ != null)
+ BigWarpInit.add(bwdata, BigWarpInit.createSources(bwdata, impQ, id, 0, false));
return bwdata;
}
@@ -1190,6 +1350,7 @@ public static < T > BigWarpData< T > createBigWarpDataFromImages( final ImagePlu
/**
* Create {@link BigWarpData} from an xml file and an {@link ImagePlus}.
*
+ * @param the type
* @param xmlFilenameP
* movingSource XML
* @param impQ
@@ -1242,6 +1403,7 @@ public static < T extends NativeType > BigWarpData< T > createBigWarpDataFrom
/**
* Create {@link BigWarpData} from an {@link ImagePlus} and an XML file.
*
+ * @param the type
* @param impP
* moving source ImagePlus
* @param xmlFilenameQ
@@ -1250,7 +1412,6 @@ public static < T extends NativeType > BigWarpData< T > createBigWarpDataFrom
*/
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();
try
{
diff --git a/src/main/java/bigwarp/BigWarpRealExporter.java b/src/main/java/bigwarp/BigWarpRealExporter.java
index d7f40e5b..59880743 100644
--- a/src/main/java/bigwarp/BigWarpRealExporter.java
+++ b/src/main/java/bigwarp/BigWarpRealExporter.java
@@ -143,7 +143,7 @@ public RandomAccessibleInterval< T > exportRai()
numChannels = bwData.numMovingSources();
for ( int i = 0; i < numChannels; i++ )
- raiList.add( (RandomAccessibleInterval)exportRai( bwData.getMovingSource( i ).getSpimSource()));
+ raiList.add( (RandomAccessibleInterval)exportRai( bwData.getMovingSourceForExport( i ).getSpimSource()));
if( singleChannelNoStack )
return raiList.get(0);
diff --git a/src/main/java/bigwarp/loader/ImagePlusLoader.java b/src/main/java/bigwarp/loader/ImagePlusLoader.java
index 4f58d54b..c3dc3bea 100644
--- a/src/main/java/bigwarp/loader/ImagePlusLoader.java
+++ b/src/main/java/bigwarp/loader/ImagePlusLoader.java
@@ -156,7 +156,6 @@ public HashMap getSetupSettings() {
public void update(final BigWarpData> data) {
for (Integer key : settingsMap.keySet()) {
- SourceAndConverter> sac = data.sources.get(key.intValue());
data.getSourceInfo(key).setColorSettings(settingsMap.get(key));
}
}
@@ -196,13 +195,13 @@ public static double sanitizeCalibration(double in, String dim) {
public SpimDataMinimal load(final int setupIdOffset, ImagePlus imp) {
// get calibration and image size
- final double pw;
- final double ph;
- final double pd;
+ final double pw = sanitizeCalibration(imp.getCalibration().pixelWidth, "x");
+ final double ph = sanitizeCalibration(imp.getCalibration().pixelHeight, "y");
+ final double pd = sanitizeCalibration(imp.getCalibration().pixelDepth, "z");
- pw = sanitizeCalibration(imp.getCalibration().pixelWidth, "x");
- ph = sanitizeCalibration(imp.getCalibration().pixelHeight, "y");
- pd = sanitizeCalibration(imp.getCalibration().pixelDepth, "z");
+ final double ox = imp.getCalibration().xOrigin;
+ final double oy = imp.getCalibration().yOrigin;
+ final double oz = imp.getCalibration().zOrigin;
String punit = imp.getCalibration().getUnit();
if (punit == null || punit.isEmpty())
@@ -274,7 +273,7 @@ public SpimDataMinimal load(final int setupIdOffset, ImagePlus imp) {
// create ViewRegistrations from the images calibration
final AffineTransform3D sourceTransform = new AffineTransform3D();
- sourceTransform.set(pw, 0, 0, 0, 0, ph, 0, 0, 0, 0, pd, 0);
+ sourceTransform.set(pw, 0, 0, ox, 0, ph, 0, oy, 0, 0, pd, oz);
final ArrayList registrations = new ArrayList();
for (int t = 0; t < numTimepoints; ++t)
for (int s = 0; s < numSetups; ++s)
@@ -321,7 +320,10 @@ public ColorSettings(int converterSetupIndex, double min, double max, ARGBType c
}
/**
- * @deprecated
+ *
+ * @param setups the SetupAssignments
+ *
+ * @deprecated use updateSetup( ConverterSetup)
*/
public void updateSetup(final SetupAssignments setups) {
diff --git a/src/main/java/bigwarp/source/SourceInfo.java b/src/main/java/bigwarp/source/SourceInfo.java
index ebc63408..7df64584 100644
--- a/src/main/java/bigwarp/source/SourceInfo.java
+++ b/src/main/java/bigwarp/source/SourceInfo.java
@@ -22,6 +22,14 @@ public class SourceInfo
private Supplier transformUriSupplier;
+ /*
+ * When using an imported fixed transform, we'll want to apply all the
+ * transforms in sequence, interpolating only once. This source should be
+ * used for export, in contrast to the source stored in BigWarpData, which
+ * should be used for visualization.
+ */
+ private SourceAndConverter> sourceForExport;
+
boolean serializable = false;
public SourceInfo( final int id, final boolean moving )
@@ -55,26 +63,36 @@ public SourceInfo( final int id, final boolean moving, final String name, final
*
* @param serializable whether to setSerialize this source or not.
*/
- public void setSerializable( final boolean serializable )
- {
+ public void setSerializable(final boolean serializable) {
+
this.serializable = serializable;
}
- public boolean isSerializable()
- {
+ public boolean isSerializable() {
+
return serializable;
}
- public String getUri()
- {
+ public String getUri() {
+
return uriSupplier.get();
}
- public void setUriSupplier( final Supplier< String > getUri )
- {
+ public void setUriSupplier(final Supplier getUri) {
+
this.uriSupplier = getUri;
}
+ public void setSourceForExport(SourceAndConverter> sourceForExport) {
+
+ this.sourceForExport = sourceForExport;
+ }
+
+ public SourceAndConverter> sourceForExport() {
+
+ return sourceForExport;
+ }
+
public int getId()
{
return id;
diff --git a/src/main/java/bigwarp/transforms/BigWarpTransform.java b/src/main/java/bigwarp/transforms/BigWarpTransform.java
index 71c089b3..dae2ab53 100644
--- a/src/main/java/bigwarp/transforms/BigWarpTransform.java
+++ b/src/main/java/bigwarp/transforms/BigWarpTransform.java
@@ -24,7 +24,6 @@
import java.util.Arrays;
import java.util.function.Supplier;
-import bdv.gui.TransformTypeSelectDialog;
import bdv.util.BoundedRange;
import bdv.viewer.SourceAndConverter;
import bdv.viewer.animate.SimilarityModel3D;
@@ -54,10 +53,10 @@
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.realtransform.InverseRealTransform;
import net.imglib2.realtransform.InvertibleRealTransform;
+import net.imglib2.realtransform.InvertibleWrapped2DTransformAs3D;
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;
import net.imglib2.type.numeric.real.DoubleType;
diff --git a/src/main/java/bigwarp/transforms/NgffTransformations.java b/src/main/java/bigwarp/transforms/NgffTransformations.java
index f8626b70..58c9475b 100644
--- a/src/main/java/bigwarp/transforms/NgffTransformations.java
+++ b/src/main/java/bigwarp/transforms/NgffTransformations.java
@@ -562,11 +562,10 @@ public static CoordinateSystem createVectorFieldCoordinateSystem(final String na
/**
* returns null if no permutation needed
*
- * @param cs
+ * @param cs a coordinate system
* @return a permutation if needed
- * @throws Exception
*/
- public static final int[] vectorAxisLastNgff( final CoordinateSystem cs ) throws Exception {
+ public static final int[] vectorAxisLastNgff( final CoordinateSystem cs ) {
final Axis[] axes = cs.getAxes();
final int n = axes.length;
@@ -576,15 +575,6 @@ public static final int[] vectorAxisLastNgff( final CoordinateSystem cs ) throws
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;
@@ -605,9 +595,6 @@ public static final int[] vectorAxisLastNgff( final CoordinateSystem cs ) throws
}
}
- /**
- * @throws Exception the exception
- */
public static final int[] vectorAxisLastNgff(
final N5Reader n5, final String dataset ) throws Exception {
diff --git a/src/main/java/bigwarp/util/BigWarpUtils.java b/src/main/java/bigwarp/util/BigWarpUtils.java
index 3cffd7d1..6de90454 100644
--- a/src/main/java/bigwarp/util/BigWarpUtils.java
+++ b/src/main/java/bigwarp/util/BigWarpUtils.java
@@ -66,9 +66,6 @@ public static void ensurePositiveZ( final AffineTransform3D xfm )
public static void ensurePositiveDeterminant( final AffineTransform3D xfm )
{
-// if( det( xfm ) < 0 )
-// permuteXY( xfm );
-
if( det( xfm ) < 0 )
flipX( xfm );
}
@@ -119,6 +116,8 @@ public static void permuteXY( final AffineTransform3D xfm )
* width of the viewer display
* @param viewerHeight
* height of the viewer display
+ * @param zoomedIn
+ * true if tighter, more "zoomedIn" bounds are desired
* @param state
* the {@link ViewerState} containing at least one source.
* @return proposed initial viewer transform.
@@ -179,7 +178,6 @@ public static AffineTransform3D initTransform( final int viewerWidth, final int
else
scale = Math.min( scaleX, scaleY );
viewerTransform.scale( scale );
-// viewerTransform.set( 1.0, 2, 2 );
// window center offset
viewerTransform.set( viewerTransform.get( 0, 3 ) + cX, 0, 3 );
@@ -204,20 +202,6 @@ 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 ];
-// double[] q1 = new double[ 4 ];
-// double[] q2 = new double[ 4 ];
-//
-// xfm1.toMatrix( tmpMat );
-// LinAlgHelpers.qu
-//
-// normalize( q1 );
-// normalize( q2 );
-//
-// }
-
public static void normalize( double[] x )
{
double magSqr = 0;
diff --git a/src/main/java/net/imglib2/realtransform/BoundingBoxEstimation.java b/src/main/java/net/imglib2/realtransform/BoundingBoxEstimation.java
index 90d3dd5f..c46dce4b 100644
--- a/src/main/java/net/imglib2/realtransform/BoundingBoxEstimation.java
+++ b/src/main/java/net/imglib2/realtransform/BoundingBoxEstimation.java
@@ -94,6 +94,21 @@ public static double[] samplesPerDim( final RealInterval itvl, final int maxSamp
return steps;
}
+ public RealInterval estimateInterval( RealTransform xfm, RealInterval interval )
+ {
+ steps = samplesPerDim( interval, samplesPerDim );
+
+ switch( method )
+ {
+ case CORNERS:
+ return cornersReal(xfm, interval);
+ case VOLUME:
+ return volumeReal(xfm, interval, steps );
+ default:
+ return facesReal( xfm, interval, steps );
+ }
+ }
+
public Interval estimatePixelInterval( RealTransform xfm, Interval interval )
{
steps = samplesPerDim( interval, samplesPerDim );
@@ -139,7 +154,7 @@ public static FinalInterval faces( RealTransform xfm, Interval interval, double[
return containingInterval(facesReal( xfm, interval, steps ));
}
- public static FinalRealInterval facesReal( RealTransform xfm, Interval interval, double[] stepsIn )
+ public static FinalRealInterval facesReal( RealTransform xfm, RealInterval interval, double[] stepsIn )
{
if( xfm == null )
return new FinalRealInterval( interval );
@@ -187,8 +202,8 @@ public static void minMaxInterval( final RealTransform xfm, final RealInterval i
for( int d = 0; d < nd; d++ )
{
- long lo = (long)Math.floor( ptxfm.getDoublePosition(d) );
- long hi = (long)Math.ceil( ptxfm.getDoublePosition(d) );
+ double lo = ptxfm.getDoublePosition(d);
+ double hi = ptxfm.getDoublePosition(d);
if( lo < min[ d ])
min[ d ] = lo;
@@ -209,7 +224,7 @@ public static void subInterval( final RealInterval interval, final double pos, f
max[dim] = pos;
}
- public static FinalRealInterval volumeReal( RealTransform xfm, Interval interval, double[] steps )
+ public static FinalRealInterval volumeReal( RealTransform xfm, RealInterval interval, double[] steps )
{
if( xfm == null )
return new FinalRealInterval( interval );
@@ -228,11 +243,12 @@ public static FinalInterval volume( RealTransform xfm, Interval interval, double
{
return containingInterval( volumeReal( xfm, interval, steps ));
}
+
- public static FinalInterval corners( RealTransform xfm, Interval interval )
+ public static RealInterval cornersReal( RealTransform xfm, RealInterval interval )
{
if( xfm == null )
- return new FinalInterval( interval );
+ return new FinalRealInterval( interval );
int nd = interval.numDimensions();
double[] pt = new double[ nd ];
@@ -253,9 +269,9 @@ public static FinalInterval corners( RealTransform xfm, Interval interval )
for( int d = 0; d < nd; d++ )
{
if( it.getLongPosition( d ) == 0 )
- pt[ d ] = interval.min( d );
+ pt[ d ] = interval.realMin( d );
else
- pt[ d ] = interval.max( d );
+ pt[ d ] = interval.realMax( d );
}
xfm.apply( pt, ptxfm );
@@ -275,4 +291,10 @@ public static FinalInterval corners( RealTransform xfm, Interval interval )
return new FinalInterval( min, max );
}
+ public static FinalInterval corners( RealTransform xfm, Interval interval )
+ {
+
+ return containingInterval(cornersReal(xfm, interval));
+ }
+
}
diff --git a/src/test/java/bigwarp/BigWarpTestUtils.java b/src/test/java/bigwarp/BigWarpTestUtils.java
index 49e45de6..4ba66bc8 100644
--- a/src/test/java/bigwarp/BigWarpTestUtils.java
+++ b/src/test/java/bigwarp/BigWarpTestUtils.java
@@ -1,8 +1,21 @@
package bigwarp;
-import bdv.gui.BigWarpViewerOptions;
-import bdv.viewer.Source;
-import bigwarp.source.SourceInfo;
+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 java.util.stream.DoubleStream;
+import java.util.stream.Stream;
+
+import org.bouncycastle.util.Arrays;
+import org.junit.Assert;
+
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;
@@ -11,31 +24,47 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
+
+import bdv.gui.BigWarpViewerOptions;
+import bdv.util.RandomAccessibleIntervalMipmapSource;
+import bdv.util.RandomAccessibleIntervalSource;
+import bdv.viewer.Source;
+import bigwarp.landmarks.LandmarkTableModel;
+import bigwarp.source.SourceInfo;
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 mpicbg.spim.data.sequence.FinalVoxelDimensions;
import net.imglib2.FinalInterval;
+import net.imglib2.Localizable;
+import net.imglib2.Point;
+import net.imglib2.RandomAccess;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.RealPoint;
+import net.imglib2.algorithm.blocks.BlockAlgoUtils;
+import net.imglib2.algorithm.blocks.BlockSupplier;
+import net.imglib2.algorithm.blocks.downsample.Downsample;
+import net.imglib2.img.array.ArrayImg;
+import net.imglib2.img.array.ArrayImgs;
+import net.imglib2.img.basictypeaccess.array.ByteArray;
import net.imglib2.img.display.imagej.ImageJFunctions;
+import net.imglib2.iterator.IntervalIterator;
+import net.imglib2.iterator.RealIntervalIterator;
import net.imglib2.position.FunctionRandomAccessible;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.realtransform.RealTransform;
+import net.imglib2.realtransform.Scale;
+import net.imglib2.realtransform.ScaleAndTranslation;
import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.NumericType;
+import net.imglib2.type.numeric.integer.AbstractIntegerType;
import net.imglib2.type.numeric.integer.UnsignedByteType;
import net.imglib2.view.Views;
-import org.junit.Assert;
+import net.imglib2.view.fluent.RandomAccessibleIntervalView.Extension;
-public class BigWarpTestUtils
-{
+public class BigWarpTestUtils{
/**
* Create a 3D image file which is deleted on exit.
@@ -51,7 +80,6 @@ public static String createTemp3DImage( String title, String format )
try
{
tmpImgPath = Files.createTempFile( title, "." + format );
- //noinspection ResultOfMethodCallIgnored
tmpImgPath.toFile().delete();
}
catch ( final IOException e )
@@ -65,7 +93,6 @@ public static String createTemp3DImage( String title, String format )
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 );
- System.out.println( tmpImgPath.toString());
IJ.saveAs(img3d, format, tmpImgPath.toString());
tmpImgPath.toFile().deleteOnExit();
@@ -95,7 +122,6 @@ public static String createTemp3DImage( final String format, Path imagePath )
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 );
- System.out.println( tmpImgPath.toString());
IJ.saveAs(img2d, format, tmpImgPath.toString());
tmpImgPath.toFile().deleteOnExit();
return tmpImgPath.toString();
@@ -115,14 +141,12 @@ public static String createTemp2DImage( String title, String format )
try
{
tmpImg = Files.createTempFile( title, "." + format );
- //noinspection ResultOfMethodCallIgnored
tmpImg.toFile().delete();
return create2DImage( format, tmpImg );
}
catch ( final Exception e )
{
if (tmpImg != null) {
- //noinspection ResultOfMethodCallIgnored
tmpImg.toFile().delete();
}
throw new RuntimeException( e );
@@ -259,7 +283,7 @@ static < T extends NativeType > BigWarp< T > createBigWarp(String sourcePath,
return new BigWarp<>( data, opts, null );
}
- static ImagePlus generateImagePlus( final String title )
+ public static ImagePlus generateImagePlus( final String title )
{
final FunctionRandomAccessible< UnsignedByteType > fimg = new FunctionRandomAccessible<>(
3,
@@ -268,8 +292,250 @@ static ImagePlus generateImagePlus( final String title )
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);
+ public static ImagePlus generateImagePlus3d(final String title,
+ final long[] size,
+ final long[] pos,
+ final int value,
+ final double[] resolution,
+ final double[] offset) {
+
+ final ArrayImg img = ArrayImgs.unsignedBytes(size);
+ img.getAt(pos).set(value);
+
+ final ImagePlus imp = ImageJFunctions.wrap(img, title);
+ imp.setDimensions(1, (int)size[2], 1);
+
+ imp.getCalibration().pixelWidth = resolution[0];
+ imp.getCalibration().pixelHeight = resolution[1];
+ imp.getCalibration().pixelDepth = resolution[2];
+
+ imp.getCalibration().xOrigin = offset[0];
+ imp.getCalibration().yOrigin = offset[1];
+ imp.getCalibration().zOrigin = offset[2];
+
+ return imp;
+ }
+
+ public static Source generateSource(
+ final String name,
+ final long[] size,
+ final long[] pos,
+ final double[] resolution,
+ final double[] offset) {
+
+ return generateSource(name, size, Stream.of(new Point(pos)), resolution, offset);
+ }
+
+ public static Source generateSource(
+ final String name,
+ final long[] size,
+ final Stream positions,
+ final double[] resolution,
+ final double[] offset) {
+
+ final ArrayImg img = ArrayImgs.unsignedBytes(size);
+ setAll(img, positions, 255);
+
+ AffineTransform3D tform = new AffineTransform3D();
+ tform.set(
+ resolution[0], 0, 0, offset[0],
+ 0, resolution[1], 0, offset[1],
+ 0, 0, resolution[2], offset[2]);
+
+ return new RandomAccessibleIntervalSource(img, img.getType(), tform, name);
+ }
+
+ public static Source generateMultiscaleSource(
+ final int numScales,
+ final String name,
+ final long[] size,
+ final long[] pos,
+ final double[] resolution,
+ final double[] offset) {
+
+ return generateMultiscaleSource(numScales, name, size, Stream.of(new Point(pos)), resolution, offset);
+ }
+
+ public static > void setAll(final RandomAccessibleInterval img, final Stream positions, final int value) {
+
+ final RandomAccess ra = img.randomAccess();
+ positions.forEach(x -> {
+ ra.setPosition(x);
+ ra.get().setInteger(value);
+ });
+ }
+
+ public static Source generateMultiscaleSource(
+ final int numScales,
+ final String name,
+ final long[] size,
+ Stream positions,
+ final double[] resolution,
+ final double[] offset) {
+
+ final ArrayImg img = ArrayImgs.unsignedBytes(size);
+ setAll(img, positions, 255);
+
+ final int nd = 3;
+ final double[] scale = new double[nd];
+ final double[] translation = new double[nd];
+ for (int i = 0; i < nd; i++) {
+ scale[i] = 0.5;
+ translation[i] = -0.25;
+ }
+
+ final ScaleAndTranslation downsampleTform = new ScaleAndTranslation(scale, translation);
+ final int[] downsampleFactors = new int[]{2, 2, 2};
+
+ AffineTransform3D tform = new AffineTransform3D();
+ tform.set(
+ resolution[0], 0, 0, offset[0],
+ 0, resolution[1], 0, offset[1],
+ 0, 0, resolution[2], offset[2]);
+
+ final RandomAccessibleInterval[] imgs = new RandomAccessibleInterval[numScales];
+ final AffineTransform3D[] tforms = new AffineTransform3D[numScales];
+
+ imgs[0] = img;
+ tforms[0] = tform.copy();
+ for (int s = 1; s < numScales; s++) {
+
+ imgs[s] = downsampleAvgBy2NativeType(imgs[s - 1], downsampleFactors,
+ downsampledSize( imgs[s-1].dimensionsAsLongArray(), downsampleFactors));
+ tform.preConcatenate(downsampleTform);
+ tforms[s] = tform.copy();
+ }
+
+ return new RandomAccessibleIntervalMipmapSource(
+ imgs,
+ new UnsignedByteType(),
+ tforms,
+ new FinalVoxelDimensions("arb", resolution),
+ name,
+ true);
}
+
+ public static > Source levelToSource( Source src, int level ) {
+
+ final AffineTransform3D tf = new AffineTransform3D();
+ src.getSourceTransform(0, level, tf);
+ return new RandomAccessibleIntervalSource(
+ src.getSource(0, level),
+ src.getType(),
+ tf,
+ src.getName() + " " + level);
+ }
+
+ private static long[] downsampledSize(long[] dimensions, int[] factors) {
+
+ long[] dsSize = new long[dimensions.length];
+ for (int i = 0; i < dimensions.length; i++)
+ dsSize[i] = (long)Math.ceil((double)dimensions[i] / factors[i]);
+
+ return dsSize;
+ }
+
+ private static > RandomAccessibleInterval downsampleAvgBy2NativeType(
+ final RandomAccessibleInterval img, final int[] downsampleFactors, final long[] dimensions) {
+
+ final int[] cellDimensions = new int[]{32};
+ final BlockSupplier blocks = BlockSupplier
+ .of(img.view().extend(Extension.border()))
+ .andThen(Downsample.downsample(downsampleFactors));
+ return BlockAlgoUtils.cellImg(blocks, dimensions, cellDimensions);
+ }
+
+ public static class TestImagePlusBuilder {
+
+ String title = "img";
+ long[] size = new long[]{32, 16, 8};
+ long[] pos = new long[]{16, 8, 4};
+ int value = 1;
+ double[] resolution = new double[]{4, 3, 2};
+ double[] offset = new double[]{0, 0, 0};
+
+ public ImagePlus build() {
+
+ return generateImagePlus3d(title, size, pos, value, resolution, offset);
+ }
+
+ public TestImagePlusBuilder title(String title) {
+
+ this.title = title;
+ return this;
+ }
+
+ public TestImagePlusBuilder size(long[] size) {
+
+ this.size = size;
+ return this;
+ }
+
+ public TestImagePlusBuilder position(long[] pos) {
+
+ this.pos = pos;
+ return this;
+ }
+
+ public TestImagePlusBuilder position(int value) {
+
+ this.value = value;
+ return this;
+ }
+
+ public TestImagePlusBuilder resolution(double[] resolution) {
+
+ this.resolution = resolution;
+ return this;
+ }
+
+ public TestImagePlusBuilder offset(double[] offset) {
+
+ this.offset = offset;
+ return this;
+ }
+
+ }
+
+ public static LandmarkTableModel identityLandmarks(int nd) {
+
+ final long[] min = new long[nd];
+ Arrays.fill(min, -1);
+
+ final long[] max = new long[nd];
+ Arrays.fill(max, 1);
+
+ final double[] ones = DoubleStream.generate(() -> 1.0).limit(nd).toArray();
+ return landmarks(new IntervalIterator(min, max), new Scale(ones));
+ }
+
+ public static LandmarkTableModel landmarks(final IntervalIterator it, RealTransform tform) {
+
+ final int nd = it.numDimensions();
+ final LandmarkTableModel ltm = new LandmarkTableModel(nd);
+
+ final RealPoint pt = new RealPoint(nd);
+ while (it.hasNext()) {
+ it.fwd();
+ tform.apply(it, pt);
+ ltm.add(it.positionAsDoubleArray(), pt.positionAsDoubleArray());
+ }
+
+ return ltm;
+ }
+
+ public static LandmarkTableModel addBboxLandmarks(LandmarkTableModel ltm,
+ RealIntervalIterator it, String nameFormat) {
+
+ int i = 0;
+ while (it.hasNext()) {
+ it.fwd();
+ ltm.add(it.positionAsDoubleArray(), false);
+ int row = ltm.getRowCount() - 1;
+ ltm.setValueAt(String.format(nameFormat, i), row, LandmarkTableModel.NAMECOLUMN);
+ i++;
+ }
+ return ltm;
+ }
+
}
diff --git a/src/test/java/bigwarp/BigWarpTransformCacheTests.java b/src/test/java/bigwarp/BigWarpTransformCacheTests.java
new file mode 100644
index 00000000..7cb88108
--- /dev/null
+++ b/src/test/java/bigwarp/BigWarpTransformCacheTests.java
@@ -0,0 +1,132 @@
+package bigwarp;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.stream.IntStream;
+
+import org.junit.Test;
+
+import bdv.viewer.Source;
+import net.imglib2.Cursor;
+import net.imglib2.Point;
+import net.imglib2.RandomAccess;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.cache.img.CachedCellImg;
+import net.imglib2.realtransform.AffineTransform3D;
+import net.imglib2.realtransform.Scale3D;
+import net.imglib2.realtransform.Translation3D;
+import net.imglib2.type.numeric.integer.AbstractIntegerType;
+import net.imglib2.type.numeric.integer.UnsignedByteType;
+import net.imglib2.view.Views;
+
+public class BigWarpTransformCacheTests {
+
+ /**
+ * Test that cached transformed sources are pixelwise identical to uncached
+ * when using an identity transformation.
+ */
+ @Test
+ public void cachedIdentityTransform() {
+
+ final Source msSrc = BigWarpTestUtils.generateMultiscaleSource(2, "msSrc",
+ new long[]{32, 16, 8},
+ IntStream.of(14, 15).mapToObj(x -> new Point(x, 8, 4)),
+ new double[]{1, 1, 1},
+ new double[]{0, 0, 0});
+
+ final Scale3D identity = new Scale3D(1, 1, 1);
+ final BigWarpData bwData = BigWarpInit.initData();
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, msSrc, 0, true), identity, () -> "identity");
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, msSrc, 1, false));
+ bwData.applyTransformations();
+ bwData.wrapMovingSources();
+
+ Source mvgSrc = bwData.getMovingSource(0).getSpimSource();
+ Source tgtSrc = bwData.getTargetSource(0).getSpimSource();
+ assertEquals("moving source is not cached", CachedCellImg.class, mvgSrc.getSource(0, 0).getClass());
+
+ assertTrue("scale level 0 not equal", equal(tgtSrc.getSource(0, 0), mvgSrc.getSource(0, 0)));
+ assertTrue("scale level 1 not equal", equal(tgtSrc.getSource(0, 1), mvgSrc.getSource(0, 1)));
+ }
+
+ /**
+ * Test that cached transformed sources with an offset are pixelwise
+ * identical to uncached when using an identity transformation.
+ */
+ @Test
+ public void cachedIdentityTransformOffset() {
+
+ final Source msSrc = BigWarpTestUtils.generateMultiscaleSource(2, "msSrc",
+ new long[]{32, 16, 8},
+ IntStream.of(14, 15).mapToObj(x -> new Point(x, 8, 4)),
+ new double[]{1, 1, 1},
+ new double[]{0.2, 1.3, -2.7});
+
+ final Scale3D identity = new Scale3D(1, 1, 1);
+ final BigWarpData bwData = BigWarpInit.initData();
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, msSrc, 0, true), identity, () -> "identity");
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, msSrc, 1, false));
+ bwData.applyTransformations();
+ bwData.wrapMovingSources();
+
+ Source mvgSrc = bwData.getMovingSource(0).getSpimSource();
+ Source tgtSrc = bwData.getTargetSource(0).getSpimSource();
+ assertEquals("moving source is not cached", CachedCellImg.class, mvgSrc.getSource(0, 0).getClass());
+
+ assertTrue("scale level 0 not equal", equal(tgtSrc.getSource(0, 0), mvgSrc.getSource(0, 0)));
+ assertTrue("scale level 1 not equal", equal(tgtSrc.getSource(0, 1), mvgSrc.getSource(0, 1)));
+ }
+
+ /**
+ * Test that cached transformed sources with an offset are pixelwise
+ * identical to uncached when using an identity transformation.
+ */
+ @Test
+ public void cachedTranslationTransformOffset() {
+
+ final Source msSrc = BigWarpTestUtils.generateMultiscaleSource(2, "msSrc",
+ new long[]{32, 16, 8},
+ IntStream.of(14, 15).mapToObj(x -> new Point(x, 8, 4)),
+ new double[]{1, 1, 1},
+ new double[]{0.2, 1.3, -2.7});
+
+ final Translation3D translation = new Translation3D(-2.5, 1.1, 3.3);
+ final BigWarpData bwData = BigWarpInit.initData();
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, msSrc, 0, true), translation, () -> "translation(-2.5, 1.1, 3.3)");
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, msSrc, 1, false));
+ bwData.applyTransformations();
+ bwData.wrapMovingSources();
+
+ Source mvgSrc = bwData.getMovingSource(0).getSpimSource();
+ Source tgtSrc = bwData.getTargetSource(0).getSpimSource();
+ assertEquals("moving source is not cached", CachedCellImg.class, mvgSrc.getSource(0, 0).getClass());
+
+ assertTrue("scale level 0 not equal", equal(tgtSrc.getSource(0, 0), mvgSrc.getSource(0, 0)));
+ assertTrue("scale level 1 not equal", equal(tgtSrc.getSource(0, 1), mvgSrc.getSource(0, 1)));
+
+ final AffineTransform3D mvgTform0 = new AffineTransform3D();
+ mvgSrc.getSourceTransform(0, 0, mvgTform0);
+
+ final AffineTransform3D tgtTform0 = new AffineTransform3D();
+ tgtSrc.getSourceTransform(0, 0, tgtTform0);
+ tgtTform0.preConcatenate(translation);
+
+ assertArrayEquals("mvg transform is not the translated tgt transform", tgtTform0.getRowPackedCopy(), mvgTform0.getRowPackedCopy(), 1e-9);
+ }
+
+ private > boolean equal(RandomAccessibleInterval a, RandomAccessibleInterval b) {
+
+ final Cursor ca = Views.flatIterable(a).cursor();
+ final RandomAccess rab = b.randomAccess();
+ while (ca.hasNext()) {
+ ca.fwd();
+ rab.setPosition(ca);
+ if (ca.get().getInteger() != rab.get().getInteger())
+ return false;
+
+ }
+ return true;
+ }
+}
diff --git a/src/test/java/bigwarp/Sources2Dtests.java b/src/test/java/bigwarp/Sources2Dtests.java
index d1d417d5..0c34c67c 100644
--- a/src/test/java/bigwarp/Sources2Dtests.java
+++ b/src/test/java/bigwarp/Sources2Dtests.java
@@ -77,7 +77,7 @@ public static & RealType> Source loadSource( Stri
AffineTransform3D xfm = new AffineTransform3D();
xfm.translate(0, 0, zOffset);
- return new RandomAccessibleIntervalSource<>(img, Util.getTypeFromInterval(img), xfm, imp.getTitle());
+ return new RandomAccessibleIntervalSource<>(img, img.getType(), xfm, imp.getTitle());
}
}
diff --git a/src/test/java/bigwarp/apply/BigWarpApplyTests.java b/src/test/java/bigwarp/apply/BigWarpApplyTests.java
new file mode 100644
index 00000000..6539d6e8
--- /dev/null
+++ b/src/test/java/bigwarp/apply/BigWarpApplyTests.java
@@ -0,0 +1,291 @@
+package bigwarp.apply;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import org.junit.Test;
+
+import bdv.ij.ApplyBigwarpPlugin;
+import bdv.viewer.Interpolation;
+import bigwarp.BigWarpData;
+import bigwarp.BigWarpInit;
+import bigwarp.BigWarpTestUtils;
+import bigwarp.landmarks.LandmarkTableModel;
+import bigwarp.transforms.BigWarpTransform;
+import ij.ImagePlus;
+import net.imglib2.img.Img;
+import net.imglib2.img.display.imagej.ImageJFunctions;
+import net.imglib2.iterator.RealIntervalIterator;
+import net.imglib2.realtransform.BoundingBoxEstimation;
+import net.imglib2.realtransform.InvertibleRealTransform;
+import net.imglib2.type.numeric.integer.UnsignedByteType;
+import net.imglib2.util.Intervals;
+
+public class BigWarpApplyTests {
+
+ private static final double EPS = 1e-6;
+
+ @Test
+ public void testExportSimple() {
+
+ final long[] pt = new long[]{16, 8, 4};
+ final ImagePlus mvg = new BigWarpTestUtils.TestImagePlusBuilder().title("mvg")
+ .position(pt).build();
+
+ final ImagePlus tgt = new BigWarpTestUtils.TestImagePlusBuilder().title("tgt")
+ .position(pt).build();
+
+ final BigWarpData bwData = BigWarpInit.initData();
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, mvg, 0, 0, true));
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, tgt, 1, 0, false));
+ bwData.wrapMovingSources();
+
+ final LandmarkTableModel ltm = BigWarpTestUtils.identityLandmarks(3);
+ final List resList = transformToTarget(mvg, tgt, ltm);
+ assertEquals(1, resList.size());
+
+ final ImagePlus res = resList.get(0);
+ assertResolutionsEqual(tgt, res);
+ assertOriginsEqual(tgt, res);;
+
+ final Img img = ImageJFunctions.wrapByte(res);
+ assertEquals(1, img.getAt(pt).get());
+ assertEquals(0, img.getAt(0, 0, 0).get());
+ assertEquals(0, img.getAt(pt[0] - 2, pt[1] - 2, pt[2] - 2).get());
+ }
+
+ @Test
+ public void testExportOffset() {
+
+ final long[] pt = new long[]{16, 8, 4};
+ final long[] tgtOffset = new long[]{-3, -2, -1};
+ final double[] tgtOffsetDouble = Arrays.stream(tgtOffset).mapToDouble(x -> x).toArray();
+
+ final long[] tlatedPt = IntStream.of(0, 1, 2).mapToLong(i -> {
+ return pt[i] - tgtOffset[i];
+ }).toArray();
+
+ double[] resolution = new double[]{1, 1, 1};
+ final ImagePlus mvg = new BigWarpTestUtils.TestImagePlusBuilder().title("mvg")
+ .resolution(resolution)
+ .position(pt).build();
+
+ final ImagePlus tgt = new BigWarpTestUtils.TestImagePlusBuilder().title("tgt")
+ .resolution(resolution)
+ .position(pt).offset(tgtOffsetDouble).build();
+
+ final BigWarpData bwData = BigWarpInit.initData();
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, mvg, 0, 0, true));
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, tgt, 1, 0, false));
+ bwData.wrapMovingSources();
+
+ final LandmarkTableModel ltm = BigWarpTestUtils.identityLandmarks(3);
+ final List resList = transformToTarget(mvg, tgt, ltm);
+ assertEquals(1, resList.size());
+
+ final ImagePlus res = resList.get(0);
+ assertResolutionsEqual(tgt, res);
+ assertOriginsEqual(tgt, res);
+
+ final Img img = ImageJFunctions.wrapByte(res);
+ assertEquals(1, img.getAt(tlatedPt).get());
+ assertEquals(0, img.getAt(0, 0, 0).get());
+ assertEquals(0, img.getAt(tlatedPt[0] - 2, tlatedPt[1] - 2, tlatedPt[2] - 2).get());
+ }
+
+ @Test
+ public void testExportFovOffset() {
+
+ final double[] resolution = new double[]{1, 1, 1};
+ final long[] pt = new long[]{16, 8, 4};
+
+ // choose the min such that the non-zero point is at [0,0,0]
+ final double[] min = Arrays.stream(pt).mapToDouble(x -> x).toArray();
+
+ // choose the fov such that the image is size [2,2,2]
+ final double[] fov = IntStream.of(0, 1, 2).mapToDouble(i -> {
+ return 1.9 * resolution[i];
+ }).toArray();
+
+ final ImagePlus mvg = new BigWarpTestUtils.TestImagePlusBuilder().title("mvg")
+ .resolution(resolution)
+ .position(pt).build();
+
+ final BigWarpData bwData = BigWarpInit.initData();
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, mvg, 0, 0, true));
+ bwData.wrapMovingSources();
+
+ final LandmarkTableModel ltm = BigWarpTestUtils.identityLandmarks(3);
+ final List resList = transformToSpec(
+ mvg,
+ min, fov, resolution,
+ ltm);
+
+ assertEquals(1, resList.size());
+ final ImagePlus result = resList.get(0);
+ assertResolutionsEqual(resolution, result);
+ assertOriginsEqual(min, result);
+
+ final Img img = ImageJFunctions.wrapByte(result);
+ assertArrayEquals("result image the wrong size", new long[]{2, 2, 2}, Intervals.dimensionsAsLongArray(img));
+
+ assertEquals(1, img.getAt(0, 0, 0).get());
+ assertEquals(0, img.getAt(1, 1, 1).get());
+ }
+
+ @Test
+ public void testExportPtsSimple() {
+
+ final double[] resolution = new double[]{1, 1, 1};
+ final long[] pt = new long[]{16, 8, 4};
+
+ final ImagePlus mvg = new BigWarpTestUtils.TestImagePlusBuilder().title("mvg")
+ .resolution(resolution)
+ .position(pt).build();
+
+ final BigWarpData bwData = BigWarpInit.initData();
+ BigWarpInit.add(bwData, BigWarpInit.createSources(bwData, mvg, 0, 0, true));
+ bwData.wrapMovingSources();
+
+ // add a set of landmarks that define a 3x3x3 box around the non-zero pixel
+ final double[] min = new double[]{15.0, 7.0, 3.0};
+ final double[] max = new double[]{17.0, 9.0, 5.0};
+ final double[] step = new double[]{1.0, 1.0, 1.0};
+ final long[] expectedResultSize = new long[]{3, 3, 3};
+
+ final LandmarkTableModel ltm = BigWarpTestUtils.identityLandmarks(3);
+ BigWarpTestUtils.addBboxLandmarks(ltm, new RealIntervalIterator(min, max, step), "bbox-%d");
+ final List resList = transformToPtsSpec(mvg, resolution, ltm, "bbox.*");
+
+ assertEquals(1, resList.size());
+ final ImagePlus result = resList.get(0);
+ assertResolutionsEqual(resolution, result);
+ assertOriginsEqual(min, result);
+
+ final Img img = ImageJFunctions.wrapByte(result);
+ assertArrayEquals("result image the wrong size", expectedResultSize, Intervals.dimensionsAsLongArray(img));
+ assertEquals(1, img.getAt(1, 1, 1).get());
+ assertEquals(0, img.getAt(0, 0, 0).get());
+ }
+
+ private static void assertResolutionsEqual(ImagePlus expected, ImagePlus actual) {
+
+ assertEquals("width", expected.getCalibration().pixelWidth, actual.getCalibration().pixelWidth, EPS);
+ assertEquals("height", expected.getCalibration().pixelHeight, actual.getCalibration().pixelHeight, EPS);
+ assertEquals("depth", expected.getCalibration().pixelDepth, actual.getCalibration().pixelDepth, EPS);
+ }
+
+ private static void assertOriginsEqual(ImagePlus expected, ImagePlus actual) {
+
+ assertEquals("origin x", expected.getCalibration().xOrigin, actual.getCalibration().xOrigin, EPS);
+ assertEquals("origin y", expected.getCalibration().yOrigin, actual.getCalibration().yOrigin, EPS);
+ assertEquals("origin z", expected.getCalibration().zOrigin, actual.getCalibration().zOrigin, EPS);
+ }
+
+ private static void assertResolutionsEqual(double[] expected, ImagePlus actual) {
+
+ assertEquals("width", expected[0], actual.getCalibration().pixelWidth, EPS);
+ assertEquals("height", expected[0], actual.getCalibration().pixelHeight, EPS);
+ assertEquals("depth", expected[2], actual.getCalibration().pixelDepth, EPS);
+ }
+
+ private static void assertOriginsEqual(double[] expected, ImagePlus actual) {
+
+ assertEquals("origin x", expected[0], actual.getCalibration().xOrigin, EPS);
+ assertEquals("origin y", expected[1], actual.getCalibration().yOrigin, EPS);
+ assertEquals("origin z", expected[2], actual.getCalibration().zOrigin, EPS);
+ }
+
+ private static List transformToTarget(ImagePlus mvg, ImagePlus tgt, LandmarkTableModel ltm) {
+
+ final BigWarpData> bwData = BigWarpInit.createBigWarpDataFromImages(mvg, tgt);
+ bwData.wrapMovingSources();
+ final BoundingBoxEstimation bboxEst = new BoundingBoxEstimation(BoundingBoxEstimation.Method.CORNERS);
+ final InvertibleRealTransform invXfm = new BigWarpTransform( ltm, BigWarpTransform.AFFINE ).getTransformation();
+
+ return ApplyBigwarpPlugin.apply(
+ bwData,
+ ltm,
+ invXfm,
+ BigWarpTransform.AFFINE, // tform type
+ ApplyBigwarpPlugin.TARGET, // fov option
+ null,
+ bboxEst,
+ ApplyBigwarpPlugin.TARGET,
+ null,
+ null,
+ null,
+ Interpolation.NEARESTNEIGHBOR,
+ false, // virtual
+ 1, // nThreads
+ true,
+ null, // writeOpts
+ false);
+ }
+
+ private static List transformToSpec(final ImagePlus mvg,
+ final double[] offset, final double[] fov, final double[] res,
+ final LandmarkTableModel ltm) {
+
+ ImagePlus tgt = null;
+ final BigWarpData> bwData = BigWarpInit.createBigWarpDataFromImages(mvg, tgt);
+ bwData.wrapMovingSources();
+ final BoundingBoxEstimation bboxEst = new BoundingBoxEstimation(BoundingBoxEstimation.Method.CORNERS);
+ final InvertibleRealTransform invXfm = new BigWarpTransform( ltm, BigWarpTransform.AFFINE ).getTransformation();
+
+ return ApplyBigwarpPlugin.apply(
+ bwData,
+ ltm,
+ invXfm,
+ BigWarpTransform.AFFINE, // tform type
+ ApplyBigwarpPlugin.SPECIFIED_PHYSICAL, // fov option
+ null,
+ bboxEst,
+ ApplyBigwarpPlugin.SPECIFIED,
+ res,
+ fov,
+ offset,
+ Interpolation.NEARESTNEIGHBOR,
+ false, // virtual
+ 1, // nThreads
+ true,
+ null, // writeOpts
+ false);
+ }
+
+ private static List transformToPtsSpec(final ImagePlus mvg,
+ final double[] res,
+ final LandmarkTableModel ltm,
+ final String fieldOfViewPointFilter) {
+
+ ImagePlus tgt = null;
+ final BigWarpData> bwData = BigWarpInit.createBigWarpDataFromImages(mvg, tgt);
+ bwData.wrapMovingSources();
+ final BoundingBoxEstimation bboxEst = new BoundingBoxEstimation(BoundingBoxEstimation.Method.CORNERS);
+ final InvertibleRealTransform invXfm = new BigWarpTransform( ltm, BigWarpTransform.AFFINE ).getTransformation();
+
+ return ApplyBigwarpPlugin.apply(
+ bwData,
+ ltm,
+ invXfm,
+ BigWarpTransform.AFFINE, // tform type
+ ApplyBigwarpPlugin.LANDMARK_POINTS, // fov option
+ fieldOfViewPointFilter,
+ bboxEst,
+ ApplyBigwarpPlugin.SPECIFIED,
+ res,
+ null, // fov
+ null, // offset
+ Interpolation.NEARESTNEIGHBOR,
+ false, // virtual
+ 1, // nThreads
+ true,
+ null, // writeOpts
+ false);
+ }
+
+}