From 982d2d807597af5a84e135f575d63c49ad8183b7 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sun, 15 Sep 2024 13:23:21 +0200 Subject: [PATCH 01/24] POM: Bump parent to pom-scijava-38.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0f201a17b..8d6a30b64 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.scijava pom-scijava - 37.0.0 + 38.0.1 From 9bc46b68d2b570ef671f97bdea937c9b5a28460a Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sun, 15 Sep 2024 13:25:06 +0200 Subject: [PATCH 02/24] POM: Bump dependency versions imglib2.version -> 7.1.1 imglib2-roi -> 0.15.1 bigdataviewer-core -> 10.6.1 Remove obsolete bigdataviewer-vistools dependency. --- pom.xml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 8d6a30b64..8f5983315 100644 --- a/pom.xml +++ b/pom.xml @@ -201,11 +201,11 @@ Jean-Yves Tinevez and Michael Zinsmaier. sign,deploy-to-scijava - 7.0.3 + 7.1.1 4.0.3 - 0.15.0 + 0.15.1 1.0.0-beta-18 - 10.4.16 + 10.6.1 @@ -255,11 +255,6 @@ Jean-Yves Tinevez and Michael Zinsmaier. bigdataviewer-core test - - sc.fiji - bigdataviewer-vistools - test - net.imglib2 imglib2-ij From 94762e8350b2e930e2495eb5d3cb78328c698b09 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sun, 15 Sep 2024 13:26:46 +0200 Subject: [PATCH 03/24] Simplify BlockProcessor.setTargetInterval(long[], int[]) default implementation. Add BlockProcessorTargetInterval wrapper. --- .../algorithm/blocks/BlockProcessor.java | 12 +---- .../blocks/BlockProcessorTargetInterval.java | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 src/main/java/net/imglib2/algorithm/blocks/BlockProcessorTargetInterval.java diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/BlockProcessor.java index 93652cfae..1bbb25658 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/BlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/BlockProcessor.java @@ -33,9 +33,6 @@ */ package net.imglib2.algorithm.blocks; -import java.util.Arrays; - -import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.blocks.PrimitiveBlocks; @@ -59,20 +56,15 @@ public interface BlockProcessor< I, O > void setTargetInterval( Interval interval ); - default void setTargetInterval( long[] srcPos, int[] size ) + default void setTargetInterval( long[] pos, int[] size ) { - final long[] srcMax = new long[ srcPos.length ]; - Arrays.setAll( srcMax, d -> srcPos[ d ] + size[ d ] - 1 ); - setTargetInterval( FinalInterval.wrap( srcPos, srcMax ) ); + setTargetInterval( new BlockProcessorTargetInterval( pos, size ) ); } long[] getSourcePos(); int[] getSourceSize(); - // TODO: Its cumbersome to have both getSourcePos()/getSourceSize() *and* getSourceInterval() - // Only have getSourcePos()/getSourceSize() ? - // Have a modifiable SourceInterval class exposing getSourcePos()/getSourceSize() ? Interval getSourceInterval(); /** diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockProcessorTargetInterval.java b/src/main/java/net/imglib2/algorithm/blocks/BlockProcessorTargetInterval.java new file mode 100644 index 000000000..84a7b9f4a --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/BlockProcessorTargetInterval.java @@ -0,0 +1,45 @@ +package net.imglib2.algorithm.blocks; + +import net.imglib2.Interval; + +/** + * Wraps {@code long[] pos} and {@code int[] size} as a {@code Interval}, for + * the default implementation of {@link BlockProcessor#setTargetInterval(long[], + * int[])}. + */ +class BlockProcessorTargetInterval implements Interval +{ + private final long[] min; + + private final int[] size; + + BlockProcessorTargetInterval( long[] min, int[] size ) + { + this.min = min; + this.size = size; + } + + @Override + public long min( final int i ) + { + return min[ i ]; + } + + @Override + public long max( final int i ) + { + return min[ i ] + size[ i ] - 1; + } + + @Override + public long dimension( final int d ) + { + return size[ d ]; + } + + @Override + public int numDimensions() + { + return min.length; + } +} From 2cd828cfdab5a6363951d2a23ba8f4720ffc8455 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sat, 14 Sep 2024 15:33:43 +0200 Subject: [PATCH 04/24] bugfix --- .../imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java index 735a89898..ae06e25bd 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java @@ -96,7 +96,8 @@ public I getSourceBuffer() @Override public void compute( final I src, final O dest ) { - p0.compute( src, p1.getSourceBuffer() ); - p1.compute( p1.getSourceBuffer(), dest ); + final K temp = p1.getSourceBuffer(); + p0.compute( src, temp ); + p1.compute( temp, dest ); } } From 86a679c1908abbdeab21812d48ab8555ec8d9f97 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Mon, 1 Jul 2024 10:01:15 +0200 Subject: [PATCH 05/24] Add BlockSupplier.numDimensions() --- .../imglib2/algorithm/blocks/BlockSupplier.java | 3 ++- .../blocks/ConcatenatedBlockSupplier.java | 16 ++++++++++++++++ .../blocks/PrimitiveBlocksSupplier.java | 12 ++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java index cd2cd621f..3edcecd3a 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java @@ -38,6 +38,7 @@ import java.util.Arrays; +import net.imglib2.EuclideanSpace; import net.imglib2.Interval; import net.imglib2.RandomAccessible; import net.imglib2.Typed; @@ -45,7 +46,7 @@ import net.imglib2.type.NativeType; import net.imglib2.util.Util; -public interface BlockSupplier< T extends NativeType< T > > extends Typed< T > +public interface BlockSupplier< T extends NativeType< T > > extends Typed< T >, EuclideanSpace { /** * Copy a block from the ({@code T}-typed) source into primitive arrays (of diff --git a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java index ca6545e44..db07ef479 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java @@ -47,6 +47,8 @@ class ConcatenatedBlockSupplier< T extends NativeType< T > > implements BlockSup private final T type; + private final int numDimensions; + private Supplier< BlockSupplier< T > > threadSafeSupplier; public < S extends NativeType< S > > ConcatenatedBlockSupplier( @@ -56,6 +58,7 @@ public < S extends NativeType< S > > ConcatenatedBlockSupplier( this.p0 = srcSupplier; this.p1 = operator.blockProcessor(); this.type = operator.getTargetType(); + this.numDimensions = srcSupplier.numDimensions(); // TODO: REVISE. The operator should determine the number of (target) dimensions. This is only to make it compile. } private ConcatenatedBlockSupplier( final ConcatenatedBlockSupplier< T > s ) @@ -63,6 +66,7 @@ private ConcatenatedBlockSupplier( final ConcatenatedBlockSupplier< T > s ) p0 = s.p0.independentCopy(); p1 = s.p1.independentCopy(); type = s.type; + numDimensions = s.numDimensions; } @Override @@ -71,6 +75,12 @@ public T getType() return type; } + @Override + public int numDimensions() + { + return numDimensions; + } + @Override public void copy( final long[] srcPos, final Object dest, final int[] size ) { @@ -99,6 +109,12 @@ public T getType() return type; } + @Override + public int numDimensions() + { + return numDimensions; + } + @Override public void copy( final long[] srcPos, final Object dest, final int[] size ) { diff --git a/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java index ab7db848b..debd5b9b8 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java @@ -56,6 +56,12 @@ public T getType() return blocks.getType(); } + @Override + public int numDimensions() + { + return blocks.numDimensions(); + } + @Override public void copy( final long[] srcPos, final Object dest, final int[] size ) { @@ -88,6 +94,12 @@ public T getType() return blocks.getType(); } + @Override + public int numDimensions() + { + return blocks.numDimensions(); + } + @Override public void copy( final long[] srcPos, final Object dest, final int[] size ) { From 48c90c22cc4469161dcba775258e2609c87dd3b3 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Wed, 3 Jul 2024 22:25:22 +0200 Subject: [PATCH 06/24] Add UnaryBlockOperator.numDimensions() --- .../blocks/ConcatenatedBlockSupplier.java | 11 +++++- .../blocks/DefaultUnaryBlockOperator.java | 32 +++++++++++++++-- .../algorithm/blocks/UnaryBlockOperator.java | 35 +++++++++++++++++++ .../algorithm/blocks/convert/Convert.java | 8 +++-- .../blocks/downsample/Downsample.java | 10 +++--- .../algorithm/blocks/transform/Transform.java | 7 ++-- 6 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java index db07ef479..a071b0222 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java @@ -58,7 +58,16 @@ public < S extends NativeType< S > > ConcatenatedBlockSupplier( this.p0 = srcSupplier; this.p1 = operator.blockProcessor(); this.type = operator.getTargetType(); - this.numDimensions = srcSupplier.numDimensions(); // TODO: REVISE. The operator should determine the number of (target) dimensions. This is only to make it compile. + if ( operator.numSourceDimensions() > 0 ) + { + if ( srcSupplier.numDimensions() != operator.numSourceDimensions() ) + throw new IllegalArgumentException( "UnaryBlockOperator cannot be concatenated: number of dimensions mismatch." ); + this.numDimensions = operator.numTargetDimensions(); + } + else + { + this.numDimensions = srcSupplier.numDimensions(); + } } private ConcatenatedBlockSupplier( final ConcatenatedBlockSupplier< T > s ) diff --git a/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java index aec938fa0..1d7b34e1a 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java @@ -42,12 +42,16 @@ public class DefaultUnaryBlockOperator< S extends NativeType< S >, T extends Nat { private final S sourceType; private final T targetType; + private final int numSourceDimensions; + private final int numTargetDimensions; private final BlockProcessor< ?, ? > blockProcessor; - public DefaultUnaryBlockOperator( S sourceType, T targetType, BlockProcessor< ?, ? > blockProcessor ) + public DefaultUnaryBlockOperator( S sourceType, T targetType, int numSourceDimensions, int numTargetDimensions, BlockProcessor< ?, ? > blockProcessor ) { this.sourceType = sourceType; this.targetType = targetType; + this.numSourceDimensions = numSourceDimensions; + this.numTargetDimensions = numTargetDimensions; this.blockProcessor = blockProcessor; } @@ -69,10 +73,22 @@ public T getTargetType() return targetType; } + @Override + public int numSourceDimensions() + { + return numSourceDimensions; + } + + @Override + public int numTargetDimensions() + { + return numTargetDimensions; + } + @Override public UnaryBlockOperator< S, T > independentCopy() { - return new DefaultUnaryBlockOperator<>( sourceType, targetType, blockProcessor.independentCopy() ); + return new DefaultUnaryBlockOperator<>( sourceType, targetType, numSourceDimensions, numTargetDimensions, blockProcessor.independentCopy() ); } private Supplier< UnaryBlockOperator< S, T > > threadSafeSupplier; @@ -102,6 +118,18 @@ public T getTargetType() return targetType; } + @Override + public int numSourceDimensions() + { + return numSourceDimensions; + } + + @Override + public int numTargetDimensions() + { + return numTargetDimensions; + } + @Override public UnaryBlockOperator< S, T > threadSafe() { diff --git a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java index ce2de27a6..9dd959a05 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java @@ -77,6 +77,32 @@ public interface UnaryBlockOperator< S extends NativeType< S >, T extends Native T getTargetType(); + /** + * Number of source dimensions. + *

+ * Some operators can be applied to arbitrary dimensions, e.g., converters. + * In this case, they should return {@code numSourceDimensions() <= 0}. It + * is expected that these operators do not modify the number dimensions, + * that is, when such an operator is applied to a 3D block, the result is + * also a 3D block. + * + * @return the number of source dimensions + */ + int numSourceDimensions(); + + /** + * Number of target dimensions. + *

+ * Some operators can be applied to arbitrary dimensions, e.g., converters. + * In this case, they should return {@code numTargetDimensions() <= 0}. It + * is expected that these operators do not modify the number dimensions, + * that is, when such an operator is applied to a 3D block, the result is + * also a 3D block. + * + * @return the number of source dimensions + */ + int numTargetDimensions(); + /** * Get a thread-safe version of this {@code UnaryBlockOperator}. * (Implemented as a wrapper that makes {@link ThreadLocal} copies). @@ -96,9 +122,18 @@ public interface UnaryBlockOperator< S extends NativeType< S >, T extends Native */ default < U extends NativeType< U > > UnaryBlockOperator< S, U > andThen( UnaryBlockOperator< T, U > op ) { + final boolean thisHasDimensions = numSourceDimensions() > 0; + final boolean opHasDimensions = op.numSourceDimensions() > 0; + if ( opHasDimensions && thisHasDimensions && numTargetDimensions() != op.numSourceDimensions() ) { + throw new IllegalArgumentException( "UnaryBlockOperator cannot be concatenated: number of dimensions mismatch." ); + } + final int numSourceDimensions = thisHasDimensions ? numSourceDimensions() : op.numSourceDimensions(); + final int numTargetDimensions = opHasDimensions ? op.numTargetDimensions() : numTargetDimensions(); return new DefaultUnaryBlockOperator<>( getSourceType(), op.getTargetType(), + numSourceDimensions, + numTargetDimensions, blockProcessor().andThen( op.blockProcessor() ) ); } diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java index f79b56987..ed73bbcb2 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java @@ -78,7 +78,9 @@ UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType ) public static < S extends NativeType< S >, T extends NativeType< T > > UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType, final ClampType clamp ) { - return new DefaultUnaryBlockOperator<>( sourceType, targetType, new ConvertBlockProcessor<>( sourceType, targetType, clamp ) ); + return new DefaultUnaryBlockOperator<>( + sourceType, targetType, 0, 0, + new ConvertBlockProcessor<>( sourceType, targetType, clamp ) ); } /** @@ -88,6 +90,8 @@ UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType, fina public static < S extends NativeType< S >, T extends NativeType< T > > UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType, Supplier< Converter< ? super S, T > > converterSupplier ) { - return new DefaultUnaryBlockOperator<>( sourceType, targetType, new ConverterBlockProcessor<>( sourceType, targetType, converterSupplier ) ); + return new DefaultUnaryBlockOperator<>( + sourceType, targetType, 0, 0, + new ConverterBlockProcessor<>( sourceType, targetType, converterSupplier ) ); } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java index 888f9eae5..388447eb7 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java @@ -280,19 +280,21 @@ UnaryBlockOperator< T, T > downsample( final T type, final int numDimensions ) - private static UnaryBlockOperator< FloatType, FloatType > downsampleFloat( Offset offset, final boolean[] downsampleInDim ) + private static UnaryBlockOperator< FloatType, FloatType > downsampleFloat( final Offset offset, final boolean[] downsampleInDim ) { final FloatType type = new FloatType(); - return new DefaultUnaryBlockOperator<>( type, type, + final int n = downsampleInDim.length; + return new DefaultUnaryBlockOperator<>( type, type, n, n, offset == Offset.HALF_PIXEL ? new HalfPixelFloat( downsampleInDim ) : new CenterFloat( downsampleInDim ) ); } - private static UnaryBlockOperator< DoubleType, DoubleType > downsampleDouble( Offset offset, final boolean[] downsampleInDim ) + private static UnaryBlockOperator< DoubleType, DoubleType > downsampleDouble( final Offset offset, final boolean[] downsampleInDim ) { final DoubleType type = new DoubleType(); - return new DefaultUnaryBlockOperator<>( type, type, + final int n = downsampleInDim.length; + return new DefaultUnaryBlockOperator<>( type, type, n, n, offset == Offset.HALF_PIXEL ? new HalfPixelDouble( downsampleInDim ) : new CenterDouble( downsampleInDim ) ); diff --git a/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java b/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java index 0722835c4..325b05479 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java +++ b/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java @@ -155,8 +155,11 @@ UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSo private static < T extends NativeType< T > > UnaryBlockOperator< T, T > _affine( final AffineGet transform, final Interpolation interpolation, final T type ) { - return new DefaultUnaryBlockOperator<>( type, type, - transform.numDimensions() == 2 + final int n = transform.numDimensions(); + if ( n < 2 || n > 3 ) + throw new IllegalArgumentException( "Only 2D and 3D affine transforms are supported currently" ); + return new DefaultUnaryBlockOperator<>( type, type, n, n, + n == 2 ? new Affine2DProcessor<>( ( AffineTransform2D ) transform, interpolation, type.getNativeTypeFactory().getPrimitiveType() ) : new Affine3DProcessor<>( ( AffineTransform3D ) transform, interpolation, type.getNativeTypeFactory().getPrimitiveType() ) ); } From 11580a5e71101d60e10d69aad3201a98ac11e15b Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sat, 6 Jul 2024 23:43:53 +0200 Subject: [PATCH 07/24] Add BlockSupplier.tile(int...) default method TilingBlockSupplier wraps a source BlockSupplier, and splits large BlockSupplier. copy requests into several smaller copy calls on the source BlockSupplier. Example use cases: - Computing large outputs (e. g. to write to N5 or wrap as ArrayImg) with operators that have better performance with smaller block sizes. - Avoiding excessively large blocks when chaining downsampling operators. --- .../algorithm/blocks/BlockSupplier.java | 29 ++- .../algorithm/blocks/TilingBlockSupplier.java | 244 ++++++++++++++++++ 2 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java index 3edcecd3a..e76cc14b3 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java @@ -11,13 +11,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 @@ -112,6 +112,31 @@ default void copy( Interval interval, Object dest ) */ BlockSupplier< T > independentCopy(); + /** + * Returns a new {@code BlockSupplier} that handles {@link #copy} requests + * by splitting into {@code tileSize} portions that are each handled by this + * {@code BlockSupplier} and assembled into the final result. + *

+ * Example use cases: + *

    + *
  • Compute large outputs (e.g. for writing to N5 or wrapping as {@code + * ArrayImg}) with operators that have better performance with small + * block sizes.
  • + *
  • Avoid excessively large blocks when chaining downsampling + * operators.
  • + *
+ * + * @param tileSize + * (maximum) dimensions of a request to the {@code srcSupplier}. + * {@code tileSize} is expanded or truncated to the necessary size. For + * example, if {@code tileSize=={64}} and this {@code BlockSupplier} is 3D, + * then {@code tileSize} is expanded to {@code {64, 64, 64}}. + */ + default BlockSupplier< T > tile( int... tileSize ) + { + return new TilingBlockSupplier<>( this, tileSize ); + } + /** * Returns a {@code UnaryBlockOperator} that is equivalent to applying * {@code this}, and then applying {@code op} to the result. diff --git a/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java new file mode 100644 index 000000000..783e5061d --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java @@ -0,0 +1,244 @@ +/*- + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package net.imglib2.algorithm.blocks; + +import java.util.function.Supplier; + +import net.imglib2.blocks.SubArrayCopy; +import net.imglib2.blocks.TempArray; +import net.imglib2.type.NativeType; +import net.imglib2.type.PrimitiveType; +import net.imglib2.util.Cast; +import net.imglib2.util.CloseableThreadLocal; +import net.imglib2.util.Intervals; +import net.imglib2.util.Util; + +/** + * {@code TilingBlockSupplier} wraps a source {@code BlockSupplier}, and splits + * large {@link BlockSupplier#copy} requests into several smaller {@code copy} + * calls on the source {@code BlockSupplier}. + *

+ * Each {@code copy} on the source {@code BlockSupplier} requests (at most) an + * interval of the {@code tileSize} specified in the constructor. The source + * {@code BlockSupplier.copy} writes to a temporary buffer, which is then copied + * into the appropriate portion of the {@code dest} buffer. + *

+ * {@link BlockSupplier#copy} requests that are smaller or equal to {@code + * tileSize} are passed directly to the source {@code BlockSupplier}. + *

+ * Example use cases: + *

    + *
  • Computing large outputs (e.g. to write to N5 or wrap as {@code ArrayImg}) + * with operators that have better performance with smaller block sizes.
  • + *
  • Avoiding excessively large blocks when chaining downsampling + * operators.
  • + *
+ * + * @param + * pixel type + * @param

+ * corresponding primitive array type + */ +class TilingBlockSupplier< T extends NativeType< T >, P > implements BlockSupplier< T > +{ + private final BlockSupplier< T > p0; + + private final int[] innerTileSize; + private final int[] borderTileSize; + private final int[] numTiles; + + private final TempArray< P > tempArray; + private final int innerTileNumElements; + + private final SubArrayCopy.Typed< P, P > subArrayCopy; + + private Supplier< BlockSupplier< T > > threadSafeSupplier; + + final int[] tile_pos_in_dest; + final long[] tile_pos_in_src; + final int[] tile_origin; + final int[] tile_size; + + /** + * Create a {@code BlockSupplier} that handles {@link BlockSupplier#copy} + * requests by splitting into {@code tileSize} portions that are each + * handled by the given {@code srcSupplier} and assembled into the final + * result. + * + * @param srcSupplier + * source {@code BlockSupplier} to wrap. + * @param tileSize + * (maximum) dimensions of a request to the {@code srcSupplier}. + * {@code tileSize} is expanded or truncated to the necessary size. + * For example, if {@code tileSize=={64}} when wrapping a 3D {@code + * srcSupplier}, {@code tileSize} is expanded to {@code {64, 64, + * 64}}. + */ + public TilingBlockSupplier( + final BlockSupplier< T > srcSupplier, + final int... tileSize ) + { + this.p0 = srcSupplier; + final int n = srcSupplier.numDimensions(); + innerTileSize = Util.expandArray( tileSize, n ); + innerTileNumElements = Util.safeInt( Intervals.numElements( innerTileSize ) ); + borderTileSize = new int[ n ]; + numTiles = new int[ n ]; + + final PrimitiveType primitiveType = srcSupplier.getType().getNativeTypeFactory().getPrimitiveType(); + tempArray = TempArray.forPrimitiveType( primitiveType ); + subArrayCopy = SubArrayCopy.forPrimitiveType( primitiveType ); + + tile_pos_in_dest = new int[ n ]; + tile_pos_in_src = new long[ n ]; + tile_origin = new int[ n ]; + tile_size = new int[ n ]; + } + + private TilingBlockSupplier( final TilingBlockSupplier< T, P > s ) + { + p0 = s.p0.independentCopy(); + innerTileSize = s.innerTileSize; + innerTileNumElements = s.innerTileNumElements; + tempArray = s.tempArray.newInstance(); + subArrayCopy = s.subArrayCopy; + + final int n = numDimensions(); + borderTileSize = new int[ n ]; + numTiles = new int[ n ]; + tile_pos_in_dest = new int[ n ]; + tile_pos_in_src = new long[ n ]; + tile_origin = new int[ n ]; + tile_size = new int[ n ]; + } + + @Override + public T getType() + { + return p0.getType(); + } + + @Override + public int numDimensions() + { + return p0.numDimensions(); + } + + @Override + public void copy( final long[] srcPos, final Object dest, final int[] size ) + { + final int n = numDimensions(); + boolean singleTile = true; + for ( int d = 0; d < n; ++d ) + { + numTiles[ d ] = ( size[ d ] - 1 ) / innerTileSize[ d ] + 1; + if ( numTiles[ d ] > 1 ) + singleTile = false; + borderTileSize[ d ] = size[ d ] - ( numTiles[ d ] - 1 ) * innerTileSize[ d ]; + } + if ( singleTile ) + { + p0.copy( srcPos, dest, size ); + } + else + { + final P tile_buf = tempArray.get( innerTileNumElements ); + compute_tiles_recursively( n - 1, srcPos, Cast.unchecked( dest ), size, tile_buf ); + } + } + + private void compute_tiles_recursively( final int d, final long[] srcPos, final P dest, final int[] dest_size, final P tile_buf ) { + final int numTiles = this.numTiles[ d ]; + for ( int i = 0; i < numTiles; ++i ) + { + tile_pos_in_dest[ d ] = innerTileSize[ d ] * i; + tile_pos_in_src[ d ] = srcPos[ d ] + tile_pos_in_dest[ d ]; + tile_size[ d ] = ( i == numTiles - 1 ) ? borderTileSize[ d ] : innerTileSize[ d ]; + if ( d == 0 ) + { + p0.copy( tile_pos_in_src, tile_buf, tile_size ); + subArrayCopy.copy( tile_buf, tile_size, tile_origin, dest, dest_size, tile_pos_in_dest, tile_size ); + } + else + { + compute_tiles_recursively( d - 1, srcPos, dest, dest_size, tile_buf ); + } + } + } + + @Override + public BlockSupplier< T > independentCopy() + { + return new TilingBlockSupplier<>( this ); + } + + @Override + public BlockSupplier< T > threadSafe() + { + if ( threadSafeSupplier == null ) + threadSafeSupplier = CloseableThreadLocal.withInitial( this::independentCopy )::get; + return new BlockSupplier< T >() + { + @Override + public T getType() + { + return p0.getType(); + } + + @Override + public int numDimensions() + { + return p0.numDimensions(); + } + + @Override + public void copy( final long[] srcPos, final Object dest, final int[] size ) + { + threadSafeSupplier.get().copy( srcPos, dest, size ); + } + + @Override + public BlockSupplier< T > independentCopy() + { + return TilingBlockSupplier.this.independentCopy().threadSafe(); + } + + @Override + public BlockSupplier< T > threadSafe() + { + return this; + } + }; + } +} From f9f3c30e284509462841a5c687eafb0f3403d80e Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Wed, 3 Jul 2024 17:59:01 +0200 Subject: [PATCH 08/24] Add auto-generation comment to TransformLine2D/3D --- .../imglib2/algorithm/blocks/transform/TransformLine2D.java | 5 +++++ .../imglib2/algorithm/blocks/transform/TransformLine3D.java | 5 +++++ .../java/net/imglib2/algorithm/blocks/TransformLine2D.vm | 5 +++++ .../java/net/imglib2/algorithm/blocks/TransformLine3D.vm | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/src/main/java/net/imglib2/algorithm/blocks/transform/TransformLine2D.java b/src/main/java/net/imglib2/algorithm/blocks/transform/TransformLine2D.java index 2009e8c31..6ee36f49e 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/transform/TransformLine2D.java +++ b/src/main/java/net/imglib2/algorithm/blocks/transform/TransformLine2D.java @@ -36,6 +36,11 @@ import net.imglib2.type.PrimitiveType; import net.imglib2.util.Cast; +/* + * This is autogenerated source code -- DO NOT EDIT. Instead, edit the + * corresponding template in templates/ and rerun bin/generate.groovy. + */ + /** * Compute a destination X line for 2D. diff --git a/src/main/java/net/imglib2/algorithm/blocks/transform/TransformLine3D.java b/src/main/java/net/imglib2/algorithm/blocks/transform/TransformLine3D.java index 25a5d0885..dafd7ba7d 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/transform/TransformLine3D.java +++ b/src/main/java/net/imglib2/algorithm/blocks/transform/TransformLine3D.java @@ -36,6 +36,11 @@ import net.imglib2.type.PrimitiveType; import net.imglib2.util.Cast; +/* + * This is autogenerated source code -- DO NOT EDIT. Instead, edit the + * corresponding template in templates/ and rerun bin/generate.groovy. + */ + /** * Compute a destination X line for 2D. diff --git a/templates/main/java/net/imglib2/algorithm/blocks/TransformLine2D.vm b/templates/main/java/net/imglib2/algorithm/blocks/TransformLine2D.vm index 52ff467f0..6deb84af1 100644 --- a/templates/main/java/net/imglib2/algorithm/blocks/TransformLine2D.vm +++ b/templates/main/java/net/imglib2/algorithm/blocks/TransformLine2D.vm @@ -36,6 +36,11 @@ package net.imglib2.algorithm.blocks.transform; import net.imglib2.type.PrimitiveType; import net.imglib2.util.Cast; +/* + * This is autogenerated source code -- DO NOT EDIT. Instead, edit the + * corresponding template in templates/ and rerun bin/generate.groovy. + */ + #parse( "PixelTypes.vm" ) /** diff --git a/templates/main/java/net/imglib2/algorithm/blocks/TransformLine3D.vm b/templates/main/java/net/imglib2/algorithm/blocks/TransformLine3D.vm index ba13977e8..455b5ec1f 100644 --- a/templates/main/java/net/imglib2/algorithm/blocks/TransformLine3D.vm +++ b/templates/main/java/net/imglib2/algorithm/blocks/TransformLine3D.vm @@ -36,6 +36,11 @@ package net.imglib2.algorithm.blocks.transform; import net.imglib2.type.PrimitiveType; import net.imglib2.util.Cast; +/* + * This is autogenerated source code -- DO NOT EDIT. Instead, edit the + * corresponding template in templates/ and rerun bin/generate.groovy. + */ + #parse( "PixelTypes.vm" ) /** From b7206d2d8633295850031cbcaa0584f53bd7d4c0 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Mon, 1 Jul 2024 10:02:39 +0200 Subject: [PATCH 09/24] Add BlockSupplier.andThen(...) with operator-generating Function --- .../java/net/imglib2/algorithm/blocks/BlockSupplier.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java index e76cc14b3..09d9b3f14 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java @@ -37,6 +37,7 @@ import static net.imglib2.util.Util.safeInt; import java.util.Arrays; +import java.util.function.Function; import net.imglib2.EuclideanSpace; import net.imglib2.Interval; @@ -146,6 +147,11 @@ default < U extends NativeType< U > > BlockSupplier< U > andThen( UnaryBlockOper return new ConcatenatedBlockSupplier<>( this.independentCopy(), operator.independentCopy() ); } + default < U extends NativeType< U > > BlockSupplier< U > andThen( Function< BlockSupplier< T >, UnaryBlockOperator< T, U > > function ) + { + return new ConcatenatedBlockSupplier<>( this.independentCopy(), function.apply( this ) ); + } + /** * Create a {@code BlockSupplier} accessor for an arbitrary {@code * RandomAccessible} source. Many View constructions (that ultimately end in From c0f3bb7d4321eaa51d659bbca5b677e06920e884 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Thu, 4 Jul 2024 07:01:36 +0200 Subject: [PATCH 10/24] Convert: add operator factories, refactor, javadoc --- .../algorithm/blocks/UnaryBlockOperator.java | 7 +- .../algorithm/blocks/convert/Convert.java | 96 ++++++++++++++++++- 2 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java index 9dd959a05..a1e4f8871 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java @@ -34,11 +34,10 @@ package net.imglib2.algorithm.blocks; import net.imglib2.algorithm.blocks.convert.ClampType; +import net.imglib2.algorithm.blocks.convert.Convert; import net.imglib2.type.NativeType; import net.imglib2.util.Cast; -import static net.imglib2.algorithm.blocks.convert.Convert.convert; - /** * Wraps {@code BlockProcessor}, where {@code I} is the primitive array * type backing ImgLib2 {@code NativeType} {@code S} and {@code O} is the @@ -147,7 +146,7 @@ default < U extends NativeType< U > > UnaryBlockOperator< U, T > adaptSourceType if ( newSourceType.getClass().isInstance( getSourceType() ) ) return Cast.unchecked( this ); else - return convert( newSourceType, getSourceType(), clamp ).andThen( this ); + return Convert.createOperator( newSourceType, getSourceType(), clamp ).andThen( this ); } /** @@ -160,6 +159,6 @@ default < U extends NativeType< U > > UnaryBlockOperator< S, U > adaptTargetTyp if ( newTargetType.getClass().isInstance( getTargetType() ) ) return Cast.unchecked( this ); else - return this.andThen( convert( getTargetType(), newTargetType, clamp ) ); + return this.andThen( Convert.createOperator( getTargetType(), newTargetType, clamp ) ); } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java index ed73bbcb2..4f7d7d589 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java @@ -33,8 +33,10 @@ */ package net.imglib2.algorithm.blocks.convert; +import java.util.function.Function; import java.util.function.Supplier; +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator; import net.imglib2.algorithm.blocks.UnaryBlockOperator; import net.imglib2.converter.Converter; @@ -59,15 +61,101 @@ */ public class Convert { + /** + * Create {@link UnaryBlockOperator} to convert blocks from {@code S} to + * {@code T}. + *

+ * Supported source/target types are {@code ByteType}, {@code + * UnsignedByteType}, {@code ShortType}, {@code UnsignedShortType}, {@code + * IntType}, {@code UnsignedIntType}, {@code LongType}, {@code + * UnsignedLongType}, {@code FloatType}, and {@code DoubleType}. + *

+ * Target values are not clamped, so overflow may occur if the source type + * has a larger range than the target type. + *

