From f2a7107963028a4b327b2670a998abe0ef7cea72 Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Thu, 29 Feb 2024 13:10:11 -0500 Subject: [PATCH] pushed up code from BigStitcher-Spark that can optionally use virtual downsampling (useful if you only access part of the image and the downsampling steps are not available) --- .../DifferenceOfGUI.java | 3 +- .../process/downsampling/DownsampleTools.java | 73 +++++++++---------- .../methods/dog/DoG.java | 6 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/main/java/net/preibisch/mvrecon/fiji/plugin/interestpointdetection/DifferenceOfGUI.java b/src/main/java/net/preibisch/mvrecon/fiji/plugin/interestpointdetection/DifferenceOfGUI.java index dfa3980f0..a4f99a9fa 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/plugin/interestpointdetection/DifferenceOfGUI.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/plugin/interestpointdetection/DifferenceOfGUI.java @@ -485,7 +485,8 @@ protected ImagePlus getImagePlusForInteractive( final String dialogHeader ) RandomAccessibleInterval> imgGeneric = DownsampleTools.openAndDownsample( spimData.getSequenceDescription().getImgLoader(), viewDescription, - new long[] { downsampleXY, downsampleXY, downsampleZ } ).getA(); + new long[] { downsampleXY, downsampleXY, downsampleZ }, + true ).getA(); if ( imgGeneric == null ) { diff --git a/src/main/java/net/preibisch/mvrecon/process/downsampling/DownsampleTools.java b/src/main/java/net/preibisch/mvrecon/process/downsampling/DownsampleTools.java index 960d7e068..84d00f183 100644 --- a/src/main/java/net/preibisch/mvrecon/process/downsampling/DownsampleTools.java +++ b/src/main/java/net/preibisch/mvrecon/process/downsampling/DownsampleTools.java @@ -33,11 +33,15 @@ import mpicbg.spim.data.sequence.VoxelDimensions; import net.imglib2.RandomAccessibleInterval; import net.imglib2.realtransform.AffineTransform3D; +import net.imglib2.type.numeric.real.FloatType; import net.imglib2.util.Pair; import net.imglib2.util.Util; import net.imglib2.util.ValuePair; +import net.imglib2.view.Views; import net.preibisch.legacy.io.IOFunctions; import net.preibisch.mvrecon.fiji.spimdata.interestpoints.InterestPoint; +import net.preibisch.mvrecon.process.downsampling.lazy.LazyDownsample2x; +import net.preibisch.mvrecon.process.interestpointdetection.methods.dog.DoGImgLib2; public class DownsampleTools { @@ -394,7 +398,7 @@ public static AffineTransform3D getMipMapTransform( { final AffineTransform3D mmt = new AffineTransform3D(); - openAndDownsample( imgLoader, vd, mmt, downsampleFactors, true ); + openAndDownsample( imgLoader, vd, mmt, downsampleFactors, true, false ); return mmt; } @@ -406,17 +410,19 @@ public static AffineTransform3D getMipMapTransform( * @param imgLoader the imgloader * @param vd the view id * @param downsampleFactors - specify which downsampling in each dimension (e.g. 1,2,4,8 ) + * @param virtualDownsampling - use virtual downsampling if the requested downsamplefactors are not precomputed * @return opened image and the mipmap transform */ @SuppressWarnings({ "rawtypes" }) public static Pair openAndDownsample( final BasicImgLoader imgLoader, final ViewId vd, - final long[] downsampleFactors ) + final long[] downsampleFactors, + final boolean virtualDownsampling ) { final AffineTransform3D mipMapTransform = new AffineTransform3D(); - final RandomAccessibleInterval img = openAndDownsample(imgLoader, vd, mipMapTransform, downsampleFactors, false ); + final RandomAccessibleInterval img = openAndDownsample(imgLoader, vd, mipMapTransform, downsampleFactors, false, virtualDownsampling ); return new ValuePair( img, mipMapTransform ); } @@ -429,6 +435,7 @@ public static Pair openAndDownsampl * @param vd the view id * @param mipMapTransform - will be filled if downsampling is performed, otherwise identity transform * @param downsampleFactors - specify which downsampling in each dimension (e.g. 1,2,4,8 ) + * @param virtualDownsampling - use virtual downsampling if the requested downsamplefactors are not precomputed * @param transformOnly - if true does not open any images but only provides the mipMapTransform (METHOD WILL RETURN NULL!) * @return opened image */ @@ -438,14 +445,9 @@ private static RandomAccessibleInterval openAndDownsample( final ViewId vd, final AffineTransform3D mipMapTransform, long[] downsampleFactors, - final boolean transformOnly ) // only for ImgLib1 legacy code + final boolean transformOnly, // only for ImgLib1 legacy code + final boolean virtualDownsampling ) { - - //if ( !transformOnly ) - // IOFunctions.println( - // "(" + new Date(System.currentTimeMillis()) + "): " - // + "Requesting Img from ImgLoader (tp=" + vd.getTimePointId() + ", setup=" + vd.getViewSetupId() + "), downsampling: " + Util.printCoordinates( downsampleFactors ) ); - long dsx = downsampleFactors[0]; long dsy = downsampleFactors[1]; long dsz = (downsampleFactors.length > 2) ? downsampleFactors[ 2 ] : 1; @@ -485,31 +487,14 @@ private static RandomAccessibleInterval openAndDownsample( if ( !transformOnly ) { - //IOFunctions.println( - // "(" + new Date(System.currentTimeMillis()) + "): " + - // "Using precomputed Multiresolution Images [" + fx + "x" + fy + "x" + fz + "], " + - // "Remaining downsampling [" + dsx + "x" + dsy + "x" + dsz + "]" ); - - //if ( openAsFloat ) - // input = ImgLib2Tools.convertVirtual( (RandomAccessibleInterval)mrImgLoader.getSetupImgLoader( vd.getViewSetupId() ).getImage( vd.getTimePointId(), bestLevel ) ); - //else - input = mrImgLoader.getSetupImgLoader( vd.getViewSetupId() ).getImage( vd.getTimePointId(), bestLevel ); + input = mrImgLoader.getSetupImgLoader( vd.getViewSetupId() ).getImage( vd.getTimePointId(), bestLevel ); } } else { if ( !transformOnly ) { - //IOFunctions.println( - // "(" + new Date(System.currentTimeMillis()) + "): " + - // "Using precomputed Multiresolution Images [1x1x1], " + - // "Remaining downsampling [" + dsx + "x" + dsy + "x" + dsz + "]" ); - - // we only need to do the complete opening when we do not perform additional downsampling below - //if ( openAsFloat ) - // input = ImgLib2Tools.convertVirtual( (RandomAccessibleInterval)imgLoader.getSetupImgLoader( vd.getViewSetupId() ).getImage( vd.getTimePointId() ) ); - //else - input = imgLoader.getSetupImgLoader( vd.getViewSetupId() ).getImage( vd.getTimePointId() ); + input = imgLoader.getSetupImgLoader( vd.getViewSetupId() ).getImage( vd.getTimePointId() ); } if ( mipMapTransform != null ) @@ -521,7 +506,7 @@ private static RandomAccessibleInterval openAndDownsample( // the additional downsampling (performed below) final AffineTransform3D additonalDS = new AffineTransform3D(); additonalDS.set( dsx, 0.0, 0.0, 0.0, 0.0, dsy, 0.0, 0.0, 0.0, 0.0, dsz, 0.0 ); - + // we need to concatenate since when correcting for the downsampling we first multiply by whatever // the manual downsampling did, and just then by the scaling+offset of the HDF5 // @@ -534,15 +519,29 @@ private static RandomAccessibleInterval openAndDownsample( if ( !transformOnly ) { - // note: every pixel is read exactly once, therefore caching the virtual input would not give any advantages - for ( ;dsx > 1; dsx /= 2 ) - input = Downsample.simple2x( input, new boolean[]{ true, false, false } ); + if ( virtualDownsampling ) + { + for ( ;dsx > 1; dsx /= 2 ) + input = LazyDownsample2x.init( Views.extendBorder( input ), input, new FloatType(), DoGImgLib2.blockSize, 0 ); - for ( ;dsy > 1; dsy /= 2 ) - input = Downsample.simple2x( input, new boolean[]{ false, true, false } ); + for ( ;dsy > 1; dsy /= 2 ) + input = LazyDownsample2x.init( Views.extendBorder( input ), input, new FloatType(), DoGImgLib2.blockSize, 1 ); - for ( ;dsz > 1; dsz /= 2 ) - input = Downsample.simple2x( input, new boolean[]{ false, false, true } ); + for ( ;dsz > 1; dsz /= 2 ) + input = LazyDownsample2x.init( Views.extendBorder( input ), input, new FloatType(), DoGImgLib2.blockSize, 2 ); + } + else + { + // note: every pixel is read exactly once, therefore caching the virtual input would not give any advantages + for ( ;dsx > 1; dsx /= 2 ) + input = Downsample.simple2x( input, new boolean[]{ true, false, false } ); + + for ( ;dsy > 1; dsy /= 2 ) + input = Downsample.simple2x( input, new boolean[]{ false, true, false } ); + + for ( ;dsz > 1; dsz /= 2 ) + input = Downsample.simple2x( input, new boolean[]{ false, false, true } ); + } } return input; diff --git a/src/main/java/net/preibisch/mvrecon/process/interestpointdetection/methods/dog/DoG.java b/src/main/java/net/preibisch/mvrecon/process/interestpointdetection/methods/dog/DoG.java index 3793b6e7c..4d2abcc47 100644 --- a/src/main/java/net/preibisch/mvrecon/process/interestpointdetection/methods/dog/DoG.java +++ b/src/main/java/net/preibisch/mvrecon/process/interestpointdetection/methods/dog/DoG.java @@ -142,15 +142,15 @@ public static void addInterestPoints( final HashMap< ViewId, List< InterestPoint final ExecutorService service = Threads.createFixedExecutorService( Threads.numThreads() ); - // TODO: downsampling is not virtual! + // downsampling is not virtual! @SuppressWarnings({"rawtypes" }) final Pair input = DownsampleTools.openAndDownsample( dog.imgloader, vd, - new long[] { dog.downsampleXY, dog.downsampleXY, dog.downsampleZ } ); + new long[] { dog.downsampleXY, dog.downsampleXY, dog.downsampleZ }, + false ); - @SuppressWarnings("unchecked") List< InterestPoint > ips = DoGImgLib2.computeDoG( Views.extendMirrorSingle( input.getA() ), null, // mask