From d2df63c4c25cc5d931bd55cedaa4e7dd9f05f8d9 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Fri, 5 Feb 2021 11:14:10 +0100 Subject: [PATCH 1/9] Init class DownsampleLabelBlockInstances --- src/main/java/bdv/export/DownsampleBlock.java | 203 +++++++++++++++++- 1 file changed, 199 insertions(+), 4 deletions(-) diff --git a/src/main/java/bdv/export/DownsampleBlock.java b/src/main/java/bdv/export/DownsampleBlock.java index 8f43abb2..7e594080 100644 --- a/src/main/java/bdv/export/DownsampleBlock.java +++ b/src/main/java/bdv/export/DownsampleBlock.java @@ -60,7 +60,7 @@ class DownsampleBlockInstances public static < T extends RealType< T > > DownsampleBlock< T > create( final int[] blockDimensions, final int[] downsamplingFactors, - final Class< ? > pixelTypeClass, + final Class< ? > pixelTypeClass, final Class< ? > inAccessClass ) { if ( provider == null ) @@ -120,13 +120,207 @@ public void downsampleBlock( { downsampleBlock3D( acc, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], in ); writeOutput3D( out, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], acc ); - } - else if ( n == 2 ) + } else if ( n == 2 ) { downsampleBlock2D( acc, dimensions[ 0 ], dimensions[ 1 ], in ); writeOutput2D( out, dimensions[ 0 ], dimensions[ 1 ], acc ); + } else + { + downsampleBlock1D( acc, dimensions[ 0 ], in ); + writeOutput1D( out, dimensions[ 0 ], acc ); + } + } + + private void clearAccumulator() + { + Arrays.fill( accumulator, 0, accumulator.length, 0 ); + } + + private void downsampleBlock3D( + final RandomAccess< DoubleType > acc, + final int asx, // size of output (resp accumulator) image + final int asy, + final int asz, + final RandomAccess< T > in ) + { + final int bsz = downsamplingFactors[ 2 ]; + final int sz = asz * bsz; + for ( int z = 0, bz = 0; z < sz; ++z ) + { + downsampleBlock2D( acc, asx, asy, in ); + in.fwd( 2 ); + if ( ++bz == bsz ) + { + bz = 0; + acc.fwd( 2 ); + } + } + in.move( -sz, 2 ); + acc.move( -asz, 2 ); + } + + private void downsampleBlock2D( + final RandomAccess< DoubleType > acc, + final int asx, // size of output (resp accumulator) image + final int asy, + final RandomAccess< T > in ) + { + final int bsy = downsamplingFactors[ 1 ]; + final int sy = asy * bsy; + for ( int y = 0, by = 0; y < sy; ++y ) + { + downsampleBlock1D( acc, asx, in ); + in.fwd( 1 ); + if ( ++by == bsy ) + { + by = 0; + acc.fwd( 1 ); + } + } + in.move( -sy, 1 ); + acc.move( -asy, 1 ); + } + + private void downsampleBlock1D( + final RandomAccess< DoubleType > acc, + final int asx, // size of output (resp accumulator) image + final RandomAccess< T > in ) + { + final int bsx = downsamplingFactors[ 0 ]; + final int sx = asx * bsx; + for ( int x = 0, bx = 0; x < sx; ++x ) + { + acc.get().set( acc.get().get() + in.get().getRealDouble() ); + in.fwd( 0 ); + if ( ++bx == bsx ) + { + bx = 0; + acc.fwd( 0 ); + } + } + in.move( -sx, 0 ); + acc.move( -asx, 0 ); + } + + private void writeOutput3D( + final Cursor< T > out, // must be flat iteration order + final int asx, // size of output (resp accumulator) image + final int asy, + final int asz, + final RandomAccess< DoubleType > acc ) + { + for ( int z = 0; z < asz; ++z ) + { + writeOutput2D( out, asx, asy, acc ); + acc.fwd( 2 ); + } + acc.move( -asz, 2 ); + } + + private void writeOutput2D( + final Cursor< T > out, // must be flat iteration order + final int asx, // size of output (resp accumulator) image + final int asy, + final RandomAccess< DoubleType > acc ) + { + for ( int y = 0; y < asy; ++y ) + { + writeOutput1D( out, asx, acc ); + acc.fwd( 1 ); + } + acc.move( -asy, 1 ); + } + + private void writeOutput1D( + final Cursor< T > out, // must be flat iteration order + final int asx, // size of output (resp accumulator) image + final RandomAccess< DoubleType > acc ) + { + final double scale = this.scale; + for ( int x = 0; x < asx; ++x ) + { + out.next().setReal( acc.get().get() * scale ); + acc.fwd( 0 ); } - else + acc.move( -asx, 0 ); + } + } +} + +class DownsampleLabelBlockInstances +{ + @SuppressWarnings( "rawtypes" ) + private static ClassCopyProvider< DownsampleBlock > provider; + + @SuppressWarnings( "unchecked" ) + public static < T extends RealType< T > > DownsampleBlock< T > create( + final int[] blockDimensions, + final int[] downsamplingFactors, + final Class< ? > pixelTypeClass, + final Class< ? > inAccessClass ) + { + if ( provider == null ) + { + synchronized ( bdv.export.DownsampleBlockInstances.class ) + { + if ( provider == null ) + provider = new ClassCopyProvider<>( bdv.export.DownsampleBlockInstances.Imp.class, DownsampleBlock.class, int[].class, int[].class ); + } + } + + final int numDimensions = blockDimensions.length; + + Object key = Arrays.asList( numDimensions, pixelTypeClass, inAccessClass ); + return provider.newInstanceForKey( key, blockDimensions, downsamplingFactors ); + } + + public static class LabelImp< T extends RealType< T > > implements DownsampleBlock< T > + { + private final int n; + + private final int[] downsamplingFactors; + + private final double scale; + + private final double[] accumulator; + + private final RandomAccess< DoubleType > acc; + + public LabelImp( + final int[] blockDimensions, + final int[] downsamplingFactors ) + { + n = blockDimensions.length; + if ( n < 1 || n > 3 ) + throw new IllegalArgumentException(); + + this.downsamplingFactors = downsamplingFactors; + scale = 1.0 / Intervals.numElements( downsamplingFactors ); + + accumulator = new double[ ( int ) Intervals.numElements( blockDimensions ) ]; + + final long[] dims = new long[ n ]; + Arrays.setAll( dims, d -> blockDimensions[ d ] ); + acc = ArrayImgs.doubles( accumulator, dims ).randomAccess(); + } + + @Override + public void downsampleBlock( + final RandomAccess< T > in, + final Cursor< T > out, // must be flat iteration order + final int[] dimensions ) + { + clearAccumulator(); + + if ( n == 3 ) + { + downsampleBlock3D( acc, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], in ); + writeOutput3D( out, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], acc ); + } else if ( n == 2 ) + { + downsampleBlock2D( acc, dimensions[ 0 ], dimensions[ 1 ], in ); + writeOutput2D( out, dimensions[ 0 ], dimensions[ 1 ], acc ); + } else { downsampleBlock1D( acc, dimensions[ 0 ], in ); writeOutput1D( out, dimensions[ 0 ], acc ); @@ -248,3 +442,4 @@ private void writeOutput1D( } } } + From 14164a22fb524d1d6c4dc15fca4ce4b92c2718c2 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Fri, 5 Feb 2021 20:27:52 +0100 Subject: [PATCH 2/9] Modify DownsampleBlock --- src/main/java/bdv/export/DownsampleBlock.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/bdv/export/DownsampleBlock.java b/src/main/java/bdv/export/DownsampleBlock.java index 7e594080..0603676f 100644 --- a/src/main/java/bdv/export/DownsampleBlock.java +++ b/src/main/java/bdv/export/DownsampleBlock.java @@ -29,6 +29,8 @@ package bdv.export; import java.util.Arrays; +import java.util.HashSet; + import net.imglib2.Cursor; import net.imglib2.RandomAccess; import net.imglib2.img.array.ArrayImgs; @@ -382,6 +384,7 @@ private void downsampleBlock1D( final int asx, // size of output (resp accumulator) image final RandomAccess< T > in ) { + final int bsx = downsamplingFactors[ 0 ]; final int sx = asx * bsx; for ( int x = 0, bx = 0; x < sx; ++x ) From ef39a5261c1d08dd7b3f354c7faeca6867f8ba80 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Sun, 7 Feb 2021 15:06:11 +0100 Subject: [PATCH 3/9] WIP Implement central pixel downsampling --- pom.xml | 3 +- src/main/java/bdv/export/DownsampleBlock.java | 153 ++++++++---------- .../java/bdv/export/ExportScalePyramid.java | 3 +- .../java/bdv/export/WriteSequenceToHdf5.java | 18 ++- 4 files changed, 80 insertions(+), 97 deletions(-) diff --git a/pom.xml b/pom.xml index a49ce776..443afcba 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,8 @@ sc.fiji bigdataviewer-core - 10.2.1-SNAPSHOT + + 10.2.1-TISCHI BigDataViewer Core BigDataViewer core classes with minimal dependencies. diff --git a/src/main/java/bdv/export/DownsampleBlock.java b/src/main/java/bdv/export/DownsampleBlock.java index 0603676f..d47f2ec5 100644 --- a/src/main/java/bdv/export/DownsampleBlock.java +++ b/src/main/java/bdv/export/DownsampleBlock.java @@ -29,7 +29,6 @@ package bdv.export; import java.util.Arrays; -import java.util.HashSet; import net.imglib2.Cursor; import net.imglib2.RandomAccess; @@ -41,15 +40,22 @@ public interface DownsampleBlock< T extends RealType< T > > { + enum DownsamplingMethod + { + Average, + CentralPixel + } + void downsampleBlock( final RandomAccess< T > in, final Cursor< T > out, final int[] dimensions ); static < T extends RealType< T > > DownsampleBlock< T > create( final int[] blockDimensions, final int[] downsamplingFactors, + final DownsamplingMethod downsamplingMethod, final Class< ? > pixelTypeClass, final Class< ? > inAccessClass ) { - return DownsampleBlockInstances.create( blockDimensions, downsamplingFactors, pixelTypeClass, inAccessClass ); + return DownsampleBlockInstances.create( blockDimensions, downsamplingFactors, downsamplingMethod, pixelTypeClass, inAccessClass ); } } @@ -62,6 +68,7 @@ class DownsampleBlockInstances public static < T extends RealType< T > > DownsampleBlock< T > create( final int[] blockDimensions, final int[] downsamplingFactors, + DownsampleBlock.DownsamplingMethod downsamplingMethod, final Class< ? > pixelTypeClass, final Class< ? > inAccessClass ) { @@ -70,7 +77,17 @@ public static < T extends RealType< T > > DownsampleBlock< T > create( synchronized ( DownsampleBlockInstances.class ) { if ( provider == null ) - provider = new ClassCopyProvider<>( Imp.class, DownsampleBlock.class, int[].class, int[].class ); + { + switch ( downsamplingMethod ) + { + case Average: + provider = new ClassCopyProvider<>( AverageDownsampler.class, DownsampleBlock.class, int[].class, int[].class ); + break; + case CentralPixel: + provider = new ClassCopyProvider<>( CentralPixelDownsampler.class, DownsampleBlock.class, int[].class, int[].class ); + break; + } + } } } @@ -80,7 +97,7 @@ public static < T extends RealType< T > > DownsampleBlock< T > create( return provider.newInstanceForKey( key, blockDimensions, downsamplingFactors ); } - public static class Imp< T extends RealType< T > > implements DownsampleBlock< T > + public static class AverageDownsampler< T extends RealType< T > > implements DownsampleBlock< T > { private final int n; @@ -92,7 +109,7 @@ public static class Imp< T extends RealType< T > > implements DownsampleBlock< T private final RandomAccess< DoubleType > acc; - public Imp( + public AverageDownsampler( final int[] blockDimensions, final int[] downsamplingFactors ) { @@ -247,36 +264,8 @@ private void writeOutput1D( acc.move( -asx, 0 ); } } -} -class DownsampleLabelBlockInstances -{ - @SuppressWarnings( "rawtypes" ) - private static ClassCopyProvider< DownsampleBlock > provider; - - @SuppressWarnings( "unchecked" ) - public static < T extends RealType< T > > DownsampleBlock< T > create( - final int[] blockDimensions, - final int[] downsamplingFactors, - final Class< ? > pixelTypeClass, - final Class< ? > inAccessClass ) - { - if ( provider == null ) - { - synchronized ( bdv.export.DownsampleBlockInstances.class ) - { - if ( provider == null ) - provider = new ClassCopyProvider<>( bdv.export.DownsampleBlockInstances.Imp.class, DownsampleBlock.class, int[].class, int[].class ); - } - } - - final int numDimensions = blockDimensions.length; - - Object key = Arrays.asList( numDimensions, pixelTypeClass, inAccessClass ); - return provider.newInstanceForKey( key, blockDimensions, downsamplingFactors ); - } - - public static class LabelImp< T extends RealType< T > > implements DownsampleBlock< T > + public static class CentralPixelDownsampler< T extends RealType< T > > implements DownsampleBlock< T > { private final int n; @@ -284,11 +273,11 @@ public static class LabelImp< T extends RealType< T > > implements DownsampleBlo private final double scale; - private final double[] accumulator; + private final double[] outImgArray; - private final RandomAccess< DoubleType > acc; + private final RandomAccess< DoubleType > outImg; - public LabelImp( + public CentralPixelDownsampler( final int[] blockDimensions, final int[] downsamplingFactors ) { @@ -299,11 +288,11 @@ public LabelImp( this.downsamplingFactors = downsamplingFactors; scale = 1.0 / Intervals.numElements( downsamplingFactors ); - accumulator = new double[ ( int ) Intervals.numElements( blockDimensions ) ]; + outImgArray = new double[ ( int ) Intervals.numElements( blockDimensions ) ]; final long[] dims = new long[ n ]; Arrays.setAll( dims, d -> blockDimensions[ d ] ); - acc = ArrayImgs.doubles( accumulator, dims ).randomAccess(); + outImg = ArrayImgs.doubles( outImgArray, dims ).randomAccess(); } @Override @@ -316,89 +305,74 @@ public void downsampleBlock( if ( n == 3 ) { - downsampleBlock3D( acc, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], in ); - writeOutput3D( out, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], acc ); + downsampleBlock3D( outImg, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], in ); + writeOutput3D( out, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], outImg ); } else if ( n == 2 ) { - downsampleBlock2D( acc, dimensions[ 0 ], dimensions[ 1 ], in ); - writeOutput2D( out, dimensions[ 0 ], dimensions[ 1 ], acc ); + downsampleBlock2D( outImg, dimensions[ 0 ], dimensions[ 1 ], in ); + writeOutput2D( out, dimensions[ 0 ], dimensions[ 1 ], outImg ); } else { - downsampleBlock1D( acc, dimensions[ 0 ], in ); - writeOutput1D( out, dimensions[ 0 ], acc ); + downsampleBlock1D( outImg, dimensions[ 0 ], in ); + writeOutput1D( out, dimensions[ 0 ], outImg ); } } private void clearAccumulator() { - Arrays.fill( accumulator, 0, accumulator.length, 0 ); + Arrays.fill( outImgArray, 0, outImgArray.length, 0 ); } private void downsampleBlock3D( - final RandomAccess< DoubleType > acc, - final int asx, // size of output (resp accumulator) image - final int asy, - final int asz, + final RandomAccess< DoubleType > out, + final int osx, // size of output image + final int osy, + final int osz, final RandomAccess< T > in ) { final int bsz = downsamplingFactors[ 2 ]; - final int sz = asz * bsz; - for ( int z = 0, bz = 0; z < sz; ++z ) + in.move( bsz / 2, 2 ); + for ( int oz = 0; oz < osz; ++oz ) { - downsampleBlock2D( acc, asx, asy, in ); - in.fwd( 2 ); - if ( ++bz == bsz ) - { - bz = 0; - acc.fwd( 2 ); - } + downsampleBlock2D( out, osx, osy, in ); + in.move( bsz, 2 ); + out.fwd( 2 ); } - in.move( -sz, 2 ); - acc.move( -asz, 2 ); + in.move( - bsz * osz - bsz / 2, 2 ); + out.move( -osz, 2 ); } private void downsampleBlock2D( - final RandomAccess< DoubleType > acc, - final int asx, // size of output (resp accumulator) image - final int asy, + final RandomAccess< DoubleType > out, + final int osx, // size of output image + final int osy, final RandomAccess< T > in ) { final int bsy = downsamplingFactors[ 1 ]; - final int sy = asy * bsy; - for ( int y = 0, by = 0; y < sy; ++y ) + in.move( bsy / 2, 1 ); + for ( int oy = 0; oy < osy; ++oy ) { - downsampleBlock1D( acc, asx, in ); - in.fwd( 1 ); - if ( ++by == bsy ) - { - by = 0; - acc.fwd( 1 ); - } + downsampleBlock1D( out, osx, in ); + in.move( bsy, 2 ); + out.fwd( 2 ); } - in.move( -sy, 1 ); - acc.move( -asy, 1 ); + in.move( - bsy * osy - bsy / 2, 2 ); + out.move( -osy, 2 ); } private void downsampleBlock1D( - final RandomAccess< DoubleType > acc, - final int asx, // size of output (resp accumulator) image + final RandomAccess< DoubleType > out, + final int osx, // size of output image final RandomAccess< T > in ) { - final int bsx = downsamplingFactors[ 0 ]; - final int sx = asx * bsx; - for ( int x = 0, bx = 0; x < sx; ++x ) + in.move( bsx / 2, 0 ); + for ( int ox = 0; ox < osx; ++ox ) { - acc.get().set( acc.get().get() + in.get().getRealDouble() ); - in.fwd( 0 ); - if ( ++bx == bsx ) - { - bx = 0; - acc.fwd( 0 ); - } + out.get().set( in.get().getRealDouble() ); } - in.move( -sx, 0 ); - acc.move( -asx, 0 ); + in.move( - bsx * osx - bsx / 2, 2 ); + out.move( -osx, 2 ); } private void writeOutput3D( @@ -446,3 +420,4 @@ private void writeOutput1D( } } + diff --git a/src/main/java/bdv/export/ExportScalePyramid.java b/src/main/java/bdv/export/ExportScalePyramid.java index 7e3a601b..a7da2b97 100644 --- a/src/main/java/bdv/export/ExportScalePyramid.java +++ b/src/main/java/bdv/export/ExportScalePyramid.java @@ -227,6 +227,7 @@ public static < T extends RealType< T > & NativeType< T >, D > void writeScalePy final RandomAccessibleInterval< T > img, final T type, final ExportMipmapInfo mipmapInfo, + final DownsampleBlock.DownsamplingMethod downsamplingMethod, final DatasetIO< D, T > io, final ExecutorService executorService, final int numThreads, @@ -362,7 +363,7 @@ public static < T extends RealType< T > & NativeType< T >, D > void writeScalePy final Class< ? extends RealType > kl1 = type.getClass(); final Class< ? extends RandomAccess > kl2 = in.getClass(); final CopyBlock< T > copyBlock = fullResolution ? CopyBlock.create( n, kl1, kl2 ) : null; - final DownsampleBlock< T > downsampleBlock = fullResolution ? null : DownsampleBlock.create( cellDimensions, factor, kl1, kl2 ); + final DownsampleBlock< T > downsampleBlock = fullResolution ? null : DownsampleBlock.create( cellDimensions, factor, downsamplingMethod, kl1, kl2 ); for ( int i = nextCellInPlane.getAndIncrement(); i < numBlocksPerPlane; i = nextCellInPlane.getAndIncrement() ) { diff --git a/src/main/java/bdv/export/WriteSequenceToHdf5.java b/src/main/java/bdv/export/WriteSequenceToHdf5.java index 591f8a4c..bd350872 100644 --- a/src/main/java/bdv/export/WriteSequenceToHdf5.java +++ b/src/main/java/bdv/export/WriteSequenceToHdf5.java @@ -133,6 +133,7 @@ public class WriteSequenceToHdf5 public static void writeHdf5File( final AbstractSequenceDescription< ?, ?, ? > seq, final Map< Integer, ExportMipmapInfo > perSetupMipmapInfo, + final DownsampleBlock.DownsamplingMethod downsamplingMethod, final boolean deflate, final File hdf5File, final LoopbackHeuristic loopbackHeuristic, @@ -149,13 +150,13 @@ public static void writeHdf5File( setupIdSequenceToPartition.put( setup.getId(), setup.getId() ); final Partition partition = new Partition( hdf5File.getPath(), timepointIdSequenceToPartition, setupIdSequenceToPartition ); - writeHdf5PartitionFile( seq, perSetupMipmapInfo, deflate, partition, loopbackHeuristic, afterEachPlane, numCellCreatorThreads, progressWriter ); + writeHdf5PartitionFile( seq, perSetupMipmapInfo, downsamplingMethod, deflate, partition, loopbackHeuristic, afterEachPlane, numCellCreatorThreads, progressWriter ); } /** * Create a hdf5 file containing image data from all views and all * timepoints in a chunked, mipmaped representation. This is the same as - * {@link WriteSequenceToHdf5#writeHdf5File(AbstractSequenceDescription, Map, boolean, File, LoopbackHeuristic, AfterEachPlane, int, ProgressWriter)} + * {@link WriteSequenceToHdf5#writeHdf5File(AbstractSequenceDescription, Map, DownsampleBlock.DownsamplingMethod, boolean, File, LoopbackHeuristic, AfterEachPlane, int, ProgressWriter)} * except that only one set of supsampling factors and and subdivision * blocksizes is given, which is used for all {@link BasicViewSetup views}. * @@ -195,6 +196,7 @@ public static void writeHdf5File( final AbstractSequenceDescription< ?, ?, ? > seq, final int[][] resolutions, final int[][] subdivisions, + final DownsampleBlock.DownsamplingMethod downsamplingMethod, final boolean deflate, final File hdf5File, final LoopbackHeuristic loopbackHeuristic, @@ -206,7 +208,7 @@ public static void writeHdf5File( final ExportMipmapInfo mipmapInfo = new ExportMipmapInfo( resolutions, subdivisions ); for ( final BasicViewSetup setup : seq.getViewSetupsOrdered() ) perSetupMipmapInfo.put( setup.getId(), mipmapInfo ); - writeHdf5File( seq, perSetupMipmapInfo, deflate, hdf5File, loopbackHeuristic, afterEachPlane, numCellCreatorThreads, progressWriter ); + writeHdf5File( seq, perSetupMipmapInfo, downsamplingMethod, deflate, hdf5File, loopbackHeuristic, afterEachPlane, numCellCreatorThreads, progressWriter ); } /** @@ -245,7 +247,7 @@ public static void writeHdf5PartitionLinkFile( final AbstractSequenceDescription * * Note that this method only writes the master file containing links. The * individual partitions need to be written with - * {@link #writeHdf5PartitionFile(AbstractSequenceDescription, Map, boolean, Partition, LoopbackHeuristic, AfterEachPlane, int, ProgressWriter)}. + * {@link #writeHdf5PartitionFile(AbstractSequenceDescription, Map, bdv.export.DownsampleBlock.DownsamplingMethod, boolean, Partition, LoopbackHeuristic, AfterEachPlane, int, ProgressWriter)}. * * @param seq * description of the sequence to be stored as hdf5. (The @@ -354,6 +356,7 @@ public static void writeHdf5PartitionLinkFile( final AbstractSequenceDescription public static void writeHdf5PartitionFile( final AbstractSequenceDescription< ?, ?, ? > seq, final Map< Integer, ExportMipmapInfo > perSetupMipmapInfo, + final DownsampleBlock.DownsamplingMethod downsamplingMethod, final boolean deflate, final Partition partition, final LoopbackHeuristic loopbackHeuristic, @@ -449,7 +452,7 @@ public static void writeHdf5PartitionFile( final ProgressWriter subProgressWriter = new SubTaskProgressWriter( progressWriter, startCompletionRatio, endCompletionRatio ); writeViewToHdf5PartitionFile( - img, timepointIdPartition, setupIdPartition, mipmapInfo, false, + img, timepointIdPartition, setupIdPartition, mipmapInfo, false, downsamplingMethod, deflate, writerQueue, executorService, numCellCreatorThreads, loopbackHeuristic, afterEachPlane, subProgressWriter ); } } @@ -515,6 +518,7 @@ public static void writeViewToHdf5PartitionFile( final int setupIdPartition, final ExportMipmapInfo mipmapInfo, final boolean writeMipmapInfo, + final DownsampleBlock.DownsamplingMethod downsamplingMethod, final boolean deflate, final LoopbackHeuristic loopbackHeuristic, final AfterEachPlane afterEachPlane, @@ -532,7 +536,7 @@ public static void writeViewToHdf5PartitionFile( try { // write the image - writeViewToHdf5PartitionFile( img, timepointIdPartition, setupIdPartition, mipmapInfo, writeMipmapInfo, deflate, writerQueue, executorService, numCellCreatorThreads, loopbackHeuristic, afterEachPlane, progressWriter ); + writeViewToHdf5PartitionFile( img, timepointIdPartition, setupIdPartition, mipmapInfo, writeMipmapInfo, downsamplingMethod, deflate, writerQueue, executorService, numCellCreatorThreads, loopbackHeuristic, afterEachPlane, progressWriter ); } finally { @@ -661,6 +665,7 @@ public static void writeViewToHdf5PartitionFile( final int setupIdPartition, final ExportMipmapInfo mipmapInfo, final boolean writeMipmapInfo, + final DownsampleBlock.DownsamplingMethod downsamplingMethod, final boolean deflate, final IHDF5Access writerQueue, final ExecutorService executorService, // TODO @@ -689,6 +694,7 @@ public static void writeViewToHdf5PartitionFile( img, new UnsignedShortType(), mipmapInfo, + downsamplingMethod, io, executorService, numThreads, From 51f7020ec354e78af0676db7adb3648191d7bbf7 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Sun, 7 Feb 2021 15:09:26 +0100 Subject: [PATCH 4/9] WIP Implement central pixel downsampling --- src/main/java/bdv/export/n5/WriteSequenceToN5.java | 8 ++------ src/main/java/bdv/tools/crop/CropDialog.java | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/bdv/export/n5/WriteSequenceToN5.java b/src/main/java/bdv/export/n5/WriteSequenceToN5.java index d5cd0dfc..4c5a8dc0 100644 --- a/src/main/java/bdv/export/n5/WriteSequenceToN5.java +++ b/src/main/java/bdv/export/n5/WriteSequenceToN5.java @@ -28,11 +28,7 @@ */ package bdv.export.n5; -import bdv.export.ExportMipmapInfo; -import bdv.export.ExportScalePyramid; -import bdv.export.ProgressWriter; -import bdv.export.ProgressWriterNull; -import bdv.export.SubTaskProgressWriter; +import bdv.export.*; import bdv.export.ExportScalePyramid.AfterEachPlane; import bdv.export.ExportScalePyramid.LoopbackHeuristic; import bdv.img.cache.SimpleCacheArrayLoader; @@ -253,7 +249,7 @@ static < T extends RealType< T > & NativeType< T > > void writeScalePyramid( final T type = setupImgLoader.getImageType(); final N5DatasetIO< T > io = new N5DatasetIO<>( n5, compression, setupId, timepointId, type ); ExportScalePyramid.writeScalePyramid( - img, type, mipmapInfo, io, + img, type, mipmapInfo, DownsampleBlock.DownsamplingMethod.Average, io, executorService, numThreads, loopbackHeuristic, afterEachPlane, progressWriter ); } diff --git a/src/main/java/bdv/tools/crop/CropDialog.java b/src/main/java/bdv/tools/crop/CropDialog.java index cce6641e..b764f86b 100644 --- a/src/main/java/bdv/tools/crop/CropDialog.java +++ b/src/main/java/bdv/tools/crop/CropDialog.java @@ -28,6 +28,7 @@ */ package bdv.tools.crop; +import bdv.export.DownsampleBlock; import bdv.viewer.SourceAndConverter; import bdv.viewer.ViewerState; import java.awt.BorderLayout; @@ -389,7 +390,7 @@ public void cropGlobal( final int minTimepointIndex, final int maxTimepointIndex } final int numThreads = Math.max( 1, Runtime.getRuntime().availableProcessors() - 2 ); - WriteSequenceToHdf5.writeHdf5File( seq, perSetupMipmapInfo, true, hdf5File, null, null, numThreads, null ); + WriteSequenceToHdf5.writeHdf5File( seq, perSetupMipmapInfo, DownsampleBlock.DownsamplingMethod.Average, true, hdf5File, null, null, numThreads, null ); // Build ViewRegistrations with adjusted transforms. final ArrayList< ViewRegistration > registrations = new ArrayList<>(); From 5dafc2847664a271cc5ff88836d4be1f2e6b94e0 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Sun, 7 Feb 2021 15:36:01 +0100 Subject: [PATCH 5/9] Remove scale --- src/main/java/bdv/export/DownsampleBlock.java | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/main/java/bdv/export/DownsampleBlock.java b/src/main/java/bdv/export/DownsampleBlock.java index d47f2ec5..32dd1ca1 100644 --- a/src/main/java/bdv/export/DownsampleBlock.java +++ b/src/main/java/bdv/export/DownsampleBlock.java @@ -271,11 +271,9 @@ public static class CentralPixelDownsampler< T extends RealType< T > > implement private final int[] downsamplingFactors; - private final double scale; - - private final double[] outImgArray; + private final double[] accumulator; - private final RandomAccess< DoubleType > outImg; + private final RandomAccess< DoubleType > acc; public CentralPixelDownsampler( final int[] blockDimensions, @@ -286,13 +284,12 @@ public CentralPixelDownsampler( throw new IllegalArgumentException(); this.downsamplingFactors = downsamplingFactors; - scale = 1.0 / Intervals.numElements( downsamplingFactors ); - outImgArray = new double[ ( int ) Intervals.numElements( blockDimensions ) ]; + accumulator = new double[ ( int ) Intervals.numElements( blockDimensions ) ]; final long[] dims = new long[ n ]; Arrays.setAll( dims, d -> blockDimensions[ d ] ); - outImg = ArrayImgs.doubles( outImgArray, dims ).randomAccess(); + acc = ArrayImgs.doubles( accumulator, dims ).randomAccess(); } @Override @@ -305,79 +302,83 @@ public void downsampleBlock( if ( n == 3 ) { - downsampleBlock3D( outImg, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], in ); - writeOutput3D( out, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], outImg ); + downsampleBlock3D( acc, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], in ); + writeOutput3D( out, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], acc ); } else if ( n == 2 ) { - downsampleBlock2D( outImg, dimensions[ 0 ], dimensions[ 1 ], in ); - writeOutput2D( out, dimensions[ 0 ], dimensions[ 1 ], outImg ); + downsampleBlock2D( acc, dimensions[ 0 ], dimensions[ 1 ], in ); + writeOutput2D( out, dimensions[ 0 ], dimensions[ 1 ], acc ); } else { - downsampleBlock1D( outImg, dimensions[ 0 ], in ); - writeOutput1D( out, dimensions[ 0 ], outImg ); + downsampleBlock1D( acc, dimensions[ 0 ], in ); + writeOutput1D( out, dimensions[ 0 ], acc ); } } private void clearAccumulator() { - Arrays.fill( outImgArray, 0, outImgArray.length, 0 ); + Arrays.fill( accumulator, 0, accumulator.length, 0 ); } private void downsampleBlock3D( - final RandomAccess< DoubleType > out, - final int osx, // size of output image - final int osy, - final int osz, + final RandomAccess< DoubleType > acc, + final int asx, // size of accumulator image + final int asy, + final int asz, final RandomAccess< T > in ) { final int bsz = downsamplingFactors[ 2 ]; in.move( bsz / 2, 2 ); - for ( int oz = 0; oz < osz; ++oz ) + for ( int oz = 0; oz < asz; ++oz ) { - downsampleBlock2D( out, osx, osy, in ); + downsampleBlock2D( acc, asx, asy, in ); in.move( bsz, 2 ); - out.fwd( 2 ); + acc.fwd( 2 ); } - in.move( - bsz * osz - bsz / 2, 2 ); - out.move( -osz, 2 ); + in.move( - bsz * asz - bsz / 2, 2 ); + acc.move( -asz, 2 ); } private void downsampleBlock2D( - final RandomAccess< DoubleType > out, - final int osx, // size of output image - final int osy, + final RandomAccess< DoubleType > acc, + final int asx, // size of accumulator image + final int asy, final RandomAccess< T > in ) { - final int bsy = downsamplingFactors[ 1 ]; - in.move( bsy / 2, 1 ); - for ( int oy = 0; oy < osy; ++oy ) + final int d = 1; + final int bsy = downsamplingFactors[ d ]; + in.move( bsy / 2, d ); + for ( int oy = 0; oy < asy; ++oy ) { - downsampleBlock1D( out, osx, in ); - in.move( bsy, 2 ); - out.fwd( 2 ); + downsampleBlock1D( acc, asx, in ); + in.move( bsy, d ); + acc.fwd( d ); } - in.move( - bsy * osy - bsy / 2, 2 ); - out.move( -osy, 2 ); + in.move( - bsy * asy - bsy / 2, d ); + acc.move( -asy, d ); } private void downsampleBlock1D( - final RandomAccess< DoubleType > out, - final int osx, // size of output image + final RandomAccess< DoubleType > acc, + final int asx, // size of output image final RandomAccess< T > in ) { - final int bsx = downsamplingFactors[ 0 ]; - in.move( bsx / 2, 0 ); - for ( int ox = 0; ox < osx; ++ox ) + final int d = 0; + final int bsx = downsamplingFactors[ d ]; + in.move( bsx / 2, d ); + for ( int ox = 0; ox < asx; ++ox ) { - out.get().set( in.get().getRealDouble() ); + acc.get().set( in.get().getRealDouble() ); + in.move( bsx, d ); + acc.fwd( d ); } - in.move( - bsx * osx - bsx / 2, 2 ); - out.move( -osx, 2 ); + in.move( - bsx * asx - bsx / 2, d ); + acc.move( -asx, d ); } private void writeOutput3D( final Cursor< T > out, // must be flat iteration order - final int asx, // size of output (resp accumulator) image + final int asx, // size of accumulator image final int asy, final int asz, final RandomAccess< DoubleType > acc ) @@ -392,7 +393,7 @@ private void writeOutput3D( private void writeOutput2D( final Cursor< T > out, // must be flat iteration order - final int asx, // size of output (resp accumulator) image + final int asx, // size of output image final int asy, final RandomAccess< DoubleType > acc ) { @@ -409,10 +410,9 @@ private void writeOutput1D( final int asx, // size of output (resp accumulator) image final RandomAccess< DoubleType > acc ) { - final double scale = this.scale; for ( int x = 0; x < asx; ++x ) { - out.next().setReal( acc.get().get() * scale ); + out.next().setReal( acc.get().get() ); acc.fwd( 0 ); } acc.move( -asx, 0 ); From c2ce20d79e015c2e7e48f6b482d044455c3b1a58 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Sun, 7 Feb 2021 16:31:47 +0100 Subject: [PATCH 6/9] Improve variable names --- src/main/java/bdv/export/DownsampleBlock.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/bdv/export/DownsampleBlock.java b/src/main/java/bdv/export/DownsampleBlock.java index 32dd1ca1..f10693e1 100644 --- a/src/main/java/bdv/export/DownsampleBlock.java +++ b/src/main/java/bdv/export/DownsampleBlock.java @@ -327,16 +327,17 @@ private void downsampleBlock3D( final int asz, final RandomAccess< T > in ) { - final int bsz = downsamplingFactors[ 2 ]; - in.move( bsz / 2, 2 ); - for ( int oz = 0; oz < asz; ++oz ) + final int d = 2; + final int bsz = downsamplingFactors[ d ]; + in.move( bsz / 2, d ); + for ( int az = 0; az < asz; ++az ) { downsampleBlock2D( acc, asx, asy, in ); - in.move( bsz, 2 ); - acc.fwd( 2 ); + in.move( bsz, d ); + acc.fwd( d ); } - in.move( - bsz * asz - bsz / 2, 2 ); - acc.move( -asz, 2 ); + in.move( - bsz * asz - bsz / 2, d ); + acc.move( -asz, d ); } private void downsampleBlock2D( @@ -348,7 +349,7 @@ private void downsampleBlock2D( final int d = 1; final int bsy = downsamplingFactors[ d ]; in.move( bsy / 2, d ); - for ( int oy = 0; oy < asy; ++oy ) + for ( int ay = 0; ay < asy; ++ay ) { downsampleBlock1D( acc, asx, in ); in.move( bsy, d ); @@ -366,7 +367,7 @@ private void downsampleBlock1D( final int d = 0; final int bsx = downsamplingFactors[ d ]; in.move( bsx / 2, d ); - for ( int ox = 0; ox < asx; ++ox ) + for ( int ax = 0; ax < asx; ++ax ) { acc.get().set( in.get().getRealDouble() ); in.move( bsx, d ); From 0107ec61a44123d04a0206e3a1113b6b420d35c7 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Sun, 7 Feb 2021 16:53:40 +0100 Subject: [PATCH 7/9] Fix version in pom --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 443afcba..ecc5ed77 100644 --- a/pom.xml +++ b/pom.xml @@ -11,8 +11,7 @@ sc.fiji bigdataviewer-core - - 10.2.1-TISCHI + 10.2.1-SNAPSHOT BigDataViewer Core BigDataViewer core classes with minimal dependencies. From a3a7840288d05d184ab257d9677f87ffd3fb6c32 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Mon, 8 Feb 2021 15:20:03 +0100 Subject: [PATCH 8/9] WIP mode downsampler --- src/main/java/bdv/export/DownsampleBlock.java | 345 +++++++++++++++++- 1 file changed, 328 insertions(+), 17 deletions(-) diff --git a/src/main/java/bdv/export/DownsampleBlock.java b/src/main/java/bdv/export/DownsampleBlock.java index f10693e1..a77dc725 100644 --- a/src/main/java/bdv/export/DownsampleBlock.java +++ b/src/main/java/bdv/export/DownsampleBlock.java @@ -6,13 +6,13 @@ * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -30,8 +30,10 @@ import java.util.Arrays; -import net.imglib2.Cursor; -import net.imglib2.RandomAccess; +import gnu.trove.iterator.TLongLongIterator; +import gnu.trove.map.hash.TLongLongHashMap; +import gnu.trove.set.TLongSet; +import net.imglib2.*; import net.imglib2.img.array.ArrayImgs; import net.imglib2.loops.ClassCopyProvider; import net.imglib2.type.numeric.RealType; @@ -43,7 +45,8 @@ public interface DownsampleBlock< T extends RealType< T > > enum DownsamplingMethod { Average, - CentralPixel + Centre, + Mode } void downsampleBlock( final RandomAccess< T > in, final Cursor< T > out, final int[] dimensions ); @@ -52,7 +55,7 @@ static < T extends RealType< T > > DownsampleBlock< T > create( final int[] blockDimensions, final int[] downsamplingFactors, final DownsamplingMethod downsamplingMethod, - final Class< ? > pixelTypeClass, + final Class< ? > pixelTypeClass, final Class< ? > inAccessClass ) { return DownsampleBlockInstances.create( blockDimensions, downsamplingFactors, downsamplingMethod, pixelTypeClass, inAccessClass ); @@ -83,8 +86,11 @@ public static < T extends RealType< T > > DownsampleBlock< T > create( case Average: provider = new ClassCopyProvider<>( AverageDownsampler.class, DownsampleBlock.class, int[].class, int[].class ); break; - case CentralPixel: - provider = new ClassCopyProvider<>( CentralPixelDownsampler.class, DownsampleBlock.class, int[].class, int[].class ); + case Centre: + provider = new ClassCopyProvider<>( CentreDownsampler.class, DownsampleBlock.class, int[].class, int[].class ); + break; + case Mode: + provider = new ClassCopyProvider<>( ModeDownsampler.class, DownsampleBlock.class, int[].class, int[].class ); break; } } @@ -265,7 +271,7 @@ private void writeOutput1D( } } - public static class CentralPixelDownsampler< T extends RealType< T > > implements DownsampleBlock< T > + public static class CentreDownsampler< T extends RealType< T > > implements DownsampleBlock< T > { private final int n; @@ -275,7 +281,7 @@ public static class CentralPixelDownsampler< T extends RealType< T > > implement private final RandomAccess< DoubleType > acc; - public CentralPixelDownsampler( + public CentreDownsampler( final int[] blockDimensions, final int[] downsamplingFactors ) { @@ -336,7 +342,7 @@ private void downsampleBlock3D( in.move( bsz, d ); acc.fwd( d ); } - in.move( - bsz * asz - bsz / 2, d ); + in.move( -bsz * asz - bsz / 2, d ); acc.move( -asz, d ); } @@ -352,10 +358,10 @@ private void downsampleBlock2D( for ( int ay = 0; ay < asy; ++ay ) { downsampleBlock1D( acc, asx, in ); - in.move( bsy, d ); - acc.fwd( d ); + in.move( bsy, d ); + acc.fwd( d ); } - in.move( - bsy * asy - bsy / 2, d ); + in.move( -bsy * asy - bsy / 2, d ); acc.move( -asy, d ); } @@ -370,10 +376,10 @@ private void downsampleBlock1D( for ( int ax = 0; ax < asx; ++ax ) { acc.get().set( in.get().getRealDouble() ); - in.move( bsx, d ); - acc.fwd( d ); + in.move( bsx, d ); + acc.fwd( d ); } - in.move( - bsx * asx - bsx / 2, d ); + in.move( -bsx * asx - bsx / 2, d ); acc.move( -asx, d ); } @@ -419,6 +425,311 @@ private void writeOutput1D( acc.move( -asx, 0 ); } } + + public static class ModeDownsampler< T extends RealType< T > > implements DownsampleBlock< T > + { + private final int n; + + private final int[] downsamplingFactors; + + private final TLongLongHashMapRandomAccess acc; + + public ModeDownsampler( + final int[] blockDimensions, + final int[] downsamplingFactors ) + { + n = blockDimensions.length; + if ( n < 1 || n > 3 ) + throw new IllegalArgumentException(); + + this.downsamplingFactors = downsamplingFactors; + + final int[] dims = new int[ n ]; + Arrays.setAll( dims, d -> blockDimensions[ d ] ); + + acc = new TLongLongHashMapRandomAccess( dims ); + } + + @Override + public void downsampleBlock( + final RandomAccess< T > in, + final Cursor< T > out, // must be flat iteration order + final int[] dimensions ) + { + clearAccumulator(); + + if ( n == 3 ) + { + downsampleBlock3D( acc, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], in ); + writeOutput3D( out, dimensions[ 0 ], dimensions[ 1 ], dimensions[ 2 ], acc ); + } else if ( n == 2 ) + { + downsampleBlock2D( acc, dimensions[ 0 ], dimensions[ 1 ], in ); + writeOutput2D( out, dimensions[ 0 ], dimensions[ 1 ], acc ); + } else + { + downsampleBlock1D( acc, dimensions[ 0 ], in ); + writeOutput1D( out, dimensions[ 0 ], acc ); + } + } + + private void clearAccumulator() + { + acc.init(); + } + + private void downsampleBlock3D( + final TLongLongHashMapRandomAccess acc, + final int asx, // size of output (resp accumulator) image + final int asy, + final int asz, + final RandomAccess< T > in ) + { + final int bsz = downsamplingFactors[ 2 ]; + final int sz = asz * bsz; + for ( int z = 0, bz = 0; z < sz; ++z ) + { + downsampleBlock2D( acc, asx, asy, in ); + in.fwd( 2 ); + if ( ++bz == bsz ) + { + bz = 0; + acc.fwd( 2 ); + } + } + in.move( -sz, 2 ); + acc.move( -asz, 2 ); + } + + private void downsampleBlock2D( + final TLongLongHashMapRandomAccess acc, + final int asx, // size of output (resp accumulator) image + final int asy, + final RandomAccess< T > in ) + { + final int bsy = downsamplingFactors[ 1 ]; + final int sy = asy * bsy; + for ( int y = 0, by = 0; y < sy; ++y ) + { + downsampleBlock1D( acc, asx, in ); + in.fwd( 1 ); + if ( ++by == bsy ) + { + by = 0; + acc.fwd( 1 ); + } + } + in.move( -sy, 1 ); + acc.move( -asy, 1 ); + } + + private void downsampleBlock1D( + final TLongLongHashMapRandomAccess acc, + final int asx, // size of output (resp accumulator) image + final RandomAccess< T > in ) + { + final int bsx = downsamplingFactors[ 0 ]; + final int sx = asx * bsx; + for ( int x = 0, bx = 0; x < sx; ++x ) + { + final long value = (long) in.get().getRealDouble(); + final TLongLongHashMap map = acc.get(); + final long newCount = map.get( value ) + 1; + map.put( value, newCount ); + + in.fwd( 0 ); + if ( ++bx == bsx ) + { + bx = 0; + acc.fwd( 0 ); + } + } + in.move( -sx, 0 ); + acc.move( -asx, 0 ); + } + + private void writeOutput3D( + final Cursor< T > out, // must be flat iteration order + final int asx, // size of output (resp accumulator) image + final int asy, + final int asz, + final TLongLongHashMapRandomAccess acc ) + { + for ( int z = 0; z < asz; ++z ) + { + writeOutput2D( out, asx, asy, acc ); + acc.fwd( 2 ); + } + acc.move( -asz, 2 ); + } + + private void writeOutput2D( + final Cursor< T > out, // must be flat iteration order + final int asx, // size of output (resp accumulator) image + final int asy, + final TLongLongHashMapRandomAccess acc ) + { + for ( int y = 0; y < asy; ++y ) + { + writeOutput1D( out, asx, acc ); + acc.fwd( 1 ); + } + acc.move( -asy, 1 ); + } + + private void writeOutput1D( + final Cursor< T > out, // must be flat iteration order + final int asx, // size of output (resp accumulator) image + final TLongLongHashMapRandomAccess acc ) + { + for ( int x = 0; x < asx; ++x ) + { + long label = getLabel( acc ); + out.next().setReal( label ); + acc.fwd( 0 ); + } + acc.move( -asx, 0 ); + } + + private long getLabel( TLongLongHashMapRandomAccess acc ) + { + final TLongLongIterator iterator = acc.get().iterator(); + long maxCount = 0; + long label = 0; + while ( iterator.hasNext() ) + { + if ( iterator.value() > maxCount ) + { + maxCount = iterator.value(); + label = iterator.key(); + } + iterator.advance(); + } + return label; + } + + } + + public static class TLongLongHashMapRandomAccess extends AbstractLocalizableInt implements RandomAccess< TLongLongHashMap > + { + private TLongLongHashMap[][][] maps; + private final int[] dims; + + public TLongLongHashMapRandomAccess( int[] dims ) + { + super( dims.length ); + + this.dims = dims; + init(); + } + + public void init() + { + if( dims.length == 1 ) + maps = new TLongLongHashMap[ dims[ 0 ] ][ 1 ][ 1 ]; + else if ( dims.length == 2 ) + maps = new TLongLongHashMap[ dims[ 0 ] ][ dims[ 1 ] ][ 1 ]; + else if ( dims.length == 3 ) + maps = new TLongLongHashMap[ dims[ 0 ] ][ dims[ 1 ] ][ dims[ 2 ] ]; + else + throw new UnsupportedOperationException( "The number of dimensions must be <= 3" ); + + for ( int x = 0; x < dims[ 0 ]; x++ ) + for ( int y = 0; y < dims[ 1 ]; y++ ) + for ( int z = 0; z < dims[ 2 ]; z++ ) + maps[ x ][ y ][ z ] = new TLongLongHashMap(); + } + + @Override + public RandomAccess< TLongLongHashMap > copyRandomAccess() + { + throw new UnsupportedOperationException( ); + } + + @Override + public void fwd( int d ) + { + position[ d ]++; + } + + @Override + public void bck( int d ) + { + position[ d ]--; + } + + @Override + public void move( int distance, int d ) + { + position[ d ] += distance; + } + + @Override + public void move( long distance, int d ) + { + position[ d ] += distance; + } + + @Override + public void move( Localizable distance ) + { + throw new UnsupportedOperationException( ); + } + + @Override + public void move( int[] distance ) + { + throw new UnsupportedOperationException( ); + } + + @Override + public void move( long[] distance ) + { + throw new UnsupportedOperationException( ); + } + + @Override + public void setPosition( Localizable position ) + { + throw new UnsupportedOperationException( ); + } + + @Override + public void setPosition( int[] position ) + { + throw new UnsupportedOperationException( ); + } + + @Override + public void setPosition( long[] position ) + { + throw new UnsupportedOperationException( ); + } + + @Override + public void setPosition( int position, int d ) + { + throw new UnsupportedOperationException( ); + } + + @Override + public void setPosition( long position, int d ) + { + throw new UnsupportedOperationException( ); + } + + @Override + public TLongLongHashMap get() + { + return maps[ position[ 0 ] ][ position[ 1 ] ][ position[ 2 ] ]; + } + + @Override + public Sampler< TLongLongHashMap > copy() + { + throw new UnsupportedOperationException( ); + } + } } From 73466b7976a7632ac5814f02b7c91e2fc6bb52d4 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Mon, 8 Feb 2021 15:50:47 +0100 Subject: [PATCH 9/9] Add mode downsampling method --- src/main/java/bdv/export/DownsampleBlock.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/bdv/export/DownsampleBlock.java b/src/main/java/bdv/export/DownsampleBlock.java index a77dc725..b71de212 100644 --- a/src/main/java/bdv/export/DownsampleBlock.java +++ b/src/main/java/bdv/export/DownsampleBlock.java @@ -598,16 +598,15 @@ private long getLabel( TLongLongHashMapRandomAccess acc ) long label = 0; while ( iterator.hasNext() ) { + iterator.advance(); if ( iterator.value() > maxCount ) { maxCount = iterator.value(); label = iterator.key(); } - iterator.advance(); } return label; } - } public static class TLongLongHashMapRandomAccess extends AbstractLocalizableInt implements RandomAccess< TLongLongHashMap >