+ * The returned factory function creates an operator matching the type + * {@code S} of the given input {@code BlockSupplier}. + * + * @param targetType + * an instance of the target type + * @param + * source type + * @param + * target type + * + * @return factory for {@code UnaryBlockOperator} to convert blocks from {@code S} to {@code T} + */ + public static < S extends NativeType< S >, T extends NativeType< T > > + Function< BlockSupplier< S >, UnaryBlockOperator< S, T > > convert( final T targetType ) + { + return convert( targetType, ClampType.NONE ); + } + + /** + * Create {@link UnaryBlockOperator} to convert blocks from {@code S} to + * {@code T}. + *

+ * Supported source/target types are {@code ByteType}, {@code + * UnsignedByteType}, {@code ShortType}, {@code UnsignedShortType}, {@code + * IntType}, {@code UnsignedIntType}, {@code LongType}, {@code + * UnsignedLongType}, {@code FloatType}, and {@code DoubleType}. + *

+ * If the target type cannot represent the full range of the source type, + * values are clamped according to the specified {@link ClampType}. + *

+ * The returned factory function creates an operator matching the type + * {@code S} of the given input {@code BlockSupplier}. + * + * @param targetType + * an instance of the target type + * @param clamp + * ClampType + * @param + * source type + * @param + * target type + * + * @return factory for {@code UnaryBlockOperator} to convert blocks from {@code S} to {@code T} + */ + public static < S extends NativeType< S >, T extends NativeType< T > > + Function< BlockSupplier< S >, UnaryBlockOperator< S, T > > convert( final T targetType, final ClampType clamp ) + { + return s -> createOperator( s.getType(), targetType, clamp ); + } + + /** + * Create {@link UnaryBlockOperator} to convert blocks from {@code S} to + * {@code T} with the specified {@code Converter}. + *

+ * The returned factory function creates an operator matching the type + * {@code S} of the given input {@code BlockSupplier}. + * + * @param targetType + * an instance of the target type + * @param converterSupplier + * creates new converter instances + * @param + * source type + * @param + * target type + * + * @return factory for {@code UnaryBlockOperator} to convert blocks from {@code S} to {@code T} + */ + public static < S extends NativeType< S >, T extends NativeType< T > > + Function< BlockSupplier< S >, UnaryBlockOperator< S, T > > convert( final T targetType, Supplier< Converter< ? super S, T > > converterSupplier ) + { + return s -> createOperator( s.getType(), targetType, converterSupplier ); + } + /** * Create {@link UnaryBlockOperator} to convert blocks between {@code * sourceType} and {@code targetType}. * No clamping. */ public static < S extends NativeType< S >, T extends NativeType< T > > - UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType ) + UnaryBlockOperator< S, T > createOperator( final S sourceType, final T targetType ) { - return convert( sourceType, targetType, ClampType.NONE ); + return createOperator( sourceType, targetType, ClampType.NONE ); } /** @@ -76,7 +164,7 @@ UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType ) * Clamp target values according to {@code clamp}. */ public static < S extends NativeType< S >, T extends NativeType< T > > - UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType, final ClampType clamp ) + UnaryBlockOperator< S, T > createOperator( final S sourceType, final T targetType, final ClampType clamp ) { return new DefaultUnaryBlockOperator<>( sourceType, targetType, 0, 0, @@ -88,7 +176,7 @@ UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType, fina * sourceType} and {@code targetType} with the specified {@code Converter}. */ public static < S extends NativeType< S >, T extends NativeType< T > > - UnaryBlockOperator< S, T > convert( final S sourceType, final T targetType, Supplier< Converter< ? super S, T > > converterSupplier ) + UnaryBlockOperator< S, T > createOperator( final S sourceType, final T targetType, Supplier< Converter< ? super S, T > > converterSupplier ) { return new DefaultUnaryBlockOperator<>( sourceType, targetType, 0, 0, From 529c0046930e920b43e997617a57603403798353 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Mon, 15 Jul 2024 13:32:20 +0200 Subject: [PATCH 11/24] Remove unnecessary type arguments from ConvertBlockProcessor --- .../blocks/convert/ConvertBlockProcessor.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java index 9c6dc34a1..bbbf9df73 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java @@ -54,12 +54,8 @@ * @param * output primitive array type, e.g., float[] */ -class ConvertBlockProcessor< S extends NativeType< S >, T extends NativeType< T >, I, O > implements BlockProcessor< I, O > +class ConvertBlockProcessor< I, O > implements BlockProcessor< I, O > { - private final S sourceType; - - private final T targetType; - private final TempArray< I > tempArray; private final ConvertLoop< I, O > loop; @@ -72,19 +68,15 @@ class ConvertBlockProcessor< S extends NativeType< S >, T extends NativeType< T private final BlockProcessorSourceInterval sourceInterval; - public ConvertBlockProcessor( final S sourceType, final T targetType, final ClampType clamp ) + public < S extends NativeType< S >, T extends NativeType< T > > ConvertBlockProcessor( final S sourceType, final T targetType, final ClampType clamp ) { - this.sourceType = sourceType; - this.targetType = targetType; tempArray = TempArray.forPrimitiveType( sourceType.getNativeTypeFactory().getPrimitiveType() ); loop = ConvertLoops.get( UnaryOperatorType.of( sourceType, targetType ), clamp ); sourceInterval = new BlockProcessorSourceInterval( this ); } - private ConvertBlockProcessor( ConvertBlockProcessor< S, T, I, O > convert ) + private ConvertBlockProcessor( ConvertBlockProcessor< I, O > convert ) { - sourceType = convert.sourceType; - targetType = convert.targetType; tempArray = convert.tempArray.newInstance(); loop = convert.loop; sourceInterval = new BlockProcessorSourceInterval( this ); From c12668b2b82fad1af893f23f2bce30787f301a62 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Wed, 17 Jul 2024 23:47:58 +0200 Subject: [PATCH 12/24] ConvertScalars: make public, move to blocks.util package, add _clamp_min variants --- .../blocks/convert/ConvertLoops.java | 76 ++--- .../blocks/convert/ConvertScalars.java | 230 --------------- .../algorithm/blocks/util/ConvertScalars.java | 276 ++++++++++++++++++ .../imglib2/algorithm/blocks/ConvertLoops.vm | 12 +- .../algorithm/blocks/ConvertScalars.list | 2 +- .../algorithm/blocks/ConvertScalars.vm | 130 +++++---- 6 files changed, 391 insertions(+), 335 deletions(-) delete mode 100644 src/main/java/net/imglib2/algorithm/blocks/convert/ConvertScalars.java create mode 100644 src/main/java/net/imglib2/algorithm/blocks/util/ConvertScalars.java diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java index 4621195ed..1d9b88800 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java @@ -11,13 +11,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 @@ -36,42 +36,42 @@ import net.imglib2.algorithm.blocks.util.UnaryOperatorType; import net.imglib2.util.Cast; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_i8; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i8; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i8_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i8_clamp_max; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_u8; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u8; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u8_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u8_clamp_max; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_i16; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i16; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i16_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i16_clamp_max; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_u16; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u16; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u16_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u16_clamp_max; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_i32; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i32; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i32_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i32_clamp_max; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_u32; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u32; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u32_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_u32_clamp_max; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_i64; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i64; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i64_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_i64_clamp_max; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_f32; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_f32; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_f32_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_f32_clamp_max; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_f64; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_f64; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_f64_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_f64_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_i8; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i8; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i8_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i8_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_u8; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u8; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u8_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u8_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_i16; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i16; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i16_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i16_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_u16; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u16; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u16_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u16_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_i32; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i32; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i32_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i32_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_u32; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u32; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u32_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u32_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_i64; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i64; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i64_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i64_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_f32; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f32; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f32_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f32_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_f64; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f64; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f64_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f64_clamp_max; /* * This is autogenerated source code -- DO NOT EDIT. Instead, edit the diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertScalars.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertScalars.java deleted file mode 100644 index 03ed085e5..000000000 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertScalars.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * #%L - * ImgLib2: a general-purpose, multidimensional image processing library. - * %% - * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, - * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, - * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, - * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, - * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, - * Jean-Yves Tinevez and Michael Zinsmaier. - * %% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * #L% - */ -package net.imglib2.algorithm.blocks.convert; - -/* - * This is autogenerated source code -- DO NOT EDIT. Instead, edit the - * corresponding template in templates/ and rerun bin/generate.groovy. - */ - -class ConvertScalars -{ - /* - * Methods to convert each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64) - * to the corresponding primitive type used for computation. - * - * i8, u8, i16, u16, i32 are all converted to int, because java - * computes in int for byte, short, and int operands. - * - * u32, i64 are converted to long, because that is the primitive type that - * can represent all values of the pixel type. - * - * f32 is converted to float - * - * f64 is converted to double - */ - static int from_i8( byte value ) { return value; } - static int from_u8( byte value ) { return value & 0xff; } - static int from_i16( short value ) { return value; } - static int from_u16( short value ) { return value & 0xffff; } - static int from_i32( int value ) { return value; } - static long from_u32( int value ) { return value & 0xffffffffL; } - static long from_i64( long value ) { return value; } - static float from_f32( float value ) { return value; } - static double from_f64( double value ) { return value; } - - /* - * Methods to convert int values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). - * - * The basic to_u8() etc methods don't do any bounds-checking or clamping. - * They only cast the argument to the output type. - * - * The to_u8_clamp() etc methods clamp the argument to the range of the - * output type. - * - * The to_u8_clamp_max() etc methods clamp only to the upper bound output - * range. This is useful for computations that could possibly overflow but - * can never underflow (like summing unsigned values). - */ - static byte to_i8( int value ) { return ( byte ) value; } - static byte to_i8_clamp_max( int value ) { return to_i8( Math.min( 0x7f, value ) ); } - static byte to_i8_clamp( int value ) { return to_i8( Math.min( 0x7f, Math.max( -0x80, value ) ) ); } - static byte to_u8( int value ) { return ( byte ) value; } - static byte to_u8_clamp_max( int value ) { return to_u8( Math.min( 0xff, value ) ); } - static byte to_u8_clamp( int value ) { return to_u8( Math.min( 0xff, Math.max( 0, value ) ) ); } - static short to_i16( int value ) { return ( short ) value; } - static short to_i16_clamp_max( int value ) { return to_i16( Math.min( 0x7fff, value ) ); } - static short to_i16_clamp( int value ) { return to_i16( Math.min( 0x7fff, Math.max( -0x8000, value ) ) ); } - static short to_u16( int value ) { return ( short ) value; } - static short to_u16_clamp_max( int value ) { return to_u16( Math.min( 0xffff, value ) ); } - static short to_u16_clamp( int value ) { return to_u16( Math.min( 0xffff, Math.max( 0, value ) ) ); } - static int to_i32( int value ) { return value; } - static int to_i32_clamp_max( int value ) { return to_i32( value ); } - static int to_i32_clamp( int value ) { return to_i32( value ); } - static int to_u32( int value ) { return value; } - static int to_u32_clamp_max( int value ) { return to_u32( Math.min( 0xffff_ffffL, value ) ); } - static int to_u32_clamp( int value ) { return to_u32( Math.min( 0xffff_ffffL, Math.max( 0L, value ) ) ); } - static long to_i64( int value ) { return value; } - static long to_i64_clamp_max( int value ) { return to_i64( value ); } - static long to_i64_clamp( int value ) { return to_i64( value ); } - static float to_f32( int value ) { return value; } - static float to_f32_clamp_max( int value ) { return to_f32( value ); } - static float to_f32_clamp( int value ) { return to_f32( value ); } - static double to_f64( int value ) { return value; } - static double to_f64_clamp_max( int value ) { return to_f64( value ); } - static double to_f64_clamp( int value ) { return to_f64( value ); } - - /* - * Methods to convert long values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). - * - * The basic to_u8() etc methods don't do any bounds-checking or clamping. - * They only cast the argument to the output type. - * - * The to_u8_clamp() etc methods clamp the argument to the range of the - * output type. - * - * The to_u8_clamp_max() etc methods clamp only to the upper bound output - * range. This is useful for computations that could possibly overflow but - * can never underflow (like summing unsigned values). - */ - static byte to_i8( long value ) { return ( byte ) value; } - static byte to_i8_clamp_max( long value ) { return to_i8( Math.min( 0x7f, value ) ); } - static byte to_i8_clamp( long value ) { return to_i8( Math.min( 0x7f, Math.max( -0x80, value ) ) ); } - static byte to_u8( long value ) { return ( byte ) value; } - static byte to_u8_clamp_max( long value ) { return to_u8( Math.min( 0xff, value ) ); } - static byte to_u8_clamp( long value ) { return to_u8( Math.min( 0xff, Math.max( 0, value ) ) ); } - static short to_i16( long value ) { return ( short ) value; } - static short to_i16_clamp_max( long value ) { return to_i16( Math.min( 0x7fff, value ) ); } - static short to_i16_clamp( long value ) { return to_i16( Math.min( 0x7fff, Math.max( -0x8000, value ) ) ); } - static short to_u16( long value ) { return ( short ) value; } - static short to_u16_clamp_max( long value ) { return to_u16( Math.min( 0xffff, value ) ); } - static short to_u16_clamp( long value ) { return to_u16( Math.min( 0xffff, Math.max( 0, value ) ) ); } - static int to_i32( long value ) { return ( int ) value; } - static int to_i32_clamp_max( long value ) { return to_i32( Math.min( 0x7fff_ffff, value ) ); } - static int to_i32_clamp( long value ) { return to_i32( Math.min( 0x7fff_ffff, Math.max( -0x8000_0000, value ) ) ); } - static int to_u32( long value ) { return ( int ) value; } - static int to_u32_clamp_max( long value ) { return to_u32( Math.min( 0xffff_ffffL, value ) ); } - static int to_u32_clamp( long value ) { return to_u32( Math.min( 0xffff_ffffL, Math.max( 0L, value ) ) ); } - static long to_i64( long value ) { return value; } - static long to_i64_clamp_max( long value ) { return to_i64( value ); } - static long to_i64_clamp( long value ) { return to_i64( value ); } - static float to_f32( long value ) { return ( float ) value; } - static float to_f32_clamp_max( long value ) { return to_f32( value ); } - static float to_f32_clamp( long value ) { return to_f32( value ); } - static double to_f64( long value ) { return value; } - static double to_f64_clamp_max( long value ) { return to_f64( value ); } - static double to_f64_clamp( long value ) { return to_f64( value ); } - - /* - * Methods to convert float values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). - * - * The basic to_u8() etc methods don't do any bounds-checking or clamping. - * They round the argument and then cast to the output type. - * - * The to_u8_clamp() etc methods additionally clamp the argument to the - * range of the output type. - * - * The to_u8_clamp_max() etc methods additionally clamp only to the upper - * bound output range. This is useful for computations that could possibly - * overflow but can never underflow (like summing unsigned values). - */ - static byte to_i8( float value ) { return to_i8( Math.round( value ) ); } - static byte to_i8_clamp_max( float value ) { return to_i8_clamp_max( Math.round( value ) ); } - static byte to_i8_clamp( float value ) { return to_i8_clamp( Math.round( value ) ); } - static byte to_u8( float value ) { return to_u8( Math.round( value ) ); } - static byte to_u8_clamp_max( float value ) { return to_u8_clamp_max( Math.round( value ) ); } - static byte to_u8_clamp( float value ) { return to_u8_clamp( Math.round( value ) ); } - static short to_i16( float value ) { return to_i16( Math.round( value ) ); } - static short to_i16_clamp_max( float value ) { return to_i16_clamp_max( Math.round( value ) ); } - static short to_i16_clamp( float value ) { return to_i16_clamp( Math.round( value ) ); } - static short to_u16( float value ) { return to_u16( Math.round( value ) ); } - static short to_u16_clamp_max( float value ) { return to_u16_clamp_max( Math.round( value ) ); } - static short to_u16_clamp( float value ) { return to_u16_clamp( Math.round( value ) ); } - static int to_i32( float value ) { return to_i32( Math.round( value ) ); } - static int to_i32_clamp_max( float value ) { return to_i32_clamp_max( Math.round( value ) ); } - static int to_i32_clamp( float value ) { return to_i32_clamp( Math.round( value ) ); } - static int to_u32( float value ) { return to_u32( Math.round( ( double ) value ) ); } - static int to_u32_clamp_max( float value ) { return to_u32_clamp_max( Math.round( ( double ) value ) ); } - static int to_u32_clamp( float value ) { return to_u32_clamp( Math.round( ( double ) value ) ); } - static long to_i64( float value ) { return to_i64( Math.round( ( double ) value ) ); } - static long to_i64_clamp_max( float value ) { return to_i64_clamp_max( Math.round( ( double ) value ) ); } - static long to_i64_clamp( float value ) { return to_i64_clamp( Math.round( ( double ) value ) ); } - static float to_f32( float value ) { return value; } - static float to_f32_clamp_max( float value ) { return to_f32( value ); } - static float to_f32_clamp( float value ) { return to_f32( value ); } - static double to_f64( float value ) { return value; } - static double to_f64_clamp_max( float value ) { return to_f64( value ); } - static double to_f64_clamp( float value ) { return to_f64( value ); } - - /* - * Methods to convert double values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). - * - * The basic to_u8() etc methods don't do any bounds-checking or clamping. - * They round the argument and then cast to the output type. - * - * The to_u8_clamp() etc methods additionally clamp the argument to the - * range of the output type. - * - * The to_u8_clamp_max() etc methods additionally clamp only to the upper - * bound output range. This is useful for computations that could possibly - * overflow but can never underflow (like summing unsigned values). - */ - static byte to_i8( double value ) { return to_i8( Math.round( value ) ); } - static byte to_i8_clamp_max( double value ) { return to_i8_clamp_max( Math.round( value ) ); } - static byte to_i8_clamp( double value ) { return to_i8_clamp( Math.round( value ) ); } - static byte to_u8( double value ) { return to_u8( Math.round( value ) ); } - static byte to_u8_clamp_max( double value ) { return to_u8_clamp_max( Math.round( value ) ); } - static byte to_u8_clamp( double value ) { return to_u8_clamp( Math.round( value ) ); } - static short to_i16( double value ) { return to_i16( Math.round( value ) ); } - static short to_i16_clamp_max( double value ) { return to_i16_clamp_max( Math.round( value ) ); } - static short to_i16_clamp( double value ) { return to_i16_clamp( Math.round( value ) ); } - static short to_u16( double value ) { return to_u16( Math.round( value ) ); } - static short to_u16_clamp_max( double value ) { return to_u16_clamp_max( Math.round( value ) ); } - static short to_u16_clamp( double value ) { return to_u16_clamp( Math.round( value ) ); } - static int to_i32( double value ) { return to_i32( Math.round( value ) ); } - static int to_i32_clamp_max( double value ) { return to_i32_clamp_max( Math.round( value ) ); } - static int to_i32_clamp( double value ) { return to_i32_clamp( Math.round( value ) ); } - static int to_u32( double value ) { return to_u32( Math.round( value ) ); } - static int to_u32_clamp_max( double value ) { return to_u32_clamp_max( Math.round( value ) ); } - static int to_u32_clamp( double value ) { return to_u32_clamp( Math.round( value ) ); } - static long to_i64( double value ) { return to_i64( Math.round( value ) ); } - static long to_i64_clamp_max( double value ) { return to_i64_clamp_max( Math.round( value ) ); } - static long to_i64_clamp( double value ) { return to_i64_clamp( Math.round( value ) ); } - static float to_f32( double value ) { return ( float ) value; } - static float to_f32_clamp_max( double value ) { return to_f32( value ); } - static float to_f32_clamp( double value ) { return to_f32( value ); } - static double to_f64( double value ) { return value; } - static double to_f64_clamp_max( double value ) { return to_f64( value ); } - static double to_f64_clamp( double value ) { return to_f64( value ); } -} diff --git a/src/main/java/net/imglib2/algorithm/blocks/util/ConvertScalars.java b/src/main/java/net/imglib2/algorithm/blocks/util/ConvertScalars.java new file mode 100644 index 000000000..4d90bc9aa --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/util/ConvertScalars.java @@ -0,0 +1,276 @@ +/* + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package net.imglib2.algorithm.blocks.util; + +/* + * This is autogenerated source code -- DO NOT EDIT. Instead, edit the + * corresponding template in templates/ and rerun bin/generate.groovy. + */ + +public class ConvertScalars +{ + /* + * Methods to convert each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64) + * to the corresponding primitive type used for computation. + * + * i8, u8, i16, u16, i32 are all converted to int, because java + * computes in int for byte, short, and int operands. + * + * u32, i64 are converted to long, because that is the primitive type that + * can represent all values of the pixel type. + * + * f32 is converted to float + * + * f64 is converted to double + */ + public static int from_i8( byte value ) { return value; } + public static int from_u8( byte value ) { return value & 0xff; } + public static int from_i16( short value ) { return value; } + public static int from_u16( short value ) { return value & 0xffff; } + public static int from_i32( int value ) { return value; } + public static long from_u32( int value ) { return value & 0xffffffffL; } + public static long from_i64( long value ) { return value; } + public static float from_f32( float value ) { return value; } + public static double from_f64( double value ) { return value; } + + /* + * Methods to convert int values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). + * + * The basic to_u8() etc methods don't do any bounds-checking or clamping. + * They only cast the argument to the output type. + * + * The to_u8_clamp() etc methods clamp the argument to the range of the + * output type. + * + * The to_u8_clamp_max() etc methods clamp only to the upper bound output + * range. This is useful for computations that could possibly overflow but + * can never underflow (like summing unsigned values). + * + * The to_u8_clamp_min() etc methods clamp only to the lower bound output + * range. This is useful for computations that could possibly underflow but + * can never overflow (like subtracting unsigned values). + */ + public static byte to_i8( int value ) { return ( byte ) value; } + public static byte to_i8_clamp_max( int value ) { return to_i8( Math.min( 0x7f, value ) ); } + public static byte to_i8_clamp_min( int value ) { return to_i8( Math.max( -0x80, value ) ); } + public static byte to_i8_clamp( int value ) { return to_i8( Math.min( 0x7f, Math.max( -0x80, value ) ) ); } + public static byte to_u8( int value ) { return ( byte ) value; } + public static byte to_u8_clamp_max( int value ) { return to_u8( Math.min( 0xff, value ) ); } + public static byte to_u8_clamp_min( int value ) { return to_u8( Math.max( 0, value ) ); } + public static byte to_u8_clamp( int value ) { return to_u8( Math.min( 0xff, Math.max( 0, value ) ) ); } + public static short to_i16( int value ) { return ( short ) value; } + public static short to_i16_clamp_max( int value ) { return to_i16( Math.min( 0x7fff, value ) ); } + public static short to_i16_clamp_min( int value ) { return to_i16( Math.max( -0x8000, value ) ); } + public static short to_i16_clamp( int value ) { return to_i16( Math.min( 0x7fff, Math.max( -0x8000, value ) ) ); } + public static short to_u16( int value ) { return ( short ) value; } + public static short to_u16_clamp_max( int value ) { return to_u16( Math.min( 0xffff, value ) ); } + public static short to_u16_clamp_min( int value ) { return to_u16( Math.max( 0, value ) ); } + public static short to_u16_clamp( int value ) { return to_u16( Math.min( 0xffff, Math.max( 0, value ) ) ); } + public static int to_i32( int value ) { return value; } + public static int to_i32_clamp_max( int value ) { return to_i32( value ); } + public static int to_i32_clamp_min( int value ) { return to_i32( value ); } + public static int to_i32_clamp( int value ) { return to_i32( value ); } + public static int to_u32( int value ) { return value; } + public static int to_u32_clamp_max( int value ) { return to_u32( Math.min( 0xffff_ffffL, value ) ); } + public static int to_u32_clamp_min( int value ) { return to_u32( Math.max( 0L, value ) ); } + public static int to_u32_clamp( int value ) { return to_u32( Math.min( 0xffff_ffffL, Math.max( 0L, value ) ) ); } + public static long to_i64( int value ) { return value; } + public static long to_i64_clamp_max( int value ) { return to_i64( value ); } + public static long to_i64_clamp_min( int value ) { return to_i64( value ); } + public static long to_i64_clamp( int value ) { return to_i64( value ); } + public static float to_f32( int value ) { return value; } + public static float to_f32_clamp_max( int value ) { return to_f32( value ); } + public static float to_f32_clamp_min( int value ) { return to_f32( value ); } + public static float to_f32_clamp( int value ) { return to_f32( value ); } + public static double to_f64( int value ) { return value; } + public static double to_f64_clamp_max( int value ) { return to_f64( value ); } + public static double to_f64_clamp_min( int value ) { return to_f64( value ); } + public static double to_f64_clamp( int value ) { return to_f64( value ); } + + /* + * Methods to convert long values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). + * + * The basic to_u8() etc methods don't do any bounds-checking or clamping. + * They only cast the argument to the output type. + * + * The to_u8_clamp() etc methods clamp the argument to the range of the + * output type. + * + * The to_u8_clamp_max() etc methods clamp only to the upper bound output + * range. This is useful for computations that could possibly overflow but + * can never underflow (like summing unsigned values). + * + * The to_u8_clamp_min() etc methods clamp only to the lower bound output + * range. This is useful for computations that could possibly underflow but + * can never overflow (like subtracting unsigned values). + */ + public static byte to_i8( long value ) { return ( byte ) value; } + public static byte to_i8_clamp_max( long value ) { return to_i8( Math.min( 0x7f, value ) ); } + public static byte to_i8_clamp_min( long value ) { return to_i8( Math.max( -0x80, value ) ); } + public static byte to_i8_clamp( long value ) { return to_i8( Math.min( 0x7f, Math.max( -0x80, value ) ) ); } + public static byte to_u8( long value ) { return ( byte ) value; } + public static byte to_u8_clamp_max( long value ) { return to_u8( Math.min( 0xff, value ) ); } + public static byte to_u8_clamp_min( long value ) { return to_u8( Math.max( 0, value ) ); } + public static byte to_u8_clamp( long value ) { return to_u8( Math.min( 0xff, Math.max( 0, value ) ) ); } + public static short to_i16( long value ) { return ( short ) value; } + public static short to_i16_clamp_max( long value ) { return to_i16( Math.min( 0x7fff, value ) ); } + public static short to_i16_clamp_min( long value ) { return to_i16( Math.max( -0x8000, value ) ); } + public static short to_i16_clamp( long value ) { return to_i16( Math.min( 0x7fff, Math.max( -0x8000, value ) ) ); } + public static short to_u16( long value ) { return ( short ) value; } + public static short to_u16_clamp_max( long value ) { return to_u16( Math.min( 0xffff, value ) ); } + public static short to_u16_clamp_min( long value ) { return to_u16( Math.max( 0, value ) ); } + public static short to_u16_clamp( long value ) { return to_u16( Math.min( 0xffff, Math.max( 0, value ) ) ); } + public static int to_i32( long value ) { return ( int ) value; } + public static int to_i32_clamp_max( long value ) { return to_i32( Math.min( 0x7fff_ffff, value ) ); } + public static int to_i32_clamp_min( long value ) { return to_i32( Math.max( -0x8000_0000, value ) ); } + public static int to_i32_clamp( long value ) { return to_i32( Math.min( 0x7fff_ffff, Math.max( -0x8000_0000, value ) ) ); } + public static int to_u32( long value ) { return ( int ) value; } + public static int to_u32_clamp_max( long value ) { return to_u32( Math.min( 0xffff_ffffL, value ) ); } + public static int to_u32_clamp_min( long value ) { return to_u32( Math.max( 0L, value ) ); } + public static int to_u32_clamp( long value ) { return to_u32( Math.min( 0xffff_ffffL, Math.max( 0L, value ) ) ); } + public static long to_i64( long value ) { return value; } + public static long to_i64_clamp_max( long value ) { return to_i64( value ); } + public static long to_i64_clamp_min( long value ) { return to_i64( value ); } + public static long to_i64_clamp( long value ) { return to_i64( value ); } + public static float to_f32( long value ) { return ( float ) value; } + public static float to_f32_clamp_max( long value ) { return to_f32( value ); } + public static float to_f32_clamp_min( long value ) { return to_f32( value ); } + public static float to_f32_clamp( long value ) { return to_f32( value ); } + public static double to_f64( long value ) { return value; } + public static double to_f64_clamp_max( long value ) { return to_f64( value ); } + public static double to_f64_clamp_min( long value ) { return to_f64( value ); } + public static double to_f64_clamp( long value ) { return to_f64( value ); } + + /* + * Methods to convert float values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). + * + * The basic to_u8() etc methods don't do any bounds-checking or clamping. + * They round the argument and then cast to the output type. + * + * The to_u8_clamp_max() etc methods clamp only to the upper bound output + * range. This is useful for computations that could possibly overflow but + * can never underflow (like summing unsigned values). + * + * The to_u8_clamp_min() etc methods clamp only to the lower bound output + * range. This is useful for computations that could possibly underflow but + * can never overflow (like subtracting unsigned values). + */ + public static byte to_i8( float value ) { return to_i8( Math.round( value ) ); } + public static byte to_i8_clamp_max( float value ) { return to_i8_clamp_max( Math.round( value ) ); } + public static byte to_i8_clamp_min( float value ) { return to_i8_clamp_min( Math.round( value ) ); } + public static byte to_i8_clamp( float value ) { return to_i8_clamp( Math.round( value ) ); } + public static byte to_u8( float value ) { return to_u8( Math.round( value ) ); } + public static byte to_u8_clamp_max( float value ) { return to_u8_clamp_max( Math.round( value ) ); } + public static byte to_u8_clamp_min( float value ) { return to_u8_clamp_min( Math.round( value ) ); } + public static byte to_u8_clamp( float value ) { return to_u8_clamp( Math.round( value ) ); } + public static short to_i16( float value ) { return to_i16( Math.round( value ) ); } + public static short to_i16_clamp_max( float value ) { return to_i16_clamp_max( Math.round( value ) ); } + public static short to_i16_clamp_min( float value ) { return to_i16_clamp_min( Math.round( value ) ); } + public static short to_i16_clamp( float value ) { return to_i16_clamp( Math.round( value ) ); } + public static short to_u16( float value ) { return to_u16( Math.round( value ) ); } + public static short to_u16_clamp_max( float value ) { return to_u16_clamp_max( Math.round( value ) ); } + public static short to_u16_clamp_min( float value ) { return to_u16_clamp_min( Math.round( value ) ); } + public static short to_u16_clamp( float value ) { return to_u16_clamp( Math.round( value ) ); } + public static int to_i32( float value ) { return to_i32( Math.round( value ) ); } + public static int to_i32_clamp_max( float value ) { return to_i32_clamp_max( Math.round( value ) ); } + public static int to_i32_clamp_min( float value ) { return to_i32_clamp_min( Math.round( value ) ); } + public static int to_i32_clamp( float value ) { return to_i32_clamp( Math.round( value ) ); } + public static int to_u32( float value ) { return to_u32( Math.round( ( double ) value ) ); } + public static int to_u32_clamp_max( float value ) { return to_u32_clamp_max( Math.round( ( double ) value ) ); } + public static int to_u32_clamp_min( float value ) { return to_u32_clamp_min( Math.round( ( double ) value ) ); } + public static int to_u32_clamp( float value ) { return to_u32_clamp( Math.round( ( double ) value ) ); } + public static long to_i64( float value ) { return to_i64( Math.round( ( double ) value ) ); } + public static long to_i64_clamp_max( float value ) { return to_i64_clamp_max( Math.round( ( double ) value ) ); } + public static long to_i64_clamp_min( float value ) { return to_i64_clamp_min( Math.round( ( double ) value ) ); } + public static long to_i64_clamp( float value ) { return to_i64_clamp( Math.round( ( double ) value ) ); } + public static float to_f32( float value ) { return value; } + public static float to_f32_clamp_max( float value ) { return to_f32( value ); } + public static float to_f32_clamp_min( float value ) { return to_f32( value ); } + public static float to_f32_clamp( float value ) { return to_f32( value ); } + public static double to_f64( float value ) { return value; } + public static double to_f64_clamp_max( float value ) { return to_f64( value ); } + public static double to_f64_clamp_min( float value ) { return to_f64( value ); } + public static double to_f64_clamp( float value ) { return to_f64( value ); } + + /* + * Methods to convert double values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). + * + * The basic to_u8() etc methods don't do any bounds-checking or clamping. + * They round the argument and then cast to the output type. + * + * The to_u8_clamp_max() etc methods clamp only to the upper bound output + * range. This is useful for computations that could possibly overflow but + * can never underflow (like summing unsigned values). + * + * The to_u8_clamp_min() etc methods clamp only to the lower bound output + * range. This is useful for computations that could possibly underflow but + * can never overflow (like subtracting unsigned values). + */ + public static byte to_i8( double value ) { return to_i8( Math.round( value ) ); } + public static byte to_i8_clamp_max( double value ) { return to_i8_clamp_max( Math.round( value ) ); } + public static byte to_i8_clamp_min( double value ) { return to_i8_clamp_min( Math.round( value ) ); } + public static byte to_i8_clamp( double value ) { return to_i8_clamp( Math.round( value ) ); } + public static byte to_u8( double value ) { return to_u8( Math.round( value ) ); } + public static byte to_u8_clamp_max( double value ) { return to_u8_clamp_max( Math.round( value ) ); } + public static byte to_u8_clamp_min( double value ) { return to_u8_clamp_min( Math.round( value ) ); } + public static byte to_u8_clamp( double value ) { return to_u8_clamp( Math.round( value ) ); } + public static short to_i16( double value ) { return to_i16( Math.round( value ) ); } + public static short to_i16_clamp_max( double value ) { return to_i16_clamp_max( Math.round( value ) ); } + public static short to_i16_clamp_min( double value ) { return to_i16_clamp_min( Math.round( value ) ); } + public static short to_i16_clamp( double value ) { return to_i16_clamp( Math.round( value ) ); } + public static short to_u16( double value ) { return to_u16( Math.round( value ) ); } + public static short to_u16_clamp_max( double value ) { return to_u16_clamp_max( Math.round( value ) ); } + public static short to_u16_clamp_min( double value ) { return to_u16_clamp_min( Math.round( value ) ); } + public static short to_u16_clamp( double value ) { return to_u16_clamp( Math.round( value ) ); } + public static int to_i32( double value ) { return to_i32( Math.round( value ) ); } + public static int to_i32_clamp_max( double value ) { return to_i32_clamp_max( Math.round( value ) ); } + public static int to_i32_clamp_min( double value ) { return to_i32_clamp_min( Math.round( value ) ); } + public static int to_i32_clamp( double value ) { return to_i32_clamp( Math.round( value ) ); } + public static int to_u32( double value ) { return to_u32( Math.round( value ) ); } + public static int to_u32_clamp_max( double value ) { return to_u32_clamp_max( Math.round( value ) ); } + public static int to_u32_clamp_min( double value ) { return to_u32_clamp_min( Math.round( value ) ); } + public static int to_u32_clamp( double value ) { return to_u32_clamp( Math.round( value ) ); } + public static long to_i64( double value ) { return to_i64( Math.round( value ) ); } + public static long to_i64_clamp_max( double value ) { return to_i64_clamp_max( Math.round( value ) ); } + public static long to_i64_clamp_min( double value ) { return to_i64_clamp_min( Math.round( value ) ); } + public static long to_i64_clamp( double value ) { return to_i64_clamp( Math.round( value ) ); } + public static float to_f32( double value ) { return ( float ) value; } + public static float to_f32_clamp_max( double value ) { return to_f32( value ); } + public static float to_f32_clamp_min( double value ) { return to_f32( value ); } + public static float to_f32_clamp( double value ) { return to_f32( value ); } + public static double to_f64( double value ) { return value; } + public static double to_f64_clamp_max( double value ) { return to_f64( value ); } + public static double to_f64_clamp_min( double value ) { return to_f64( value ); } + public static double to_f64_clamp( double value ) { return to_f64( value ); } +} diff --git a/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm b/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm index 4d673e277..1a7d7fc28 100644 --- a/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm +++ b/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm @@ -11,13 +11,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 @@ -38,10 +38,10 @@ import net.imglib2.util.Cast; #parse( "PixelTypes.vm" ) #foreach( $t1 in $types ) -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.from_${t1}; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_${t1}; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_${t1}_clamp; -import static net.imglib2.algorithm.blocks.convert.ConvertScalars.to_${t1}_clamp_max; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_${t1}; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_${t1}; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_${t1}_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_${t1}_clamp_max; #end /* diff --git a/templates/main/java/net/imglib2/algorithm/blocks/ConvertScalars.list b/templates/main/java/net/imglib2/algorithm/blocks/ConvertScalars.list index efdb9f9ee..db0f9dfab 100644 --- a/templates/main/java/net/imglib2/algorithm/blocks/ConvertScalars.list +++ b/templates/main/java/net/imglib2/algorithm/blocks/ConvertScalars.list @@ -1 +1 @@ -[convert/ConvertScalars.java] +[util/ConvertScalars.java] diff --git a/templates/main/java/net/imglib2/algorithm/blocks/ConvertScalars.vm b/templates/main/java/net/imglib2/algorithm/blocks/ConvertScalars.vm index 75bce27ee..bfca43ef3 100644 --- a/templates/main/java/net/imglib2/algorithm/blocks/ConvertScalars.vm +++ b/templates/main/java/net/imglib2/algorithm/blocks/ConvertScalars.vm @@ -11,13 +11,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 @@ -31,7 +31,7 @@ * POSSIBILITY OF SUCH DAMAGE. * #L% */ -package net.imglib2.algorithm.blocks.convert; +package net.imglib2.algorithm.blocks.util; /* * This is autogenerated source code -- DO NOT EDIT. Instead, edit the @@ -39,64 +39,70 @@ package net.imglib2.algorithm.blocks.convert; */ #parse( "PixelTypes.vm" ) -class ConvertScalars +public class ConvertScalars { ## ## from_i8(), etc., with corresponding compute_primitive as result type ## - /* - * Methods to convert each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64) - * to the corresponding primitive type used for computation. - * - * i8, u8, i16, u16, i32 are all converted to int, because java - * computes in int for byte, short, and int operands. - * - * u32, i64 are converted to long, because that is the primitive type that - * can represent all values of the pixel type. - * - * f32 is converted to float - * - * f64 is converted to double - */ + /* + * Methods to convert each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64) + * to the corresponding primitive type used for computation. + * + * i8, u8, i16, u16, i32 are all converted to int, because java + * computes in int for byte, short, and int operands. + * + * u32, i64 are converted to long, because that is the primitive type that + * can represent all values of the pixel type. + * + * f32 is converted to float + * + * f64 is converted to double + */ #foreach( $t in $types ) #set( $cp = $compute_primitive[$t] ) #set( $sp = $storage_primitive[$t] ) #set( $m = $mask[$t] ) - static $cp from_$t( $sp value ) { return value#if( $m ) & $m#end; } + public static $cp from_$t( $sp value ) { return value#if( $m ) & $m#end; } #end ## ## to_i8(), etc., for int/long ## #foreach( $cp in ["int", "long"] ) - /* - * Methods to convert ${cp} values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). - * - * The basic to_u8() etc methods don't do any bounds-checking or clamping. - * They only cast the argument to the output type. - * - * The to_u8_clamp() etc methods clamp the argument to the range of the - * output type. - * - * The to_u8_clamp_max() etc methods clamp only to the upper bound output - * range. This is useful for computations that could possibly overflow but - * can never underflow (like summing unsigned values). - */ + /* + * Methods to convert ${cp} values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). + * + * The basic to_u8() etc methods don't do any bounds-checking or clamping. + * They only cast the argument to the output type. + * + * The to_u8_clamp() etc methods clamp the argument to the range of the + * output type. + * + * The to_u8_clamp_max() etc methods clamp only to the upper bound output + * range. This is useful for computations that could possibly overflow but + * can never underflow (like summing unsigned values). + * + * The to_u8_clamp_min() etc methods clamp only to the lower bound output + * range. This is useful for computations that could possibly underflow but + * can never overflow (like subtracting unsigned values). + */ #foreach( $t in $types ) #set( $sp = $storage_primitive[$t] ) #set( $max = $max_value[$t] ) #set( $min = $min_value[$t] ) #if( $nbits[$sp] >= $nbits[$cp] ) - static $sp to_${t}( $cp value ) { return value; } + public static $sp to_${t}( $cp value ) { return value; } #else - static $sp to_${t}( $cp value ) { return ( $sp ) value; } + public static $sp to_${t}( $cp value ) { return ( $sp ) value; } #end #if( $max && !( $cp=="int" && $t=="i32" ) ) - static $sp to_${t}_clamp_max( $cp value ) { return to_${t}( Math.min( $max, value ) ); } - static $sp to_${t}_clamp( $cp value ) { return to_${t}( Math.min( $max, Math.max( $min, value ) ) ); } + public static $sp to_${t}_clamp_max( $cp value ) { return to_${t}( Math.min( $max, value ) ); } + public static $sp to_${t}_clamp_min( $cp value ) { return to_${t}( Math.max( $min, value ) ); } + public static $sp to_${t}_clamp( $cp value ) { return to_${t}( Math.min( $max, Math.max( $min, value ) ) ); } #else - static $sp to_${t}_clamp_max( $cp value ) { return to_${t}( value ); } - static $sp to_${t}_clamp( $cp value ) { return to_${t}( value ); } + public static $sp to_${t}_clamp_max( $cp value ) { return to_${t}( value ); } + public static $sp to_${t}_clamp_min( $cp value ) { return to_${t}( value ); } + public static $sp to_${t}_clamp( $cp value ) { return to_${t}( value ); } #end #end #end @@ -106,35 +112,39 @@ class ConvertScalars ## #foreach( $cp in ["float", "double"] ) - /* - * Methods to convert ${cp} values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). - * - * The basic to_u8() etc methods don't do any bounds-checking or clamping. - * They round the argument and then cast to the output type. - * - * The to_u8_clamp() etc methods additionally clamp the argument to the - * range of the output type. - * - * The to_u8_clamp_max() etc methods additionally clamp only to the upper - * bound output range. This is useful for computations that could possibly - * overflow but can never underflow (like summing unsigned values). - */ + /* + * Methods to convert ${cp} values to each pixel type (i8, u8, i16, u16, i32, u32, i64, f32, f64). + * + * The basic to_u8() etc methods don't do any bounds-checking or clamping. + * They round the argument and then cast to the output type. + * + * The to_u8_clamp_max() etc methods clamp only to the upper bound output + * range. This is useful for computations that could possibly overflow but + * can never underflow (like summing unsigned values). + * + * The to_u8_clamp_min() etc methods clamp only to the lower bound output + * range. This is useful for computations that could possibly underflow but + * can never overflow (like subtracting unsigned values). + */ #foreach( $t in $types ) #set( $sp = $storage_primitive[$t] ) #set( $no_rounding = ["f32", "f64"] ) #set( $double_rounding = ["u32", "i64"] ) #if( $cp.equals("float") && $double_rounding.contains($t) ) - static $sp to_${t}( $cp value ) { return to_${t}( Math.round( ( double ) value ) ); } - static $sp to_${t}_clamp_max( $cp value ) { return to_${t}_clamp_max( Math.round( ( double ) value ) ); } - static $sp to_${t}_clamp( $cp value ) { return to_${t}_clamp( Math.round( ( double ) value ) ); } + public static $sp to_${t}( $cp value ) { return to_${t}( Math.round( ( double ) value ) ); } + public static $sp to_${t}_clamp_max( $cp value ) { return to_${t}_clamp_max( Math.round( ( double ) value ) ); } + public static $sp to_${t}_clamp_min( $cp value ) { return to_${t}_clamp_min( Math.round( ( double ) value ) ); } + public static $sp to_${t}_clamp( $cp value ) { return to_${t}_clamp( Math.round( ( double ) value ) ); } #elseif( $no_rounding.contains($t) ) - static $sp to_${t}( $cp value ) { return #if( $nbits[$sp] < $nbits[$cp] )( $sp ) #end value; } - static $sp to_${t}_clamp_max( $cp value ) { return to_${t}( value ); } - static $sp to_${t}_clamp( $cp value ) { return to_${t}( value ); } + public static $sp to_${t}( $cp value ) { return #if( $nbits[$sp] < $nbits[$cp] )( $sp ) #end value; } + public static $sp to_${t}_clamp_max( $cp value ) { return to_${t}( value ); } + public static $sp to_${t}_clamp_min( $cp value ) { return to_${t}( value ); } + public static $sp to_${t}_clamp( $cp value ) { return to_${t}( value ); } #else - static $sp to_${t}( $cp value ) { return to_${t}( Math.round( value ) ); } - static $sp to_${t}_clamp_max( $cp value ) { return to_${t}_clamp_max( Math.round( value ) ); } - static $sp to_${t}_clamp( $cp value ) { return to_${t}_clamp( Math.round( value ) ); } + public static $sp to_${t}( $cp value ) { return to_${t}( Math.round( value ) ); } + public static $sp to_${t}_clamp_max( $cp value ) { return to_${t}_clamp_max( Math.round( value ) ); } + public static $sp to_${t}_clamp_min( $cp value ) { return to_${t}_clamp_min( Math.round( value ) ); } + public static $sp to_${t}_clamp( $cp value ) { return to_${t}_clamp( Math.round( value ) ); } #end #end #end From 9f537f6c1671ceafa4761637d1113d74f772a204 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Mon, 22 Jul 2024 17:20:43 +0200 Subject: [PATCH 13/24] Make ClampType global --- .../algorithm/blocks/{convert => }/ClampType.java | 15 ++++++++++----- .../algorithm/blocks/UnaryBlockOperator.java | 1 - .../imglib2/algorithm/blocks/convert/Convert.java | 1 + .../blocks/convert/ConvertBlockProcessor.java | 1 + .../algorithm/blocks/convert/ConvertLoops.java | 1 + .../algorithm/blocks/downsample/Downsample.java | 6 +++--- .../algorithm/blocks/transform/Transform.java | 2 +- .../net/imglib2/algorithm/blocks/ConvertLoops.vm | 1 + 8 files changed, 18 insertions(+), 10 deletions(-) rename src/main/java/net/imglib2/algorithm/blocks/{convert => }/ClampType.java (92%) diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ClampType.java b/src/main/java/net/imglib2/algorithm/blocks/ClampType.java similarity index 92% rename from src/main/java/net/imglib2/algorithm/blocks/convert/ClampType.java rename to src/main/java/net/imglib2/algorithm/blocks/ClampType.java index 2957132c8..39eefd2a1 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ClampType.java +++ b/src/main/java/net/imglib2/algorithm/blocks/ClampType.java @@ -11,13 +11,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 @@ -31,10 +31,10 @@ * POSSIBILITY OF SUCH DAMAGE. * #L% */ -package net.imglib2.algorithm.blocks.convert; +package net.imglib2.algorithm.blocks; /** - * How to clamp values when converting between {@link net.imglib2.algorithm.blocks.util.OperandType}. + * How to clamp values when converting to target type. */ public enum ClampType { @@ -48,8 +48,13 @@ public enum ClampType */ CLAMP, + /** + * clamp only to lower bound + */ + CLAMP_MIN, + /** * clamp only to upper bound */ - CLAMP_MAX; + CLAMP_MAX } diff --git a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java index a1e4f8871..9dfef4150 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java @@ -33,7 +33,6 @@ */ package net.imglib2.algorithm.blocks; -import net.imglib2.algorithm.blocks.convert.ClampType; import net.imglib2.algorithm.blocks.convert.Convert; import net.imglib2.type.NativeType; import net.imglib2.util.Cast; diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java index 4f7d7d589..d57e406b2 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java @@ -37,6 +37,7 @@ import java.util.function.Supplier; import net.imglib2.algorithm.blocks.BlockSupplier; +import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator; import net.imglib2.algorithm.blocks.UnaryBlockOperator; import net.imglib2.converter.Converter; diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java index bbbf9df73..efa579125 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java @@ -39,6 +39,7 @@ import net.imglib2.Interval; import net.imglib2.algorithm.blocks.BlockProcessor; +import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; import net.imglib2.algorithm.blocks.util.UnaryOperatorType; import net.imglib2.blocks.TempArray; diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java index 1d9b88800..5a4933d57 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java @@ -33,6 +33,7 @@ */ package net.imglib2.algorithm.blocks.convert; +import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.algorithm.blocks.util.UnaryOperatorType; import net.imglib2.util.Cast; diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java index 388447eb7..819e8cef4 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java @@ -11,13 +11,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 @@ -34,7 +34,7 @@ package net.imglib2.algorithm.blocks.downsample; import java.util.Arrays; -import net.imglib2.algorithm.blocks.convert.ClampType; +import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterDouble; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterFloat; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.HalfPixelDouble; diff --git a/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java b/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java index 325b05479..9fa9e8932 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java +++ b/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java @@ -35,7 +35,7 @@ import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator; import net.imglib2.algorithm.blocks.UnaryBlockOperator; -import net.imglib2.algorithm.blocks.convert.ClampType; +import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.AffineTransform2D; import net.imglib2.realtransform.AffineTransform3D; diff --git a/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm b/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm index 1a7d7fc28..f9a08944c 100644 --- a/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm +++ b/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm @@ -33,6 +33,7 @@ */ package net.imglib2.algorithm.blocks.convert; +import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.algorithm.blocks.util.UnaryOperatorType; import net.imglib2.util.Cast; From 97d84ecd39ce55e705827b2838f4baa9e83be831 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sun, 15 Sep 2024 14:54:59 +0200 Subject: [PATCH 14/24] ConvertLoops: clamp_min --- .../blocks/convert/ConvertLoops.java | 1620 ++++++++++++++--- .../imglib2/algorithm/blocks/ConvertLoops.vm | 90 +- 2 files changed, 1401 insertions(+), 309 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java index 5a4933d57..7ab9fbefe 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertLoops.java @@ -40,38 +40,47 @@ import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_i8; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i8; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i8_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i8_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i8_clamp_max; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_u8; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u8; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u8_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u8_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u8_clamp_max; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_i16; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i16; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i16_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i16_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i16_clamp_max; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_u16; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u16; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u16_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u16_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u16_clamp_max; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_i32; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i32; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i32_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i32_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i32_clamp_max; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_u32; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u32; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u32_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u32_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_u32_clamp_max; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_i64; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i64; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i64_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i64_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_i64_clamp_max; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_f32; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f32; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f32_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f32_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f32_clamp_max; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_f64; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f64; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f64_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f64_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_f64_clamp_max; /* @@ -81,280 +90,367 @@ class ConvertLoops { - static < I, O > ConvertLoop< I, O > get( UnaryOperatorType type ) - { - return get( type, ClampType.NONE ); - } - - static < I, O > ConvertLoop< I, O > get( UnaryOperatorType type, ClampType clampType ) - { - switch ( clampType ) - { - case NONE: - switch( type ) - { - case I8_TO_I8: return Cast.unchecked( Convert_i8_to_i8.INSTANCE ); - case I8_TO_U8: return Cast.unchecked( Convert_i8_to_u8.INSTANCE ); - case I8_TO_I16: return Cast.unchecked( Convert_i8_to_i16.INSTANCE ); - case I8_TO_U16: return Cast.unchecked( Convert_i8_to_u16.INSTANCE ); - case I8_TO_I32: return Cast.unchecked( Convert_i8_to_i32.INSTANCE ); - case I8_TO_U32: return Cast.unchecked( Convert_i8_to_u32.INSTANCE ); - case I8_TO_I64: return Cast.unchecked( Convert_i8_to_i64.INSTANCE ); - case I8_TO_F32: return Cast.unchecked( Convert_i8_to_f32.INSTANCE ); - case I8_TO_F64: return Cast.unchecked( Convert_i8_to_f64.INSTANCE ); - case U8_TO_I8: return Cast.unchecked( Convert_u8_to_i8.INSTANCE ); - case U8_TO_U8: return Cast.unchecked( Convert_u8_to_u8.INSTANCE ); - case U8_TO_I16: return Cast.unchecked( Convert_u8_to_i16.INSTANCE ); - case U8_TO_U16: return Cast.unchecked( Convert_u8_to_u16.INSTANCE ); - case U8_TO_I32: return Cast.unchecked( Convert_u8_to_i32.INSTANCE ); - case U8_TO_U32: return Cast.unchecked( Convert_u8_to_u32.INSTANCE ); - case U8_TO_I64: return Cast.unchecked( Convert_u8_to_i64.INSTANCE ); - case U8_TO_F32: return Cast.unchecked( Convert_u8_to_f32.INSTANCE ); - case U8_TO_F64: return Cast.unchecked( Convert_u8_to_f64.INSTANCE ); - case I16_TO_I8: return Cast.unchecked( Convert_i16_to_i8.INSTANCE ); - case I16_TO_U8: return Cast.unchecked( Convert_i16_to_u8.INSTANCE ); - case I16_TO_I16: return Cast.unchecked( Convert_i16_to_i16.INSTANCE ); - case I16_TO_U16: return Cast.unchecked( Convert_i16_to_u16.INSTANCE ); - case I16_TO_I32: return Cast.unchecked( Convert_i16_to_i32.INSTANCE ); - case I16_TO_U32: return Cast.unchecked( Convert_i16_to_u32.INSTANCE ); - case I16_TO_I64: return Cast.unchecked( Convert_i16_to_i64.INSTANCE ); - case I16_TO_F32: return Cast.unchecked( Convert_i16_to_f32.INSTANCE ); - case I16_TO_F64: return Cast.unchecked( Convert_i16_to_f64.INSTANCE ); - case U16_TO_I8: return Cast.unchecked( Convert_u16_to_i8.INSTANCE ); - case U16_TO_U8: return Cast.unchecked( Convert_u16_to_u8.INSTANCE ); - case U16_TO_I16: return Cast.unchecked( Convert_u16_to_i16.INSTANCE ); - case U16_TO_U16: return Cast.unchecked( Convert_u16_to_u16.INSTANCE ); - case U16_TO_I32: return Cast.unchecked( Convert_u16_to_i32.INSTANCE ); - case U16_TO_U32: return Cast.unchecked( Convert_u16_to_u32.INSTANCE ); - case U16_TO_I64: return Cast.unchecked( Convert_u16_to_i64.INSTANCE ); - case U16_TO_F32: return Cast.unchecked( Convert_u16_to_f32.INSTANCE ); - case U16_TO_F64: return Cast.unchecked( Convert_u16_to_f64.INSTANCE ); - case I32_TO_I8: return Cast.unchecked( Convert_i32_to_i8.INSTANCE ); - case I32_TO_U8: return Cast.unchecked( Convert_i32_to_u8.INSTANCE ); - case I32_TO_I16: return Cast.unchecked( Convert_i32_to_i16.INSTANCE ); - case I32_TO_U16: return Cast.unchecked( Convert_i32_to_u16.INSTANCE ); - case I32_TO_I32: return Cast.unchecked( Convert_i32_to_i32.INSTANCE ); - case I32_TO_U32: return Cast.unchecked( Convert_i32_to_u32.INSTANCE ); - case I32_TO_I64: return Cast.unchecked( Convert_i32_to_i64.INSTANCE ); - case I32_TO_F32: return Cast.unchecked( Convert_i32_to_f32.INSTANCE ); - case I32_TO_F64: return Cast.unchecked( Convert_i32_to_f64.INSTANCE ); - case U32_TO_I8: return Cast.unchecked( Convert_u32_to_i8.INSTANCE ); - case U32_TO_U8: return Cast.unchecked( Convert_u32_to_u8.INSTANCE ); - case U32_TO_I16: return Cast.unchecked( Convert_u32_to_i16.INSTANCE ); - case U32_TO_U16: return Cast.unchecked( Convert_u32_to_u16.INSTANCE ); - case U32_TO_I32: return Cast.unchecked( Convert_u32_to_i32.INSTANCE ); - case U32_TO_U32: return Cast.unchecked( Convert_u32_to_u32.INSTANCE ); - case U32_TO_I64: return Cast.unchecked( Convert_u32_to_i64.INSTANCE ); - case U32_TO_F32: return Cast.unchecked( Convert_u32_to_f32.INSTANCE ); - case U32_TO_F64: return Cast.unchecked( Convert_u32_to_f64.INSTANCE ); - case I64_TO_I8: return Cast.unchecked( Convert_i64_to_i8.INSTANCE ); - case I64_TO_U8: return Cast.unchecked( Convert_i64_to_u8.INSTANCE ); - case I64_TO_I16: return Cast.unchecked( Convert_i64_to_i16.INSTANCE ); - case I64_TO_U16: return Cast.unchecked( Convert_i64_to_u16.INSTANCE ); - case I64_TO_I32: return Cast.unchecked( Convert_i64_to_i32.INSTANCE ); - case I64_TO_U32: return Cast.unchecked( Convert_i64_to_u32.INSTANCE ); - case I64_TO_I64: return Cast.unchecked( Convert_i64_to_i64.INSTANCE ); - case I64_TO_F32: return Cast.unchecked( Convert_i64_to_f32.INSTANCE ); - case I64_TO_F64: return Cast.unchecked( Convert_i64_to_f64.INSTANCE ); - case F32_TO_I8: return Cast.unchecked( Convert_f32_to_i8.INSTANCE ); - case F32_TO_U8: return Cast.unchecked( Convert_f32_to_u8.INSTANCE ); - case F32_TO_I16: return Cast.unchecked( Convert_f32_to_i16.INSTANCE ); - case F32_TO_U16: return Cast.unchecked( Convert_f32_to_u16.INSTANCE ); - case F32_TO_I32: return Cast.unchecked( Convert_f32_to_i32.INSTANCE ); - case F32_TO_U32: return Cast.unchecked( Convert_f32_to_u32.INSTANCE ); - case F32_TO_I64: return Cast.unchecked( Convert_f32_to_i64.INSTANCE ); - case F32_TO_F32: return Cast.unchecked( Convert_f32_to_f32.INSTANCE ); - case F32_TO_F64: return Cast.unchecked( Convert_f32_to_f64.INSTANCE ); - case F64_TO_I8: return Cast.unchecked( Convert_f64_to_i8.INSTANCE ); - case F64_TO_U8: return Cast.unchecked( Convert_f64_to_u8.INSTANCE ); - case F64_TO_I16: return Cast.unchecked( Convert_f64_to_i16.INSTANCE ); - case F64_TO_U16: return Cast.unchecked( Convert_f64_to_u16.INSTANCE ); - case F64_TO_I32: return Cast.unchecked( Convert_f64_to_i32.INSTANCE ); - case F64_TO_U32: return Cast.unchecked( Convert_f64_to_u32.INSTANCE ); - case F64_TO_I64: return Cast.unchecked( Convert_f64_to_i64.INSTANCE ); - case F64_TO_F32: return Cast.unchecked( Convert_f64_to_f32.INSTANCE ); - case F64_TO_F64: return Cast.unchecked( Convert_f64_to_f64.INSTANCE ); - default: - throw new IllegalArgumentException(); - } - case CLAMP: - switch( type ) - { - case I8_TO_I8: return Cast.unchecked( Convert_i8_to_i8_clamp.INSTANCE ); - case I8_TO_U8: return Cast.unchecked( Convert_i8_to_u8_clamp.INSTANCE ); - case I8_TO_I16: return Cast.unchecked( Convert_i8_to_i16_clamp.INSTANCE ); - case I8_TO_U16: return Cast.unchecked( Convert_i8_to_u16_clamp.INSTANCE ); - case I8_TO_I32: return Cast.unchecked( Convert_i8_to_i32_clamp.INSTANCE ); - case I8_TO_U32: return Cast.unchecked( Convert_i8_to_u32_clamp.INSTANCE ); - case I8_TO_I64: return Cast.unchecked( Convert_i8_to_i64_clamp.INSTANCE ); - case I8_TO_F32: return Cast.unchecked( Convert_i8_to_f32_clamp.INSTANCE ); - case I8_TO_F64: return Cast.unchecked( Convert_i8_to_f64_clamp.INSTANCE ); - case U8_TO_I8: return Cast.unchecked( Convert_u8_to_i8_clamp.INSTANCE ); - case U8_TO_U8: return Cast.unchecked( Convert_u8_to_u8_clamp.INSTANCE ); - case U8_TO_I16: return Cast.unchecked( Convert_u8_to_i16_clamp.INSTANCE ); - case U8_TO_U16: return Cast.unchecked( Convert_u8_to_u16_clamp.INSTANCE ); - case U8_TO_I32: return Cast.unchecked( Convert_u8_to_i32_clamp.INSTANCE ); - case U8_TO_U32: return Cast.unchecked( Convert_u8_to_u32_clamp.INSTANCE ); - case U8_TO_I64: return Cast.unchecked( Convert_u8_to_i64_clamp.INSTANCE ); - case U8_TO_F32: return Cast.unchecked( Convert_u8_to_f32_clamp.INSTANCE ); - case U8_TO_F64: return Cast.unchecked( Convert_u8_to_f64_clamp.INSTANCE ); - case I16_TO_I8: return Cast.unchecked( Convert_i16_to_i8_clamp.INSTANCE ); - case I16_TO_U8: return Cast.unchecked( Convert_i16_to_u8_clamp.INSTANCE ); - case I16_TO_I16: return Cast.unchecked( Convert_i16_to_i16_clamp.INSTANCE ); - case I16_TO_U16: return Cast.unchecked( Convert_i16_to_u16_clamp.INSTANCE ); - case I16_TO_I32: return Cast.unchecked( Convert_i16_to_i32_clamp.INSTANCE ); - case I16_TO_U32: return Cast.unchecked( Convert_i16_to_u32_clamp.INSTANCE ); - case I16_TO_I64: return Cast.unchecked( Convert_i16_to_i64_clamp.INSTANCE ); - case I16_TO_F32: return Cast.unchecked( Convert_i16_to_f32_clamp.INSTANCE ); - case I16_TO_F64: return Cast.unchecked( Convert_i16_to_f64_clamp.INSTANCE ); - case U16_TO_I8: return Cast.unchecked( Convert_u16_to_i8_clamp.INSTANCE ); - case U16_TO_U8: return Cast.unchecked( Convert_u16_to_u8_clamp.INSTANCE ); - case U16_TO_I16: return Cast.unchecked( Convert_u16_to_i16_clamp.INSTANCE ); - case U16_TO_U16: return Cast.unchecked( Convert_u16_to_u16_clamp.INSTANCE ); - case U16_TO_I32: return Cast.unchecked( Convert_u16_to_i32_clamp.INSTANCE ); - case U16_TO_U32: return Cast.unchecked( Convert_u16_to_u32_clamp.INSTANCE ); - case U16_TO_I64: return Cast.unchecked( Convert_u16_to_i64_clamp.INSTANCE ); - case U16_TO_F32: return Cast.unchecked( Convert_u16_to_f32_clamp.INSTANCE ); - case U16_TO_F64: return Cast.unchecked( Convert_u16_to_f64_clamp.INSTANCE ); - case I32_TO_I8: return Cast.unchecked( Convert_i32_to_i8_clamp.INSTANCE ); - case I32_TO_U8: return Cast.unchecked( Convert_i32_to_u8_clamp.INSTANCE ); - case I32_TO_I16: return Cast.unchecked( Convert_i32_to_i16_clamp.INSTANCE ); - case I32_TO_U16: return Cast.unchecked( Convert_i32_to_u16_clamp.INSTANCE ); - case I32_TO_I32: return Cast.unchecked( Convert_i32_to_i32_clamp.INSTANCE ); - case I32_TO_U32: return Cast.unchecked( Convert_i32_to_u32_clamp.INSTANCE ); - case I32_TO_I64: return Cast.unchecked( Convert_i32_to_i64_clamp.INSTANCE ); - case I32_TO_F32: return Cast.unchecked( Convert_i32_to_f32_clamp.INSTANCE ); - case I32_TO_F64: return Cast.unchecked( Convert_i32_to_f64_clamp.INSTANCE ); - case U32_TO_I8: return Cast.unchecked( Convert_u32_to_i8_clamp.INSTANCE ); - case U32_TO_U8: return Cast.unchecked( Convert_u32_to_u8_clamp.INSTANCE ); - case U32_TO_I16: return Cast.unchecked( Convert_u32_to_i16_clamp.INSTANCE ); - case U32_TO_U16: return Cast.unchecked( Convert_u32_to_u16_clamp.INSTANCE ); - case U32_TO_I32: return Cast.unchecked( Convert_u32_to_i32_clamp.INSTANCE ); - case U32_TO_U32: return Cast.unchecked( Convert_u32_to_u32_clamp.INSTANCE ); - case U32_TO_I64: return Cast.unchecked( Convert_u32_to_i64_clamp.INSTANCE ); - case U32_TO_F32: return Cast.unchecked( Convert_u32_to_f32_clamp.INSTANCE ); - case U32_TO_F64: return Cast.unchecked( Convert_u32_to_f64_clamp.INSTANCE ); - case I64_TO_I8: return Cast.unchecked( Convert_i64_to_i8_clamp.INSTANCE ); - case I64_TO_U8: return Cast.unchecked( Convert_i64_to_u8_clamp.INSTANCE ); - case I64_TO_I16: return Cast.unchecked( Convert_i64_to_i16_clamp.INSTANCE ); - case I64_TO_U16: return Cast.unchecked( Convert_i64_to_u16_clamp.INSTANCE ); - case I64_TO_I32: return Cast.unchecked( Convert_i64_to_i32_clamp.INSTANCE ); - case I64_TO_U32: return Cast.unchecked( Convert_i64_to_u32_clamp.INSTANCE ); - case I64_TO_I64: return Cast.unchecked( Convert_i64_to_i64_clamp.INSTANCE ); - case I64_TO_F32: return Cast.unchecked( Convert_i64_to_f32_clamp.INSTANCE ); - case I64_TO_F64: return Cast.unchecked( Convert_i64_to_f64_clamp.INSTANCE ); - case F32_TO_I8: return Cast.unchecked( Convert_f32_to_i8_clamp.INSTANCE ); - case F32_TO_U8: return Cast.unchecked( Convert_f32_to_u8_clamp.INSTANCE ); - case F32_TO_I16: return Cast.unchecked( Convert_f32_to_i16_clamp.INSTANCE ); - case F32_TO_U16: return Cast.unchecked( Convert_f32_to_u16_clamp.INSTANCE ); - case F32_TO_I32: return Cast.unchecked( Convert_f32_to_i32_clamp.INSTANCE ); - case F32_TO_U32: return Cast.unchecked( Convert_f32_to_u32_clamp.INSTANCE ); - case F32_TO_I64: return Cast.unchecked( Convert_f32_to_i64_clamp.INSTANCE ); - case F32_TO_F32: return Cast.unchecked( Convert_f32_to_f32_clamp.INSTANCE ); - case F32_TO_F64: return Cast.unchecked( Convert_f32_to_f64_clamp.INSTANCE ); - case F64_TO_I8: return Cast.unchecked( Convert_f64_to_i8_clamp.INSTANCE ); - case F64_TO_U8: return Cast.unchecked( Convert_f64_to_u8_clamp.INSTANCE ); - case F64_TO_I16: return Cast.unchecked( Convert_f64_to_i16_clamp.INSTANCE ); - case F64_TO_U16: return Cast.unchecked( Convert_f64_to_u16_clamp.INSTANCE ); - case F64_TO_I32: return Cast.unchecked( Convert_f64_to_i32_clamp.INSTANCE ); - case F64_TO_U32: return Cast.unchecked( Convert_f64_to_u32_clamp.INSTANCE ); - case F64_TO_I64: return Cast.unchecked( Convert_f64_to_i64_clamp.INSTANCE ); - case F64_TO_F32: return Cast.unchecked( Convert_f64_to_f32_clamp.INSTANCE ); - case F64_TO_F64: return Cast.unchecked( Convert_f64_to_f64_clamp.INSTANCE ); - default: - throw new IllegalArgumentException(); - } - case CLAMP_MAX: - switch( type ) - { - case I8_TO_I8: return Cast.unchecked( Convert_i8_to_i8_clamp_max.INSTANCE ); - case I8_TO_U8: return Cast.unchecked( Convert_i8_to_u8_clamp_max.INSTANCE ); - case I8_TO_I16: return Cast.unchecked( Convert_i8_to_i16_clamp_max.INSTANCE ); - case I8_TO_U16: return Cast.unchecked( Convert_i8_to_u16_clamp_max.INSTANCE ); - case I8_TO_I32: return Cast.unchecked( Convert_i8_to_i32_clamp_max.INSTANCE ); - case I8_TO_U32: return Cast.unchecked( Convert_i8_to_u32_clamp_max.INSTANCE ); - case I8_TO_I64: return Cast.unchecked( Convert_i8_to_i64_clamp_max.INSTANCE ); - case I8_TO_F32: return Cast.unchecked( Convert_i8_to_f32_clamp_max.INSTANCE ); - case I8_TO_F64: return Cast.unchecked( Convert_i8_to_f64_clamp_max.INSTANCE ); - case U8_TO_I8: return Cast.unchecked( Convert_u8_to_i8_clamp_max.INSTANCE ); - case U8_TO_U8: return Cast.unchecked( Convert_u8_to_u8_clamp_max.INSTANCE ); - case U8_TO_I16: return Cast.unchecked( Convert_u8_to_i16_clamp_max.INSTANCE ); - case U8_TO_U16: return Cast.unchecked( Convert_u8_to_u16_clamp_max.INSTANCE ); - case U8_TO_I32: return Cast.unchecked( Convert_u8_to_i32_clamp_max.INSTANCE ); - case U8_TO_U32: return Cast.unchecked( Convert_u8_to_u32_clamp_max.INSTANCE ); - case U8_TO_I64: return Cast.unchecked( Convert_u8_to_i64_clamp_max.INSTANCE ); - case U8_TO_F32: return Cast.unchecked( Convert_u8_to_f32_clamp_max.INSTANCE ); - case U8_TO_F64: return Cast.unchecked( Convert_u8_to_f64_clamp_max.INSTANCE ); - case I16_TO_I8: return Cast.unchecked( Convert_i16_to_i8_clamp_max.INSTANCE ); - case I16_TO_U8: return Cast.unchecked( Convert_i16_to_u8_clamp_max.INSTANCE ); - case I16_TO_I16: return Cast.unchecked( Convert_i16_to_i16_clamp_max.INSTANCE ); - case I16_TO_U16: return Cast.unchecked( Convert_i16_to_u16_clamp_max.INSTANCE ); - case I16_TO_I32: return Cast.unchecked( Convert_i16_to_i32_clamp_max.INSTANCE ); - case I16_TO_U32: return Cast.unchecked( Convert_i16_to_u32_clamp_max.INSTANCE ); - case I16_TO_I64: return Cast.unchecked( Convert_i16_to_i64_clamp_max.INSTANCE ); - case I16_TO_F32: return Cast.unchecked( Convert_i16_to_f32_clamp_max.INSTANCE ); - case I16_TO_F64: return Cast.unchecked( Convert_i16_to_f64_clamp_max.INSTANCE ); - case U16_TO_I8: return Cast.unchecked( Convert_u16_to_i8_clamp_max.INSTANCE ); - case U16_TO_U8: return Cast.unchecked( Convert_u16_to_u8_clamp_max.INSTANCE ); - case U16_TO_I16: return Cast.unchecked( Convert_u16_to_i16_clamp_max.INSTANCE ); - case U16_TO_U16: return Cast.unchecked( Convert_u16_to_u16_clamp_max.INSTANCE ); - case U16_TO_I32: return Cast.unchecked( Convert_u16_to_i32_clamp_max.INSTANCE ); - case U16_TO_U32: return Cast.unchecked( Convert_u16_to_u32_clamp_max.INSTANCE ); - case U16_TO_I64: return Cast.unchecked( Convert_u16_to_i64_clamp_max.INSTANCE ); - case U16_TO_F32: return Cast.unchecked( Convert_u16_to_f32_clamp_max.INSTANCE ); - case U16_TO_F64: return Cast.unchecked( Convert_u16_to_f64_clamp_max.INSTANCE ); - case I32_TO_I8: return Cast.unchecked( Convert_i32_to_i8_clamp_max.INSTANCE ); - case I32_TO_U8: return Cast.unchecked( Convert_i32_to_u8_clamp_max.INSTANCE ); - case I32_TO_I16: return Cast.unchecked( Convert_i32_to_i16_clamp_max.INSTANCE ); - case I32_TO_U16: return Cast.unchecked( Convert_i32_to_u16_clamp_max.INSTANCE ); - case I32_TO_I32: return Cast.unchecked( Convert_i32_to_i32_clamp_max.INSTANCE ); - case I32_TO_U32: return Cast.unchecked( Convert_i32_to_u32_clamp_max.INSTANCE ); - case I32_TO_I64: return Cast.unchecked( Convert_i32_to_i64_clamp_max.INSTANCE ); - case I32_TO_F32: return Cast.unchecked( Convert_i32_to_f32_clamp_max.INSTANCE ); - case I32_TO_F64: return Cast.unchecked( Convert_i32_to_f64_clamp_max.INSTANCE ); - case U32_TO_I8: return Cast.unchecked( Convert_u32_to_i8_clamp_max.INSTANCE ); - case U32_TO_U8: return Cast.unchecked( Convert_u32_to_u8_clamp_max.INSTANCE ); - case U32_TO_I16: return Cast.unchecked( Convert_u32_to_i16_clamp_max.INSTANCE ); - case U32_TO_U16: return Cast.unchecked( Convert_u32_to_u16_clamp_max.INSTANCE ); - case U32_TO_I32: return Cast.unchecked( Convert_u32_to_i32_clamp_max.INSTANCE ); - case U32_TO_U32: return Cast.unchecked( Convert_u32_to_u32_clamp_max.INSTANCE ); - case U32_TO_I64: return Cast.unchecked( Convert_u32_to_i64_clamp_max.INSTANCE ); - case U32_TO_F32: return Cast.unchecked( Convert_u32_to_f32_clamp_max.INSTANCE ); - case U32_TO_F64: return Cast.unchecked( Convert_u32_to_f64_clamp_max.INSTANCE ); - case I64_TO_I8: return Cast.unchecked( Convert_i64_to_i8_clamp_max.INSTANCE ); - case I64_TO_U8: return Cast.unchecked( Convert_i64_to_u8_clamp_max.INSTANCE ); - case I64_TO_I16: return Cast.unchecked( Convert_i64_to_i16_clamp_max.INSTANCE ); - case I64_TO_U16: return Cast.unchecked( Convert_i64_to_u16_clamp_max.INSTANCE ); - case I64_TO_I32: return Cast.unchecked( Convert_i64_to_i32_clamp_max.INSTANCE ); - case I64_TO_U32: return Cast.unchecked( Convert_i64_to_u32_clamp_max.INSTANCE ); - case I64_TO_I64: return Cast.unchecked( Convert_i64_to_i64_clamp_max.INSTANCE ); - case I64_TO_F32: return Cast.unchecked( Convert_i64_to_f32_clamp_max.INSTANCE ); - case I64_TO_F64: return Cast.unchecked( Convert_i64_to_f64_clamp_max.INSTANCE ); - case F32_TO_I8: return Cast.unchecked( Convert_f32_to_i8_clamp_max.INSTANCE ); - case F32_TO_U8: return Cast.unchecked( Convert_f32_to_u8_clamp_max.INSTANCE ); - case F32_TO_I16: return Cast.unchecked( Convert_f32_to_i16_clamp_max.INSTANCE ); - case F32_TO_U16: return Cast.unchecked( Convert_f32_to_u16_clamp_max.INSTANCE ); - case F32_TO_I32: return Cast.unchecked( Convert_f32_to_i32_clamp_max.INSTANCE ); - case F32_TO_U32: return Cast.unchecked( Convert_f32_to_u32_clamp_max.INSTANCE ); - case F32_TO_I64: return Cast.unchecked( Convert_f32_to_i64_clamp_max.INSTANCE ); - case F32_TO_F32: return Cast.unchecked( Convert_f32_to_f32_clamp_max.INSTANCE ); - case F32_TO_F64: return Cast.unchecked( Convert_f32_to_f64_clamp_max.INSTANCE ); - case F64_TO_I8: return Cast.unchecked( Convert_f64_to_i8_clamp_max.INSTANCE ); - case F64_TO_U8: return Cast.unchecked( Convert_f64_to_u8_clamp_max.INSTANCE ); - case F64_TO_I16: return Cast.unchecked( Convert_f64_to_i16_clamp_max.INSTANCE ); - case F64_TO_U16: return Cast.unchecked( Convert_f64_to_u16_clamp_max.INSTANCE ); - case F64_TO_I32: return Cast.unchecked( Convert_f64_to_i32_clamp_max.INSTANCE ); - case F64_TO_U32: return Cast.unchecked( Convert_f64_to_u32_clamp_max.INSTANCE ); - case F64_TO_I64: return Cast.unchecked( Convert_f64_to_i64_clamp_max.INSTANCE ); - case F64_TO_F32: return Cast.unchecked( Convert_f64_to_f32_clamp_max.INSTANCE ); - case F64_TO_F64: return Cast.unchecked( Convert_f64_to_f64_clamp_max.INSTANCE ); - default: - throw new IllegalArgumentException(); - } - default: - throw new IllegalArgumentException(); - } - } + static < I, O > ConvertLoop< I, O > get( UnaryOperatorType type ) + { + return get( type, ClampType.NONE ); + } + + static < I, O > ConvertLoop< I, O > get( UnaryOperatorType type, ClampType clampType ) + { + switch ( clampType ) + { + case NONE: + switch( type ) + { + case I8_TO_I8: return Cast.unchecked( Convert_i8_to_i8.INSTANCE ); + case I8_TO_U8: return Cast.unchecked( Convert_i8_to_u8.INSTANCE ); + case I8_TO_I16: return Cast.unchecked( Convert_i8_to_i16.INSTANCE ); + case I8_TO_U16: return Cast.unchecked( Convert_i8_to_u16.INSTANCE ); + case I8_TO_I32: return Cast.unchecked( Convert_i8_to_i32.INSTANCE ); + case I8_TO_U32: return Cast.unchecked( Convert_i8_to_u32.INSTANCE ); + case I8_TO_I64: return Cast.unchecked( Convert_i8_to_i64.INSTANCE ); + case I8_TO_F32: return Cast.unchecked( Convert_i8_to_f32.INSTANCE ); + case I8_TO_F64: return Cast.unchecked( Convert_i8_to_f64.INSTANCE ); + case U8_TO_I8: return Cast.unchecked( Convert_u8_to_i8.INSTANCE ); + case U8_TO_U8: return Cast.unchecked( Convert_u8_to_u8.INSTANCE ); + case U8_TO_I16: return Cast.unchecked( Convert_u8_to_i16.INSTANCE ); + case U8_TO_U16: return Cast.unchecked( Convert_u8_to_u16.INSTANCE ); + case U8_TO_I32: return Cast.unchecked( Convert_u8_to_i32.INSTANCE ); + case U8_TO_U32: return Cast.unchecked( Convert_u8_to_u32.INSTANCE ); + case U8_TO_I64: return Cast.unchecked( Convert_u8_to_i64.INSTANCE ); + case U8_TO_F32: return Cast.unchecked( Convert_u8_to_f32.INSTANCE ); + case U8_TO_F64: return Cast.unchecked( Convert_u8_to_f64.INSTANCE ); + case I16_TO_I8: return Cast.unchecked( Convert_i16_to_i8.INSTANCE ); + case I16_TO_U8: return Cast.unchecked( Convert_i16_to_u8.INSTANCE ); + case I16_TO_I16: return Cast.unchecked( Convert_i16_to_i16.INSTANCE ); + case I16_TO_U16: return Cast.unchecked( Convert_i16_to_u16.INSTANCE ); + case I16_TO_I32: return Cast.unchecked( Convert_i16_to_i32.INSTANCE ); + case I16_TO_U32: return Cast.unchecked( Convert_i16_to_u32.INSTANCE ); + case I16_TO_I64: return Cast.unchecked( Convert_i16_to_i64.INSTANCE ); + case I16_TO_F32: return Cast.unchecked( Convert_i16_to_f32.INSTANCE ); + case I16_TO_F64: return Cast.unchecked( Convert_i16_to_f64.INSTANCE ); + case U16_TO_I8: return Cast.unchecked( Convert_u16_to_i8.INSTANCE ); + case U16_TO_U8: return Cast.unchecked( Convert_u16_to_u8.INSTANCE ); + case U16_TO_I16: return Cast.unchecked( Convert_u16_to_i16.INSTANCE ); + case U16_TO_U16: return Cast.unchecked( Convert_u16_to_u16.INSTANCE ); + case U16_TO_I32: return Cast.unchecked( Convert_u16_to_i32.INSTANCE ); + case U16_TO_U32: return Cast.unchecked( Convert_u16_to_u32.INSTANCE ); + case U16_TO_I64: return Cast.unchecked( Convert_u16_to_i64.INSTANCE ); + case U16_TO_F32: return Cast.unchecked( Convert_u16_to_f32.INSTANCE ); + case U16_TO_F64: return Cast.unchecked( Convert_u16_to_f64.INSTANCE ); + case I32_TO_I8: return Cast.unchecked( Convert_i32_to_i8.INSTANCE ); + case I32_TO_U8: return Cast.unchecked( Convert_i32_to_u8.INSTANCE ); + case I32_TO_I16: return Cast.unchecked( Convert_i32_to_i16.INSTANCE ); + case I32_TO_U16: return Cast.unchecked( Convert_i32_to_u16.INSTANCE ); + case I32_TO_I32: return Cast.unchecked( Convert_i32_to_i32.INSTANCE ); + case I32_TO_U32: return Cast.unchecked( Convert_i32_to_u32.INSTANCE ); + case I32_TO_I64: return Cast.unchecked( Convert_i32_to_i64.INSTANCE ); + case I32_TO_F32: return Cast.unchecked( Convert_i32_to_f32.INSTANCE ); + case I32_TO_F64: return Cast.unchecked( Convert_i32_to_f64.INSTANCE ); + case U32_TO_I8: return Cast.unchecked( Convert_u32_to_i8.INSTANCE ); + case U32_TO_U8: return Cast.unchecked( Convert_u32_to_u8.INSTANCE ); + case U32_TO_I16: return Cast.unchecked( Convert_u32_to_i16.INSTANCE ); + case U32_TO_U16: return Cast.unchecked( Convert_u32_to_u16.INSTANCE ); + case U32_TO_I32: return Cast.unchecked( Convert_u32_to_i32.INSTANCE ); + case U32_TO_U32: return Cast.unchecked( Convert_u32_to_u32.INSTANCE ); + case U32_TO_I64: return Cast.unchecked( Convert_u32_to_i64.INSTANCE ); + case U32_TO_F32: return Cast.unchecked( Convert_u32_to_f32.INSTANCE ); + case U32_TO_F64: return Cast.unchecked( Convert_u32_to_f64.INSTANCE ); + case I64_TO_I8: return Cast.unchecked( Convert_i64_to_i8.INSTANCE ); + case I64_TO_U8: return Cast.unchecked( Convert_i64_to_u8.INSTANCE ); + case I64_TO_I16: return Cast.unchecked( Convert_i64_to_i16.INSTANCE ); + case I64_TO_U16: return Cast.unchecked( Convert_i64_to_u16.INSTANCE ); + case I64_TO_I32: return Cast.unchecked( Convert_i64_to_i32.INSTANCE ); + case I64_TO_U32: return Cast.unchecked( Convert_i64_to_u32.INSTANCE ); + case I64_TO_I64: return Cast.unchecked( Convert_i64_to_i64.INSTANCE ); + case I64_TO_F32: return Cast.unchecked( Convert_i64_to_f32.INSTANCE ); + case I64_TO_F64: return Cast.unchecked( Convert_i64_to_f64.INSTANCE ); + case F32_TO_I8: return Cast.unchecked( Convert_f32_to_i8.INSTANCE ); + case F32_TO_U8: return Cast.unchecked( Convert_f32_to_u8.INSTANCE ); + case F32_TO_I16: return Cast.unchecked( Convert_f32_to_i16.INSTANCE ); + case F32_TO_U16: return Cast.unchecked( Convert_f32_to_u16.INSTANCE ); + case F32_TO_I32: return Cast.unchecked( Convert_f32_to_i32.INSTANCE ); + case F32_TO_U32: return Cast.unchecked( Convert_f32_to_u32.INSTANCE ); + case F32_TO_I64: return Cast.unchecked( Convert_f32_to_i64.INSTANCE ); + case F32_TO_F32: return Cast.unchecked( Convert_f32_to_f32.INSTANCE ); + case F32_TO_F64: return Cast.unchecked( Convert_f32_to_f64.INSTANCE ); + case F64_TO_I8: return Cast.unchecked( Convert_f64_to_i8.INSTANCE ); + case F64_TO_U8: return Cast.unchecked( Convert_f64_to_u8.INSTANCE ); + case F64_TO_I16: return Cast.unchecked( Convert_f64_to_i16.INSTANCE ); + case F64_TO_U16: return Cast.unchecked( Convert_f64_to_u16.INSTANCE ); + case F64_TO_I32: return Cast.unchecked( Convert_f64_to_i32.INSTANCE ); + case F64_TO_U32: return Cast.unchecked( Convert_f64_to_u32.INSTANCE ); + case F64_TO_I64: return Cast.unchecked( Convert_f64_to_i64.INSTANCE ); + case F64_TO_F32: return Cast.unchecked( Convert_f64_to_f32.INSTANCE ); + case F64_TO_F64: return Cast.unchecked( Convert_f64_to_f64.INSTANCE ); + default: + throw new IllegalArgumentException(); + } + case CLAMP: + switch( type ) + { + case I8_TO_I8: return Cast.unchecked( Convert_i8_to_i8_clamp.INSTANCE ); + case I8_TO_U8: return Cast.unchecked( Convert_i8_to_u8_clamp.INSTANCE ); + case I8_TO_I16: return Cast.unchecked( Convert_i8_to_i16_clamp.INSTANCE ); + case I8_TO_U16: return Cast.unchecked( Convert_i8_to_u16_clamp.INSTANCE ); + case I8_TO_I32: return Cast.unchecked( Convert_i8_to_i32_clamp.INSTANCE ); + case I8_TO_U32: return Cast.unchecked( Convert_i8_to_u32_clamp.INSTANCE ); + case I8_TO_I64: return Cast.unchecked( Convert_i8_to_i64_clamp.INSTANCE ); + case I8_TO_F32: return Cast.unchecked( Convert_i8_to_f32_clamp.INSTANCE ); + case I8_TO_F64: return Cast.unchecked( Convert_i8_to_f64_clamp.INSTANCE ); + case U8_TO_I8: return Cast.unchecked( Convert_u8_to_i8_clamp.INSTANCE ); + case U8_TO_U8: return Cast.unchecked( Convert_u8_to_u8_clamp.INSTANCE ); + case U8_TO_I16: return Cast.unchecked( Convert_u8_to_i16_clamp.INSTANCE ); + case U8_TO_U16: return Cast.unchecked( Convert_u8_to_u16_clamp.INSTANCE ); + case U8_TO_I32: return Cast.unchecked( Convert_u8_to_i32_clamp.INSTANCE ); + case U8_TO_U32: return Cast.unchecked( Convert_u8_to_u32_clamp.INSTANCE ); + case U8_TO_I64: return Cast.unchecked( Convert_u8_to_i64_clamp.INSTANCE ); + case U8_TO_F32: return Cast.unchecked( Convert_u8_to_f32_clamp.INSTANCE ); + case U8_TO_F64: return Cast.unchecked( Convert_u8_to_f64_clamp.INSTANCE ); + case I16_TO_I8: return Cast.unchecked( Convert_i16_to_i8_clamp.INSTANCE ); + case I16_TO_U8: return Cast.unchecked( Convert_i16_to_u8_clamp.INSTANCE ); + case I16_TO_I16: return Cast.unchecked( Convert_i16_to_i16_clamp.INSTANCE ); + case I16_TO_U16: return Cast.unchecked( Convert_i16_to_u16_clamp.INSTANCE ); + case I16_TO_I32: return Cast.unchecked( Convert_i16_to_i32_clamp.INSTANCE ); + case I16_TO_U32: return Cast.unchecked( Convert_i16_to_u32_clamp.INSTANCE ); + case I16_TO_I64: return Cast.unchecked( Convert_i16_to_i64_clamp.INSTANCE ); + case I16_TO_F32: return Cast.unchecked( Convert_i16_to_f32_clamp.INSTANCE ); + case I16_TO_F64: return Cast.unchecked( Convert_i16_to_f64_clamp.INSTANCE ); + case U16_TO_I8: return Cast.unchecked( Convert_u16_to_i8_clamp.INSTANCE ); + case U16_TO_U8: return Cast.unchecked( Convert_u16_to_u8_clamp.INSTANCE ); + case U16_TO_I16: return Cast.unchecked( Convert_u16_to_i16_clamp.INSTANCE ); + case U16_TO_U16: return Cast.unchecked( Convert_u16_to_u16_clamp.INSTANCE ); + case U16_TO_I32: return Cast.unchecked( Convert_u16_to_i32_clamp.INSTANCE ); + case U16_TO_U32: return Cast.unchecked( Convert_u16_to_u32_clamp.INSTANCE ); + case U16_TO_I64: return Cast.unchecked( Convert_u16_to_i64_clamp.INSTANCE ); + case U16_TO_F32: return Cast.unchecked( Convert_u16_to_f32_clamp.INSTANCE ); + case U16_TO_F64: return Cast.unchecked( Convert_u16_to_f64_clamp.INSTANCE ); + case I32_TO_I8: return Cast.unchecked( Convert_i32_to_i8_clamp.INSTANCE ); + case I32_TO_U8: return Cast.unchecked( Convert_i32_to_u8_clamp.INSTANCE ); + case I32_TO_I16: return Cast.unchecked( Convert_i32_to_i16_clamp.INSTANCE ); + case I32_TO_U16: return Cast.unchecked( Convert_i32_to_u16_clamp.INSTANCE ); + case I32_TO_I32: return Cast.unchecked( Convert_i32_to_i32_clamp.INSTANCE ); + case I32_TO_U32: return Cast.unchecked( Convert_i32_to_u32_clamp.INSTANCE ); + case I32_TO_I64: return Cast.unchecked( Convert_i32_to_i64_clamp.INSTANCE ); + case I32_TO_F32: return Cast.unchecked( Convert_i32_to_f32_clamp.INSTANCE ); + case I32_TO_F64: return Cast.unchecked( Convert_i32_to_f64_clamp.INSTANCE ); + case U32_TO_I8: return Cast.unchecked( Convert_u32_to_i8_clamp.INSTANCE ); + case U32_TO_U8: return Cast.unchecked( Convert_u32_to_u8_clamp.INSTANCE ); + case U32_TO_I16: return Cast.unchecked( Convert_u32_to_i16_clamp.INSTANCE ); + case U32_TO_U16: return Cast.unchecked( Convert_u32_to_u16_clamp.INSTANCE ); + case U32_TO_I32: return Cast.unchecked( Convert_u32_to_i32_clamp.INSTANCE ); + case U32_TO_U32: return Cast.unchecked( Convert_u32_to_u32_clamp.INSTANCE ); + case U32_TO_I64: return Cast.unchecked( Convert_u32_to_i64_clamp.INSTANCE ); + case U32_TO_F32: return Cast.unchecked( Convert_u32_to_f32_clamp.INSTANCE ); + case U32_TO_F64: return Cast.unchecked( Convert_u32_to_f64_clamp.INSTANCE ); + case I64_TO_I8: return Cast.unchecked( Convert_i64_to_i8_clamp.INSTANCE ); + case I64_TO_U8: return Cast.unchecked( Convert_i64_to_u8_clamp.INSTANCE ); + case I64_TO_I16: return Cast.unchecked( Convert_i64_to_i16_clamp.INSTANCE ); + case I64_TO_U16: return Cast.unchecked( Convert_i64_to_u16_clamp.INSTANCE ); + case I64_TO_I32: return Cast.unchecked( Convert_i64_to_i32_clamp.INSTANCE ); + case I64_TO_U32: return Cast.unchecked( Convert_i64_to_u32_clamp.INSTANCE ); + case I64_TO_I64: return Cast.unchecked( Convert_i64_to_i64_clamp.INSTANCE ); + case I64_TO_F32: return Cast.unchecked( Convert_i64_to_f32_clamp.INSTANCE ); + case I64_TO_F64: return Cast.unchecked( Convert_i64_to_f64_clamp.INSTANCE ); + case F32_TO_I8: return Cast.unchecked( Convert_f32_to_i8_clamp.INSTANCE ); + case F32_TO_U8: return Cast.unchecked( Convert_f32_to_u8_clamp.INSTANCE ); + case F32_TO_I16: return Cast.unchecked( Convert_f32_to_i16_clamp.INSTANCE ); + case F32_TO_U16: return Cast.unchecked( Convert_f32_to_u16_clamp.INSTANCE ); + case F32_TO_I32: return Cast.unchecked( Convert_f32_to_i32_clamp.INSTANCE ); + case F32_TO_U32: return Cast.unchecked( Convert_f32_to_u32_clamp.INSTANCE ); + case F32_TO_I64: return Cast.unchecked( Convert_f32_to_i64_clamp.INSTANCE ); + case F32_TO_F32: return Cast.unchecked( Convert_f32_to_f32_clamp.INSTANCE ); + case F32_TO_F64: return Cast.unchecked( Convert_f32_to_f64_clamp.INSTANCE ); + case F64_TO_I8: return Cast.unchecked( Convert_f64_to_i8_clamp.INSTANCE ); + case F64_TO_U8: return Cast.unchecked( Convert_f64_to_u8_clamp.INSTANCE ); + case F64_TO_I16: return Cast.unchecked( Convert_f64_to_i16_clamp.INSTANCE ); + case F64_TO_U16: return Cast.unchecked( Convert_f64_to_u16_clamp.INSTANCE ); + case F64_TO_I32: return Cast.unchecked( Convert_f64_to_i32_clamp.INSTANCE ); + case F64_TO_U32: return Cast.unchecked( Convert_f64_to_u32_clamp.INSTANCE ); + case F64_TO_I64: return Cast.unchecked( Convert_f64_to_i64_clamp.INSTANCE ); + case F64_TO_F32: return Cast.unchecked( Convert_f64_to_f32_clamp.INSTANCE ); + case F64_TO_F64: return Cast.unchecked( Convert_f64_to_f64_clamp.INSTANCE ); + default: + throw new IllegalArgumentException(); + } + case CLAMP_MIN: + switch( type ) + { + case I8_TO_I8: return Cast.unchecked( Convert_i8_to_i8_clamp_min.INSTANCE ); + case I8_TO_U8: return Cast.unchecked( Convert_i8_to_u8_clamp_min.INSTANCE ); + case I8_TO_I16: return Cast.unchecked( Convert_i8_to_i16_clamp_min.INSTANCE ); + case I8_TO_U16: return Cast.unchecked( Convert_i8_to_u16_clamp_min.INSTANCE ); + case I8_TO_I32: return Cast.unchecked( Convert_i8_to_i32_clamp_min.INSTANCE ); + case I8_TO_U32: return Cast.unchecked( Convert_i8_to_u32_clamp_min.INSTANCE ); + case I8_TO_I64: return Cast.unchecked( Convert_i8_to_i64_clamp_min.INSTANCE ); + case I8_TO_F32: return Cast.unchecked( Convert_i8_to_f32_clamp_min.INSTANCE ); + case I8_TO_F64: return Cast.unchecked( Convert_i8_to_f64_clamp_min.INSTANCE ); + case U8_TO_I8: return Cast.unchecked( Convert_u8_to_i8_clamp_min.INSTANCE ); + case U8_TO_U8: return Cast.unchecked( Convert_u8_to_u8_clamp_min.INSTANCE ); + case U8_TO_I16: return Cast.unchecked( Convert_u8_to_i16_clamp_min.INSTANCE ); + case U8_TO_U16: return Cast.unchecked( Convert_u8_to_u16_clamp_min.INSTANCE ); + case U8_TO_I32: return Cast.unchecked( Convert_u8_to_i32_clamp_min.INSTANCE ); + case U8_TO_U32: return Cast.unchecked( Convert_u8_to_u32_clamp_min.INSTANCE ); + case U8_TO_I64: return Cast.unchecked( Convert_u8_to_i64_clamp_min.INSTANCE ); + case U8_TO_F32: return Cast.unchecked( Convert_u8_to_f32_clamp_min.INSTANCE ); + case U8_TO_F64: return Cast.unchecked( Convert_u8_to_f64_clamp_min.INSTANCE ); + case I16_TO_I8: return Cast.unchecked( Convert_i16_to_i8_clamp_min.INSTANCE ); + case I16_TO_U8: return Cast.unchecked( Convert_i16_to_u8_clamp_min.INSTANCE ); + case I16_TO_I16: return Cast.unchecked( Convert_i16_to_i16_clamp_min.INSTANCE ); + case I16_TO_U16: return Cast.unchecked( Convert_i16_to_u16_clamp_min.INSTANCE ); + case I16_TO_I32: return Cast.unchecked( Convert_i16_to_i32_clamp_min.INSTANCE ); + case I16_TO_U32: return Cast.unchecked( Convert_i16_to_u32_clamp_min.INSTANCE ); + case I16_TO_I64: return Cast.unchecked( Convert_i16_to_i64_clamp_min.INSTANCE ); + case I16_TO_F32: return Cast.unchecked( Convert_i16_to_f32_clamp_min.INSTANCE ); + case I16_TO_F64: return Cast.unchecked( Convert_i16_to_f64_clamp_min.INSTANCE ); + case U16_TO_I8: return Cast.unchecked( Convert_u16_to_i8_clamp_min.INSTANCE ); + case U16_TO_U8: return Cast.unchecked( Convert_u16_to_u8_clamp_min.INSTANCE ); + case U16_TO_I16: return Cast.unchecked( Convert_u16_to_i16_clamp_min.INSTANCE ); + case U16_TO_U16: return Cast.unchecked( Convert_u16_to_u16_clamp_min.INSTANCE ); + case U16_TO_I32: return Cast.unchecked( Convert_u16_to_i32_clamp_min.INSTANCE ); + case U16_TO_U32: return Cast.unchecked( Convert_u16_to_u32_clamp_min.INSTANCE ); + case U16_TO_I64: return Cast.unchecked( Convert_u16_to_i64_clamp_min.INSTANCE ); + case U16_TO_F32: return Cast.unchecked( Convert_u16_to_f32_clamp_min.INSTANCE ); + case U16_TO_F64: return Cast.unchecked( Convert_u16_to_f64_clamp_min.INSTANCE ); + case I32_TO_I8: return Cast.unchecked( Convert_i32_to_i8_clamp_min.INSTANCE ); + case I32_TO_U8: return Cast.unchecked( Convert_i32_to_u8_clamp_min.INSTANCE ); + case I32_TO_I16: return Cast.unchecked( Convert_i32_to_i16_clamp_min.INSTANCE ); + case I32_TO_U16: return Cast.unchecked( Convert_i32_to_u16_clamp_min.INSTANCE ); + case I32_TO_I32: return Cast.unchecked( Convert_i32_to_i32_clamp_min.INSTANCE ); + case I32_TO_U32: return Cast.unchecked( Convert_i32_to_u32_clamp_min.INSTANCE ); + case I32_TO_I64: return Cast.unchecked( Convert_i32_to_i64_clamp_min.INSTANCE ); + case I32_TO_F32: return Cast.unchecked( Convert_i32_to_f32_clamp_min.INSTANCE ); + case I32_TO_F64: return Cast.unchecked( Convert_i32_to_f64_clamp_min.INSTANCE ); + case U32_TO_I8: return Cast.unchecked( Convert_u32_to_i8_clamp_min.INSTANCE ); + case U32_TO_U8: return Cast.unchecked( Convert_u32_to_u8_clamp_min.INSTANCE ); + case U32_TO_I16: return Cast.unchecked( Convert_u32_to_i16_clamp_min.INSTANCE ); + case U32_TO_U16: return Cast.unchecked( Convert_u32_to_u16_clamp_min.INSTANCE ); + case U32_TO_I32: return Cast.unchecked( Convert_u32_to_i32_clamp_min.INSTANCE ); + case U32_TO_U32: return Cast.unchecked( Convert_u32_to_u32_clamp_min.INSTANCE ); + case U32_TO_I64: return Cast.unchecked( Convert_u32_to_i64_clamp_min.INSTANCE ); + case U32_TO_F32: return Cast.unchecked( Convert_u32_to_f32_clamp_min.INSTANCE ); + case U32_TO_F64: return Cast.unchecked( Convert_u32_to_f64_clamp_min.INSTANCE ); + case I64_TO_I8: return Cast.unchecked( Convert_i64_to_i8_clamp_min.INSTANCE ); + case I64_TO_U8: return Cast.unchecked( Convert_i64_to_u8_clamp_min.INSTANCE ); + case I64_TO_I16: return Cast.unchecked( Convert_i64_to_i16_clamp_min.INSTANCE ); + case I64_TO_U16: return Cast.unchecked( Convert_i64_to_u16_clamp_min.INSTANCE ); + case I64_TO_I32: return Cast.unchecked( Convert_i64_to_i32_clamp_min.INSTANCE ); + case I64_TO_U32: return Cast.unchecked( Convert_i64_to_u32_clamp_min.INSTANCE ); + case I64_TO_I64: return Cast.unchecked( Convert_i64_to_i64_clamp_min.INSTANCE ); + case I64_TO_F32: return Cast.unchecked( Convert_i64_to_f32_clamp_min.INSTANCE ); + case I64_TO_F64: return Cast.unchecked( Convert_i64_to_f64_clamp_min.INSTANCE ); + case F32_TO_I8: return Cast.unchecked( Convert_f32_to_i8_clamp_min.INSTANCE ); + case F32_TO_U8: return Cast.unchecked( Convert_f32_to_u8_clamp_min.INSTANCE ); + case F32_TO_I16: return Cast.unchecked( Convert_f32_to_i16_clamp_min.INSTANCE ); + case F32_TO_U16: return Cast.unchecked( Convert_f32_to_u16_clamp_min.INSTANCE ); + case F32_TO_I32: return Cast.unchecked( Convert_f32_to_i32_clamp_min.INSTANCE ); + case F32_TO_U32: return Cast.unchecked( Convert_f32_to_u32_clamp_min.INSTANCE ); + case F32_TO_I64: return Cast.unchecked( Convert_f32_to_i64_clamp_min.INSTANCE ); + case F32_TO_F32: return Cast.unchecked( Convert_f32_to_f32_clamp_min.INSTANCE ); + case F32_TO_F64: return Cast.unchecked( Convert_f32_to_f64_clamp_min.INSTANCE ); + case F64_TO_I8: return Cast.unchecked( Convert_f64_to_i8_clamp_min.INSTANCE ); + case F64_TO_U8: return Cast.unchecked( Convert_f64_to_u8_clamp_min.INSTANCE ); + case F64_TO_I16: return Cast.unchecked( Convert_f64_to_i16_clamp_min.INSTANCE ); + case F64_TO_U16: return Cast.unchecked( Convert_f64_to_u16_clamp_min.INSTANCE ); + case F64_TO_I32: return Cast.unchecked( Convert_f64_to_i32_clamp_min.INSTANCE ); + case F64_TO_U32: return Cast.unchecked( Convert_f64_to_u32_clamp_min.INSTANCE ); + case F64_TO_I64: return Cast.unchecked( Convert_f64_to_i64_clamp_min.INSTANCE ); + case F64_TO_F32: return Cast.unchecked( Convert_f64_to_f32_clamp_min.INSTANCE ); + case F64_TO_F64: return Cast.unchecked( Convert_f64_to_f64_clamp_min.INSTANCE ); + default: + throw new IllegalArgumentException(); + } + case CLAMP_MAX: + switch( type ) + { + case I8_TO_I8: return Cast.unchecked( Convert_i8_to_i8_clamp_max.INSTANCE ); + case I8_TO_U8: return Cast.unchecked( Convert_i8_to_u8_clamp_max.INSTANCE ); + case I8_TO_I16: return Cast.unchecked( Convert_i8_to_i16_clamp_max.INSTANCE ); + case I8_TO_U16: return Cast.unchecked( Convert_i8_to_u16_clamp_max.INSTANCE ); + case I8_TO_I32: return Cast.unchecked( Convert_i8_to_i32_clamp_max.INSTANCE ); + case I8_TO_U32: return Cast.unchecked( Convert_i8_to_u32_clamp_max.INSTANCE ); + case I8_TO_I64: return Cast.unchecked( Convert_i8_to_i64_clamp_max.INSTANCE ); + case I8_TO_F32: return Cast.unchecked( Convert_i8_to_f32_clamp_max.INSTANCE ); + case I8_TO_F64: return Cast.unchecked( Convert_i8_to_f64_clamp_max.INSTANCE ); + case U8_TO_I8: return Cast.unchecked( Convert_u8_to_i8_clamp_max.INSTANCE ); + case U8_TO_U8: return Cast.unchecked( Convert_u8_to_u8_clamp_max.INSTANCE ); + case U8_TO_I16: return Cast.unchecked( Convert_u8_to_i16_clamp_max.INSTANCE ); + case U8_TO_U16: return Cast.unchecked( Convert_u8_to_u16_clamp_max.INSTANCE ); + case U8_TO_I32: return Cast.unchecked( Convert_u8_to_i32_clamp_max.INSTANCE ); + case U8_TO_U32: return Cast.unchecked( Convert_u8_to_u32_clamp_max.INSTANCE ); + case U8_TO_I64: return Cast.unchecked( Convert_u8_to_i64_clamp_max.INSTANCE ); + case U8_TO_F32: return Cast.unchecked( Convert_u8_to_f32_clamp_max.INSTANCE ); + case U8_TO_F64: return Cast.unchecked( Convert_u8_to_f64_clamp_max.INSTANCE ); + case I16_TO_I8: return Cast.unchecked( Convert_i16_to_i8_clamp_max.INSTANCE ); + case I16_TO_U8: return Cast.unchecked( Convert_i16_to_u8_clamp_max.INSTANCE ); + case I16_TO_I16: return Cast.unchecked( Convert_i16_to_i16_clamp_max.INSTANCE ); + case I16_TO_U16: return Cast.unchecked( Convert_i16_to_u16_clamp_max.INSTANCE ); + case I16_TO_I32: return Cast.unchecked( Convert_i16_to_i32_clamp_max.INSTANCE ); + case I16_TO_U32: return Cast.unchecked( Convert_i16_to_u32_clamp_max.INSTANCE ); + case I16_TO_I64: return Cast.unchecked( Convert_i16_to_i64_clamp_max.INSTANCE ); + case I16_TO_F32: return Cast.unchecked( Convert_i16_to_f32_clamp_max.INSTANCE ); + case I16_TO_F64: return Cast.unchecked( Convert_i16_to_f64_clamp_max.INSTANCE ); + case U16_TO_I8: return Cast.unchecked( Convert_u16_to_i8_clamp_max.INSTANCE ); + case U16_TO_U8: return Cast.unchecked( Convert_u16_to_u8_clamp_max.INSTANCE ); + case U16_TO_I16: return Cast.unchecked( Convert_u16_to_i16_clamp_max.INSTANCE ); + case U16_TO_U16: return Cast.unchecked( Convert_u16_to_u16_clamp_max.INSTANCE ); + case U16_TO_I32: return Cast.unchecked( Convert_u16_to_i32_clamp_max.INSTANCE ); + case U16_TO_U32: return Cast.unchecked( Convert_u16_to_u32_clamp_max.INSTANCE ); + case U16_TO_I64: return Cast.unchecked( Convert_u16_to_i64_clamp_max.INSTANCE ); + case U16_TO_F32: return Cast.unchecked( Convert_u16_to_f32_clamp_max.INSTANCE ); + case U16_TO_F64: return Cast.unchecked( Convert_u16_to_f64_clamp_max.INSTANCE ); + case I32_TO_I8: return Cast.unchecked( Convert_i32_to_i8_clamp_max.INSTANCE ); + case I32_TO_U8: return Cast.unchecked( Convert_i32_to_u8_clamp_max.INSTANCE ); + case I32_TO_I16: return Cast.unchecked( Convert_i32_to_i16_clamp_max.INSTANCE ); + case I32_TO_U16: return Cast.unchecked( Convert_i32_to_u16_clamp_max.INSTANCE ); + case I32_TO_I32: return Cast.unchecked( Convert_i32_to_i32_clamp_max.INSTANCE ); + case I32_TO_U32: return Cast.unchecked( Convert_i32_to_u32_clamp_max.INSTANCE ); + case I32_TO_I64: return Cast.unchecked( Convert_i32_to_i64_clamp_max.INSTANCE ); + case I32_TO_F32: return Cast.unchecked( Convert_i32_to_f32_clamp_max.INSTANCE ); + case I32_TO_F64: return Cast.unchecked( Convert_i32_to_f64_clamp_max.INSTANCE ); + case U32_TO_I8: return Cast.unchecked( Convert_u32_to_i8_clamp_max.INSTANCE ); + case U32_TO_U8: return Cast.unchecked( Convert_u32_to_u8_clamp_max.INSTANCE ); + case U32_TO_I16: return Cast.unchecked( Convert_u32_to_i16_clamp_max.INSTANCE ); + case U32_TO_U16: return Cast.unchecked( Convert_u32_to_u16_clamp_max.INSTANCE ); + case U32_TO_I32: return Cast.unchecked( Convert_u32_to_i32_clamp_max.INSTANCE ); + case U32_TO_U32: return Cast.unchecked( Convert_u32_to_u32_clamp_max.INSTANCE ); + case U32_TO_I64: return Cast.unchecked( Convert_u32_to_i64_clamp_max.INSTANCE ); + case U32_TO_F32: return Cast.unchecked( Convert_u32_to_f32_clamp_max.INSTANCE ); + case U32_TO_F64: return Cast.unchecked( Convert_u32_to_f64_clamp_max.INSTANCE ); + case I64_TO_I8: return Cast.unchecked( Convert_i64_to_i8_clamp_max.INSTANCE ); + case I64_TO_U8: return Cast.unchecked( Convert_i64_to_u8_clamp_max.INSTANCE ); + case I64_TO_I16: return Cast.unchecked( Convert_i64_to_i16_clamp_max.INSTANCE ); + case I64_TO_U16: return Cast.unchecked( Convert_i64_to_u16_clamp_max.INSTANCE ); + case I64_TO_I32: return Cast.unchecked( Convert_i64_to_i32_clamp_max.INSTANCE ); + case I64_TO_U32: return Cast.unchecked( Convert_i64_to_u32_clamp_max.INSTANCE ); + case I64_TO_I64: return Cast.unchecked( Convert_i64_to_i64_clamp_max.INSTANCE ); + case I64_TO_F32: return Cast.unchecked( Convert_i64_to_f32_clamp_max.INSTANCE ); + case I64_TO_F64: return Cast.unchecked( Convert_i64_to_f64_clamp_max.INSTANCE ); + case F32_TO_I8: return Cast.unchecked( Convert_f32_to_i8_clamp_max.INSTANCE ); + case F32_TO_U8: return Cast.unchecked( Convert_f32_to_u8_clamp_max.INSTANCE ); + case F32_TO_I16: return Cast.unchecked( Convert_f32_to_i16_clamp_max.INSTANCE ); + case F32_TO_U16: return Cast.unchecked( Convert_f32_to_u16_clamp_max.INSTANCE ); + case F32_TO_I32: return Cast.unchecked( Convert_f32_to_i32_clamp_max.INSTANCE ); + case F32_TO_U32: return Cast.unchecked( Convert_f32_to_u32_clamp_max.INSTANCE ); + case F32_TO_I64: return Cast.unchecked( Convert_f32_to_i64_clamp_max.INSTANCE ); + case F32_TO_F32: return Cast.unchecked( Convert_f32_to_f32_clamp_max.INSTANCE ); + case F32_TO_F64: return Cast.unchecked( Convert_f32_to_f64_clamp_max.INSTANCE ); + case F64_TO_I8: return Cast.unchecked( Convert_f64_to_i8_clamp_max.INSTANCE ); + case F64_TO_U8: return Cast.unchecked( Convert_f64_to_u8_clamp_max.INSTANCE ); + case F64_TO_I16: return Cast.unchecked( Convert_f64_to_i16_clamp_max.INSTANCE ); + case F64_TO_U16: return Cast.unchecked( Convert_f64_to_u16_clamp_max.INSTANCE ); + case F64_TO_I32: return Cast.unchecked( Convert_f64_to_i32_clamp_max.INSTANCE ); + case F64_TO_U32: return Cast.unchecked( Convert_f64_to_u32_clamp_max.INSTANCE ); + case F64_TO_I64: return Cast.unchecked( Convert_f64_to_i64_clamp_max.INSTANCE ); + case F64_TO_F32: return Cast.unchecked( Convert_f64_to_f32_clamp_max.INSTANCE ); + case F64_TO_F64: return Cast.unchecked( Convert_f64_to_f64_clamp_max.INSTANCE ); + default: + throw new IllegalArgumentException(); + } + default: + throw new IllegalArgumentException(); + } + } static class Convert_i8_to_i8 implements ConvertLoop< byte[], byte[] > @@ -381,6 +477,18 @@ public void apply( final byte[] src, final byte[] dest, final int length ) } } + static class Convert_i8_to_i8_clamp_min implements ConvertLoop< byte[], byte[] > + { + static final Convert_i8_to_i8_clamp_min INSTANCE = new Convert_i8_to_i8_clamp_min(); + + @Override + public void apply( final byte[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_i8_clamp_max implements ConvertLoop< byte[], byte[] > { static final Convert_i8_to_i8_clamp_max INSTANCE = new Convert_i8_to_i8_clamp_max(); @@ -417,6 +525,18 @@ public void apply( final byte[] src, final byte[] dest, final int length ) } } + static class Convert_i8_to_u8_clamp_min implements ConvertLoop< byte[], byte[] > + { + static final Convert_i8_to_u8_clamp_min INSTANCE = new Convert_i8_to_u8_clamp_min(); + + @Override + public void apply( final byte[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_u8_clamp_max implements ConvertLoop< byte[], byte[] > { static final Convert_i8_to_u8_clamp_max INSTANCE = new Convert_i8_to_u8_clamp_max(); @@ -453,6 +573,18 @@ public void apply( final byte[] src, final short[] dest, final int length ) } } + static class Convert_i8_to_i16_clamp_min implements ConvertLoop< byte[], short[] > + { + static final Convert_i8_to_i16_clamp_min INSTANCE = new Convert_i8_to_i16_clamp_min(); + + @Override + public void apply( final byte[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_i16_clamp_max implements ConvertLoop< byte[], short[] > { static final Convert_i8_to_i16_clamp_max INSTANCE = new Convert_i8_to_i16_clamp_max(); @@ -489,6 +621,18 @@ public void apply( final byte[] src, final short[] dest, final int length ) } } + static class Convert_i8_to_u16_clamp_min implements ConvertLoop< byte[], short[] > + { + static final Convert_i8_to_u16_clamp_min INSTANCE = new Convert_i8_to_u16_clamp_min(); + + @Override + public void apply( final byte[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_u16_clamp_max implements ConvertLoop< byte[], short[] > { static final Convert_i8_to_u16_clamp_max INSTANCE = new Convert_i8_to_u16_clamp_max(); @@ -525,6 +669,18 @@ public void apply( final byte[] src, final int[] dest, final int length ) } } + static class Convert_i8_to_i32_clamp_min implements ConvertLoop< byte[], int[] > + { + static final Convert_i8_to_i32_clamp_min INSTANCE = new Convert_i8_to_i32_clamp_min(); + + @Override + public void apply( final byte[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_i32_clamp_max implements ConvertLoop< byte[], int[] > { static final Convert_i8_to_i32_clamp_max INSTANCE = new Convert_i8_to_i32_clamp_max(); @@ -561,6 +717,18 @@ public void apply( final byte[] src, final int[] dest, final int length ) } } + static class Convert_i8_to_u32_clamp_min implements ConvertLoop< byte[], int[] > + { + static final Convert_i8_to_u32_clamp_min INSTANCE = new Convert_i8_to_u32_clamp_min(); + + @Override + public void apply( final byte[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_u32_clamp_max implements ConvertLoop< byte[], int[] > { static final Convert_i8_to_u32_clamp_max INSTANCE = new Convert_i8_to_u32_clamp_max(); @@ -597,6 +765,18 @@ public void apply( final byte[] src, final long[] dest, final int length ) } } + static class Convert_i8_to_i64_clamp_min implements ConvertLoop< byte[], long[] > + { + static final Convert_i8_to_i64_clamp_min INSTANCE = new Convert_i8_to_i64_clamp_min(); + + @Override + public void apply( final byte[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_i64_clamp_max implements ConvertLoop< byte[], long[] > { static final Convert_i8_to_i64_clamp_max INSTANCE = new Convert_i8_to_i64_clamp_max(); @@ -633,6 +813,18 @@ public void apply( final byte[] src, final float[] dest, final int length ) } } + static class Convert_i8_to_f32_clamp_min implements ConvertLoop< byte[], float[] > + { + static final Convert_i8_to_f32_clamp_min INSTANCE = new Convert_i8_to_f32_clamp_min(); + + @Override + public void apply( final byte[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_f32_clamp_max implements ConvertLoop< byte[], float[] > { static final Convert_i8_to_f32_clamp_max INSTANCE = new Convert_i8_to_f32_clamp_max(); @@ -669,6 +861,18 @@ public void apply( final byte[] src, final double[] dest, final int length ) } } + static class Convert_i8_to_f64_clamp_min implements ConvertLoop< byte[], double[] > + { + static final Convert_i8_to_f64_clamp_min INSTANCE = new Convert_i8_to_f64_clamp_min(); + + @Override + public void apply( final byte[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_i8( src[ i ] ) ); + } + } + static class Convert_i8_to_f64_clamp_max implements ConvertLoop< byte[], double[] > { static final Convert_i8_to_f64_clamp_max INSTANCE = new Convert_i8_to_f64_clamp_max(); @@ -705,6 +909,18 @@ public void apply( final byte[] src, final byte[] dest, final int length ) } } + static class Convert_u8_to_i8_clamp_min implements ConvertLoop< byte[], byte[] > + { + static final Convert_u8_to_i8_clamp_min INSTANCE = new Convert_u8_to_i8_clamp_min(); + + @Override + public void apply( final byte[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_i8_clamp_max implements ConvertLoop< byte[], byte[] > { static final Convert_u8_to_i8_clamp_max INSTANCE = new Convert_u8_to_i8_clamp_max(); @@ -741,6 +957,18 @@ public void apply( final byte[] src, final byte[] dest, final int length ) } } + static class Convert_u8_to_u8_clamp_min implements ConvertLoop< byte[], byte[] > + { + static final Convert_u8_to_u8_clamp_min INSTANCE = new Convert_u8_to_u8_clamp_min(); + + @Override + public void apply( final byte[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_u8_clamp_max implements ConvertLoop< byte[], byte[] > { static final Convert_u8_to_u8_clamp_max INSTANCE = new Convert_u8_to_u8_clamp_max(); @@ -777,6 +1005,18 @@ public void apply( final byte[] src, final short[] dest, final int length ) } } + static class Convert_u8_to_i16_clamp_min implements ConvertLoop< byte[], short[] > + { + static final Convert_u8_to_i16_clamp_min INSTANCE = new Convert_u8_to_i16_clamp_min(); + + @Override + public void apply( final byte[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_i16_clamp_max implements ConvertLoop< byte[], short[] > { static final Convert_u8_to_i16_clamp_max INSTANCE = new Convert_u8_to_i16_clamp_max(); @@ -813,6 +1053,18 @@ public void apply( final byte[] src, final short[] dest, final int length ) } } + static class Convert_u8_to_u16_clamp_min implements ConvertLoop< byte[], short[] > + { + static final Convert_u8_to_u16_clamp_min INSTANCE = new Convert_u8_to_u16_clamp_min(); + + @Override + public void apply( final byte[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_u16_clamp_max implements ConvertLoop< byte[], short[] > { static final Convert_u8_to_u16_clamp_max INSTANCE = new Convert_u8_to_u16_clamp_max(); @@ -849,6 +1101,18 @@ public void apply( final byte[] src, final int[] dest, final int length ) } } + static class Convert_u8_to_i32_clamp_min implements ConvertLoop< byte[], int[] > + { + static final Convert_u8_to_i32_clamp_min INSTANCE = new Convert_u8_to_i32_clamp_min(); + + @Override + public void apply( final byte[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_i32_clamp_max implements ConvertLoop< byte[], int[] > { static final Convert_u8_to_i32_clamp_max INSTANCE = new Convert_u8_to_i32_clamp_max(); @@ -885,6 +1149,18 @@ public void apply( final byte[] src, final int[] dest, final int length ) } } + static class Convert_u8_to_u32_clamp_min implements ConvertLoop< byte[], int[] > + { + static final Convert_u8_to_u32_clamp_min INSTANCE = new Convert_u8_to_u32_clamp_min(); + + @Override + public void apply( final byte[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_u32_clamp_max implements ConvertLoop< byte[], int[] > { static final Convert_u8_to_u32_clamp_max INSTANCE = new Convert_u8_to_u32_clamp_max(); @@ -921,6 +1197,18 @@ public void apply( final byte[] src, final long[] dest, final int length ) } } + static class Convert_u8_to_i64_clamp_min implements ConvertLoop< byte[], long[] > + { + static final Convert_u8_to_i64_clamp_min INSTANCE = new Convert_u8_to_i64_clamp_min(); + + @Override + public void apply( final byte[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_i64_clamp_max implements ConvertLoop< byte[], long[] > { static final Convert_u8_to_i64_clamp_max INSTANCE = new Convert_u8_to_i64_clamp_max(); @@ -957,6 +1245,18 @@ public void apply( final byte[] src, final float[] dest, final int length ) } } + static class Convert_u8_to_f32_clamp_min implements ConvertLoop< byte[], float[] > + { + static final Convert_u8_to_f32_clamp_min INSTANCE = new Convert_u8_to_f32_clamp_min(); + + @Override + public void apply( final byte[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_f32_clamp_max implements ConvertLoop< byte[], float[] > { static final Convert_u8_to_f32_clamp_max INSTANCE = new Convert_u8_to_f32_clamp_max(); @@ -993,6 +1293,18 @@ public void apply( final byte[] src, final double[] dest, final int length ) } } + static class Convert_u8_to_f64_clamp_min implements ConvertLoop< byte[], double[] > + { + static final Convert_u8_to_f64_clamp_min INSTANCE = new Convert_u8_to_f64_clamp_min(); + + @Override + public void apply( final byte[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_u8( src[ i ] ) ); + } + } + static class Convert_u8_to_f64_clamp_max implements ConvertLoop< byte[], double[] > { static final Convert_u8_to_f64_clamp_max INSTANCE = new Convert_u8_to_f64_clamp_max(); @@ -1029,6 +1341,18 @@ public void apply( final short[] src, final byte[] dest, final int length ) } } + static class Convert_i16_to_i8_clamp_min implements ConvertLoop< short[], byte[] > + { + static final Convert_i16_to_i8_clamp_min INSTANCE = new Convert_i16_to_i8_clamp_min(); + + @Override + public void apply( final short[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_i8_clamp_max implements ConvertLoop< short[], byte[] > { static final Convert_i16_to_i8_clamp_max INSTANCE = new Convert_i16_to_i8_clamp_max(); @@ -1065,6 +1389,18 @@ public void apply( final short[] src, final byte[] dest, final int length ) } } + static class Convert_i16_to_u8_clamp_min implements ConvertLoop< short[], byte[] > + { + static final Convert_i16_to_u8_clamp_min INSTANCE = new Convert_i16_to_u8_clamp_min(); + + @Override + public void apply( final short[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_u8_clamp_max implements ConvertLoop< short[], byte[] > { static final Convert_i16_to_u8_clamp_max INSTANCE = new Convert_i16_to_u8_clamp_max(); @@ -1101,6 +1437,18 @@ public void apply( final short[] src, final short[] dest, final int length ) } } + static class Convert_i16_to_i16_clamp_min implements ConvertLoop< short[], short[] > + { + static final Convert_i16_to_i16_clamp_min INSTANCE = new Convert_i16_to_i16_clamp_min(); + + @Override + public void apply( final short[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_i16_clamp_max implements ConvertLoop< short[], short[] > { static final Convert_i16_to_i16_clamp_max INSTANCE = new Convert_i16_to_i16_clamp_max(); @@ -1137,6 +1485,18 @@ public void apply( final short[] src, final short[] dest, final int length ) } } + static class Convert_i16_to_u16_clamp_min implements ConvertLoop< short[], short[] > + { + static final Convert_i16_to_u16_clamp_min INSTANCE = new Convert_i16_to_u16_clamp_min(); + + @Override + public void apply( final short[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_u16_clamp_max implements ConvertLoop< short[], short[] > { static final Convert_i16_to_u16_clamp_max INSTANCE = new Convert_i16_to_u16_clamp_max(); @@ -1173,6 +1533,18 @@ public void apply( final short[] src, final int[] dest, final int length ) } } + static class Convert_i16_to_i32_clamp_min implements ConvertLoop< short[], int[] > + { + static final Convert_i16_to_i32_clamp_min INSTANCE = new Convert_i16_to_i32_clamp_min(); + + @Override + public void apply( final short[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_i32_clamp_max implements ConvertLoop< short[], int[] > { static final Convert_i16_to_i32_clamp_max INSTANCE = new Convert_i16_to_i32_clamp_max(); @@ -1209,6 +1581,18 @@ public void apply( final short[] src, final int[] dest, final int length ) } } + static class Convert_i16_to_u32_clamp_min implements ConvertLoop< short[], int[] > + { + static final Convert_i16_to_u32_clamp_min INSTANCE = new Convert_i16_to_u32_clamp_min(); + + @Override + public void apply( final short[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_u32_clamp_max implements ConvertLoop< short[], int[] > { static final Convert_i16_to_u32_clamp_max INSTANCE = new Convert_i16_to_u32_clamp_max(); @@ -1245,6 +1629,18 @@ public void apply( final short[] src, final long[] dest, final int length ) } } + static class Convert_i16_to_i64_clamp_min implements ConvertLoop< short[], long[] > + { + static final Convert_i16_to_i64_clamp_min INSTANCE = new Convert_i16_to_i64_clamp_min(); + + @Override + public void apply( final short[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_i64_clamp_max implements ConvertLoop< short[], long[] > { static final Convert_i16_to_i64_clamp_max INSTANCE = new Convert_i16_to_i64_clamp_max(); @@ -1281,6 +1677,18 @@ public void apply( final short[] src, final float[] dest, final int length ) } } + static class Convert_i16_to_f32_clamp_min implements ConvertLoop< short[], float[] > + { + static final Convert_i16_to_f32_clamp_min INSTANCE = new Convert_i16_to_f32_clamp_min(); + + @Override + public void apply( final short[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_f32_clamp_max implements ConvertLoop< short[], float[] > { static final Convert_i16_to_f32_clamp_max INSTANCE = new Convert_i16_to_f32_clamp_max(); @@ -1317,6 +1725,18 @@ public void apply( final short[] src, final double[] dest, final int length ) } } + static class Convert_i16_to_f64_clamp_min implements ConvertLoop< short[], double[] > + { + static final Convert_i16_to_f64_clamp_min INSTANCE = new Convert_i16_to_f64_clamp_min(); + + @Override + public void apply( final short[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_i16( src[ i ] ) ); + } + } + static class Convert_i16_to_f64_clamp_max implements ConvertLoop< short[], double[] > { static final Convert_i16_to_f64_clamp_max INSTANCE = new Convert_i16_to_f64_clamp_max(); @@ -1353,6 +1773,18 @@ public void apply( final short[] src, final byte[] dest, final int length ) } } + static class Convert_u16_to_i8_clamp_min implements ConvertLoop< short[], byte[] > + { + static final Convert_u16_to_i8_clamp_min INSTANCE = new Convert_u16_to_i8_clamp_min(); + + @Override + public void apply( final short[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_u16( src[ i ] ) ); + } + } + static class Convert_u16_to_i8_clamp_max implements ConvertLoop< short[], byte[] > { static final Convert_u16_to_i8_clamp_max INSTANCE = new Convert_u16_to_i8_clamp_max(); @@ -1389,9 +1821,21 @@ public void apply( final short[] src, final byte[] dest, final int length ) } } - static class Convert_u16_to_u8_clamp_max implements ConvertLoop< short[], byte[] > + static class Convert_u16_to_u8_clamp_min implements ConvertLoop< short[], byte[] > { - static final Convert_u16_to_u8_clamp_max INSTANCE = new Convert_u16_to_u8_clamp_max(); + static final Convert_u16_to_u8_clamp_min INSTANCE = new Convert_u16_to_u8_clamp_min(); + + @Override + public void apply( final short[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_u16( src[ i ] ) ); + } + } + + static class Convert_u16_to_u8_clamp_max implements ConvertLoop< short[], byte[] > + { + static final Convert_u16_to_u8_clamp_max INSTANCE = new Convert_u16_to_u8_clamp_max(); @Override public void apply( final short[] src, final byte[] dest, final int length ) @@ -1425,6 +1869,18 @@ public void apply( final short[] src, final short[] dest, final int length ) } } + static class Convert_u16_to_i16_clamp_min implements ConvertLoop< short[], short[] > + { + static final Convert_u16_to_i16_clamp_min INSTANCE = new Convert_u16_to_i16_clamp_min(); + + @Override + public void apply( final short[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_u16( src[ i ] ) ); + } + } + static class Convert_u16_to_i16_clamp_max implements ConvertLoop< short[], short[] > { static final Convert_u16_to_i16_clamp_max INSTANCE = new Convert_u16_to_i16_clamp_max(); @@ -1461,6 +1917,18 @@ public void apply( final short[] src, final short[] dest, final int length ) } } + static class Convert_u16_to_u16_clamp_min implements ConvertLoop< short[], short[] > + { + static final Convert_u16_to_u16_clamp_min INSTANCE = new Convert_u16_to_u16_clamp_min(); + + @Override + public void apply( final short[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_u16( src[ i ] ) ); + } + } + static class Convert_u16_to_u16_clamp_max implements ConvertLoop< short[], short[] > { static final Convert_u16_to_u16_clamp_max INSTANCE = new Convert_u16_to_u16_clamp_max(); @@ -1497,6 +1965,18 @@ public void apply( final short[] src, final int[] dest, final int length ) } } + static class Convert_u16_to_i32_clamp_min implements ConvertLoop< short[], int[] > + { + static final Convert_u16_to_i32_clamp_min INSTANCE = new Convert_u16_to_i32_clamp_min(); + + @Override + public void apply( final short[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_u16( src[ i ] ) ); + } + } + static class Convert_u16_to_i32_clamp_max implements ConvertLoop< short[], int[] > { static final Convert_u16_to_i32_clamp_max INSTANCE = new Convert_u16_to_i32_clamp_max(); @@ -1533,6 +2013,18 @@ public void apply( final short[] src, final int[] dest, final int length ) } } + static class Convert_u16_to_u32_clamp_min implements ConvertLoop< short[], int[] > + { + static final Convert_u16_to_u32_clamp_min INSTANCE = new Convert_u16_to_u32_clamp_min(); + + @Override + public void apply( final short[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_u16( src[ i ] ) ); + } + } + static class Convert_u16_to_u32_clamp_max implements ConvertLoop< short[], int[] > { static final Convert_u16_to_u32_clamp_max INSTANCE = new Convert_u16_to_u32_clamp_max(); @@ -1569,6 +2061,18 @@ public void apply( final short[] src, final long[] dest, final int length ) } } + static class Convert_u16_to_i64_clamp_min implements ConvertLoop< short[], long[] > + { + static final Convert_u16_to_i64_clamp_min INSTANCE = new Convert_u16_to_i64_clamp_min(); + + @Override + public void apply( final short[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_u16( src[ i ] ) ); + } + } + static class Convert_u16_to_i64_clamp_max implements ConvertLoop< short[], long[] > { static final Convert_u16_to_i64_clamp_max INSTANCE = new Convert_u16_to_i64_clamp_max(); @@ -1605,6 +2109,18 @@ public void apply( final short[] src, final float[] dest, final int length ) } } + static class Convert_u16_to_f32_clamp_min implements ConvertLoop< short[], float[] > + { + static final Convert_u16_to_f32_clamp_min INSTANCE = new Convert_u16_to_f32_clamp_min(); + + @Override + public void apply( final short[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_u16( src[ i ] ) ); + } + } + static class Convert_u16_to_f32_clamp_max implements ConvertLoop< short[], float[] > { static final Convert_u16_to_f32_clamp_max INSTANCE = new Convert_u16_to_f32_clamp_max(); @@ -1641,6 +2157,18 @@ public void apply( final short[] src, final double[] dest, final int length ) } } + static class Convert_u16_to_f64_clamp_min implements ConvertLoop< short[], double[] > + { + static final Convert_u16_to_f64_clamp_min INSTANCE = new Convert_u16_to_f64_clamp_min(); + + @Override + public void apply( final short[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_u16( src[ i ] ) ); + } + } + static class Convert_u16_to_f64_clamp_max implements ConvertLoop< short[], double[] > { static final Convert_u16_to_f64_clamp_max INSTANCE = new Convert_u16_to_f64_clamp_max(); @@ -1677,6 +2205,18 @@ public void apply( final int[] src, final byte[] dest, final int length ) } } + static class Convert_i32_to_i8_clamp_min implements ConvertLoop< int[], byte[] > + { + static final Convert_i32_to_i8_clamp_min INSTANCE = new Convert_i32_to_i8_clamp_min(); + + @Override + public void apply( final int[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_i8_clamp_max implements ConvertLoop< int[], byte[] > { static final Convert_i32_to_i8_clamp_max INSTANCE = new Convert_i32_to_i8_clamp_max(); @@ -1713,6 +2253,18 @@ public void apply( final int[] src, final byte[] dest, final int length ) } } + static class Convert_i32_to_u8_clamp_min implements ConvertLoop< int[], byte[] > + { + static final Convert_i32_to_u8_clamp_min INSTANCE = new Convert_i32_to_u8_clamp_min(); + + @Override + public void apply( final int[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_u8_clamp_max implements ConvertLoop< int[], byte[] > { static final Convert_i32_to_u8_clamp_max INSTANCE = new Convert_i32_to_u8_clamp_max(); @@ -1749,6 +2301,18 @@ public void apply( final int[] src, final short[] dest, final int length ) } } + static class Convert_i32_to_i16_clamp_min implements ConvertLoop< int[], short[] > + { + static final Convert_i32_to_i16_clamp_min INSTANCE = new Convert_i32_to_i16_clamp_min(); + + @Override + public void apply( final int[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_i16_clamp_max implements ConvertLoop< int[], short[] > { static final Convert_i32_to_i16_clamp_max INSTANCE = new Convert_i32_to_i16_clamp_max(); @@ -1785,6 +2349,18 @@ public void apply( final int[] src, final short[] dest, final int length ) } } + static class Convert_i32_to_u16_clamp_min implements ConvertLoop< int[], short[] > + { + static final Convert_i32_to_u16_clamp_min INSTANCE = new Convert_i32_to_u16_clamp_min(); + + @Override + public void apply( final int[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_u16_clamp_max implements ConvertLoop< int[], short[] > { static final Convert_i32_to_u16_clamp_max INSTANCE = new Convert_i32_to_u16_clamp_max(); @@ -1821,6 +2397,18 @@ public void apply( final int[] src, final int[] dest, final int length ) } } + static class Convert_i32_to_i32_clamp_min implements ConvertLoop< int[], int[] > + { + static final Convert_i32_to_i32_clamp_min INSTANCE = new Convert_i32_to_i32_clamp_min(); + + @Override + public void apply( final int[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_i32_clamp_max implements ConvertLoop< int[], int[] > { static final Convert_i32_to_i32_clamp_max INSTANCE = new Convert_i32_to_i32_clamp_max(); @@ -1857,6 +2445,18 @@ public void apply( final int[] src, final int[] dest, final int length ) } } + static class Convert_i32_to_u32_clamp_min implements ConvertLoop< int[], int[] > + { + static final Convert_i32_to_u32_clamp_min INSTANCE = new Convert_i32_to_u32_clamp_min(); + + @Override + public void apply( final int[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_u32_clamp_max implements ConvertLoop< int[], int[] > { static final Convert_i32_to_u32_clamp_max INSTANCE = new Convert_i32_to_u32_clamp_max(); @@ -1893,6 +2493,18 @@ public void apply( final int[] src, final long[] dest, final int length ) } } + static class Convert_i32_to_i64_clamp_min implements ConvertLoop< int[], long[] > + { + static final Convert_i32_to_i64_clamp_min INSTANCE = new Convert_i32_to_i64_clamp_min(); + + @Override + public void apply( final int[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_i64_clamp_max implements ConvertLoop< int[], long[] > { static final Convert_i32_to_i64_clamp_max INSTANCE = new Convert_i32_to_i64_clamp_max(); @@ -1929,6 +2541,18 @@ public void apply( final int[] src, final float[] dest, final int length ) } } + static class Convert_i32_to_f32_clamp_min implements ConvertLoop< int[], float[] > + { + static final Convert_i32_to_f32_clamp_min INSTANCE = new Convert_i32_to_f32_clamp_min(); + + @Override + public void apply( final int[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_f32_clamp_max implements ConvertLoop< int[], float[] > { static final Convert_i32_to_f32_clamp_max INSTANCE = new Convert_i32_to_f32_clamp_max(); @@ -1965,6 +2589,18 @@ public void apply( final int[] src, final double[] dest, final int length ) } } + static class Convert_i32_to_f64_clamp_min implements ConvertLoop< int[], double[] > + { + static final Convert_i32_to_f64_clamp_min INSTANCE = new Convert_i32_to_f64_clamp_min(); + + @Override + public void apply( final int[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_i32( src[ i ] ) ); + } + } + static class Convert_i32_to_f64_clamp_max implements ConvertLoop< int[], double[] > { static final Convert_i32_to_f64_clamp_max INSTANCE = new Convert_i32_to_f64_clamp_max(); @@ -2001,6 +2637,18 @@ public void apply( final int[] src, final byte[] dest, final int length ) } } + static class Convert_u32_to_i8_clamp_min implements ConvertLoop< int[], byte[] > + { + static final Convert_u32_to_i8_clamp_min INSTANCE = new Convert_u32_to_i8_clamp_min(); + + @Override + public void apply( final int[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_i8_clamp_max implements ConvertLoop< int[], byte[] > { static final Convert_u32_to_i8_clamp_max INSTANCE = new Convert_u32_to_i8_clamp_max(); @@ -2037,6 +2685,18 @@ public void apply( final int[] src, final byte[] dest, final int length ) } } + static class Convert_u32_to_u8_clamp_min implements ConvertLoop< int[], byte[] > + { + static final Convert_u32_to_u8_clamp_min INSTANCE = new Convert_u32_to_u8_clamp_min(); + + @Override + public void apply( final int[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_u8_clamp_max implements ConvertLoop< int[], byte[] > { static final Convert_u32_to_u8_clamp_max INSTANCE = new Convert_u32_to_u8_clamp_max(); @@ -2073,6 +2733,18 @@ public void apply( final int[] src, final short[] dest, final int length ) } } + static class Convert_u32_to_i16_clamp_min implements ConvertLoop< int[], short[] > + { + static final Convert_u32_to_i16_clamp_min INSTANCE = new Convert_u32_to_i16_clamp_min(); + + @Override + public void apply( final int[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_i16_clamp_max implements ConvertLoop< int[], short[] > { static final Convert_u32_to_i16_clamp_max INSTANCE = new Convert_u32_to_i16_clamp_max(); @@ -2109,6 +2781,18 @@ public void apply( final int[] src, final short[] dest, final int length ) } } + static class Convert_u32_to_u16_clamp_min implements ConvertLoop< int[], short[] > + { + static final Convert_u32_to_u16_clamp_min INSTANCE = new Convert_u32_to_u16_clamp_min(); + + @Override + public void apply( final int[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_u16_clamp_max implements ConvertLoop< int[], short[] > { static final Convert_u32_to_u16_clamp_max INSTANCE = new Convert_u32_to_u16_clamp_max(); @@ -2145,6 +2829,18 @@ public void apply( final int[] src, final int[] dest, final int length ) } } + static class Convert_u32_to_i32_clamp_min implements ConvertLoop< int[], int[] > + { + static final Convert_u32_to_i32_clamp_min INSTANCE = new Convert_u32_to_i32_clamp_min(); + + @Override + public void apply( final int[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_i32_clamp_max implements ConvertLoop< int[], int[] > { static final Convert_u32_to_i32_clamp_max INSTANCE = new Convert_u32_to_i32_clamp_max(); @@ -2181,6 +2877,18 @@ public void apply( final int[] src, final int[] dest, final int length ) } } + static class Convert_u32_to_u32_clamp_min implements ConvertLoop< int[], int[] > + { + static final Convert_u32_to_u32_clamp_min INSTANCE = new Convert_u32_to_u32_clamp_min(); + + @Override + public void apply( final int[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_u32_clamp_max implements ConvertLoop< int[], int[] > { static final Convert_u32_to_u32_clamp_max INSTANCE = new Convert_u32_to_u32_clamp_max(); @@ -2217,6 +2925,18 @@ public void apply( final int[] src, final long[] dest, final int length ) } } + static class Convert_u32_to_i64_clamp_min implements ConvertLoop< int[], long[] > + { + static final Convert_u32_to_i64_clamp_min INSTANCE = new Convert_u32_to_i64_clamp_min(); + + @Override + public void apply( final int[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_i64_clamp_max implements ConvertLoop< int[], long[] > { static final Convert_u32_to_i64_clamp_max INSTANCE = new Convert_u32_to_i64_clamp_max(); @@ -2253,6 +2973,18 @@ public void apply( final int[] src, final float[] dest, final int length ) } } + static class Convert_u32_to_f32_clamp_min implements ConvertLoop< int[], float[] > + { + static final Convert_u32_to_f32_clamp_min INSTANCE = new Convert_u32_to_f32_clamp_min(); + + @Override + public void apply( final int[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_f32_clamp_max implements ConvertLoop< int[], float[] > { static final Convert_u32_to_f32_clamp_max INSTANCE = new Convert_u32_to_f32_clamp_max(); @@ -2289,6 +3021,18 @@ public void apply( final int[] src, final double[] dest, final int length ) } } + static class Convert_u32_to_f64_clamp_min implements ConvertLoop< int[], double[] > + { + static final Convert_u32_to_f64_clamp_min INSTANCE = new Convert_u32_to_f64_clamp_min(); + + @Override + public void apply( final int[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_u32( src[ i ] ) ); + } + } + static class Convert_u32_to_f64_clamp_max implements ConvertLoop< int[], double[] > { static final Convert_u32_to_f64_clamp_max INSTANCE = new Convert_u32_to_f64_clamp_max(); @@ -2325,6 +3069,18 @@ public void apply( final long[] src, final byte[] dest, final int length ) } } + static class Convert_i64_to_i8_clamp_min implements ConvertLoop< long[], byte[] > + { + static final Convert_i64_to_i8_clamp_min INSTANCE = new Convert_i64_to_i8_clamp_min(); + + @Override + public void apply( final long[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_i8_clamp_max implements ConvertLoop< long[], byte[] > { static final Convert_i64_to_i8_clamp_max INSTANCE = new Convert_i64_to_i8_clamp_max(); @@ -2361,6 +3117,18 @@ public void apply( final long[] src, final byte[] dest, final int length ) } } + static class Convert_i64_to_u8_clamp_min implements ConvertLoop< long[], byte[] > + { + static final Convert_i64_to_u8_clamp_min INSTANCE = new Convert_i64_to_u8_clamp_min(); + + @Override + public void apply( final long[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_u8_clamp_max implements ConvertLoop< long[], byte[] > { static final Convert_i64_to_u8_clamp_max INSTANCE = new Convert_i64_to_u8_clamp_max(); @@ -2397,6 +3165,18 @@ public void apply( final long[] src, final short[] dest, final int length ) } } + static class Convert_i64_to_i16_clamp_min implements ConvertLoop< long[], short[] > + { + static final Convert_i64_to_i16_clamp_min INSTANCE = new Convert_i64_to_i16_clamp_min(); + + @Override + public void apply( final long[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_i16_clamp_max implements ConvertLoop< long[], short[] > { static final Convert_i64_to_i16_clamp_max INSTANCE = new Convert_i64_to_i16_clamp_max(); @@ -2433,6 +3213,18 @@ public void apply( final long[] src, final short[] dest, final int length ) } } + static class Convert_i64_to_u16_clamp_min implements ConvertLoop< long[], short[] > + { + static final Convert_i64_to_u16_clamp_min INSTANCE = new Convert_i64_to_u16_clamp_min(); + + @Override + public void apply( final long[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_u16_clamp_max implements ConvertLoop< long[], short[] > { static final Convert_i64_to_u16_clamp_max INSTANCE = new Convert_i64_to_u16_clamp_max(); @@ -2469,6 +3261,18 @@ public void apply( final long[] src, final int[] dest, final int length ) } } + static class Convert_i64_to_i32_clamp_min implements ConvertLoop< long[], int[] > + { + static final Convert_i64_to_i32_clamp_min INSTANCE = new Convert_i64_to_i32_clamp_min(); + + @Override + public void apply( final long[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_i32_clamp_max implements ConvertLoop< long[], int[] > { static final Convert_i64_to_i32_clamp_max INSTANCE = new Convert_i64_to_i32_clamp_max(); @@ -2505,6 +3309,18 @@ public void apply( final long[] src, final int[] dest, final int length ) } } + static class Convert_i64_to_u32_clamp_min implements ConvertLoop< long[], int[] > + { + static final Convert_i64_to_u32_clamp_min INSTANCE = new Convert_i64_to_u32_clamp_min(); + + @Override + public void apply( final long[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_u32_clamp_max implements ConvertLoop< long[], int[] > { static final Convert_i64_to_u32_clamp_max INSTANCE = new Convert_i64_to_u32_clamp_max(); @@ -2541,6 +3357,18 @@ public void apply( final long[] src, final long[] dest, final int length ) } } + static class Convert_i64_to_i64_clamp_min implements ConvertLoop< long[], long[] > + { + static final Convert_i64_to_i64_clamp_min INSTANCE = new Convert_i64_to_i64_clamp_min(); + + @Override + public void apply( final long[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_i64_clamp_max implements ConvertLoop< long[], long[] > { static final Convert_i64_to_i64_clamp_max INSTANCE = new Convert_i64_to_i64_clamp_max(); @@ -2577,6 +3405,18 @@ public void apply( final long[] src, final float[] dest, final int length ) } } + static class Convert_i64_to_f32_clamp_min implements ConvertLoop< long[], float[] > + { + static final Convert_i64_to_f32_clamp_min INSTANCE = new Convert_i64_to_f32_clamp_min(); + + @Override + public void apply( final long[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_f32_clamp_max implements ConvertLoop< long[], float[] > { static final Convert_i64_to_f32_clamp_max INSTANCE = new Convert_i64_to_f32_clamp_max(); @@ -2613,6 +3453,18 @@ public void apply( final long[] src, final double[] dest, final int length ) } } + static class Convert_i64_to_f64_clamp_min implements ConvertLoop< long[], double[] > + { + static final Convert_i64_to_f64_clamp_min INSTANCE = new Convert_i64_to_f64_clamp_min(); + + @Override + public void apply( final long[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_i64( src[ i ] ) ); + } + } + static class Convert_i64_to_f64_clamp_max implements ConvertLoop< long[], double[] > { static final Convert_i64_to_f64_clamp_max INSTANCE = new Convert_i64_to_f64_clamp_max(); @@ -2649,6 +3501,18 @@ public void apply( final float[] src, final byte[] dest, final int length ) } } + static class Convert_f32_to_i8_clamp_min implements ConvertLoop< float[], byte[] > + { + static final Convert_f32_to_i8_clamp_min INSTANCE = new Convert_f32_to_i8_clamp_min(); + + @Override + public void apply( final float[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_i8_clamp_max implements ConvertLoop< float[], byte[] > { static final Convert_f32_to_i8_clamp_max INSTANCE = new Convert_f32_to_i8_clamp_max(); @@ -2685,6 +3549,18 @@ public void apply( final float[] src, final byte[] dest, final int length ) } } + static class Convert_f32_to_u8_clamp_min implements ConvertLoop< float[], byte[] > + { + static final Convert_f32_to_u8_clamp_min INSTANCE = new Convert_f32_to_u8_clamp_min(); + + @Override + public void apply( final float[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_u8_clamp_max implements ConvertLoop< float[], byte[] > { static final Convert_f32_to_u8_clamp_max INSTANCE = new Convert_f32_to_u8_clamp_max(); @@ -2721,6 +3597,18 @@ public void apply( final float[] src, final short[] dest, final int length ) } } + static class Convert_f32_to_i16_clamp_min implements ConvertLoop< float[], short[] > + { + static final Convert_f32_to_i16_clamp_min INSTANCE = new Convert_f32_to_i16_clamp_min(); + + @Override + public void apply( final float[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_i16_clamp_max implements ConvertLoop< float[], short[] > { static final Convert_f32_to_i16_clamp_max INSTANCE = new Convert_f32_to_i16_clamp_max(); @@ -2757,6 +3645,18 @@ public void apply( final float[] src, final short[] dest, final int length ) } } + static class Convert_f32_to_u16_clamp_min implements ConvertLoop< float[], short[] > + { + static final Convert_f32_to_u16_clamp_min INSTANCE = new Convert_f32_to_u16_clamp_min(); + + @Override + public void apply( final float[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_u16_clamp_max implements ConvertLoop< float[], short[] > { static final Convert_f32_to_u16_clamp_max INSTANCE = new Convert_f32_to_u16_clamp_max(); @@ -2793,6 +3693,18 @@ public void apply( final float[] src, final int[] dest, final int length ) } } + static class Convert_f32_to_i32_clamp_min implements ConvertLoop< float[], int[] > + { + static final Convert_f32_to_i32_clamp_min INSTANCE = new Convert_f32_to_i32_clamp_min(); + + @Override + public void apply( final float[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_i32_clamp_max implements ConvertLoop< float[], int[] > { static final Convert_f32_to_i32_clamp_max INSTANCE = new Convert_f32_to_i32_clamp_max(); @@ -2829,6 +3741,18 @@ public void apply( final float[] src, final int[] dest, final int length ) } } + static class Convert_f32_to_u32_clamp_min implements ConvertLoop< float[], int[] > + { + static final Convert_f32_to_u32_clamp_min INSTANCE = new Convert_f32_to_u32_clamp_min(); + + @Override + public void apply( final float[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_u32_clamp_max implements ConvertLoop< float[], int[] > { static final Convert_f32_to_u32_clamp_max INSTANCE = new Convert_f32_to_u32_clamp_max(); @@ -2865,6 +3789,18 @@ public void apply( final float[] src, final long[] dest, final int length ) } } + static class Convert_f32_to_i64_clamp_min implements ConvertLoop< float[], long[] > + { + static final Convert_f32_to_i64_clamp_min INSTANCE = new Convert_f32_to_i64_clamp_min(); + + @Override + public void apply( final float[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_i64_clamp_max implements ConvertLoop< float[], long[] > { static final Convert_f32_to_i64_clamp_max INSTANCE = new Convert_f32_to_i64_clamp_max(); @@ -2901,6 +3837,18 @@ public void apply( final float[] src, final float[] dest, final int length ) } } + static class Convert_f32_to_f32_clamp_min implements ConvertLoop< float[], float[] > + { + static final Convert_f32_to_f32_clamp_min INSTANCE = new Convert_f32_to_f32_clamp_min(); + + @Override + public void apply( final float[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_f32_clamp_max implements ConvertLoop< float[], float[] > { static final Convert_f32_to_f32_clamp_max INSTANCE = new Convert_f32_to_f32_clamp_max(); @@ -2937,6 +3885,18 @@ public void apply( final float[] src, final double[] dest, final int length ) } } + static class Convert_f32_to_f64_clamp_min implements ConvertLoop< float[], double[] > + { + static final Convert_f32_to_f64_clamp_min INSTANCE = new Convert_f32_to_f64_clamp_min(); + + @Override + public void apply( final float[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_f32( src[ i ] ) ); + } + } + static class Convert_f32_to_f64_clamp_max implements ConvertLoop< float[], double[] > { static final Convert_f32_to_f64_clamp_max INSTANCE = new Convert_f32_to_f64_clamp_max(); @@ -2973,6 +3933,18 @@ public void apply( final double[] src, final byte[] dest, final int length ) } } + static class Convert_f64_to_i8_clamp_min implements ConvertLoop< double[], byte[] > + { + static final Convert_f64_to_i8_clamp_min INSTANCE = new Convert_f64_to_i8_clamp_min(); + + @Override + public void apply( final double[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i8_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_i8_clamp_max implements ConvertLoop< double[], byte[] > { static final Convert_f64_to_i8_clamp_max INSTANCE = new Convert_f64_to_i8_clamp_max(); @@ -3009,6 +3981,18 @@ public void apply( final double[] src, final byte[] dest, final int length ) } } + static class Convert_f64_to_u8_clamp_min implements ConvertLoop< double[], byte[] > + { + static final Convert_f64_to_u8_clamp_min INSTANCE = new Convert_f64_to_u8_clamp_min(); + + @Override + public void apply( final double[] src, final byte[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u8_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_u8_clamp_max implements ConvertLoop< double[], byte[] > { static final Convert_f64_to_u8_clamp_max INSTANCE = new Convert_f64_to_u8_clamp_max(); @@ -3045,6 +4029,18 @@ public void apply( final double[] src, final short[] dest, final int length ) } } + static class Convert_f64_to_i16_clamp_min implements ConvertLoop< double[], short[] > + { + static final Convert_f64_to_i16_clamp_min INSTANCE = new Convert_f64_to_i16_clamp_min(); + + @Override + public void apply( final double[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i16_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_i16_clamp_max implements ConvertLoop< double[], short[] > { static final Convert_f64_to_i16_clamp_max INSTANCE = new Convert_f64_to_i16_clamp_max(); @@ -3081,6 +4077,18 @@ public void apply( final double[] src, final short[] dest, final int length ) } } + static class Convert_f64_to_u16_clamp_min implements ConvertLoop< double[], short[] > + { + static final Convert_f64_to_u16_clamp_min INSTANCE = new Convert_f64_to_u16_clamp_min(); + + @Override + public void apply( final double[] src, final short[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u16_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_u16_clamp_max implements ConvertLoop< double[], short[] > { static final Convert_f64_to_u16_clamp_max INSTANCE = new Convert_f64_to_u16_clamp_max(); @@ -3117,6 +4125,18 @@ public void apply( final double[] src, final int[] dest, final int length ) } } + static class Convert_f64_to_i32_clamp_min implements ConvertLoop< double[], int[] > + { + static final Convert_f64_to_i32_clamp_min INSTANCE = new Convert_f64_to_i32_clamp_min(); + + @Override + public void apply( final double[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i32_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_i32_clamp_max implements ConvertLoop< double[], int[] > { static final Convert_f64_to_i32_clamp_max INSTANCE = new Convert_f64_to_i32_clamp_max(); @@ -3153,6 +4173,18 @@ public void apply( final double[] src, final int[] dest, final int length ) } } + static class Convert_f64_to_u32_clamp_min implements ConvertLoop< double[], int[] > + { + static final Convert_f64_to_u32_clamp_min INSTANCE = new Convert_f64_to_u32_clamp_min(); + + @Override + public void apply( final double[] src, final int[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_u32_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_u32_clamp_max implements ConvertLoop< double[], int[] > { static final Convert_f64_to_u32_clamp_max INSTANCE = new Convert_f64_to_u32_clamp_max(); @@ -3189,6 +4221,18 @@ public void apply( final double[] src, final long[] dest, final int length ) } } + static class Convert_f64_to_i64_clamp_min implements ConvertLoop< double[], long[] > + { + static final Convert_f64_to_i64_clamp_min INSTANCE = new Convert_f64_to_i64_clamp_min(); + + @Override + public void apply( final double[] src, final long[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_i64_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_i64_clamp_max implements ConvertLoop< double[], long[] > { static final Convert_f64_to_i64_clamp_max INSTANCE = new Convert_f64_to_i64_clamp_max(); @@ -3225,6 +4269,18 @@ public void apply( final double[] src, final float[] dest, final int length ) } } + static class Convert_f64_to_f32_clamp_min implements ConvertLoop< double[], float[] > + { + static final Convert_f64_to_f32_clamp_min INSTANCE = new Convert_f64_to_f32_clamp_min(); + + @Override + public void apply( final double[] src, final float[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f32_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_f32_clamp_max implements ConvertLoop< double[], float[] > { static final Convert_f64_to_f32_clamp_max INSTANCE = new Convert_f64_to_f32_clamp_max(); @@ -3261,6 +4317,18 @@ public void apply( final double[] src, final double[] dest, final int length ) } } + static class Convert_f64_to_f64_clamp_min implements ConvertLoop< double[], double[] > + { + static final Convert_f64_to_f64_clamp_min INSTANCE = new Convert_f64_to_f64_clamp_min(); + + @Override + public void apply( final double[] src, final double[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_f64_clamp_min( from_f64( src[ i ] ) ); + } + } + static class Convert_f64_to_f64_clamp_max implements ConvertLoop< double[], double[] > { static final Convert_f64_to_f64_clamp_max INSTANCE = new Convert_f64_to_f64_clamp_max(); diff --git a/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm b/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm index f9a08944c..51e764c57 100644 --- a/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm +++ b/templates/main/java/net/imglib2/algorithm/blocks/ConvertLoops.vm @@ -42,6 +42,7 @@ import net.imglib2.util.Cast; import static net.imglib2.algorithm.blocks.util.ConvertScalars.from_${t1}; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_${t1}; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_${t1}_clamp; +import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_${t1}_clamp_min; import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_${t1}_clamp_max; #end @@ -52,52 +53,63 @@ import static net.imglib2.algorithm.blocks.util.ConvertScalars.to_${t1}_clamp_ma class ConvertLoops { - static < I, O > ConvertLoop< I, O > get( UnaryOperatorType type ) - { - return get( type, ClampType.NONE ); - } + static < I, O > ConvertLoop< I, O > get( UnaryOperatorType type ) + { + return get( type, ClampType.NONE ); + } - static < I, O > ConvertLoop< I, O > get( UnaryOperatorType type, ClampType clampType ) - { - switch ( clampType ) - { - case NONE: - switch( type ) - { + static < I, O > ConvertLoop< I, O > get( UnaryOperatorType type, ClampType clampType ) + { + switch ( clampType ) + { + case NONE: + switch( type ) + { +#foreach( $t1 in $types ) +#foreach( $t2 in $types ) + case ${t1.toUpperCase()}_TO_${t2.toUpperCase()}: return Cast.unchecked( Convert_${t1}_to_${t2}.INSTANCE ); +#end +#end + default: + throw new IllegalArgumentException(); + } + case CLAMP: + switch( type ) + { #foreach( $t1 in $types ) #foreach( $t2 in $types ) - case ${t1.toUpperCase()}_TO_${t2.toUpperCase()}: return Cast.unchecked( Convert_${t1}_to_${t2}.INSTANCE ); + case ${t1.toUpperCase()}_TO_${t2.toUpperCase()}: return Cast.unchecked( Convert_${t1}_to_${t2}_clamp.INSTANCE ); #end #end - default: - throw new IllegalArgumentException(); - } - case CLAMP: - switch( type ) - { + default: + throw new IllegalArgumentException(); + } + case CLAMP_MIN: + switch( type ) + { #foreach( $t1 in $types ) #foreach( $t2 in $types ) - case ${t1.toUpperCase()}_TO_${t2.toUpperCase()}: return Cast.unchecked( Convert_${t1}_to_${t2}_clamp.INSTANCE ); + case ${t1.toUpperCase()}_TO_${t2.toUpperCase()}: return Cast.unchecked( Convert_${t1}_to_${t2}_clamp_min.INSTANCE ); #end #end - default: - throw new IllegalArgumentException(); - } - case CLAMP_MAX: - switch( type ) - { + default: + throw new IllegalArgumentException(); + } + case CLAMP_MAX: + switch( type ) + { #foreach( $t1 in $types ) #foreach( $t2 in $types ) - case ${t1.toUpperCase()}_TO_${t2.toUpperCase()}: return Cast.unchecked( Convert_${t1}_to_${t2}_clamp_max.INSTANCE ); + case ${t1.toUpperCase()}_TO_${t2.toUpperCase()}: return Cast.unchecked( Convert_${t1}_to_${t2}_clamp_max.INSTANCE ); #end #end - default: - throw new IllegalArgumentException(); - } - default: - throw new IllegalArgumentException(); - } - } + default: + throw new IllegalArgumentException(); + } + default: + throw new IllegalArgumentException(); + } + } #foreach( $t1 in $types ) #set( $sp1 = $storage_primitive[$t1] ) @@ -128,6 +140,18 @@ class ConvertLoops } } + static class Convert_${t1}_to_${t2}_clamp_min implements ConvertLoop< ${sp1}[], ${sp2}[] > + { + static final Convert_${t1}_to_${t2}_clamp_min INSTANCE = new Convert_${t1}_to_${t2}_clamp_min(); + + @Override + public void apply( final ${sp1}[] src, final ${sp2}[] dest, final int length ) + { + for ( int i = 0; i < length; ++i ) + dest[ i ] = to_${t2}_clamp_min( from_$t1( src[ i ] ) ); + } + } + static class Convert_${t1}_to_${t2}_clamp_max implements ConvertLoop< ${sp1}[], ${sp2}[] > { static final Convert_${t1}_to_${t2}_clamp_max INSTANCE = new Convert_${t1}_to_${t2}_clamp_max(); From 965387fe7bb4250c4b9924c1a8da2c70c9c10b5a Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sun, 15 Sep 2024 14:21:58 +0200 Subject: [PATCH 15/24] Downsample: add operator factories, refactor, javadoc --- .../blocks/downsample/Downsample.java | 377 +++++++++++++----- .../downsample/DownsampleBdvBenchmark.java | 32 +- .../downsample/DownsampleBdvPlayground.java | 16 +- .../downsample/DownsampleBdvPlayground2.java | 15 +- .../DownsampleDoublePlayground.java | 11 +- .../downsample/DownsampleMemProfile.java | 17 +- .../DownsampleUnsignedBytePlayground.java | 16 +- 7 files changed, 304 insertions(+), 180 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java index 819e8cef4..a1676dde4 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java @@ -34,6 +34,9 @@ package net.imglib2.algorithm.blocks.downsample; import java.util.Arrays; +import java.util.function.Function; + +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterDouble; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterFloat; @@ -45,15 +48,82 @@ import net.imglib2.type.PrimitiveType; import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; +import net.imglib2.util.Util; import static net.imglib2.type.PrimitiveType.FLOAT; /** - * Downsampling by factor 2. - * Coordinates of downsampled pixel: either centered, or shifted by half a pixel. + * Downsampling by factor 2 in selected dimensions. + *

+ * Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, + * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code + * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). + *

+ * For {@code T} other than {@code DoubleType} or {@code FloatType}, the input + * will be converted to float/double for computation and the result converted + * back to {@code T}. To avoid unnecessary conversions, if you want the result + * as {@code FloatType} then you should explicitly convert to {@code FloatType} + * before applying the downsampling operator. + * This code: + *

{@code
+ * RandomAccessible< UnsignedByteType > input;
+ * BlockSupplier< FloatType > downsampled = BlockSupplier.of( input )
+ *         .andThen( Convert.convert( new FloatType() ) )
+ *         .andThen( Downsample.downsample( Offset.HALF_PIXEL ) );
+ * }
+ * avoids loss of precision and is more efficient than + *
{@code
+ * RandomAccessible< UnsignedByteType > input;
+ * BlockSupplier< FloatType > downsampled = BlockSupplier.of( input )
+ *         .andThen( Downsample.downsample( Offset.HALF_PIXEL ) )
+ *         .andThen( Convert.convert( new FloatType() ) );
+ * }
+ *

+ * The {@link #downsample(ComputationType, Offset)} methods return factory + * functions that create {@code UnaryBlockOperator} to match the type and + * dimensionality of a given input {@code BlockSupplier}. For example, the + * following code creates 2D downsampling operator for 2D {@code input}, a 3D + * operator for 3D {@code input}, etc. + *

{@code
+ * RandomAccessible< UnsignedByteType > input;
+ * BlockSupplier< UnsignedByteType > downsampled = BlockSupplier.of( input )
+ *         .andThen( Downsample.downsample( Offset.HALF_PIXEL ) );
+ * }
+ *

+ * An {@link Offset} specifies whether downsampled pixels are placed on corners or centers of input pixels: + *

    + *
  • {@link Offset#HALF_PIXEL} means that each downsampled pixel is computed + * as the average of 2 neighboring pixels (respectively 4 pixels for 2D, 8 + * voxels for 3D, etc.) Downsampled pixels are shifted by half a pixel. + *
  • + *
  • {@link Offset#CENTERED} means that each downsampled pixel is computed as + * the weighted average (with weights {@code {.25, .5, .25}}) of 3 neighboring + * pixels (respectively 9 pixels for 2D, 27 voxels for 3D, etc.). Downsampled + * pixels are centered on input pixels. + *
  • + *
+ * */ public class Downsample { + /** + * Returns recommended size of the downsampled image, given an input image + * of size {@code imgDimensions}. In each dimension the recommended size is + * input size / 2, rounding up (e.g., a 5 pixel input image should be + * downsampled to a 3 pixel image). + * + * @param imgDimensions + * dimensions of the input image + * + * @return the recommended size of the downsampled image + */ + public static long[] getDownsampledDimensions( final long[] imgDimensions ) + { + final long[] destSize = new long[ imgDimensions.length ]; + Arrays.setAll( destSize, d -> ( imgDimensions[ d ] + 1 ) / 2 ); + return destSize; + } + /** * Returns recommended size of the downsampled image, given an input image * of size {@code imgDimensions}. In each dimension (that should be @@ -61,18 +131,23 @@ public class Downsample * a 5 pixel input image should be downsampled to a 3 pixel image). * * @param imgDimensions - * dimensions of the input image + * dimensions of the input image * @param downsampleInDim - * for each dimension (same length as imgDimensions}: {@code true} if the input image should be down - * @return + * for each dimension {@code d}: if {@code downsampleInDim[d]==true} then + * the input image should be downsampled in dimension {@code d}. + * {@code downsampleInDim} is expanded or truncated to the necessary size. + * For example, if {@code downsampleInDim=={true,true,false}} and the + * operator is applied to a 2D image, {@code downsampleInDim} is truncated + * to {@code {true, true}}. If the operator is applied to a 5D image, {@code + * downsampleInDim} is expanded to {@code {true, true, false, false, false}} + * + * @return the recommended size of the downsampled image */ public static long[] getDownsampledDimensions( final long[] imgDimensions, final boolean[] downsampleInDim ) { - final int n = imgDimensions.length; - if ( downsampleInDim.length != n ) - throw new IllegalArgumentException(); - final long[] destSize = new long[ n ]; - Arrays.setAll( destSize, d -> downsampleInDim[ d ] ? ( imgDimensions[ d ] + 1 ) / 2 : imgDimensions[ d ] ); + final boolean[] dDimsX = Util.expandArray( downsampleInDim, imgDimensions.length ); + final long[] destSize = new long[ imgDimensions.length ]; + Arrays.setAll( destSize, d -> dDimsX[ d ] ? ( imgDimensions[ d ] + 1 ) / 2 : imgDimensions[ d ] ); return destSize; } @@ -96,154 +171,237 @@ public enum Offset * Downsampled pixel centers fall on input pixel centers. * Each downsampled pixel is computed as the weighted average (with * weights {@code {.25, .5, .25}}) of 3 neighboring pixels (respectively - * 9 pixels for 2D, 27 voxels for 3D, etc). + * 9 pixels for 2D, 27 voxels for 3D, etc.) */ CENTERED, /** * Downsampled pixels are shifted by half a pixel. * Each downsampled pixel is computed as the average of 2 neighboring - * pixels (respectively 4 pixels for 2D, 8 voxels for 3D, etc). + * pixels (respectively 4 pixels for 2D, 8 voxels for 3D, etc.) */ HALF_PIXEL } /** - * Create a {@code UnaryBlockOperator} to downsample (by factor 2) blocks of - * the standard ImgLib2 {@code RealType}. The {@code downsampleInDim} - * argument spwecifies in which dimensions the input should be downsampled. + * Downsample (by factor 2, in all dimensions) blocks of the standard + * ImgLib2 {@code RealType}s. *

* Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). + *

+ * Precision for intermediate values is chosen as to represent the + * input/output type without loss of precision. That is, {@code FLOAT} for + * u8, i8, u16, i16, i32, f32, and otherwise {@code DOUBLE} for u32, i64, + * f64. + *

+ * Downsampled pixels are computed as the average of 2 neighboring pixels + * (respectively 4 pixels for 2D, 8 voxels for 3D, etc.) This means + * downsampled pixels are shifted by half a pixel. + *

+ * The returned factory function creates an operator matching the + * type and dimensionality of a given input {@code BlockSupplier}. + * + * @param + * the input/output type + * + * @return factory for {@code UnaryBlockOperator} to downsample blocks of type {@code T} + */ + public static < T extends NativeType< T > > + Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > downsample() + { + return downsample( Offset.HALF_PIXEL ); + } + + /** + * Downsample (by factor 2, in all dimensions) blocks of the standard + * ImgLib2 {@code RealType}s. + *

+ * Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, + * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code + * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). + *

+ * Precision for intermediate values is chosen as to represent the + * input/output type without loss of precision. That is, {@code FLOAT} for + * u8, i8, u16, i16, i32, f32, and otherwise {@code DOUBLE} for u32, i64, + * f64. + *

+ * The returned factory function creates an operator matching the + * type and dimensionality of a given input {@code BlockSupplier}. + * + * @param offset + * Specifies where downsampled pixels should be placed. + * {@code HALF_PIXEL} means that each downsampled pixel is computed + * as the average of 2 neighboring pixels (respectively 4 pixels for + * 2D, 8 voxels for 3D, etc.), and downsampled pixels are shifted by + * half a pixel. + * {@code CENTERED} means that each downsampled pixel is computed as + * the weighted average (with weights {@code {.25, .5, .25}}) of 3 + * neighboring pixels (respectively 9 pixels for 2D, 27 voxels for 3D, + * etc.) Downsampled pixels are centered on input pixels. + * @param + * the input/output type + * + * @return factory for {@code UnaryBlockOperator} to downsample blocks of type {@code T} + */ + public static < T extends NativeType< T > > + Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > downsample( final Offset offset ) + { + return downsample( ComputationType.AUTO, offset ); + } + + /** + * Downsample (by factor 2, in all dimensions) blocks of the standard + * ImgLib2 {@code RealType}s. + *

+ * Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, + * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code + * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). + *

+ * The returned factory function creates an operator matching the + * type and dimensionality of a given input {@code BlockSupplier}. * - * @param type - * instance of the input type * @param computationType * specifies in which precision intermediate values should be - * computed. For {@code AUTO}, the type that can represent the - * input/output type without loss of precision is picked. That is, - * {@code FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code - * DOUBLE} for u32, i64, f64. + * computed. For {@code AUTO}, the type that can represent the + * input/output type without loss of precision is picked. That is, + * {@code FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code + * DOUBLE} for u32, i64, f64. * @param offset * Specifies where downsampled pixels should be placed. * {@code HALF_PIXEL} means that each downsampled pixel is computed - * as the average of 2 neighboring pixels (respectively 4 pixels for - * 2D, 8 voxels for 3D, etc), and downsampled pixels are shifted by - * half a pixel. - * {@code CENTERED} means that each downsampled pixel is computed as - * the weighted average (with weights {@code {.25, .5, .25}}) of 3 - * neighboring pixels (respectively 9 pixels for 2D, 27 voxels for 3D, - * etc). Downsampled pixels are centered on input pixels. - * @param downsampleInDim - * for each dimension {@code d}: if {@code downsampleInDim[d]==true} if - * the input image should be downsampled in dimension {@code d}. + * as the average of 2 neighboring pixels (respectively 4 pixels for + * 2D, 8 voxels for 3D, etc.), and downsampled pixels are shifted by + * half a pixel. + * {@code CENTERED} means that each downsampled pixel is computed as + * the weighted average (with weights {@code {.25, .5, .25}}) of 3 + * neighboring pixels (respectively 9 pixels for 2D, 27 voxels for 3D, + * etc.) Downsampled pixels are centered on input pixels. * @param * the input/output type * - * @return {@code UnaryBlockOperator} to downsample blocks of type {@code T} + * @return factory for {@code UnaryBlockOperator} to downsample blocks of type {@code T} */ public static < T extends NativeType< T > > - UnaryBlockOperator< T, T > downsample( final T type, final ComputationType computationType, final Offset offset, final boolean[] downsampleInDim ) + Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > downsample( final ComputationType computationType, final Offset offset ) { - final boolean processAsFloat; - switch ( computationType ) - { - case FLOAT: - processAsFloat = true; - break; - case DOUBLE: - processAsFloat = false; - break; - default: - case AUTO: - final PrimitiveType pt = type.getNativeTypeFactory().getPrimitiveType(); - processAsFloat = pt.equals( FLOAT ) || pt.getByteCount() < FLOAT.getByteCount(); - break; - } - final UnaryBlockOperator< ?, ? > op = processAsFloat - ? downsampleFloat( offset, downsampleInDim ) - : downsampleDouble( offset, downsampleInDim ); - return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, ClampType.NONE ); + return s -> { + final T type = s.getType(); + final int n = s.numDimensions(); + return createOperator( type, computationType, offset, n ); + }; } /** - * Create a {@code UnaryBlockOperator} to downsample (by factor 2, in all - * dimensions) blocks of the standard ImgLib2 {@code RealType}. + * Downsample (by factor 2) blocks of the standard ImgLib2 {@code + * RealType}s. The {@code downsampleInDim} argument specifies in which + * dimensions the input should be downsampled. *

* Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). + *

+ * The returned factory function creates an operator matching the + * type and dimensionality of a given input {@code BlockSupplier}. * - * @param type - * instance of the input type * @param computationType * specifies in which precision intermediate values should be - * computed. For {@code AUTO}, the type that can represent the - * input/output type without loss of precision is picked. That is, - * {@code FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code - * DOUBLE} for u32, i64, f64. + * computed. For {@code AUTO}, the type that can represent the + * input/output type without loss of precision is picked. That is, + * {@code FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code + * DOUBLE} for u32, i64, f64. * @param offset * Specifies where downsampled pixels should be placed. * {@code HALF_PIXEL} means that each downsampled pixel is computed - * as the average of 2 neighboring pixels (respectively 4 pixels for - * 2D, 8 voxels for 3D, etc), and downsampled pixels are shifted by - * half a pixel. - * {@code CENTERED} means that each downsampled pixel is computed as - * the weighted average (with weights {@code {.25, .5, .25}}) of 3 - * neighboring pixels (respectively 9 pixels for 2D, 27 voxels for 3D, - * etc). Downsampled pixels are centered on input pixels. - * @param numDimensions - * number of dimensions in input/output image. + * as the average of 2 neighboring pixels (respectively 4 pixels for + * 2D, 8 voxels for 3D, etc.), and downsampled pixels are shifted by + * half a pixel. + * {@code CENTERED} means that each downsampled pixel is computed as + * the weighted average (with weights {@code {.25, .5, .25}}) of 3 + * neighboring pixels (respectively 9 pixels for 2D, 27 voxels for 3D, + * etc.) Downsampled pixels are centered on input pixels. + * @param downsampleInDim + * for each dimension {@code d}: if {@code downsampleInDim[d]==true} then + * the input image should be downsampled in dimension {@code d}. + * {@code downsampleInDim} is expanded or truncated to the necessary size. + * For example, if {@code downsampleInDim=={true,true,false}} and the + * operator is applied to a 2D image, {@code downsampleInDim} is truncated + * to {@code {true, true}}. If the operator is applied to a 5D image, {@code + * downsampleInDim} is expanded to {@code {true, true, false, false, false}} * @param * the input/output type * - * @return {@code UnaryBlockOperator} to downsample blocks of type {@code T} + * @return factory for {@code UnaryBlockOperator} to downsample blocks of type {@code T} */ public static < T extends NativeType< T > > - UnaryBlockOperator< T, T > downsample( final T type, final ComputationType computationType, final Offset offset, final int numDimensions ) + Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > downsample( final ComputationType computationType, final Offset offset, final boolean[] downsampleInDim ) { - final boolean[] downsampleInDim = new boolean[ numDimensions ]; - Arrays.fill( downsampleInDim, true ); - return downsample( type, computationType, offset, downsampleInDim ); + return s -> { + final T type = s.getType(); + final int n = s.numDimensions(); + final boolean[] expandedDownsampleInDim = Util.expandArray( downsampleInDim, n ); + return createOperator( type, computationType, offset, expandedDownsampleInDim ); + }; } /** - * Create a {@code UnaryBlockOperator} to downsample (by factor 2, in all - * dimensions) blocks of the standard ImgLib2 {@code RealType}. + * Create a {@code UnaryBlockOperator} to downsample (by factor 2) blocks of + * the standard ImgLib2 {@code RealType}. The {@code downsampleInDim} + * argument specifies in which dimensions the input should be downsampled. *

* Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). - *

- * Precision for intermediate values is chosen as to represent the - * input/output type without loss of precision is picked. That is, {@code - * FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code DOUBLE} for - * u32, i64, f64. * * @param type * instance of the input type + * @param computationType + * specifies in which precision intermediate values should be + * computed. For {@code AUTO}, the type that can represent the + * input/output type without loss of precision is picked. That is, + * {@code FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code + * DOUBLE} for u32, i64, f64. * @param offset * Specifies where downsampled pixels should be placed. * {@code HALF_PIXEL} means that each downsampled pixel is computed - * as the average of 2 neighboring pixels (respectively 4 pixels for - * 2D, 8 voxels for 3D, etc), and downsampled pixels are shifted by - * half a pixel. - * {@code CENTERED} means that each downsampled pixel is computed as - * the weighted average (with weights {@code {.25, .5, .25}}) of 3 - * neighboring pixels (respectively 9 pixels for 2D, 27 voxels for 3D, - * etc). Downsampled pixels are centered on input pixels. - * @param numDimensions - * number of dimensions in input/output image. + * as the average of 2 neighboring pixels (respectively 4 pixels for + * 2D, 8 voxels for 3D, etc.), and downsampled pixels are shifted by + * half a pixel. + * {@code CENTERED} means that each downsampled pixel is computed as + * the weighted average (with weights {@code {.25, .5, .25}}) of 3 + * neighboring pixels (respectively 9 pixels for 2D, 27 voxels for 3D, + * etc.) Downsampled pixels are centered on input pixels. + * @param downsampleInDim + * for each dimension {@code d}: if {@code downsampleInDim[d]==true} then + * the input image should be downsampled in dimension {@code d}. * @param * the input/output type * * @return {@code UnaryBlockOperator} to downsample blocks of type {@code T} */ public static < T extends NativeType< T > > - UnaryBlockOperator< T, T > downsample( final T type, final Offset offset, final int numDimensions ) + UnaryBlockOperator< T, T > createOperator( final T type, final ComputationType computationType, final Offset offset, final boolean[] downsampleInDim ) { - return downsample( type, ComputationType.AUTO, offset, numDimensions ); + final boolean processAsFloat; + switch ( computationType ) + { + case FLOAT: + processAsFloat = true; + break; + case DOUBLE: + processAsFloat = false; + break; + default: + case AUTO: + final PrimitiveType pt = type.getNativeTypeFactory().getPrimitiveType(); + processAsFloat = pt.equals( FLOAT ) || pt.getByteCount() < FLOAT.getByteCount(); + break; + } + final UnaryBlockOperator< ?, ? > op = processAsFloat + ? downsampleFloat( offset, downsampleInDim ) + : downsampleDouble( offset, downsampleInDim ); + return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, ClampType.NONE ); } /** @@ -253,33 +411,40 @@ UnaryBlockOperator< T, T > downsample( final T type, final Offset offset, final * Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). - *

- * Precision for intermediate values is chosen as to represent the - * input/output type without loss of precision is picked. That is, {@code - * FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code DOUBLE} for - * u32, i64, f64. - *

- * Downsampled pixels are computed as the average of 2 neighboring pixels - * (respectively 4 pixels for 2D, 8 voxels for 3D, etc). This means - * downsampled pixels are shifted by half a pixel. * * @param type * instance of the input type + * @param computationType + * specifies in which precision intermediate values should be + * computed. For {@code AUTO}, the type that can represent the + * input/output type without loss of precision is picked. That is, + * {@code FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code + * DOUBLE} for u32, i64, f64. + * @param offset + * Specifies where downsampled pixels should be placed. + * {@code HALF_PIXEL} means that each downsampled pixel is computed + * as the average of 2 neighboring pixels (respectively 4 pixels for + * 2D, 8 voxels for 3D, etc.), and downsampled pixels are shifted by + * half a pixel. + * {@code CENTERED} means that each downsampled pixel is computed as + * the weighted average (with weights {@code {.25, .5, .25}}) of 3 + * neighboring pixels (respectively 9 pixels for 2D, 27 voxels for 3D, + * etc.) Downsampled pixels are centered on input pixels. * @param numDimensions - * number of dimensions in input/output image. + * number of dimensions in input/output image. * @param * the input/output type * * @return {@code UnaryBlockOperator} to downsample blocks of type {@code T} */ public static < T extends NativeType< T > > - UnaryBlockOperator< T, T > downsample( final T type, final int numDimensions ) + UnaryBlockOperator< T, T > createOperator( final T type, final ComputationType computationType, final Offset offset, final int numDimensions ) { - return downsample( type, ComputationType.AUTO, Offset.HALF_PIXEL, numDimensions ); + final boolean[] downsampleInDim = new boolean[ numDimensions ]; + Arrays.fill( downsampleInDim, true ); + return createOperator( type, computationType, offset, downsampleInDim ); } - - private static UnaryBlockOperator< FloatType, FloatType > downsampleFloat( final Offset offset, final boolean[] downsampleInDim ) { final FloatType type = new FloatType(); diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvBenchmark.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvBenchmark.java index f18ee2e4c..5b3cefd64 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvBenchmark.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvBenchmark.java @@ -44,10 +44,10 @@ import net.imglib2.RandomAccess; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.downsample.Downsample.ComputationType; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; import net.imglib2.algorithm.blocks.BlockAlgoUtils; -import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.cache.img.CachedCellImg; import net.imglib2.cache.img.CellLoader; import net.imglib2.cache.img.ReadOnlyCachedCellImgFactory; @@ -130,17 +130,10 @@ public void benchmarkBdv() @Benchmark public void benchmarkDownsampleDouble() { - final PrimitiveBlocks< UnsignedByteType > blocks = PrimitiveBlocks.of( Views.extendBorder( raw ) ); - -// final CellLoader< DoubleType> loader = cellLoader( blocks, net.imglib2.algorithm.blocks.downsample.Downsample.downsample( new DoubleType(), ComputationType.AUTO, Offset.CENTERED, downsampleInDim ) ); -// final CachedCellImg< DoubleType, ? > downsampleDouble = new ReadOnlyCachedCellImgFactory().create( -// downsampledDimensions, -// new DoubleType(), -// loader, -// ReadOnlyCachedCellImgOptions.options().cellDimensions( cellDimensions).cacheType( BOUNDED ).maxCacheSize( 1 ) ); - final CachedCellImg< UnsignedByteType, ? > downsampleDouble = BlockAlgoUtils.cellImg( - blocks, Downsample.downsample( new UnsignedByteType(), ComputationType.DOUBLE, Offset.HALF_PIXEL, downsampleInDim ), new UnsignedByteType(), downsampledDimensions, cellDimensions ); - + final BlockSupplier< UnsignedByteType > blocks = BlockSupplier + .of( Views.extendBorder( raw ) ) + .andThen( Downsample.downsample( ComputationType.DOUBLE, Offset.HALF_PIXEL, downsampleInDim ) ); + final CachedCellImg< UnsignedByteType, ? > downsampleDouble = BlockAlgoUtils.cellImg( blocks, downsampledDimensions, cellDimensions ); touchAllCellsSingleThreaded( downsampleDouble ); downsampleDouble.getCache().invalidateAll(); } @@ -148,17 +141,10 @@ public void benchmarkDownsampleDouble() @Benchmark public void benchmarkDownsampleFloat() { - final PrimitiveBlocks< UnsignedByteType > blocksFloat = PrimitiveBlocks.of( Views.extendBorder( raw ) ); - -// final CellLoader< FloatType> loader = cellLoader( blocksFloat, net.imglib2.algorithm.blocks.downsample.Downsample.downsample( new FloatType(), ComputationType.AUTO, Offset.CENTERED, downsampleInDim ) ); -// final CachedCellImg< FloatType, ? > downsampleFloat = new ReadOnlyCachedCellImgFactory().create( -// downsampledDimensions, -// new FloatType(), -// loader, -// ReadOnlyCachedCellImgOptions.options().cellDimensions( cellDimensions).cacheType( BOUNDED ).maxCacheSize( 1 ) ); - final CachedCellImg< UnsignedByteType, ? > downsampleFloat = BlockAlgoUtils.cellImg( - blocksFloat, Downsample.downsample( new UnsignedByteType(), ComputationType.FLOAT, Offset.HALF_PIXEL, downsampleInDim ), new UnsignedByteType(), downsampledDimensions, cellDimensions ); - + final BlockSupplier< UnsignedByteType > blocks = BlockSupplier + .of( Views.extendBorder( raw ) ) + .andThen( Downsample.downsample( ComputationType.FLOAT, Offset.HALF_PIXEL, downsampleInDim ) ); + final CachedCellImg< UnsignedByteType, ? > downsampleFloat = BlockAlgoUtils.cellImg( blocks, downsampledDimensions, cellDimensions ); touchAllCellsSingleThreaded( downsampleFloat ); downsampleFloat.getCache().invalidateAll(); } diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground.java index b71586f27..b28b4a15e 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground.java @@ -43,10 +43,10 @@ import ij.ImagePlus; import java.util.Arrays; import net.imglib2.RandomAccess; +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.downsample.Downsample.ComputationType; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; import net.imglib2.algorithm.blocks.BlockAlgoUtils; -import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.cache.img.CachedCellImg; import net.imglib2.cache.img.CellLoader; import net.imglib2.cache.img.ReadOnlyCachedCellImgFactory; @@ -58,8 +58,6 @@ import net.imglib2.view.ExtendedRandomAccessibleInterval; import net.imglib2.view.Views; -import static net.imglib2.algorithm.blocks.downsample.Downsample.downsample; - public class DownsampleBdvPlayground { public static void main( String[] args ) @@ -83,7 +81,6 @@ public static void main( String[] args ) final int[] cellDimensions = { 64, 64, 64 }; final ExtendedRandomAccessibleInterval< UnsignedByteType, Img< UnsignedByteType > > extended = Views.extendBorder( img ); - final PrimitiveBlocks< UnsignedByteType > blocks = PrimitiveBlocks.of( extended ); final UnsignedByteType type = new UnsignedByteType(); final double[] calib = new double[ 3 ]; @@ -121,13 +118,10 @@ public static void main( String[] args ) out.setColor( new ARGBType( 0xff0000 ) ); - - final CachedCellImg< UnsignedByteType, ? > downsampled2 = BlockAlgoUtils.cellImg( - blocks, - downsample( type, ComputationType.AUTO, Offset.HALF_PIXEL, downsampleInDim ), - type, - downsampledDimensions, - cellDimensions ); + final BlockSupplier< UnsignedByteType > blocks = BlockSupplier + .of( extended ) + .andThen( Downsample.downsample( ComputationType.AUTO, Offset.HALF_PIXEL, downsampleInDim ) ); + final CachedCellImg< UnsignedByteType, ? > downsampled2 = BlockAlgoUtils.cellImg( blocks, downsampledDimensions, cellDimensions ); final BdvSource out2 = BdvFunctions.show( VolatileViews.wrapAsVolatile( downsampled2 ), "downsampled half-pixel", diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground2.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground2.java index ef2ecdd1c..73eb1fa2f 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground2.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground2.java @@ -11,13 +11,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 @@ -45,10 +45,7 @@ import ij.ImagePlus; import net.imglib2.algorithm.blocks.BlockAlgoUtils; import net.imglib2.algorithm.blocks.BlockSupplier; -import net.imglib2.algorithm.blocks.UnaryBlockOperator; -import net.imglib2.algorithm.blocks.convert.Convert; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; -import net.imglib2.cache.img.CachedCellImg; import net.imglib2.img.Img; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.type.numeric.ARGBType; @@ -80,12 +77,10 @@ public static void main( String[] args ) final double[] calib = new double[ 3 ]; Arrays.setAll(calib, d -> downsampleInDim[ d ] ? 2 : 1 ); - final BlockSupplier< UnsignedByteType > blocks = BlockSupplier + BlockSupplier< UnsignedByteType > blocks = BlockSupplier .of( Views.extendMirrorDouble( img ) ) - .andThen( Downsample.downsample( - img.getType(), - Offset.HALF_PIXEL, - img.numDimensions() ) ); + .andThen( Downsample.downsample( Offset.HALF_PIXEL ) ) + .tile( 16 ); final Img< UnsignedByteType > downsampled = BlockAlgoUtils.cellImg( blocks, diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleDoublePlayground.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleDoublePlayground.java index f894b9b48..865c637b4 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleDoublePlayground.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleDoublePlayground.java @@ -43,10 +43,7 @@ import java.util.Arrays; import net.imglib2.algorithm.blocks.BlockSupplier; -import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterDouble; -import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.HalfPixelDouble; import net.imglib2.algorithm.blocks.BlockAlgoUtils; -import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.cache.img.CachedCellImg; import net.imglib2.converter.Converters; import net.imglib2.converter.RealDoubleConverter; @@ -83,10 +80,8 @@ public static void main( String[] args ) final int[] cellDimensions = { 64, 64, 64 }; final CachedCellImg< DoubleType, ? > downsampled = BlockAlgoUtils.cellImg( blocks.andThen( Downsample.downsample( - new DoubleType(), Downsample.ComputationType.DOUBLE, - Downsample.Offset.CENTERED, - 3 ) + Downsample.Offset.CENTERED ) ), downsampledDimensions, cellDimensions ); @@ -103,10 +98,8 @@ public static void main( String[] args ) final CachedCellImg< DoubleType, ? > downsampled2 = BlockAlgoUtils.cellImg( blocks.andThen( Downsample.downsample( - new DoubleType(), Downsample.ComputationType.DOUBLE, - Downsample.Offset.HALF_PIXEL, - 3 ) + Downsample.Offset.HALF_PIXEL ) ), downsampledDimensions, cellDimensions ); final BdvSource out2 = BdvFunctions.show( diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleMemProfile.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleMemProfile.java index 2334596bf..cff4291a5 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleMemProfile.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleMemProfile.java @@ -36,13 +36,14 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; import java.util.stream.IntStream; + import net.imglib2.Cursor; import net.imglib2.IterableInterval; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.algorithm.blocks.BlockAlgoUtils; +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.downsample.Downsample.ComputationType; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; -import net.imglib2.algorithm.blocks.BlockAlgoUtils; -import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.cache.img.CachedCellImg; import net.imglib2.img.array.ArrayImgs; import net.imglib2.img.cell.AbstractCellImg; @@ -76,16 +77,12 @@ public DownsampleMemProfile() public void benchmarkDownsampleFloat() { - final PrimitiveBlocks< UnsignedByteType > blocksFloat = PrimitiveBlocks.of( Views.extendBorder( raw ) ); + final BlockSupplier< UnsignedByteType > blocksFloat = BlockSupplier + .of( Views.extendBorder( raw ) ) + .andThen( Downsample.downsample(ComputationType.FLOAT, Offset.CENTERED, downsampleInDim ) ); -// final CellLoader< FloatType> loader = cellLoader( blocksFloat, net.imglib2.algorithm.blocks.downsample.Downsample.downsample( new FloatType(), ComputationType.AUTO, Offset.CENTERED, downsampleInDim ) ); -// final CachedCellImg< FloatType, ? > downsampleFloat = new ReadOnlyCachedCellImgFactory().create( -// downsampledDimensions, -// new FloatType(), -// loader, -// ReadOnlyCachedCellImgOptions.options().cellDimensions( cellDimensions).cacheType( BOUNDED ).maxCacheSize( 1 ) ); final CachedCellImg< UnsignedByteType, ? > downsampleFloat = BlockAlgoUtils.cellImg( - blocksFloat, Downsample.downsample( new UnsignedByteType(), ComputationType.FLOAT, Offset.CENTERED, downsampleInDim ), new UnsignedByteType(), downsampledDimensions, cellDimensions ); + blocksFloat, downsampledDimensions, cellDimensions ); // touchAllCellsSingleThreaded( downsampleFloat ); touchAllCells( downsampleFloat ); diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleUnsignedBytePlayground.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleUnsignedBytePlayground.java index faee7e4ea..45a7dc38f 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleUnsignedBytePlayground.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleUnsignedBytePlayground.java @@ -41,10 +41,11 @@ import ij.IJ; import ij.ImagePlus; import java.util.Arrays; + +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.downsample.Downsample.ComputationType; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; import net.imglib2.algorithm.blocks.BlockAlgoUtils; -import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.cache.img.CachedCellImg; import net.imglib2.img.Img; import net.imglib2.img.display.imagej.ImageJFunctions; @@ -52,8 +53,6 @@ import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.view.Views; -import static net.imglib2.algorithm.blocks.downsample.Downsample.downsample; - public class DownsampleUnsignedBytePlayground { public static void main( String[] args ) @@ -76,13 +75,10 @@ public static void main( String[] args ) final long[] downsampledDimensions = Downsample.getDownsampledDimensions( img.dimensionsAsLongArray(), downsampleInDim ); final int[] cellDimensions = { 64, 64, 64 }; - final PrimitiveBlocks< UnsignedByteType > blocks = PrimitiveBlocks.of( Views.extendBorder( img ) ); - final UnsignedByteType type = new UnsignedByteType(); + final BlockSupplier< UnsignedByteType > blocks = BlockSupplier.of( Views.extendBorder( img ) ); final CachedCellImg< UnsignedByteType, ? > downsampled = BlockAlgoUtils.cellImg( - blocks, - downsample( type, ComputationType.AUTO, Offset.CENTERED, downsampleInDim ), - type, + blocks.andThen( Downsample.downsample( ComputationType.AUTO, Offset.CENTERED, downsampleInDim ) ), downsampledDimensions, cellDimensions ); @@ -98,9 +94,7 @@ public static void main( String[] args ) out.setColor( new ARGBType( 0xff0000 ) ); final CachedCellImg< UnsignedByteType, ? > downsampled2 = BlockAlgoUtils.cellImg( - blocks, - downsample( type, ComputationType.AUTO, Offset.HALF_PIXEL, downsampleInDim ), - type, + blocks.andThen( Downsample.downsample( ComputationType.AUTO, Offset.HALF_PIXEL, downsampleInDim ) ), downsampledDimensions, cellDimensions ); final BdvSource out2 = BdvFunctions.show( From 58ade11b08bbe0a720cd3e6376d77a2eda99e266 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Thu, 4 Jul 2024 11:48:59 +0200 Subject: [PATCH 16/24] Transform: add operator factories, refactor, javadoc --- .../algorithm/blocks/transform/Transform.java | 59 +++++++++++++++---- .../transform/TransformBenchmark3D.java | 11 +++- .../transform/TransformPlayground3D.java | 18 ++---- 3 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java b/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java index 9fa9e8932..d1190c068 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java +++ b/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java @@ -11,13 +11,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 @@ -33,6 +33,7 @@ */ package net.imglib2.algorithm.blocks.transform; +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator; import net.imglib2.algorithm.blocks.UnaryBlockOperator; import net.imglib2.algorithm.blocks.ClampType; @@ -46,6 +47,8 @@ import static net.imglib2.type.PrimitiveType.FLOAT; +import java.util.function.Function; + /** * Affine transform in 2D/3D with n-linear or nearest-neighbor interpolation. */ @@ -69,13 +72,14 @@ public enum Interpolation } /** - * Create a {@code UnaryBlockOperator} to interpolate and affine-transform - * blocks of the standard ImgLib2 {@code RealType}s. + * Interpolate and affine-transform blocks of the standard ImgLib2 {@code + * RealType}s. *

* Only 2D and 3D are supported currently! + *

+ * The returned factory function creates an operator matching the type a + * given input {@code BlockSupplier}. * - * @param type - * instance of the input type * @param transformFromSource * a 2D or 3D affine transform * @param interpolation @@ -83,12 +87,43 @@ public enum Interpolation * @param * the input/output type * - * @return {@code UnaryBlockOperator} to affine-transform blocks of type {@code T} + * @return factory for {@code UnaryBlockOperator} to affine-transform blocks of type {@code T} + */ + public static < T extends NativeType< T > > + Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > affine( final AffineGet transformFromSource, Interpolation interpolation ) + { + return affine( transformFromSource, interpolation, ComputationType.AUTO ); + } + + /** + * Interpolate and affine-transform blocks of the standard ImgLib2 {@code + * RealType}s. + *

+ * Only 2D and 3D are supported currently! + *

+ * The returned factory function creates an operator matching the type a + * given input {@code BlockSupplier}. + * + * @param transformFromSource + * a 2D or 3D affine transform + * @param interpolation + * which interpolation method to use + * @param computationType + * For n-linear interpolation, this specifies in which precision + * intermediate values should be computed. For {@code AUTO}, the type + * that can represent the input/output type without loss of precision + * is picked. That is, {@code FLOAT} for u8, i8, u16, i16, i32, f32, + * and otherwise {@code DOUBLE} for u32, i64, f64. For nearest-neighbor + * interpolation, {@code computationType} is not used. + * @param + * the input/output type + * + * @return factory for {@code UnaryBlockOperator} to affine-transform blocks of type {@code T} */ public static < T extends NativeType< T > > - UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSource, Interpolation interpolation ) + Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > affine( final AffineGet transformFromSource, Interpolation interpolation, final ComputationType computationType ) { - return affine( type, transformFromSource, interpolation, ComputationType.AUTO ); + return s -> createAffineOperator( s.getType(), transformFromSource, interpolation, computationType, ClampType.CLAMP ); } /** @@ -116,7 +151,7 @@ UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSo * @return {@code UnaryBlockOperator} to affine-transform blocks of type {@code T} */ public static < T extends NativeType< T > > - UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSource, Interpolation interpolation, final ComputationType computationType ) + UnaryBlockOperator< T, T > createAffineOperator( final T type, final AffineGet transformFromSource, Interpolation interpolation, final ComputationType computationType, final ClampType clampType ) { final int n = transformFromSource.numDimensions(); if ( n < 2 || n > 3 ) { @@ -145,7 +180,7 @@ UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSo final UnaryBlockOperator< ?, ? > op = processAsFloat ? _affine( transformToSource, interpolation, new FloatType() ) : _affine( transformToSource, interpolation, new DoubleType() ); - return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, ClampType.CLAMP ); + return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, clampType ); } else // if ( interpolation == Interpolation.NEARESTNEIGHBOR ) { @@ -156,8 +191,6 @@ UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSo private static < T extends NativeType< T > > UnaryBlockOperator< T, T > _affine( final AffineGet transform, final Interpolation interpolation, final T type ) { final int n = transform.numDimensions(); - if ( n < 2 || n > 3 ) - throw new IllegalArgumentException( "Only 2D and 3D affine transforms are supported currently" ); return new DefaultUnaryBlockOperator<>( type, type, n, n, n == 2 ? new Affine2DProcessor<>( ( AffineTransform2D ) transform, interpolation, type.getNativeTypeFactory().getPrimitiveType() ) diff --git a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java index 2f102050b..274dea813 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java +++ b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java @@ -43,6 +43,8 @@ import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealRandomAccessible; import net.imglib2.algorithm.blocks.BlockProcessor; +import net.imglib2.algorithm.blocks.ClampType; +import net.imglib2.algorithm.blocks.transform.Transform.ComputationType; import net.imglib2.algorithm.blocks.transform.Transform.Interpolation; import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.converter.Converters; @@ -151,15 +153,18 @@ public void blocksnaiveSetup() Views.extendZero( img ), new RealFloatConverter<>(), new FloatType() ) ); - processor = Transform.affine( new FloatType(), affine, Interpolation.NLINEAR ).blockProcessor(); + final FloatType type2 = new FloatType(); + processor = Transform.createAffineOperator( type2, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor(); blocksDouble = PrimitiveBlocks.of( Converters.convert( Views.extendZero( img ), new RealDoubleConverter<>(), new DoubleType() ) ); - processorDouble = Transform.affine( new DoubleType(), affine, Interpolation.NLINEAR ).blockProcessor(); + final DoubleType type1 = new DoubleType(); + processorDouble = Transform.createAffineOperator( type1, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor(); blocksUnsignedByte = PrimitiveBlocks.of( Views.extendZero( img ) ); - processorUnsignedByte = Transform.affine( new UnsignedByteType(), affine, Interpolation.NLINEAR ).blockProcessor(); + final UnsignedByteType type = new UnsignedByteType(); + processorUnsignedByte = Transform.createAffineOperator( type, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor(); blocksFloat(); blocksDouble(); blocksUnsignedByte(); diff --git a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformPlayground3D.java b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformPlayground3D.java index 8f78f45dc..b85b9d534 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformPlayground3D.java +++ b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformPlayground3D.java @@ -40,13 +40,11 @@ import ij.ImagePlus; import java.util.Arrays; import net.imglib2.Cursor; -import net.imglib2.FinalInterval; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealRandomAccessible; -import net.imglib2.algorithm.blocks.BlockProcessor; +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.transform.Transform.Interpolation; -import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.img.Img; import net.imglib2.img.array.ArrayImg; import net.imglib2.img.array.ArrayImgFactory; @@ -105,19 +103,13 @@ public static void main( String[] args ) final int[] size = { 64, 64, 64 }; final RandomAccessibleInterval< UnsignedByteType > copy = copy( transformed, new UnsignedByteType(), min, size ); - - final PrimitiveBlocks< UnsignedByteType > blocks = PrimitiveBlocks.of( Views.extendZero( img ) ); - BlockProcessor< byte[], byte[] > processor = Transform.affine( new UnsignedByteType(), affine, Interpolation.NLINEAR ).blockProcessor(); - long[] max = new long[ size.length ]; - Arrays.setAll( max, d -> min[ d ] + size[ d ] - 1 ); - processor.setTargetInterval( FinalInterval.wrap( min, max ) ); - blocks.copy( processor.getSourcePos(), processor.getSourceBuffer(), processor.getSourceSize() ); + final BlockSupplier< UnsignedByteType > blocks = BlockSupplier + .of( Views.extendZero( img ) ) + .andThen( Transform.affine( affine, Interpolation.NLINEAR ) ); final byte[] dest = new byte[ ( int ) Intervals.numElements( size ) ]; - processor.compute( processor.getSourceBuffer(), dest ); + blocks.copy( min, dest, size ); final RandomAccessibleInterval< UnsignedByteType > destImg = ArrayImgs.unsignedBytes( dest, size[ 0 ], size[ 1 ], size[ 2 ] ); - - // ---------------------------------------------- final BdvSource bdv2 = BdvFunctions.show( From c181a811528ad0ca25a0192e9cd2ee52bfcf616d Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Mon, 22 Jul 2024 20:52:59 +0200 Subject: [PATCH 17/24] Make ComputationType global --- .../imglib2/algorithm/blocks/ComputationType.java | 12 ++++++++++++ .../algorithm/blocks/downsample/Downsample.java | 12 +----------- .../algorithm/blocks/transform/Transform.java | 11 +---------- .../blocks/downsample/DownsampleBdvBenchmark.java | 2 +- .../blocks/downsample/DownsampleBdvPlayground.java | 2 +- .../downsample/DownsampleDoublePlayground.java | 5 +++-- .../blocks/downsample/DownsampleMemProfile.java | 2 +- .../downsample/DownsampleUnsignedBytePlayground.java | 2 +- .../blocks/transform/TransformBenchmark3D.java | 2 +- 9 files changed, 22 insertions(+), 28 deletions(-) create mode 100644 src/main/java/net/imglib2/algorithm/blocks/ComputationType.java diff --git a/src/main/java/net/imglib2/algorithm/blocks/ComputationType.java b/src/main/java/net/imglib2/algorithm/blocks/ComputationType.java new file mode 100644 index 000000000..f2e8f9918 --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/ComputationType.java @@ -0,0 +1,12 @@ +package net.imglib2.algorithm.blocks; + +/** + * Specify in which precision should intermediate values be computed. (For + * {@code AUTO}, the type that can represent the input/output type without + * loss of precision is picked. That is, {@code FLOAT} for u8, i8, u16, i16, + * i32, f32, and otherwise {@code DOUBLE} for u32, i64, f64. + */ +public enum ComputationType +{ + FLOAT, DOUBLE, AUTO +} diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java index a1676dde4..07e08a3c3 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java @@ -38,6 +38,7 @@ import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.ClampType; +import net.imglib2.algorithm.blocks.ComputationType; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterDouble; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterFloat; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.HalfPixelDouble; @@ -151,17 +152,6 @@ public static long[] getDownsampledDimensions( final long[] imgDimensions, final return destSize; } - /** - * Specify in which precision should intermediate values be computed. (For - * {@code AUTO}, the type that can represent the input/output type without - * loss of precision is picked. That is, {@code FLOAT} for u8, i8, u16, i16, - * i32, f32, and otherwise {@code DOUBLE} for u32, i64, f64. - */ - public enum ComputationType - { - FLOAT, DOUBLE, AUTO - } - /** * Specify where downsampled pixels should be placed. */ diff --git a/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java b/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java index d1190c068..3e9e9f5b2 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java +++ b/src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java @@ -37,6 +37,7 @@ import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator; import net.imglib2.algorithm.blocks.UnaryBlockOperator; import net.imglib2.algorithm.blocks.ClampType; +import net.imglib2.algorithm.blocks.ComputationType; import net.imglib2.realtransform.AffineGet; import net.imglib2.realtransform.AffineTransform2D; import net.imglib2.realtransform.AffineTransform3D; @@ -54,16 +55,6 @@ */ public class Transform { - /** - * Specify in which precision should intermediate values be computed. (For - * {@code AUTO}, the type that can represent the input/output type without - * loss of precision is picked. That is, {@code FLOAT} for u8, i8, u16, i16, - * i32, f32, and otherwise {@code DOUBLE} for u32, i64, f64. - */ - public enum ComputationType - { - FLOAT, DOUBLE, AUTO - } public enum Interpolation { diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvBenchmark.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvBenchmark.java index 5b3cefd64..c776e8e5e 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvBenchmark.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvBenchmark.java @@ -45,7 +45,7 @@ import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; import net.imglib2.algorithm.blocks.BlockSupplier; -import net.imglib2.algorithm.blocks.downsample.Downsample.ComputationType; +import net.imglib2.algorithm.blocks.ComputationType; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; import net.imglib2.algorithm.blocks.BlockAlgoUtils; import net.imglib2.cache.img.CachedCellImg; diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground.java index b28b4a15e..b4bb038f5 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBdvPlayground.java @@ -44,7 +44,7 @@ import java.util.Arrays; import net.imglib2.RandomAccess; import net.imglib2.algorithm.blocks.BlockSupplier; -import net.imglib2.algorithm.blocks.downsample.Downsample.ComputationType; +import net.imglib2.algorithm.blocks.ComputationType; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; import net.imglib2.algorithm.blocks.BlockAlgoUtils; import net.imglib2.cache.img.CachedCellImg; diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleDoublePlayground.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleDoublePlayground.java index 865c637b4..94060cb6c 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleDoublePlayground.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleDoublePlayground.java @@ -44,6 +44,7 @@ import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.BlockAlgoUtils; +import net.imglib2.algorithm.blocks.ComputationType; import net.imglib2.cache.img.CachedCellImg; import net.imglib2.converter.Converters; import net.imglib2.converter.RealDoubleConverter; @@ -80,7 +81,7 @@ public static void main( String[] args ) final int[] cellDimensions = { 64, 64, 64 }; final CachedCellImg< DoubleType, ? > downsampled = BlockAlgoUtils.cellImg( blocks.andThen( Downsample.downsample( - Downsample.ComputationType.DOUBLE, + ComputationType.DOUBLE, Downsample.Offset.CENTERED ) ), downsampledDimensions, cellDimensions ); @@ -98,7 +99,7 @@ public static void main( String[] args ) final CachedCellImg< DoubleType, ? > downsampled2 = BlockAlgoUtils.cellImg( blocks.andThen( Downsample.downsample( - Downsample.ComputationType.DOUBLE, + ComputationType.DOUBLE, Downsample.Offset.HALF_PIXEL ) ), downsampledDimensions, cellDimensions ); diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleMemProfile.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleMemProfile.java index cff4291a5..b577503db 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleMemProfile.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleMemProfile.java @@ -42,7 +42,7 @@ import net.imglib2.RandomAccessibleInterval; import net.imglib2.algorithm.blocks.BlockAlgoUtils; import net.imglib2.algorithm.blocks.BlockSupplier; -import net.imglib2.algorithm.blocks.downsample.Downsample.ComputationType; +import net.imglib2.algorithm.blocks.ComputationType; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; import net.imglib2.cache.img.CachedCellImg; import net.imglib2.img.array.ArrayImgs; diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleUnsignedBytePlayground.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleUnsignedBytePlayground.java index 45a7dc38f..1b6a9fab4 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleUnsignedBytePlayground.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleUnsignedBytePlayground.java @@ -43,7 +43,7 @@ import java.util.Arrays; import net.imglib2.algorithm.blocks.BlockSupplier; -import net.imglib2.algorithm.blocks.downsample.Downsample.ComputationType; +import net.imglib2.algorithm.blocks.ComputationType; import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; import net.imglib2.algorithm.blocks.BlockAlgoUtils; import net.imglib2.cache.img.CachedCellImg; diff --git a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java index 274dea813..ae0ab159b 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java +++ b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java @@ -44,7 +44,7 @@ import net.imglib2.RealRandomAccessible; import net.imglib2.algorithm.blocks.BlockProcessor; import net.imglib2.algorithm.blocks.ClampType; -import net.imglib2.algorithm.blocks.transform.Transform.ComputationType; +import net.imglib2.algorithm.blocks.ComputationType; import net.imglib2.algorithm.blocks.transform.Transform.Interpolation; import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.converter.Converters; From 6a0d71155d65a0bb3e8a7a1b601972f86de978fd Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Tue, 3 Sep 2024 05:33:42 +0200 Subject: [PATCH 18/24] New BlockAvg Downsample variants downsample by averaging over arbitrarily sized blocks (like in BDV export) --- .../AbstractDownsampleAvgBlock.java | 118 ++++++++++ .../blocks/downsample/Downsample.java | 208 +++++++++++++++--- .../downsample/DownsampleBlockProcessors.java | 202 ++++++++++++++++- .../downsample/DownsampleARGBPlayground.java | 100 +++++++++ .../DownsampleAvgBdvPlayground.java | 100 +++++++++ .../downsample/DownsampleBenchmarkFull2.java | 154 +++++++++++++ 6 files changed, 853 insertions(+), 29 deletions(-) create mode 100644 src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleAvgBlock.java create mode 100644 src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleARGBPlayground.java create mode 100644 src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleAvgBdvPlayground.java create mode 100644 src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull2.java diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleAvgBlock.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleAvgBlock.java new file mode 100644 index 000000000..7943acaa0 --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleAvgBlock.java @@ -0,0 +1,118 @@ +/*- + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package net.imglib2.algorithm.blocks.downsample; + +import static net.imglib2.util.Util.safeInt; + +import java.util.Arrays; + +import net.imglib2.Interval; +import net.imglib2.algorithm.blocks.BlockProcessor; +import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; +import net.imglib2.blocks.TempArray; +import net.imglib2.type.PrimitiveType; +import net.imglib2.util.Intervals; + +abstract class AbstractDownsampleAvgBlock< T extends AbstractDownsampleAvgBlock< T, P >, P > extends AbstractDownsample< T, P > +{ + final int[] downsamplingFactors; + + AbstractDownsampleAvgBlock( final int[] downsamplingFactors, final PrimitiveType primitiveType ) + { + super( downsampleInDim( downsamplingFactors ), primitiveType ); + this.downsamplingFactors = downsamplingFactors; + } + + private static boolean[] downsampleInDim( final int[] downsamplingFactors ) + { + final int n = downsamplingFactors.length; + final boolean[] downsampleInDim = new boolean[ n ]; + for ( int d = 0; d < n; d++ ) + { + if ( downsamplingFactors[ d ] < 1 ) + throw new IllegalArgumentException(); + downsampleInDim[ d ] = ( downsamplingFactors[ d ] > 1 ); + } + return downsampleInDim; + } + + AbstractDownsampleAvgBlock( T downsample ) + { + super( downsample ); + downsamplingFactors = downsample.downsamplingFactors; + } + + @Override + public void setTargetInterval( final Interval interval ) + { + boolean destSizeChanged = false; + for ( int d = 0; d < n; ++d ) + { + final long tpos = interval.min( d ); + sourcePos[ d ] = tpos * downsamplingFactors[ d ]; + + final int tdim = safeInt( interval.dimension( d ) ); + if ( tdim != destSize[ d ] ) + { + destSize[ d ] = tdim; + sourceSize[ d ] = tdim * downsamplingFactors[ d ]; + destSizeChanged = true; + } + } + + if ( destSizeChanged ) + recomputeTempArraySizes(); + } + + @Override + public void setTargetInterval( final long[] pos, final int[] size ) + { + boolean destSizeChanged = false; + for ( int d = 0; d < n; ++d ) + { + sourcePos[ d ] = pos[ d ] * downsamplingFactors[ d ]; + + final int tdim = safeInt( size[ d ] ); + if ( tdim != destSize[ d ] ) + { + destSize[ d ] = tdim; + sourceSize[ d ] = tdim * downsamplingFactors[ d ]; + destSizeChanged = true; + } + } + + if ( destSizeChanged ) + recomputeTempArraySizes(); + } +} diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java index 07e08a3c3..3cb5d93ed 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/Downsample.java @@ -39,6 +39,8 @@ import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.algorithm.blocks.ComputationType; +import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.AvgBlockDouble; +import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.AvgBlockFloat; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterDouble; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.CenterFloat; import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.HalfPixelDouble; @@ -103,7 +105,11 @@ * pixels are centered on input pixels. * * - * + *

+ * The {@link #downsample(ComputationType, int[])} methods support downsampling + * with arbitrary integer factor by averaging blocks of pixels. (With {@code + * factors={2,2,2,...}}, this is equivalent to downsampling with {@link + * Offset#HALF_PIXEL}). */ public class Downsample { @@ -152,6 +158,34 @@ public static long[] getDownsampledDimensions( final long[] imgDimensions, final return destSize; } + /** + * Returns recommended size of the downsampled image, given an input image + * of size {@code imgDimensions}. In each dimension, the recommended size is + * input {@code imgDimension} / {@code downsamplingFactor}, rounding up + * (e.g., a 5 pixel input image downsampled with factor 2, should yield a 3 + * pixel image). + * + * @param imgDimensions + * dimensions of the input image + * @param downsamplingFactors + * in each dimension {@code d}, {@code downsamplingFactors[d]} + * pixels in the input image should be averaged to one output pixel. + * {@code downsamplingFactors} is expanded or truncated to the + * necessary size. For example, if {@code downsamplingFactors=={2,2,1}} and + * the operator is applied to a 2D image, {@code downsamplingFactors} is + * truncated to {@code {2, 2}}. If the operator is applied to a 5D image, + * {@code downsamplingFactors} is expanded to {@code {2, 2, 1, 1, 1}} + * + * @return the recommended size of the downsampled image + */ + public static long[] getDownsampledDimensions( final long[] imgDimensions, final int[] downsamplingFactors ) + { + final int[] dFactorsX = Util.expandArray( downsamplingFactors, imgDimensions.length ); + final long[] destSize = new long[ imgDimensions.length ]; + Arrays.setAll( destSize, d -> ( imgDimensions[ d ] + dFactorsX[ d ] - 1 ) / dFactorsX[ d ] ); + return destSize; + } + /** * Specify where downsampled pixels should be placed. */ @@ -335,6 +369,82 @@ Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > downsample( final Com }; } + /** + * Downsample (by the given {@code downsamplingFactors}) blocks of the + * standard ImgLib2 {@code RealType}s. + *

+ * Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, + * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code + * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). + *

+ * Precision for intermediate values is chosen as to represent the + * input/output type without loss of precision. That is, {@code FLOAT} for + * u8, i8, u16, i16, i32, f32, and otherwise {@code DOUBLE} for u32, i64, + * f64. + *

+ * The returned factory function creates an operator matching the + * type and dimensionality of a given input {@code BlockSupplier}. + * + * @param downsamplingFactors + * in each dimension {@code d}, {@code downsamplingFactors[d]} + * pixels in the input image should be averaged to one output pixel. + * {@code downsamplingFactors} is expanded or truncated to the + * necessary size. For example, if {@code downsamplingFactors=={2,2,1}} and + * the operator is applied to a 2D image, {@code downsamplingFactors} is + * truncated to {@code {2, 2}}. If the operator is applied to a 5D image, + * {@code downsamplingFactors} is expanded to {@code {2, 2, 1, 1, 1}} + * @param + * the input/output type + * + * @return factory for {@code UnaryBlockOperator} to downsample blocks of type {@code T} + */ + public static < T extends NativeType< T > > + Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > downsample( final int[] downsamplingFactors ) + { + return downsample( ComputationType.AUTO, downsamplingFactors ); + } + + /** + * Downsample (by the given {@code downsamplingFactors}) blocks of the + * standard ImgLib2 {@code RealType}s. + *

+ * Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, + * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code + * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). + *

+ * The returned factory function creates an operator matching the + * type and dimensionality of a given input {@code BlockSupplier}. + * + * @param computationType + * specifies in which precision intermediate values should be + * computed. For {@code AUTO}, the type that can represent the + * input/output type without loss of precision is picked. That is, + * {@code FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code + * DOUBLE} for u32, i64, f64. + * @param downsamplingFactors + * in each dimension {@code d}, {@code downsamplingFactors[d]} + * pixels in the input image should be averaged to one output pixel. + * {@code downsamplingFactors} is expanded or truncated to the + * necessary size. For example, if {@code downsamplingFactors=={2,2,1}} and + * the operator is applied to a 2D image, {@code downsamplingFactors} is + * truncated to {@code {2, 2}}. If the operator is applied to a 5D image, + * {@code downsamplingFactors} is expanded to {@code {2, 2, 1, 1, 1}} + * @param + * the input/output type + * + * @return factory for {@code UnaryBlockOperator} to downsample blocks of type {@code T} + */ + public static < T extends NativeType< T > > + Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > downsample( final ComputationType computationType, final int[] downsamplingFactors ) + { + return s -> { + final T type = s.getType(); + final int n = s.numDimensions(); + final int[] expandedDownsamplingFactors = Util.expandArray( downsamplingFactors, n ); + return createOperator( type, computationType, expandedDownsamplingFactors ); + }; + } + /** * Create a {@code UnaryBlockOperator} to downsample (by factor 2) blocks of * the standard ImgLib2 {@code RealType}. The {@code downsampleInDim} @@ -373,25 +483,45 @@ Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > downsample( final Com public static < T extends NativeType< T > > UnaryBlockOperator< T, T > createOperator( final T type, final ComputationType computationType, final Offset offset, final boolean[] downsampleInDim ) { - final boolean processAsFloat; + final UnaryBlockOperator< ?, ? > op = processAsFloat( computationType, type ) + ? downsampleFloat( offset, downsampleInDim ) + : downsampleDouble( offset, downsampleInDim ); + return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, ClampType.NONE ); + } + + private static < T extends NativeType< T > > boolean processAsFloat( final ComputationType computationType, final T type ) + { switch ( computationType ) { case FLOAT: - processAsFloat = true; - break; + return true; case DOUBLE: - processAsFloat = false; - break; - default: + return true; case AUTO: + default: final PrimitiveType pt = type.getNativeTypeFactory().getPrimitiveType(); - processAsFloat = pt.equals( FLOAT ) || pt.getByteCount() < FLOAT.getByteCount(); - break; + return pt.equals( FLOAT ) || pt.getByteCount() < FLOAT.getByteCount(); } - final UnaryBlockOperator< ?, ? > op = processAsFloat - ? downsampleFloat( offset, downsampleInDim ) - : downsampleDouble( offset, downsampleInDim ); - return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, ClampType.NONE ); + } + + private static UnaryBlockOperator< FloatType, FloatType > downsampleFloat( final Offset offset, final boolean[] downsampleInDim ) + { + final FloatType type = new FloatType(); + final int n = downsampleInDim.length; + return new DefaultUnaryBlockOperator<>( type, type, n, n, + offset == Offset.HALF_PIXEL + ? new HalfPixelFloat( downsampleInDim ) + : new CenterFloat( downsampleInDim ) ); + } + + private static UnaryBlockOperator< DoubleType, DoubleType > downsampleDouble( final Offset offset, final boolean[] downsampleInDim ) + { + final DoubleType type = new DoubleType(); + final int n = downsampleInDim.length; + return new DefaultUnaryBlockOperator<>( type, type, n, n, + offset == Offset.HALF_PIXEL + ? new HalfPixelDouble( downsampleInDim ) + : new CenterDouble( downsampleInDim ) ); } /** @@ -435,23 +565,51 @@ UnaryBlockOperator< T, T > createOperator( final T type, final ComputationType c return createOperator( type, computationType, offset, downsampleInDim ); } - private static UnaryBlockOperator< FloatType, FloatType > downsampleFloat( final Offset offset, final boolean[] downsampleInDim ) + /** + * Create a {@code UnaryBlockOperator} to downsample (by the given {@code + * downsamplingFactors}) blocks of the standard ImgLib2 {@code RealType}. + *

+ * Supported types are {@code UnsignedByteType}, {@code UnsignedShortType}, + * {@code UnsignedIntType}, {@code ByteType}, {@code ShortType}, {@code + * IntType}, {@code LongType}, {@code FloatType}, {@code DoubleType}). + * + * @param type + * instance of the input type + * @param computationType + * specifies in which precision intermediate values should be + * computed. For {@code AUTO}, the type that can represent the + * input/output type without loss of precision is picked. That is, + * {@code FLOAT} for u8, i8, u16, i16, i32, f32, and otherwise {@code + * DOUBLE} for u32, i64, f64. + * @param downsamplingFactors + * in each dimension {@code d}, {@code downsamplingFactors[d]} + * pixels in the input image should be averaged to one output pixel. + * @param + * the input/output type + * + * @return {@code UnaryBlockOperator} to downsample blocks of type {@code T} + */ + public static < T extends NativeType< T > > + UnaryBlockOperator< T, T > createOperator( final T type, final ComputationType computationType, final int[] downsamplingFactors ) + { + final UnaryBlockOperator< ?, ? > op = processAsFloat( computationType, type ) + ? downsampleFloat( downsamplingFactors ) + : downsampleDouble( downsamplingFactors ); + return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, ClampType.NONE ); + } + + private static UnaryBlockOperator< FloatType, FloatType > downsampleFloat( final int[] downsamplingFactors ) { final FloatType type = new FloatType(); - final int n = downsampleInDim.length; - return new DefaultUnaryBlockOperator<>( type, type, n, n, - offset == Offset.HALF_PIXEL - ? new HalfPixelFloat( downsampleInDim ) - : new CenterFloat( downsampleInDim ) ); + final int n = downsamplingFactors.length; + return new DefaultUnaryBlockOperator<>( type, type, n, n, new AvgBlockFloat( downsamplingFactors ) ); } - private static UnaryBlockOperator< DoubleType, DoubleType > downsampleDouble( final Offset offset, final boolean[] downsampleInDim ) + private static UnaryBlockOperator< DoubleType, DoubleType > downsampleDouble( final int[] downsamplingFactors ) { final DoubleType type = new DoubleType(); - final int n = downsampleInDim.length; - return new DefaultUnaryBlockOperator<>( type, type, n, n, - offset == Offset.HALF_PIXEL - ? new HalfPixelDouble( downsampleInDim ) - : new CenterDouble( downsampleInDim ) ); + final int n = downsamplingFactors.length; + return new DefaultUnaryBlockOperator<>( type, type, n, n, new AvgBlockDouble( downsamplingFactors ) ); } + } diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/DownsampleBlockProcessors.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/DownsampleBlockProcessors.java index b811a66eb..e1084db28 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/DownsampleBlockProcessors.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/DownsampleBlockProcessors.java @@ -11,13 +11,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 @@ -140,6 +140,58 @@ void downsample( final double[] source, final int[] destSize, final double[] des } } + static class AvgBlockFloat extends AbstractDownsampleAvgBlock< AvgBlockFloat, float[] > + { + public AvgBlockFloat( final int[] downsamplingFactors ) + { + super( downsamplingFactors, FLOAT ); + } + + private AvgBlockFloat( AvgBlockFloat downsample ) + { + super( downsample ); + } + + @Override + public BlockProcessor< float[], float[] > independentCopy() + { + return new AvgBlockFloat( this ); + } + + @Override + void downsample( final float[] source, final int[] destSize, final float[] dest, final int dim ) + { + final int factor = this.downsamplingFactors[ dim ]; + downsample_avgblock_float( source, destSize, dest, dim, factor ); + } + } + + static class AvgBlockDouble extends AbstractDownsampleAvgBlock< AvgBlockDouble, double[] > + { + public AvgBlockDouble( final int[] downsamplingFactors ) + { + super( downsamplingFactors, DOUBLE ); + } + + private AvgBlockDouble( AvgBlockDouble downsample ) + { + super( downsample ); + } + + @Override + public BlockProcessor< double[], double[] > independentCopy() + { + return new AvgBlockDouble( this ); + } + + @Override + void downsample( final double[] source, final int[] destSize, final double[] dest, final int dim ) + { + final int factor = this.downsamplingFactors[ dim ]; + downsample_avgblock_double( source, destSize, dest, dim, factor ); + } + } + private static void downsample_float( final float[] source, final int[] destSize, final float[] dest, final int dim ) { if ( dim == 0 ) @@ -268,7 +320,7 @@ private static void downsampleX_halfpixel_float( final float[] source, final int source[ 2 * x + 1 ] ); } - static void downsampleN_halfpixel_float( final float[] source, final int[] destSize, final float[] dest, final int dim ) + private static void downsampleN_halfpixel_float( final float[] source, final int[] destSize, final float[] dest, final int dim ) { int len0 = mulDims( destSize, 0, dim ); int len1 = mulDims( destSize, dim, destSize.length ); @@ -306,7 +358,7 @@ private static void downsampleX_halfpixel_double( final double[] source, final i source[ 2 * x + 1 ] ); } - static void downsampleN_halfpixel_double( final double[] source, final int[] destSize, final double[] dest, final int dim ) + private static void downsampleN_halfpixel_double( final double[] source, final int[] destSize, final double[] dest, final int dim ) { int len0 = mulDims( destSize, 0, dim ); int len1 = mulDims( destSize, dim, destSize.length ); @@ -327,6 +379,148 @@ private static double avg_double( final double a, final double b ) return 0.5 * ( a + b ); } + private static void downsample_avgblock_float( final float[] source, final int[] destSize, final float[] dest, final int dim, final int factor ) + { + if ( factor == 2 ) + downsample_halfpixel_float( source, destSize, dest, dim ); + else if ( dim == 0 ) + downsampleX_avgblock_float( source, destSize, dest, factor ); + else + downsampleN_avgblock_float( source, destSize, dest, dim, factor ); + } + + private static final int bw_float = 128; + + private static void downsampleX_avgblock_float( + final float[] source, final int[] destSize, final float[] dest, + final int factor ) + { + final float scale = ( float ) ( 1.0 / factor ); + final int len = mulDims( destSize, 0, destSize.length ); + + final int nBlocks = ( len - 1 ) / bw_float + 1; + final int trailing = len - ( nBlocks - 1 ) * bw_float; + for ( int b = 0; b < nBlocks; ++b ) + { + final int tob = b * bw_float; + final int bwb = ( b == nBlocks - 1 ) ? trailing : bw_float; + + final int sob = factor * tob; + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] = source[ sob + factor * x ]; + for ( int i = 1; i < factor; ++i ) + { + final int sobi = sob + i; + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] += source[ sobi + factor * x ]; + } + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] *= scale; + } + } + + private static void downsampleN_avgblock_float( + final float[] source, final int[] destSize, final float[] dest, + final int dim, final int factor ) + { + final float scale = ( float ) ( 1.0 / factor ); + int len0 = mulDims( destSize, 0, dim ); + int len1 = mulDims( destSize, dim, destSize.length ); + + final int nBlocks = ( len0 - 1 ) / bw_float + 1; + final int trailing = len0 - ( nBlocks - 1 ) * bw_float; + for ( int y = 0; y < len1; ++y ) + { + final int destOffset = y * len0; + for ( int b = 0; b < nBlocks; ++b ) + { + final int tob = b * bw_float + destOffset; + final int bwb = ( b == nBlocks - 1 ) ? trailing : bw_float; + final int sob = factor * destOffset + b * bw_float; + System.arraycopy( source, sob, dest, tob, bwb ); + for ( int i = 1; i < factor; ++i ) + { + final int sobi = sob + i * len0; + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] += source[ sobi + x ]; + } + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] *= scale; + } + } + } + + private static void downsample_avgblock_double( final double[] source, final int[] destSize, final double[] dest, final int dim, final int factor ) + { + if ( factor == 2 ) + downsample_halfpixel_double( source, destSize, dest, dim ); + else if ( dim == 0 ) + downsampleX_avgblock_double( source, destSize, dest, factor ); + else + downsampleN_avgblock_double( source, destSize, dest, dim, factor ); + } + + private static final int bw_double = 64; + + private static void downsampleX_avgblock_double( + final double[] source, final int[] destSize, final double[] dest, + final int factor ) + { + final double scale = ( double ) ( 1.0 / factor ); + final int len = mulDims( destSize, 0, destSize.length ); + + final int nBlocks = ( len - 1 ) / bw_double + 1; + final int trailing = len - ( nBlocks - 1 ) * bw_double; + for ( int b = 0; b < nBlocks; ++b ) + { + final int tob = b * bw_double; + final int bwb = ( b == nBlocks - 1 ) ? trailing : bw_double; + + final int sob = factor * tob; + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] = source[ sob + factor * x ]; + for ( int i = 1; i < factor; ++i ) + { + final int sobi = sob + i; + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] += source[ sobi + factor * x ]; + } + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] *= scale; + } + } + + private static void downsampleN_avgblock_double( + final double[] source, final int[] destSize, final double[] dest, + final int dim, final int factor ) + { + final double scale = ( double ) ( 1.0 / factor ); + int len0 = mulDims( destSize, 0, dim ); + int len1 = mulDims( destSize, dim, destSize.length ); + + final int nBlocks = ( len0 - 1 ) / bw_double + 1; + final int trailing = len0 - ( nBlocks - 1 ) * bw_double; + for ( int y = 0; y < len1; ++y ) + { + final int destOffset = y * len0; + for ( int b = 0; b < nBlocks; ++b ) + { + final int tob = b * bw_double + destOffset; + final int bwb = ( b == nBlocks - 1 ) ? trailing : bw_double; + final int sob = factor * destOffset + b * bw_double; + System.arraycopy( source, sob, dest, tob, bwb ); + for ( int i = 1; i < factor; ++i ) + { + final int sobi = sob + i * len0; + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] += source[ sobi + x ]; + } + for ( int x = 0; x < bwb; ++x ) + dest[ tob + x ] *= scale; + } + } + } + private static int mulDims( int[] dims, int from, int to ) { int product = 1; diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleARGBPlayground.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleARGBPlayground.java new file mode 100644 index 000000000..24acd8634 --- /dev/null +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleARGBPlayground.java @@ -0,0 +1,100 @@ +/*- + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package net.imglib2.algorithm.blocks.downsample; + +import java.util.Arrays; + +import bdv.cache.SharedQueue; +import bdv.util.Bdv; +import bdv.util.BdvFunctions; +import bdv.util.BdvSource; +import bdv.util.volatiles.VolatileViews; +import bdv.viewer.DisplayMode; +import ij.IJ; +import ij.ImagePlus; +import net.imglib2.algorithm.blocks.BlockAlgoUtils; +import net.imglib2.algorithm.blocks.BlockSupplier; +import net.imglib2.algorithm.blocks.downsample.Downsample.Offset; +import net.imglib2.img.Img; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.type.NativeType; +import net.imglib2.type.numeric.ARGBType; +import net.imglib2.type.numeric.integer.UnsignedByteType; +import net.imglib2.view.Views; + +public class DownsampleARGBPlayground +{ + public static void main( String[] args ) + { + System.setProperty("apple.laf.useScreenMenuBar", "true"); + + final String fn = "/Users/pietzsch/workspace/data/first-instar-brain.tif"; + final ImagePlus imp = IJ.openImage( fn ); + final Img< ARGBType > img = ImageJFunctions.wrapRGBA( imp ); + + final BdvSource bdv = BdvFunctions.show( + img, + "img", + Bdv.options() ); + bdv.setDisplayRange( 0, 255 ); + + final boolean[] downsampleInDim = { true, true, true }; + final long[] downsampledDimensions = Downsample.getDownsampledDimensions( img.dimensionsAsLongArray(), downsampleInDim ); + final int[] cellDimensions = { 64, 64, 64 }; + + final double[] calib = new double[ 3 ]; + Arrays.setAll(calib, d -> downsampleInDim[ d ] ? 2 : 1 ); + + BlockSupplier< ARGBType > blocks = BlockSupplier + .of( Views.extendMirrorDouble( img ) ) + .andThen( Downsample.downsample( Offset.HALF_PIXEL ) ) + .tile( 16 ); + + final Img< ARGBType > downsampled = BlockAlgoUtils.cellImg( + blocks, + downsampledDimensions, + cellDimensions ); + + final BdvSource out = BdvFunctions.show( + VolatileViews.wrapAsVolatile( downsampled, new SharedQueue( 32, 1 ) ), + "downsampled half-pixel", + Bdv.options() + .addTo( bdv ) + .sourceTransform( calib ) + ); + out.setDisplayRange( 0, 255 ); + + + } +} diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleAvgBdvPlayground.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleAvgBdvPlayground.java new file mode 100644 index 000000000..2b516b9b7 --- /dev/null +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleAvgBdvPlayground.java @@ -0,0 +1,100 @@ +/*- + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package net.imglib2.algorithm.blocks.downsample; + +import java.util.Arrays; + +import bdv.cache.SharedQueue; +import bdv.util.Bdv; +import bdv.util.BdvFunctions; +import bdv.util.BdvSource; +import bdv.util.volatiles.VolatileViews; +import bdv.viewer.DisplayMode; +import ij.IJ; +import ij.ImagePlus; +import net.imglib2.algorithm.blocks.BlockAlgoUtils; +import net.imglib2.algorithm.blocks.BlockSupplier; +import net.imglib2.algorithm.blocks.ComputationType; +import net.imglib2.img.Img; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.type.numeric.ARGBType; +import net.imglib2.type.numeric.integer.UnsignedByteType; +import net.imglib2.view.Views; + +public class DownsampleAvgBdvPlayground +{ + public static void main( String[] args ) + { + System.setProperty("apple.laf.useScreenMenuBar", "true"); + + final String fn = "/Users/pietzsch/workspace/data/e002_stack_fused-8bit.tif"; + final ImagePlus imp = IJ.openImage( fn ); + final Img< UnsignedByteType > img = ImageJFunctions.wrapByte( imp ); + + final BdvSource bdv = BdvFunctions.show( + img, + "img", + Bdv.options() ); + bdv.setColor( new ARGBType( 0xffffff ) ); + bdv.setDisplayRange( 0, 255 ); + bdv.getBdvHandle().getViewerPanel().setDisplayMode( DisplayMode.SINGLE ); + + final int[] downsamplingFactors = { 3, 3, 2 }; + final long[] downsampledDimensions = Downsample.getDownsampledDimensions( img.dimensionsAsLongArray(), downsamplingFactors ); + final int[] cellDimensions = { 64, 64, 64 }; + + final double[] calib = new double[ 3 ]; + Arrays.setAll(calib, d -> downsamplingFactors[ d ] ); + + BlockSupplier< UnsignedByteType > blocks = BlockSupplier + .of( Views.extendMirrorDouble( img ) ) + .andThen( Downsample.downsample( ComputationType.FLOAT, downsamplingFactors ) ) + .tile( 16 ); + + final Img< UnsignedByteType > downsampled = BlockAlgoUtils.cellImg( + blocks, + downsampledDimensions, + cellDimensions ); + + final BdvSource out = BdvFunctions.show( + VolatileViews.wrapAsVolatile( downsampled, new SharedQueue( 32, 1 ) ), + "downsampled avg-block", + Bdv.options() + .addTo( bdv ) + .sourceTransform( calib ) + ); + out.setDisplayRange( 0, 255 ); + out.setColor( new ARGBType( 0x00ff00 ) ); + } +} diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull2.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull2.java new file mode 100644 index 000000000..05e147dee --- /dev/null +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull2.java @@ -0,0 +1,154 @@ +/*- + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package net.imglib2.algorithm.blocks.downsample; + +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import net.imglib2.FinalInterval; +import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.AvgBlockFloat; +import net.imglib2.algorithm.blocks.downsample.DownsampleBlockProcessors.HalfPixelFloat; +import net.imglib2.util.Intervals; +import net.imglib2.util.Util; + +@State( Scope.Benchmark ) +@Warmup( iterations = 10, time = 100, timeUnit = TimeUnit.MILLISECONDS ) +@Measurement( iterations = 20, time = 100, timeUnit = TimeUnit.MILLISECONDS ) +@BenchmarkMode( Mode.AverageTime ) +@OutputTimeUnit( TimeUnit.MILLISECONDS ) +@Fork( 1 ) +public class DownsampleBenchmarkFull2 +{ + int[] imgSize; + + int[] outputSize; + int[] inputSize; + float[] inputF; + float[] outputF; + HalfPixelFloat halfPixelFloat; + AvgBlockFloat avgBlockFloat; + +// @Param( { "X", "Y", "Z", "XYZ" } ) + @Param( { "XYZ" } ) +// @Param( { "Z" } ) + public String scenario; + +// @Param( { "128", "256", "512" } ) + @Param( { "128" } ) + public int size; + + + @Setup(Level.Trial) + public void setUp() { + final Random random = new Random( 1 ); + + final int n = 3; + inputSize = new int[ n ]; + outputSize = new int[ n ]; + + boolean[] downsampleInDim = null; + switch ( scenario ) + { + case "X": + downsampleInDim = new boolean[] { true, false, false }; + break; + case "Y": + downsampleInDim = new boolean[] { false, true, false }; + break; + case "Z": + downsampleInDim = new boolean[] { false, false, true }; + break; + case "XYZ": + downsampleInDim = new boolean[] { true, true, true }; + break; + } + int[] downsamplingFactors = new int[ downsampleInDim.length ]; + for ( int d = 0; d < downsamplingFactors.length; d++ ) + downsamplingFactors[ d ] = downsampleInDim[ d ] ? 2 : 1; + + imgSize = new int[] { size, size, size }; + + final long[] destSize = Downsample.getDownsampledDimensions( Util.int2long( imgSize ), downsampleInDim ); + System.out.println( "destSize = " + Arrays.toString( destSize ) ); + Arrays.setAll( outputSize, d -> ( int ) destSize[ d ] ); + + halfPixelFloat = new HalfPixelFloat( downsampleInDim ); + halfPixelFloat.setTargetInterval( new FinalInterval( Util.int2long( outputSize ) ) ); + + System.arraycopy( halfPixelFloat.getSourceSize(), 0, inputSize, 0, inputSize.length ); + inputF = new float[ ( int ) Intervals.numElements( inputSize ) ]; + for ( int i = 0; i < inputF.length; i++ ) + inputF[ i ] = random.nextFloat(); + outputF = new float[ ( int ) Intervals.numElements( outputSize ) ]; + + avgBlockFloat = new AvgBlockFloat( downsamplingFactors ); + avgBlockFloat.setTargetInterval( new FinalInterval( Util.int2long( outputSize ) ) ); + } + +// @Benchmark + public void benchmarkHalfPixelFloat() + { + halfPixelFloat.compute( inputF, outputF ); + } + + @Benchmark + public void benchmarkAvgBlockFloat() + { + avgBlockFloat.compute( inputF, outputF ); + } + + public static void main( String... args ) throws RunnerException + { + Options options = new OptionsBuilder().include( DownsampleBenchmarkFull2.class.getSimpleName() + "\\." ).build(); + new Runner( options ).run(); + } +} From 8e793cccc5c5b56f965de7b09fdfba98d6fa0072 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Wed, 11 Sep 2024 10:57:02 +0200 Subject: [PATCH 19/24] fix javadoc --- .../net/imglib2/algorithm/blocks/UnaryBlockOperator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java index 9dfef4150..0010986b9 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java @@ -80,7 +80,7 @@ public interface UnaryBlockOperator< S extends NativeType< S >, T extends Native *

* Some operators can be applied to arbitrary dimensions, e.g., converters. * In this case, they should return {@code numSourceDimensions() <= 0}. It - * is expected that these operators do not modify the number dimensions, + * is expected that these operators do not modify the number of dimensions, * that is, when such an operator is applied to a 3D block, the result is * also a 3D block. * @@ -93,11 +93,11 @@ public interface UnaryBlockOperator< S extends NativeType< S >, T extends Native *

* Some operators can be applied to arbitrary dimensions, e.g., converters. * In this case, they should return {@code numTargetDimensions() <= 0}. It - * is expected that these operators do not modify the number dimensions, + * is expected that these operators do not modify the number of dimensions, * that is, when such an operator is applied to a 3D block, the result is * also a 3D block. * - * @return the number of source dimensions + * @return the number of target dimensions */ int numTargetDimensions(); From bc74610254ce1134204a859fd7d065e0b5f3583d Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Wed, 11 Sep 2024 10:59:30 +0200 Subject: [PATCH 20/24] Add No-Op UnaryBlockOperator that is used when converting type to itself --- .../algorithm/blocks/BlockSupplier.java | 12 ++- .../blocks/NoOpUnaryBlockOperator.java | 97 +++++++++++++++++++ .../algorithm/blocks/UnaryBlockOperator.java | 3 + .../algorithm/blocks/convert/Convert.java | 5 + 4 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/imglib2/algorithm/blocks/NoOpUnaryBlockOperator.java diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java index 09d9b3f14..3a2e5818b 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java @@ -45,6 +45,7 @@ import net.imglib2.Typed; import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.type.NativeType; +import net.imglib2.util.Cast; import net.imglib2.util.Util; public interface BlockSupplier< T extends NativeType< T > > extends Typed< T >, EuclideanSpace @@ -144,12 +145,19 @@ default BlockSupplier< T > tile( int... tileSize ) */ default < U extends NativeType< U > > BlockSupplier< U > andThen( UnaryBlockOperator< T, U > operator ) { - return new ConcatenatedBlockSupplier<>( this.independentCopy(), operator.independentCopy() ); + if ( operator instanceof NoOpUnaryBlockOperator ) + return Cast.unchecked( this ); + else + return new ConcatenatedBlockSupplier<>( this.independentCopy(), operator.independentCopy() ); } default < U extends NativeType< U > > BlockSupplier< U > andThen( Function< BlockSupplier< T >, UnaryBlockOperator< T, U > > function ) { - return new ConcatenatedBlockSupplier<>( this.independentCopy(), function.apply( this ) ); + final UnaryBlockOperator< T, U > op = function.apply( this ); + if ( op instanceof NoOpUnaryBlockOperator ) + return Cast.unchecked( this ); + else + return new ConcatenatedBlockSupplier<>( this.independentCopy(), op ); } /** diff --git a/src/main/java/net/imglib2/algorithm/blocks/NoOpUnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/NoOpUnaryBlockOperator.java new file mode 100644 index 000000000..cf6b123ea --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/NoOpUnaryBlockOperator.java @@ -0,0 +1,97 @@ +/*- + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2024 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package net.imglib2.algorithm.blocks; + +import java.util.function.Supplier; + +import net.imglib2.type.NativeType; +import net.imglib2.util.Cast; +import net.imglib2.util.CloseableThreadLocal; + +/** + * Does nothing. This should be eliminated when concatenating through + * {@link UnaryBlockOperator#andThen(UnaryBlockOperator)} or {@link BlockSupplier#andThen(UnaryBlockOperator)}. + * + * @param + */ +public class NoOpUnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > implements UnaryBlockOperator< S, T > +{ + @Override + public < I, O > BlockProcessor< I, O > blockProcessor() + { + throw new UnsupportedOperationException(); + } + + @Override + public < U extends NativeType< U > > UnaryBlockOperator< S, U > andThen( UnaryBlockOperator< T, U > op ) + { + return Cast.unchecked( op ); + } + + @Override + public S getSourceType() + { + throw new UnsupportedOperationException(); + } + + @Override + public T getTargetType() + { + throw new UnsupportedOperationException(); + } + + @Override + public int numSourceDimensions() + { + return 0; + } + + @Override + public int numTargetDimensions() + { + return 0; + } + + @Override + public UnaryBlockOperator< S, T > independentCopy() + { + return this; + } + + @Override + public UnaryBlockOperator< S, T > threadSafe() + { + return this; + } +} diff --git a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java index 0010986b9..0c2f31b91 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java @@ -120,6 +120,9 @@ public interface UnaryBlockOperator< S extends NativeType< S >, T extends Native */ default < U extends NativeType< U > > UnaryBlockOperator< S, U > andThen( UnaryBlockOperator< T, U > op ) { + if ( op instanceof NoOpUnaryBlockOperator ) + return Cast.unchecked( this ); + final boolean thisHasDimensions = numSourceDimensions() > 0; final boolean opHasDimensions = op.numSourceDimensions() > 0; if ( opHasDimensions && thisHasDimensions && numTargetDimensions() != op.numSourceDimensions() ) { diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java index d57e406b2..efff1ad31 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java @@ -33,12 +33,14 @@ */ package net.imglib2.algorithm.blocks.convert; +import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.ClampType; import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator; +import net.imglib2.algorithm.blocks.NoOpUnaryBlockOperator; import net.imglib2.algorithm.blocks.UnaryBlockOperator; import net.imglib2.converter.Converter; import net.imglib2.type.NativeType; @@ -167,6 +169,9 @@ UnaryBlockOperator< S, T > createOperator( final S sourceType, final T targetTyp public static < S extends NativeType< S >, T extends NativeType< T > > UnaryBlockOperator< S, T > createOperator( final S sourceType, final T targetType, final ClampType clamp ) { + if ( Objects.equals( sourceType.getClass(), targetType.getClass() ) ) + return new NoOpUnaryBlockOperator<>(); + return new DefaultUnaryBlockOperator<>( sourceType, targetType, 0, 0, new ConvertBlockProcessor<>( sourceType, targetType, clamp ) ); From 4546a8a11932aaa338474daaa7a1e787bace4839 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Wed, 11 Sep 2024 10:59:58 +0200 Subject: [PATCH 21/24] Pull BlockSupplier.threadSafe() implementation into AbstractBlockSupplier --- .../blocks/AbstractBlockSupplier.java | 54 +++++++++++++++++++ .../blocks/ConcatenatedBlockSupplier.java | 50 ++--------------- .../blocks/PrimitiveBlocksSupplier.java | 50 ++--------------- .../algorithm/blocks/TilingBlockSupplier.java | 46 +--------------- 4 files changed, 61 insertions(+), 139 deletions(-) create mode 100644 src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java diff --git a/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java new file mode 100644 index 000000000..df35e3784 --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java @@ -0,0 +1,54 @@ +package net.imglib2.algorithm.blocks; + +import java.util.function.Supplier; + +import net.imglib2.type.NativeType; +import net.imglib2.util.CloseableThreadLocal; + +/** + * Implements {@link BlockSupplier#threadSafe()} as a wrapper that makes {@link + * ThreadLocal} {@link BlockSupplier#independentCopy()} copies. + */ +public abstract class AbstractBlockSupplier< T extends NativeType< T > > implements BlockSupplier< T > +{ + private Supplier< BlockSupplier< T > > threadSafeSupplier; + + @Override + public BlockSupplier< T > threadSafe() + { + if ( threadSafeSupplier == null ) + threadSafeSupplier = CloseableThreadLocal.withInitial( this::independentCopy )::get; + return new BlockSupplier< T >() + { + @Override + public T getType() + { + return AbstractBlockSupplier.this.getType(); + } + + @Override + public int numDimensions() + { + return AbstractBlockSupplier.this.numDimensions(); + } + + @Override + public void copy( final long[] srcPos, final Object dest, final int[] size ) + { + threadSafeSupplier.get().copy( srcPos, dest, size ); + } + + @Override + public BlockSupplier< T > independentCopy() + { + return AbstractBlockSupplier.this.independentCopy().threadSafe(); + } + + @Override + public BlockSupplier< T > threadSafe() + { + return this; + } + }; + } +} diff --git a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java index a071b0222..f217b958d 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java @@ -11,13 +11,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 @@ -33,13 +33,10 @@ */ package net.imglib2.algorithm.blocks; -import java.util.function.Supplier; - import net.imglib2.type.NativeType; import net.imglib2.util.Cast; -import net.imglib2.util.CloseableThreadLocal; -class ConcatenatedBlockSupplier< T extends NativeType< T > > implements BlockSupplier< T > +class ConcatenatedBlockSupplier< T extends NativeType< T > > extends AbstractBlockSupplier< T > { private final BlockSupplier< ? > p0; @@ -49,8 +46,6 @@ class ConcatenatedBlockSupplier< T extends NativeType< T > > implements BlockSup private final int numDimensions; - private Supplier< BlockSupplier< T > > threadSafeSupplier; - public < S extends NativeType< S > > ConcatenatedBlockSupplier( final BlockSupplier< S > srcSupplier, final UnaryBlockOperator< S, T > operator ) @@ -104,43 +99,4 @@ public BlockSupplier< T > independentCopy() { return new ConcatenatedBlockSupplier<>( this ); } - - @Override - public BlockSupplier< T > threadSafe() - { - if ( threadSafeSupplier == null ) - threadSafeSupplier = CloseableThreadLocal.withInitial( this::independentCopy )::get; - return new BlockSupplier< T >() - { - @Override - public T getType() - { - return type; - } - - @Override - public int numDimensions() - { - return numDimensions; - } - - @Override - public void copy( final long[] srcPos, final Object dest, final int[] size ) - { - threadSafeSupplier.get().copy( srcPos, dest, size ); - } - - @Override - public BlockSupplier< T > independentCopy() - { - return ConcatenatedBlockSupplier.this.independentCopy().threadSafe(); - } - - @Override - public BlockSupplier< T > threadSafe() - { - return this; - } - }; - } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java index debd5b9b8..ca4696a4a 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java @@ -11,13 +11,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 @@ -33,18 +33,13 @@ */ package net.imglib2.algorithm.blocks; -import java.util.function.Supplier; - import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.type.NativeType; -import net.imglib2.util.CloseableThreadLocal; -class PrimitiveBlocksSupplier< T extends NativeType< T > > implements BlockSupplier< T > +class PrimitiveBlocksSupplier< T extends NativeType< T > > extends AbstractBlockSupplier< T > { private final PrimitiveBlocks< T > blocks; - private Supplier< BlockSupplier< T > > threadSafeSupplier; - PrimitiveBlocksSupplier( final PrimitiveBlocks< T > blocks ) { this.blocks = blocks; @@ -80,43 +75,4 @@ public BlockSupplier< T > independentCopy() final PrimitiveBlocks< T > blocksCopy = blocks.independentCopy(); return blocksCopy == blocks ? this : new PrimitiveBlocksSupplier<>( blocksCopy ); } - - @Override - public BlockSupplier< T > threadSafe() - { - if ( threadSafeSupplier == null ) - threadSafeSupplier = CloseableThreadLocal.withInitial( this::independentCopy )::get; - return new BlockSupplier< T >() - { - @Override - public T getType() - { - return blocks.getType(); - } - - @Override - public int numDimensions() - { - return blocks.numDimensions(); - } - - @Override - public void copy( final long[] srcPos, final Object dest, final int[] size ) - { - threadSafeSupplier.get().copy( srcPos, dest, size ); - } - - @Override - public BlockSupplier< T > independentCopy() - { - return PrimitiveBlocksSupplier.this.independentCopy().threadSafe(); - } - - @Override - public BlockSupplier< T > threadSafe() - { - return this; - } - }; - } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java index 783e5061d..f9113e562 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java @@ -33,14 +33,11 @@ */ package net.imglib2.algorithm.blocks; -import java.util.function.Supplier; - import net.imglib2.blocks.SubArrayCopy; import net.imglib2.blocks.TempArray; import net.imglib2.type.NativeType; import net.imglib2.type.PrimitiveType; import net.imglib2.util.Cast; -import net.imglib2.util.CloseableThreadLocal; import net.imglib2.util.Intervals; import net.imglib2.util.Util; @@ -70,7 +67,7 @@ * @param

* corresponding primitive array type */ -class TilingBlockSupplier< T extends NativeType< T >, P > implements BlockSupplier< T > +class TilingBlockSupplier< T extends NativeType< T >, P > extends AbstractBlockSupplier< T > { private final BlockSupplier< T > p0; @@ -83,8 +80,6 @@ class TilingBlockSupplier< T extends NativeType< T >, P > implements BlockSuppli private final SubArrayCopy.Typed< P, P > subArrayCopy; - private Supplier< BlockSupplier< T > > threadSafeSupplier; - final int[] tile_pos_in_dest; final long[] tile_pos_in_src; final int[] tile_origin; @@ -202,43 +197,4 @@ public BlockSupplier< T > independentCopy() { return new TilingBlockSupplier<>( this ); } - - @Override - public BlockSupplier< T > threadSafe() - { - if ( threadSafeSupplier == null ) - threadSafeSupplier = CloseableThreadLocal.withInitial( this::independentCopy )::get; - return new BlockSupplier< T >() - { - @Override - public T getType() - { - return p0.getType(); - } - - @Override - public int numDimensions() - { - return p0.numDimensions(); - } - - @Override - public void copy( final long[] srcPos, final Object dest, final int[] size ) - { - threadSafeSupplier.get().copy( srcPos, dest, size ); - } - - @Override - public BlockSupplier< T > independentCopy() - { - return TilingBlockSupplier.this.independentCopy().threadSafe(); - } - - @Override - public BlockSupplier< T > threadSafe() - { - return this; - } - }; - } } From c41149a583ac57710ac3abee1b4ac4b9854d938f Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Wed, 11 Sep 2024 11:55:12 +0200 Subject: [PATCH 22/24] Wrap BlockProcessor.setTargetInterval(long[] pos, int[] size) as Interval --- .../blocks/ConcatenatedBlockProcessor.java | 7 ------- .../blocks/convert/ConvertBlockProcessor.java | 14 ------------- .../convert/ConverterBlockProcessor.java | 14 ------------- .../blocks/downsample/AbstractDownsample.java | 21 ------------------- .../AbstractDownsampleAvgBlock.java | 21 ------------------- .../AbstractDownsampleHalfPixel.java | 21 ------------------- 6 files changed, 98 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java index ae06e25bd..6b2d26040 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java @@ -62,13 +62,6 @@ public void setTargetInterval( final Interval interval ) p0.setTargetInterval( p1.getSourceInterval() ); } - @Override - public void setTargetInterval( final long[] srcPos, final int[] size ) - { - p1.setTargetInterval( srcPos, size ); - p0.setTargetInterval( p1.getSourcePos(), p1.getSourceSize() ); - } - @Override public long[] getSourcePos() { diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java index efa579125..6a3c49c2c 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java @@ -103,20 +103,6 @@ public void setTargetInterval( final Interval interval ) sourceLength = safeInt( Intervals.numElements( sourceSize ) ); } - @Override - public void setTargetInterval( final long[] pos, final int[] size ) - { - final int n = pos.length; - if ( sourcePos == null || sourcePos.length != n ) - { - sourcePos = new long[ n ]; - sourceSize = new int[ n ]; - } - System.arraycopy( pos, 0, sourcePos, 0, n ); - System.arraycopy( size, 0, sourceSize, 0, n ); - sourceLength = safeInt( Intervals.numElements( sourceSize ) ); - } - @Override public long[] getSourcePos() { diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConverterBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConverterBlockProcessor.java index a3c751d92..515faff74 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConverterBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConverterBlockProcessor.java @@ -136,20 +136,6 @@ public void setTargetInterval( final Interval interval ) sourceLength = safeInt( Intervals.numElements( sourceSize ) ); } - @Override - public void setTargetInterval( final long[] pos, final int[] size ) - { - final int n = pos.length; - if ( sourcePos == null || sourcePos.length != n ) - { - sourcePos = new long[ n ]; - sourceSize = new int[ n ]; - } - System.arraycopy( pos, 0, sourcePos, 0, n ); - System.arraycopy( size, 0, sourceSize, 0, n ); - sourceLength = safeInt( Intervals.numElements( sourceSize ) ); - } - @Override public long[] getSourcePos() { diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsample.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsample.java index 558126c35..639f5c9c4 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsample.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsample.java @@ -166,27 +166,6 @@ protected void recomputeTempArraySizes() } } - @Override - public void setTargetInterval( final long[] pos, final int[] size ) - { - boolean destSizeChanged = false; - for ( int d = 0; d < n; ++d ) - { - sourcePos[ d ] = downsampleInDim[ d ] ? pos[ d ] * 2 - 1 : pos[ d ]; - - final int tdim = safeInt( size[ d ] ); - if ( tdim != destSize[ d ] ) - { - destSize[ d ] = tdim; - sourceSize[ d ] = downsampleInDim[ d ] ? tdim * 2 + 1 : tdim; - destSizeChanged = true; - } - } - - if ( destSizeChanged ) - recomputeTempArraySizes(); - } - @Override public int[] getSourceSize() { diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleAvgBlock.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleAvgBlock.java index 7943acaa0..93b58ab78 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleAvgBlock.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleAvgBlock.java @@ -94,25 +94,4 @@ public void setTargetInterval( final Interval interval ) if ( destSizeChanged ) recomputeTempArraySizes(); } - - @Override - public void setTargetInterval( final long[] pos, final int[] size ) - { - boolean destSizeChanged = false; - for ( int d = 0; d < n; ++d ) - { - sourcePos[ d ] = pos[ d ] * downsamplingFactors[ d ]; - - final int tdim = safeInt( size[ d ] ); - if ( tdim != destSize[ d ] ) - { - destSize[ d ] = tdim; - sourceSize[ d ] = tdim * downsamplingFactors[ d ]; - destSizeChanged = true; - } - } - - if ( destSizeChanged ) - recomputeTempArraySizes(); - } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleHalfPixel.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleHalfPixel.java index d7372e266..2a5daec58 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleHalfPixel.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsampleHalfPixel.java @@ -71,25 +71,4 @@ public void setTargetInterval( final Interval interval ) if ( destSizeChanged ) recomputeTempArraySizes(); } - - @Override - public void setTargetInterval( final long[] pos, final int[] size ) - { - boolean destSizeChanged = false; - for ( int d = 0; d < n; ++d ) - { - sourcePos[ d ] = downsampleInDim[ d ] ? pos[ d ] * 2 : pos[ d ]; - - final int tdim = safeInt( size[ d ] ); - if ( tdim != destSize[ d ] ) - { - destSize[ d ] = tdim; - sourceSize[ d ] = downsampleInDim[ d ] ? tdim * 2 : tdim; - destSizeChanged = true; - } - } - - if ( destSizeChanged ) - recomputeTempArraySizes(); - } } From 0ebbccc5ca65489758ab0dbbe2614fddd33fab41 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Wed, 11 Sep 2024 20:27:12 +0200 Subject: [PATCH 23/24] Add AbstractBlockProcessor to reduce boiler-plate in BlockProcessor implementations --- .../blocks/AbstractBlockProcessor.java | 96 +++++++++++++++ .../AbstractDimensionlessBlockProcessor.java | 111 ++++++++++++++++++ .../blocks/convert/ConvertBlockProcessor.java | 71 ++--------- .../convert/ConverterBlockProcessor.java | 71 ++--------- .../blocks/downsample/AbstractDownsample.java | 45 ++----- .../transform/AbstractTransformProcessor.java | 58 ++------- 6 files changed, 238 insertions(+), 214 deletions(-) create mode 100644 src/main/java/net/imglib2/algorithm/blocks/AbstractBlockProcessor.java create mode 100644 src/main/java/net/imglib2/algorithm/blocks/AbstractDimensionlessBlockProcessor.java diff --git a/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockProcessor.java new file mode 100644 index 000000000..a15ecad19 --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockProcessor.java @@ -0,0 +1,96 @@ +package net.imglib2.algorithm.blocks; + +import static net.imglib2.util.Util.safeInt; + +import java.util.Arrays; + +import net.imglib2.Interval; +import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; +import net.imglib2.blocks.TempArray; +import net.imglib2.type.PrimitiveType; +import net.imglib2.util.Intervals; + +/** + * Boilerplate for {@link BlockProcessor} to simplify implementations. + *

+ * This is intented as a base class for {@code BlockProcessor} that have source + * dimensionality fixed at construction. For {@code BlockProcessor} with + * adaptable number of dimensions (such as converters), see {@link + * AbstractDimensionlessBlockProcessor}. + *

+ * {@link BlockProcessor#getSourcePos() getSourcePos()}, {@link + * BlockProcessor#getSourceSize() getSourceSize()}, and {@link + * BlockProcessor#getSourceInterval() getSourceInterval()} are implemented to + * return the {@code protected} fields {@code long[] sourcePos} and {@code + * }int[] sourceSize}. The {@code }protected} method {@code }int sourceLength()} + * can be used to get the number of elements in the source interval. + *

+ * {@link BlockProcessor#getSourceBuffer() getSourceBuffer()} is implemented + * according to the {@code sourcePrimitiveType} specified at construction. + * + * @param + * input primitive array type, e.g., float[] + * @param + * output primitive array type, e.g., float[] + */ +public abstract class AbstractBlockProcessor< I, O > implements BlockProcessor< I, O > +{ + private final TempArray< I > tempArray; + + protected final long[] sourcePos; + + protected final int[] sourceSize; + + private final BlockProcessorSourceInterval sourceInterval = new BlockProcessorSourceInterval( this ); + + protected AbstractBlockProcessor( final PrimitiveType sourcePrimitiveType, final int numSourceDimensions ) + { + tempArray = TempArray.forPrimitiveType( sourcePrimitiveType ); + sourcePos = new long[ numSourceDimensions ]; + sourceSize = new int[ numSourceDimensions ]; + } + + protected AbstractBlockProcessor( final AbstractBlockProcessor< I, O > proc ) + { + tempArray = proc.tempArray.newInstance(); + final int numSourceDimensions = proc.sourcePos.length; + sourcePos = new long[ numSourceDimensions ]; + sourceSize = new int[ numSourceDimensions ]; + } + + protected int sourceLength() + { + return safeInt( Intervals.numElements( sourceSize ) ); + } + + @Override + public void setTargetInterval( final Interval interval ) + { + interval.min( sourcePos ); + Arrays.setAll( sourceSize, d -> safeInt( interval.dimension( d ) ) ); + } + + @Override + public long[] getSourcePos() + { + return sourcePos; + } + + @Override + public int[] getSourceSize() + { + return sourceSize; + } + + @Override + public Interval getSourceInterval() + { + return sourceInterval; + } + + @Override + public I getSourceBuffer() + { + return tempArray.get( sourceLength() ); + } +} diff --git a/src/main/java/net/imglib2/algorithm/blocks/AbstractDimensionlessBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/AbstractDimensionlessBlockProcessor.java new file mode 100644 index 000000000..c4657b3f6 --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/AbstractDimensionlessBlockProcessor.java @@ -0,0 +1,111 @@ +package net.imglib2.algorithm.blocks; + +import static net.imglib2.util.Util.safeInt; + +import java.util.Arrays; + +import net.imglib2.Interval; +import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; +import net.imglib2.blocks.TempArray; +import net.imglib2.type.PrimitiveType; +import net.imglib2.util.Intervals; + +/** + * Boilerplate for {@link BlockProcessor} to simplify implementations. + *

+ * This is intented as a base class for {@code BlockProcessor} with an adaptable + * number of dimensions (such as converters). For {@code BlockProcessor} with a + * fixed number of source dimensions, see {@link AbstractBlockProcessor}. + *

+ * {@link BlockProcessor#getSourcePos() getSourcePos()}, {@link + * BlockProcessor#getSourceSize() getSourceSize()}, and {@link + * BlockProcessor#getSourceInterval() getSourceInterval()} are implemented to + * return the {@code protected} fields {@code long[] sourcePos} and {@code + * }int[] sourceSize}. The {@code }protected} method {@code }int sourceLength()} + * can be used to get the number of elements in the source interval. + *

+ * {@link BlockProcessor#getSourceBuffer() getSourceBuffer()} is implemented + * according to the {@code sourcePrimitiveType} specified at construction. + * + * @param + * input primitive array type, e.g., float[] + * @param + * output primitive array type, e.g., float[] + */ +public abstract class AbstractDimensionlessBlockProcessor< I, O > implements BlockProcessor< I, O > +{ + private final TempArray< I > tempArray; + + protected long[] sourcePos; + + protected int[] sourceSize; + + private final BlockProcessorSourceInterval sourceInterval = new BlockProcessorSourceInterval( this ); + + protected AbstractDimensionlessBlockProcessor( final PrimitiveType sourcePrimitiveType ) + { + tempArray = TempArray.forPrimitiveType( sourcePrimitiveType ); + } + + protected AbstractDimensionlessBlockProcessor( final AbstractDimensionlessBlockProcessor< I, O > proc ) + { + tempArray = proc.tempArray.newInstance(); + } + + @Override + public void setTargetInterval( final Interval interval ) + { + updateNumSourceDimsensions( interval.numDimensions() ); + interval.min( sourcePos ); + Arrays.setAll( sourceSize, d -> safeInt( interval.dimension( d ) ) ); + } + + /** + * Re-allocates {@code sourcePos} and {@code sourceSize} arrays if they do + * not already exist and have {@code length==n}. + * + * @param n + * new number of source dimensions + * + * @return {@code true} if {@code sourcePos} and {@code sourceSize} arrays were re-allocated + */ + protected boolean updateNumSourceDimsensions( final int n ) + { + if ( sourcePos == null || sourcePos.length != n ) + { + sourcePos = new long[ n ]; + sourceSize = new int[ n ]; + return true; + } + return false; + } + + protected int sourceLength() + { + return safeInt( Intervals.numElements( sourceSize ) ); + } + + @Override + public long[] getSourcePos() + { + return sourcePos; + } + + @Override + public int[] getSourceSize() + { + return sourceSize; + } + + @Override + public Interval getSourceInterval() + { + return sourceInterval; + } + + @Override + public I getSourceBuffer() + { + return tempArray.get( sourceLength() ); + } +} diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java index 6a3c49c2c..88f36a03f 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConvertBlockProcessor.java @@ -11,13 +11,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 @@ -33,18 +33,11 @@ */ package net.imglib2.algorithm.blocks.convert; -import static net.imglib2.util.Util.safeInt; - -import java.util.Arrays; - -import net.imglib2.Interval; +import net.imglib2.algorithm.blocks.AbstractDimensionlessBlockProcessor; import net.imglib2.algorithm.blocks.BlockProcessor; import net.imglib2.algorithm.blocks.ClampType; -import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; import net.imglib2.algorithm.blocks.util.UnaryOperatorType; -import net.imglib2.blocks.TempArray; import net.imglib2.type.NativeType; -import net.imglib2.util.Intervals; /** * Convert primitive arrays between standard ImgLib2 {@code Type}s. @@ -55,32 +48,20 @@ * @param * output primitive array type, e.g., float[] */ -class ConvertBlockProcessor< I, O > implements BlockProcessor< I, O > +class ConvertBlockProcessor< I, O > extends AbstractDimensionlessBlockProcessor< I, O > { - private final TempArray< I > tempArray; - private final ConvertLoop< I, O > loop; - private long[] sourcePos; - - private int[] sourceSize; - - private int sourceLength; - - private final BlockProcessorSourceInterval sourceInterval; - public < S extends NativeType< S >, T extends NativeType< T > > ConvertBlockProcessor( final S sourceType, final T targetType, final ClampType clamp ) { - tempArray = TempArray.forPrimitiveType( sourceType.getNativeTypeFactory().getPrimitiveType() ); + super( sourceType.getNativeTypeFactory().getPrimitiveType() ); loop = ConvertLoops.get( UnaryOperatorType.of( sourceType, targetType ), clamp ); - sourceInterval = new BlockProcessorSourceInterval( this ); } private ConvertBlockProcessor( ConvertBlockProcessor< I, O > convert ) { - tempArray = convert.tempArray.newInstance(); + super( convert ); loop = convert.loop; - sourceInterval = new BlockProcessorSourceInterval( this ); } @Override @@ -89,47 +70,9 @@ public BlockProcessor< I, O > independentCopy() return new ConvertBlockProcessor<>( this ); } - @Override - public void setTargetInterval( final Interval interval ) - { - final int n = interval.numDimensions(); - if ( sourcePos == null || sourcePos.length != n ) - { - sourcePos = new long[ n ]; - sourceSize = new int[ n ]; - } - interval.min( sourcePos ); - Arrays.setAll( sourceSize, d -> safeInt( interval.dimension( d ) ) ); - sourceLength = safeInt( Intervals.numElements( sourceSize ) ); - } - - @Override - public long[] getSourcePos() - { - return sourcePos; - } - - @Override - public int[] getSourceSize() - { - return sourceSize; - } - - @Override - public Interval getSourceInterval() - { - return sourceInterval; - } - - @Override - public I getSourceBuffer() - { - return tempArray.get( sourceLength ); - } - @Override public void compute( final I src, final O dest ) { - loop.apply( src, dest, sourceLength ); + loop.apply( src, dest, sourceLength() ); } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/convert/ConverterBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/convert/ConverterBlockProcessor.java index 515faff74..dc7f68a3a 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/ConverterBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/ConverterBlockProcessor.java @@ -11,13 +11,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 @@ -33,17 +33,12 @@ */ package net.imglib2.algorithm.blocks.convert; -import static net.imglib2.util.Util.safeInt; - -import java.util.Arrays; import java.util.function.Supplier; import net.imglib2.Cursor; -import net.imglib2.Interval; import net.imglib2.RandomAccess; +import net.imglib2.algorithm.blocks.AbstractDimensionlessBlockProcessor; import net.imglib2.algorithm.blocks.BlockProcessor; -import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; -import net.imglib2.blocks.TempArray; import net.imglib2.converter.Converter; import net.imglib2.img.AbstractImg; import net.imglib2.img.Img; @@ -52,7 +47,6 @@ import net.imglib2.type.NativeType; import net.imglib2.type.NativeTypeFactory; import net.imglib2.util.Cast; -import net.imglib2.util.Intervals; /** * Convert primitive arrays between ImgLib2 {@code NativeType}s using a {@link }Converter}. @@ -66,7 +60,7 @@ * @param * output primitive array type, e.g., float[]. Must correspond to T. */ -class ConverterBlockProcessor< S extends NativeType< S >, T extends NativeType< T >, I, O > implements BlockProcessor< I, O > +class ConverterBlockProcessor< S extends NativeType< S >, T extends NativeType< T >, I, O > extends AbstractDimensionlessBlockProcessor< I, O > { private final S sourceType; @@ -74,16 +68,6 @@ class ConverterBlockProcessor< S extends NativeType< S >, T extends NativeType< private final Supplier< Converter< ? super S, T > > converterSupplier; - private final TempArray< I > tempArray; - - private long[] sourcePos; - - private int[] sourceSize; - - private int sourceLength; - - private final BlockProcessorSourceInterval sourceInterval; - private final Converter< ? super S, T > converter; private final Wrapper< S > wrapSource; @@ -92,12 +76,11 @@ class ConverterBlockProcessor< S extends NativeType< S >, T extends NativeType< public ConverterBlockProcessor( final S sourceType, final T targetType, final Supplier< Converter< ? super S, T > > converterSupplier ) { + super( sourceType.getNativeTypeFactory().getPrimitiveType() ); this.sourceType = sourceType; this.targetType = targetType; this.converterSupplier = converterSupplier; - tempArray = TempArray.forPrimitiveType( sourceType.getNativeTypeFactory().getPrimitiveType() ); - sourceInterval = new BlockProcessorSourceInterval( this ); converter = converterSupplier.get(); wrapSource = Wrapper.of( sourceType ); wrapTarget = Wrapper.of( targetType ); @@ -105,12 +88,11 @@ public ConverterBlockProcessor( final S sourceType, final T targetType, final Su private ConverterBlockProcessor( ConverterBlockProcessor< S, T, I, O > convert ) { + super( convert ); sourceType = convert.sourceType; targetType = convert.targetType; converterSupplier = convert.converterSupplier; - tempArray = convert.tempArray.newInstance(); - sourceInterval = new BlockProcessorSourceInterval( this ); converter = converterSupplier.get(); wrapSource = Wrapper.of( sourceType ); wrapTarget = Wrapper.of( targetType ); @@ -122,50 +104,13 @@ public BlockProcessor< I, O > independentCopy() return new ConverterBlockProcessor<>( this ); } - @Override - public void setTargetInterval( final Interval interval ) - { - final int n = interval.numDimensions(); - if ( sourcePos == null || sourcePos.length != n ) - { - sourcePos = new long[ n ]; - sourceSize = new int[ n ]; - } - interval.min( sourcePos ); - Arrays.setAll( sourceSize, d -> safeInt( interval.dimension( d ) ) ); - sourceLength = safeInt( Intervals.numElements( sourceSize ) ); - } - - @Override - public long[] getSourcePos() - { - return sourcePos; - } - - @Override - public int[] getSourceSize() - { - return sourceSize; - } - - @Override - public Interval getSourceInterval() - { - return sourceInterval; - } - - @Override - public I getSourceBuffer() - { - return tempArray.get( sourceLength ); - } - @Override public void compute( final I src, final O dest ) { final S in = wrapSource.wrap( src ); final T out = wrapTarget.wrap( dest ); - for ( int i = 0; i < sourceLength; i++ ) + final int len = sourceLength(); + for ( int i = 0; i < len; i++ ) { in.index().set( i ); out.index().set( i ); diff --git a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsample.java b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsample.java index 639f5c9c4..ffa7aa936 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsample.java +++ b/src/main/java/net/imglib2/algorithm/blocks/downsample/AbstractDownsample.java @@ -11,13 +11,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 @@ -38,21 +38,17 @@ import java.util.Arrays; import net.imglib2.Interval; -import net.imglib2.algorithm.blocks.BlockProcessor; -import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; +import net.imglib2.algorithm.blocks.AbstractBlockProcessor; import net.imglib2.blocks.TempArray; import net.imglib2.type.PrimitiveType; import net.imglib2.util.Intervals; -import net.imglib2.util.Util; -abstract class AbstractDownsample< T extends AbstractDownsample< T, P >, P > implements BlockProcessor< P, P > +abstract class AbstractDownsample< T extends AbstractDownsample< T, P >, P > extends AbstractBlockProcessor< P, P > { PrimitiveType primitiveType; final int n; final int[] destSize; - final long[] sourcePos; - final int[] sourceSize; final boolean[] downsampleInDim; final int[] downsampleDims; @@ -64,15 +60,13 @@ abstract class AbstractDownsample< T extends AbstractDownsample< T, P >, P > imp private final TempArray< P >[] tempArrays; final int[] tempArraySizes; - private final BlockProcessorSourceInterval sourceInterval; - AbstractDownsample( final boolean[] downsampleInDim, final PrimitiveType primitiveType ) { - n = downsampleInDim.length; + super( primitiveType, downsampleInDim.length ); this.primitiveType = primitiveType; + + n = downsampleInDim.length; destSize = new int[ n ]; - sourceSize = new int[ n ]; - sourcePos = new long[ n ]; this.downsampleInDim = downsampleInDim; downsampleDims = downsampleDimIndices( downsampleInDim ); @@ -80,8 +74,6 @@ abstract class AbstractDownsample< T extends AbstractDownsample< T, P >, P > imp tempArrays = createTempArrays( steps, primitiveType ); tempArraySizes = new int[ steps ]; - - sourceInterval = new BlockProcessorSourceInterval( this ); } private static int[] downsampleDimIndices( final boolean[] downsampleInDim ) @@ -114,6 +106,8 @@ private static < P > TempArray< P >[] createTempArrays( final int steps, final P AbstractDownsample( T downsample ) { + super( downsample ); + // re-use primitiveType = downsample.primitiveType; n = downsample.n; @@ -123,13 +117,10 @@ private static < P > TempArray< P >[] createTempArrays( final int steps, final P // init empty destSize = new int[ n ]; - sourcePos = new long[ n ]; - sourceSize = new int[ n ]; tempArraySizes = new int[ steps ]; // init new instance tempArrays = createTempArrays( steps, primitiveType ); - sourceInterval = new BlockProcessorSourceInterval( this ); } @Override @@ -166,24 +157,6 @@ protected void recomputeTempArraySizes() } } - @Override - public int[] getSourceSize() - { - return sourceSize; - } - - @Override - public long[] getSourcePos() - { - return sourcePos; - } - - @Override - public Interval getSourceInterval() - { - return sourceInterval; - } - // optional. also other arrays can be passed to compute() @Override public P getSourceBuffer() diff --git a/src/main/java/net/imglib2/algorithm/blocks/transform/AbstractTransformProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/transform/AbstractTransformProcessor.java index bae9c6718..e61cd6592 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/transform/AbstractTransformProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/transform/AbstractTransformProcessor.java @@ -11,13 +11,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 @@ -40,6 +40,7 @@ import net.imglib2.Interval; import net.imglib2.RealInterval; +import net.imglib2.algorithm.blocks.AbstractBlockProcessor; import net.imglib2.algorithm.blocks.BlockProcessor; import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; import net.imglib2.blocks.TempArray; @@ -56,7 +57,7 @@ * @param

* input/output primitive array type (i.e., float[] or double[]) */ -abstract class AbstractTransformProcessor< T extends AbstractTransformProcessor< T, P >, P > implements BlockProcessor< P, P > +abstract class AbstractTransformProcessor< T extends AbstractTransformProcessor< T, P >, P > extends AbstractBlockProcessor< P, P > { PrimitiveType primitiveType; @@ -68,48 +69,28 @@ abstract class AbstractTransformProcessor< T extends AbstractTransformProcessor< final int[] destSize; - final long[] sourcePos; - - final int[] sourceSize; - - private int sourceLength; - - private final BlockProcessorSourceInterval sourceInterval; - - private final TempArray< P > tempArray; - - Supplier< T > threadSafeSupplier; - AbstractTransformProcessor( final int n, final Transform.Interpolation interpolation, final PrimitiveType primitiveType ) { + super( primitiveType, n ); this.primitiveType = primitiveType; this.interpolation = interpolation; this.n = n; destPos = new long[ n ]; destSize = new int[ n ]; - sourcePos = new long[ n ]; - sourceSize = new int[ n ]; - sourceInterval = new BlockProcessorSourceInterval( this ); - tempArray = TempArray.forPrimitiveType( primitiveType ); } AbstractTransformProcessor( T transform ) { + super( transform ); + // re-use primitiveType = transform.primitiveType; interpolation = transform.interpolation; n = transform.n; - threadSafeSupplier = transform.threadSafeSupplier; // init empty destPos = new long[ n ]; destSize = new int[ n ]; - sourcePos = new long[ n ]; - sourceSize = new int[ n ]; - - // init new instance - sourceInterval = new BlockProcessorSourceInterval( this ); - tempArray = TempArray.forPrimitiveType( primitiveType ); } abstract RealInterval estimateBounds( Interval interval ); @@ -132,30 +113,5 @@ public void setTargetInterval( final Interval interval ) Arrays.setAll( sourceSize, d -> ( int ) ( ( long ) Math.floor( bounds.realMax( d ) + 0.5 ) - sourcePos[ d ] ) + 2 ); break; } - sourceLength = safeInt( Intervals.numElements( sourceSize ) ); - } - - @Override - public long[] getSourcePos() - { - return sourcePos; - } - - @Override - public int[] getSourceSize() - { - return sourceSize; - } - - @Override - public Interval getSourceInterval() - { - return sourceInterval; - } - - @Override - public P getSourceBuffer() - { - return tempArray.get( sourceLength ); } } From 3db98edec8913839091c303337bcf6c18564c8c9 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sun, 15 Sep 2024 12:44:59 +0200 Subject: [PATCH 24/24] Add javadoc --- .../algorithm/blocks/AbstractBlockSupplier.java | 2 ++ .../blocks/DefaultUnaryBlockOperator.java | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java index df35e3784..7d5b7a0f5 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java @@ -6,6 +6,8 @@ import net.imglib2.util.CloseableThreadLocal; /** + * Boilerplate for {@link BlockSupplier} to simplify implementations. + *

* Implements {@link BlockSupplier#threadSafe()} as a wrapper that makes {@link * ThreadLocal} {@link BlockSupplier#independentCopy()} copies. */ diff --git a/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java index 1d7b34e1a..fdba81fcc 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java @@ -38,6 +38,23 @@ import net.imglib2.util.Cast; import net.imglib2.util.CloseableThreadLocal; +/** + * Default implementation of {@link UnaryBlockOperator}. + *

+ * If you implement a {@code BlockProcessor}, you typically wrap it with a + * {@code DefaultUnaryBlockOperator}, specifying the source {@code S} and target + * {@code T} ImgLib2 {@code NativeType}s corresponding to primitive array types + * {@code I} and {@code O}, and the number of source and target dimension. + *

+ * The {@link UnaryBlockOperator} can then be used in {@link + * BlockSupplier#andThen(UnaryBlockOperator)} chains in a type- and + * simensionality-safe manner. + * + * @param + * source type + * @param + * target type + */ public class DefaultUnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > implements UnaryBlockOperator< S, T > { private final S sourceType;