diff --git a/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockProcessor.java index abd095b9b..6c1923486 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockProcessor.java @@ -35,10 +35,8 @@ 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.BlockInterval; import net.imglib2.blocks.TempArray; import net.imglib2.type.PrimitiveType; import net.imglib2.util.Intervals; @@ -51,12 +49,12 @@ * 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. + * A {@link BlockInterval} of the desired number of dimensions is exposed + * through {@link #getSourceInterval()}. (For convenience, {@code min} and + * {@code dimensions} of the interval are also exposed through the {@code + * protected} fields {@link #sourcePos} and {@link #sourceSize}.) The {@code + * protected} method {@link #sourceLength()} returns the number of elements in + * the source interval. *

* {@link BlockProcessor#getSourceBuffer() getSourceBuffer()} is implemented * according to the {@code sourcePrimitiveType} specified at construction. @@ -70,53 +68,41 @@ public abstract class AbstractBlockProcessor< I, O > implements BlockProcessor< { private final TempArray< I > tempArray; + private final BlockInterval sourceInterval; + 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 ]; + sourceInterval = new BlockInterval( numSourceDimensions ); + sourcePos = sourceInterval.min(); + sourceSize = sourceInterval.size(); } 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 ]; + sourceInterval = new BlockInterval( proc.sourceInterval.numDimensions() ); + sourcePos = sourceInterval.min(); + sourceSize = sourceInterval.size(); } protected int sourceLength() { - return safeInt( Intervals.numElements( sourceSize ) ); + return safeInt( Intervals.numElements( sourceInterval ) ); } @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; + sourceInterval.setFrom( interval ); } @Override - public Interval getSourceInterval() + public BlockInterval getSourceInterval() { return sourceInterval; } diff --git a/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java index 7e0d513c3..80e734201 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/AbstractBlockSupplier.java @@ -35,6 +35,7 @@ import java.util.function.Supplier; +import net.imglib2.Interval; import net.imglib2.type.NativeType; import net.imglib2.util.CloseableThreadLocal; @@ -68,9 +69,9 @@ public int numDimensions() } @Override - public void copy( final long[] srcPos, final Object dest, final int[] size ) + public void copy( final Interval interval, final Object dest ) { - threadSafeSupplier.get().copy( srcPos, dest, size ); + threadSafeSupplier.get().copy( interval, dest ); } @Override diff --git a/src/main/java/net/imglib2/algorithm/blocks/AbstractDimensionlessBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/AbstractDimensionlessBlockProcessor.java index e73bc918b..97f5c0fd2 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/AbstractDimensionlessBlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/AbstractDimensionlessBlockProcessor.java @@ -35,10 +35,8 @@ 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.BlockInterval; import net.imglib2.blocks.TempArray; import net.imglib2.type.PrimitiveType; import net.imglib2.util.Intervals; @@ -50,12 +48,10 @@ * 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. + * A {@link BlockInterval} is exposed through {@link #getSourceInterval()} + * (after {@link #setTargetInterval} has been called). The {@code protected} + * method {@link #sourceLength()} returns the number of elements in the source + * interval. *

* {@link BlockProcessor#getSourceBuffer() getSourceBuffer()} is implemented * according to the {@code sourcePrimitiveType} specified at construction. @@ -69,11 +65,7 @@ public abstract class AbstractDimensionlessBlockProcessor< I, O > implements Blo { private final TempArray< I > tempArray; - protected long[] sourcePos; - - protected int[] sourceSize; - - private final BlockProcessorSourceInterval sourceInterval = new BlockProcessorSourceInterval( this ); + protected BlockInterval sourceInterval; protected AbstractDimensionlessBlockProcessor( final PrimitiveType sourcePrimitiveType ) { @@ -88,26 +80,24 @@ protected AbstractDimensionlessBlockProcessor( final AbstractDimensionlessBlockP @Override public void setTargetInterval( final Interval interval ) { - updateNumSourceDimsensions( interval.numDimensions() ); - interval.min( sourcePos ); - Arrays.setAll( sourceSize, d -> safeInt( interval.dimension( d ) ) ); + updateNumSourceDimensions( interval.numDimensions() ); + sourceInterval.setFrom( interval ); } /** - * Re-allocates {@code sourcePos} and {@code sourceSize} arrays if they do - * not already exist and have {@code length==n}. + * Re-allocates {@code sourceInterval} if it does not already exist and + * match {@code numDimensions()==n}. * * @param n * new number of source dimensions * - * @return {@code true} if {@code sourcePos} and {@code sourceSize} arrays were re-allocated + * @return {@code true} if {@code sourceInterval} was re-allocated */ - protected boolean updateNumSourceDimsensions( final int n ) + protected boolean updateNumSourceDimensions( final int n ) { - if ( sourcePos == null || sourcePos.length != n ) + if ( sourceInterval == null || sourceInterval.numDimensions() != n ) { - sourcePos = new long[ n ]; - sourceSize = new int[ n ]; + sourceInterval = new BlockInterval( n ); return true; } return false; @@ -115,23 +105,11 @@ protected boolean updateNumSourceDimsensions( final int n ) protected int sourceLength() { - return safeInt( Intervals.numElements( sourceSize ) ); - } - - @Override - public long[] getSourcePos() - { - return sourcePos; - } - - @Override - public int[] getSourceSize() - { - return sourceSize; + return safeInt( Intervals.numElements( sourceInterval ) ); } @Override - public Interval getSourceInterval() + public BlockInterval getSourceInterval() { return sourceInterval; } diff --git a/src/main/java/net/imglib2/algorithm/blocks/NoOpUnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/AbstractUnaryBlockOperator.java similarity index 66% rename from src/main/java/net/imglib2/algorithm/blocks/NoOpUnaryBlockOperator.java rename to src/main/java/net/imglib2/algorithm/blocks/AbstractUnaryBlockOperator.java index be69c830b..26786b261 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/NoOpUnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/AbstractUnaryBlockOperator.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,65 +33,61 @@ */ 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)}. + * Abstract implementation of {@link UnaryBlockOperator}. + * Takes care of source/target type/dimensionality boilerplate. * + * @param + * source type * @param + * target type */ -public class NoOpUnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > implements UnaryBlockOperator< S, T > +public abstract class AbstractUnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > implements UnaryBlockOperator< S, T > { - @Override - public < I, O > BlockProcessor< I, O > blockProcessor() + private final S sourceType; + private final T targetType; + private final int numSourceDimensions; + private final int numTargetDimensions; + + protected AbstractUnaryBlockOperator( S sourceType, T targetType, int numSourceDimensions, int numTargetDimensions ) { - throw new UnsupportedOperationException(); + this.sourceType = sourceType; + this.targetType = targetType; + this.numSourceDimensions = numSourceDimensions; + this.numTargetDimensions = numTargetDimensions; } - @Override - public < U extends NativeType< U > > UnaryBlockOperator< S, U > andThen( UnaryBlockOperator< T, U > op ) + protected AbstractUnaryBlockOperator( AbstractUnaryBlockOperator< S, T > op ) { - return Cast.unchecked( op ); + this.sourceType = op.sourceType; + this.targetType = op.targetType; + this.numSourceDimensions = op.numSourceDimensions; + this.numTargetDimensions = op.numTargetDimensions; } @Override public S getSourceType() { - throw new UnsupportedOperationException(); + return sourceType; } @Override public T getTargetType() { - throw new UnsupportedOperationException(); + return targetType; } @Override public int numSourceDimensions() { - return 0; + return numSourceDimensions; } @Override public int numTargetDimensions() { - return 0; - } - - @Override - public UnaryBlockOperator< S, T > independentCopy() - { - return this; - } - - @Override - public UnaryBlockOperator< S, T > threadSafe() - { - return this; + return numTargetDimensions; } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/BlockProcessor.java index 1bbb25658..fbfae4a09 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/BlockProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/BlockProcessor.java @@ -34,14 +34,13 @@ package net.imglib2.algorithm.blocks; import net.imglib2.Interval; -import net.imglib2.blocks.PrimitiveBlocks; /** * A {@code BlockProcessor} computes values in a flattened primitive output * array from values in a flattened primitive input array. *

- * Typically, {@code BlockProcessor} should not be used directly, but - * wrapped in {@link UnaryBlockOperator} which has the ImgLib2 {@code Type}s + * Typically, {@code BlockProcessor} should not be used directly, but wrapped in + * {@link DefaultUnaryBlockOperator} which has the ImgLib2 {@code Type}s * corresponding to {@code I}, {@code O}. This helps to avoid mistakes with * unchecked (primitive array) type casts. * @@ -56,21 +55,26 @@ public interface BlockProcessor< I, O > void setTargetInterval( Interval interval ); - default void setTargetInterval( long[] pos, int[] size ) - { - setTargetInterval( new BlockProcessorTargetInterval( pos, size ) ); - } - - long[] getSourcePos(); - - int[] getSourceSize(); - Interval getSourceInterval(); /** * Get a {@code src} array of sufficient size. *

- * Consecutive calls may return the same array, but don't have to. + * Consecutive calls may return the same array (but don't have to). + *

+ * E.g., this is a BUG: + *

{@code
+	 *     blockProcessor.setTargetInterval( interval );
+	 *     blockSupplier.copy( blockProcessor.getSourceInterval(), blockProcessor.getSourceBuffer() );
+	 *     blockProcessor.compute( blockProcessor.getSourceBuffer(), dest );
+	 * }
+ * Use this instead: + *
{@code
+	 *     blockProcessor.setTargetInterval( interval );
+	 *     Object buf = blockProcessor.getSourceBuffer();
+	 *     blockSupplier.copy( blockProcessor.getSourceInterval(), buf );
+	 *     blockProcessor.compute( buf, dest );
+	 * }
*/ I getSourceBuffer(); @@ -78,18 +82,17 @@ default void setTargetInterval( long[] pos, int[] size ) * Compute the {@code dest} array from the {@code src} array. *

* {@code src} and {@code dest} are expected to be flattened arrays of the - * dimensions specified in {@link #setTargetInterval} and computed in {@link - * #getSourceSize}, respectively. The typical sequence is: + * dimensions specified in {@link #setTargetInterval} and provided in {@link + * #getSourceInterval}, respectively. The typical sequence is: *

    *
  1. A given target array {@code dest} with known flattened layout and min * position should be computed.
  2. *
  3. Call {@link #setTargetInterval}. This will compute the corresponding - * {@link #getSourceInterval source interval} (also available as {@link - * #getSourcePos}, {@link #getSourceSize}) including {@code + * {@link #getSourceInterval source interval} including {@code * BlockProcessor}-specific transformations, padding, etc.
  4. *
  5. Fill a {@code src} array (either provided by {@link * #getSourceBuffer}, or otherwise allocated) with the input data (see - * {@link PrimitiveBlocks#copy}).
  6. + * {@link BlockSupplier#copy}). *
  7. Call {@code compute(src, dest)} to compute the target array.
  8. *
* Note, that the {@code src} and {@code dest} arrays may be larger than @@ -97,8 +100,8 @@ default void setTargetInterval( long[] pos, int[] size ) * case the trailing elements are ignored. *

* Typically, {@code BlockProcessor} should not be used directly, but - * wrapped in {@link UnaryBlockOperator} which has the ImgLib2 {@code Type}s - * corresponding to {@code I}, {@code O}. + * wrapped in {@link DefaultUnaryBlockOperator} which has the ImgLib2 {@code + * Type}s corresponding to {@code I}, {@code O}. * * @param src * flattened primitive array with input values @@ -106,20 +109,4 @@ default void setTargetInterval( long[] pos, int[] size ) * flattened primitive array to fill with output values */ void compute( I src, O dest ); - - /** - * Returns a {@code BlockProcessor concatenated} such that - *

{@code
-	 *   concatenated.compute(src, dest);
-	 * }
- * is equivalent to - *
{@code
-	 *   this.compute(src, tmp);
-	 *   processor.compute(tmp, dest);
-	 * }
- */ - default < P > BlockProcessor< I, P > andThen( BlockProcessor< O, P > processor ) - { - return new ConcatenatedBlockProcessor<>( this, processor ); - } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockProcessorTargetInterval.java b/src/main/java/net/imglib2/algorithm/blocks/BlockProcessorTargetInterval.java deleted file mode 100644 index 08c2862dd..000000000 --- a/src/main/java/net/imglib2/algorithm/blocks/BlockProcessorTargetInterval.java +++ /dev/null @@ -1,78 +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; - -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; - } -} diff --git a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java index b8983f452..34cf27acb 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/BlockSupplier.java @@ -33,12 +33,6 @@ */ package net.imglib2.algorithm.blocks; -import static net.imglib2.blocks.PrimitiveBlocks.OnFallback.WARN; -import static net.imglib2.util.Util.safeInt; - -import java.util.Arrays; -import java.util.function.Function; - import net.imglib2.EuclideanSpace; import net.imglib2.Interval; import net.imglib2.RandomAccessible; @@ -46,44 +40,50 @@ import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.cache.img.CachedCellImg; 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 -{ - /** - * Copy a block from the ({@code T}-typed) source into primitive arrays (of - * the appropriate type). - * - * @param srcPos - * min coordinate of the block to copy - * @param dest - * primitive array to copy into. Must correspond to {@code T}, for - * example, if {@code T} is {@code UnsignedByteType} then {@code dest} must - * be {@code byte[]}. - * @param size - * the size of the block to copy - */ - void copy( long[] srcPos, Object dest, int[] size ); +import java.util.function.Function; - /** - * Copy a block from the ({@code T}-typed) source into primitive arrays (of - * the appropriate type). - * - * @param srcPos - * min coordinate of the block to copy - * @param dest - * primitive array to copy into. Must correspond to {@code T}, for - * example, if {@code T} is {@code UnsignedByteType} then {@code dest} must - * be {@code byte[]}. - * @param size - * the size of the block to copy - */ - default void copy( int[] srcPos, Object dest, int[] size ) - { - copy( Util.int2long( srcPos ), dest, size ); - } +import static net.imglib2.blocks.PrimitiveBlocks.OnFallback.WARN; +/** + * Provides blocks of data from a {@code NativeType} source. + * Use the {@link BlockSupplier#copy} method to copy a block out of the + * source into flat primitive array (of the appropriate type). + *

+ * Use the static method {@link BlockSupplier#of(RandomAccessible) + * BlockSupplier.of} to create a {@code BlockSupplier} accessor from an {@code + * RandomAccessible} source. (This is just a thin wrapper around {@link + * PrimitiveBlocks}). + *

+ * Currently, only pixel types {@code T} are supported that map one-to-one to a + * primitive type. (For example, {@code ComplexDoubleType} or {@code + * Unsigned4BitType} are not supported.) + *

+ * If a source {@code RandomAccessible} view construction cannot be understood, + * {@link BlockSupplier#of(RandomAccessible) BlockSupplier.of} will return a + * fall-back implementation. Fallback can be configured with the optional {@link + * PrimitiveBlocks.OnFallback OnFallback} argument to {@link + * BlockSupplier#of(RandomAccessible, PrimitiveBlocks.OnFallback) + * BlockSupplier.of}. + *

+ * Use {@link BlockSupplier#andThen} to decorate a {@code BlockSupplier} with a + * sequence of {@code UnaryBlockOperator}s. + *

+ * Use {@link BlockSupplier#toCellImg} to create {@code CachedCellImg} which + * copies cells from a {@code BlockSupplier}. + *

+ * Implementations are not thread-safe in general. Use {@link #threadSafe()} to + * obtain a thread-safe instance (implemented using {@link ThreadLocal} copies). + * E.g., + *

{@code
+ * 		BlockSupplier blocks = BlockSupplier.of(view).threadSafe();
+ * }
+ * + * @param + * pixel type + */ +public interface BlockSupplier< T extends NativeType< T > > extends Typed< T >, EuclideanSpace +{ /** * Copy a block from the ({@code T}-typed) source into primitive arrays (of * the appropriate type). @@ -95,13 +95,7 @@ default void copy( int[] srcPos, Object dest, int[] size ) * example, if {@code T} is {@code UnsignedByteType} then {@code dest} must * be {@code byte[]}. */ - default void copy( Interval interval, Object dest ) - { - final long[] srcPos = interval.minAsLongArray(); - final int[] size = new int[ srcPos.length ]; - Arrays.setAll( size, d -> safeInt( interval.dimension( d ) ) ); - copy( srcPos, dest, size ); - } + void copy( Interval interval, Object dest ); /** * Get a thread-safe version of this {@code BlockSupplier}. @@ -116,40 +110,12 @@ 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. + * Returns a {@code BlockSupplier} that provide blocks using the given + * {@code operator} with this {@code BlockSupplier} as input. */ default < U extends NativeType< U > > BlockSupplier< U > andThen( UnaryBlockOperator< T, U > operator ) { - if ( operator instanceof NoOpUnaryBlockOperator ) - return Cast.unchecked( this ); - else - return new ConcatenatedBlockSupplier<>( this.independentCopy(), operator.independentCopy() ); + return operator.applyTo( this ); } default < U extends NativeType< U > > BlockSupplier< U > andThen( Function< BlockSupplier< T >, UnaryBlockOperator< T, U > > function ) @@ -157,25 +123,6 @@ default < U extends NativeType< U > > BlockSupplier< U > andThen( Function< Bloc return andThen( function.apply( this ) ); } - /** - * Return a {@code CachedCellImg} which copies cells from this {@code BlockSupplier}. - * - * @param dimensions - * dimensions of the {@code CachedCellImg} to create - * @param cellDimensions - * block size of the {@code CachedCellImg} to create. - * This is extended or truncated as necessary. - * For example if {@code cellDimensions={64,32}} then for creating a 3D - * image it will be augmented to {@code {64,32,32}}. For creating a 1D image - * it will be truncated to {@code {64}}. - * - * @return a {@code CachedCellImg} which copies cells from this {@code BlockSupplier}. - */ - default CachedCellImg< T, ? > toCellImg( final long[] dimensions, final int... cellDimensions ) - { - return BlockAlgoUtils.cellImg( this, dimensions, cellDimensions ); - } - /** * Create a {@code BlockSupplier} accessor for an arbitrary {@code * RandomAccessible} source. Many View constructions (that ultimately end in @@ -229,11 +176,47 @@ static < T extends NativeType< T > > BlockSupplier< T > of( return new PrimitiveBlocksSupplier<>( PrimitiveBlocks.of( ra, onFallback ) ); } - /* - * Wrap the given {@code PrimitiveBlocks} as a {@code BlockSupplier}. + /** + * Return a {@code CachedCellImg} which copies cells from this {@code BlockSupplier}. + * + * @param dimensions + * dimensions of the {@code CachedCellImg} to create + * @param cellDimensions + * block size of the {@code CachedCellImg} to create. + * This is extended or truncated as necessary. + * For example if {@code cellDimensions={64,32}} then for creating a 3D + * image it will be augmented to {@code {64,32,32}}. For creating a 1D image + * it will be truncated to {@code {64}}. + * + * @return a {@code CachedCellImg} which copies cells from this {@code BlockSupplier}. + */ + default CachedCellImg< T, ? > toCellImg( final long[] dimensions, final int... cellDimensions ) + { + return BlockAlgoUtils.cellImg( this, dimensions, cellDimensions ); + } + + /** + * 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}}. */ -// static < T extends NativeType< T > > BlockSupplier< T > of( PrimitiveBlocks< T > blocks ) -// { -// return new PrimitiveBlocksSupplier<>( blocks ); -// } + default BlockSupplier< T > tile( int... tileSize ) + { + return this.andThen( new TilingUnaryBlockOperator<>( getType(), numDimensions(), tileSize ) ); + } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java deleted file mode 100644 index 6b2d26040..000000000 --- a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockProcessor.java +++ /dev/null @@ -1,96 +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; - -import net.imglib2.Interval; - -class ConcatenatedBlockProcessor< I, K, O > implements BlockProcessor< I, O > -{ - private final BlockProcessor< I, K > p0; - - private final BlockProcessor< K, O > p1; - - public ConcatenatedBlockProcessor( - BlockProcessor< I, K > p0, - BlockProcessor< K, O > p1 ) - { - this.p0 = p0; - this.p1 = p1; - } - - @Override - public ConcatenatedBlockProcessor< I, K, O > independentCopy() - { - return new ConcatenatedBlockProcessor<>( p0.independentCopy(), p1.independentCopy() ); - } - - @Override - public void setTargetInterval( final Interval interval ) - { - p1.setTargetInterval( interval ); - p0.setTargetInterval( p1.getSourceInterval() ); - } - - @Override - public long[] getSourcePos() - { - return p0.getSourcePos(); - } - - @Override - public int[] getSourceSize() - { - return p0.getSourceSize(); - } - - @Override - public Interval getSourceInterval() - { - return p0.getSourceInterval(); - } - - @Override - public I getSourceBuffer() - { - return p0.getSourceBuffer(); - } - - @Override - public void compute( final I src, final O dest ) - { - final K temp = p1.getSourceBuffer(); - p0.compute( src, temp ); - p1.compute( temp, dest ); - } -} diff --git a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java index b7917073f..691b7572c 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedBlockSupplier.java @@ -33,26 +33,23 @@ */ package net.imglib2.algorithm.blocks; +import net.imglib2.Interval; import net.imglib2.type.NativeType; -import net.imglib2.util.Cast; -class ConcatenatedBlockSupplier< T extends NativeType< T > > extends AbstractBlockSupplier< T > +class ConcatenatedBlockSupplier< S extends NativeType< S >, T extends NativeType< T > > extends AbstractBlockSupplier< T > { - private final BlockSupplier< ? > p0; + private final BlockSupplier< S > src; - private final BlockProcessor< ?, ? > p1; - - private final T type; + private final UnaryBlockOperator< S, T > operator; private final int numDimensions; - public < S extends NativeType< S > > ConcatenatedBlockSupplier( + ConcatenatedBlockSupplier( final BlockSupplier< S > srcSupplier, final UnaryBlockOperator< S, T > operator ) { - this.p0 = srcSupplier; - this.p1 = operator.blockProcessor(); - this.type = operator.getTargetType(); + this.src = srcSupplier; + this.operator = operator; if ( operator.numSourceDimensions() > 0 ) { if ( srcSupplier.numDimensions() != operator.numSourceDimensions() ) @@ -65,18 +62,17 @@ public < S extends NativeType< S > > ConcatenatedBlockSupplier( } } - private ConcatenatedBlockSupplier( final ConcatenatedBlockSupplier< T > s ) + private ConcatenatedBlockSupplier( final ConcatenatedBlockSupplier< S, T > s ) { - p0 = s.p0.independentCopy(); - p1 = s.p1.independentCopy(); - type = s.type; + src = s.src.independentCopy(); + operator = s.operator.independentCopy(); numDimensions = s.numDimensions; } @Override public T getType() { - return type; + return operator.getTargetType(); } @Override @@ -86,12 +82,9 @@ public int numDimensions() } @Override - public void copy( final long[] srcPos, final Object dest, final int[] size ) + public void copy( final Interval interval, final Object dest ) { - p1.setTargetInterval( srcPos, size ); - final Object src = p1.getSourceBuffer(); - p0.copy( p1.getSourcePos(), src, p1.getSourceSize() ); - p1.compute( Cast.unchecked( src ), Cast.unchecked( dest ) ); + operator.compute( src, interval, dest ); } @Override diff --git a/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedUnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedUnaryBlockOperator.java new file mode 100644 index 000000000..3c8c9907d --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/blocks/ConcatenatedUnaryBlockOperator.java @@ -0,0 +1,80 @@ +package net.imglib2.algorithm.blocks; + +import net.imglib2.Interval; +import net.imglib2.type.NativeType; + +class ConcatenatedUnaryBlockOperator< + S extends NativeType< S >, + T extends NativeType< T >, + U extends NativeType< U > > + implements UnaryBlockOperator< S, U > +{ + private final UnaryBlockOperator< S, T > op1; + private final UnaryBlockOperator< T, U > op2; + private final int numSourceDimensions; + private final int numTargetDimensions; + + ConcatenatedUnaryBlockOperator( UnaryBlockOperator< S, T > op1, UnaryBlockOperator< T, U > op2 ) + { + this.op1 = op1; + this.op2 = op2; + + final boolean op1HasDims = op1.numSourceDimensions() > 0; + final boolean op2HasDims = op2.numSourceDimensions() > 0; + if ( op2HasDims && op1HasDims && op1.numTargetDimensions() != op2.numSourceDimensions() ) { + throw new IllegalArgumentException( "UnaryBlockOperator cannot be concatenated: number of dimensions mismatch." ); + } + this.numSourceDimensions = op1HasDims ? op1.numSourceDimensions() : op2.numSourceDimensions(); + this.numTargetDimensions = op2HasDims ? op2.numTargetDimensions() : op1.numTargetDimensions(); + } + + private ConcatenatedUnaryBlockOperator( ConcatenatedUnaryBlockOperator< S, T, U > op ) + { + this.op1 = op.op1.independentCopy(); + this.op2 = op.op2.independentCopy(); + this.numSourceDimensions = op.numSourceDimensions; + this.numTargetDimensions = op.numTargetDimensions; + } + + @Override + public void compute( final BlockSupplier< S > src, final Interval interval, final Object dest ) + { + applyTo( src ).copy( interval, dest ); + } + + @Override + public S getSourceType() + { + return op1.getSourceType(); + } + + @Override + public U getTargetType() + { + return op2.getTargetType(); + } + + @Override + public int numSourceDimensions() + { + return 0; + } + + @Override + public int numTargetDimensions() + { + return 0; + } + + @Override + public UnaryBlockOperator< S, U > independentCopy() + { + return new ConcatenatedUnaryBlockOperator<>( this ); + } + + @Override + public BlockSupplier< U > applyTo( final BlockSupplier< S > blocks ) + { + return op2.applyTo( op1.applyTo( blocks ) ); + } +} diff --git a/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java index fdba81fcc..cf059fbe2 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/DefaultUnaryBlockOperator.java @@ -33,10 +33,9 @@ */ package net.imglib2.algorithm.blocks; -import java.util.function.Supplier; +import net.imglib2.Interval; import net.imglib2.type.NativeType; import net.imglib2.util.Cast; -import net.imglib2.util.CloseableThreadLocal; /** * Default implementation of {@link UnaryBlockOperator}. @@ -48,117 +47,64 @@ *

* The {@link UnaryBlockOperator} can then be used in {@link * BlockSupplier#andThen(UnaryBlockOperator)} chains in a type- and - * simensionality-safe manner. + * dimensionality-safe manner. * * @param * source type * @param * target type */ -public class DefaultUnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > implements UnaryBlockOperator< S, T > +public class DefaultUnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > extends AbstractUnaryBlockOperator< S, T > { - private final S sourceType; - private final T targetType; - private final int numSourceDimensions; - private final int numTargetDimensions; - private final BlockProcessor< ?, ? > blockProcessor; + @SuppressWarnings( "rawtypes" ) + private final 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; + super( sourceType, targetType, numSourceDimensions, numTargetDimensions ); this.blockProcessor = blockProcessor; } - @Override - public < I, O > BlockProcessor< I, O > blockProcessor() - { - return Cast.unchecked( blockProcessor ); - } - - @Override - public S getSourceType() - { - return sourceType; - } - - @Override - public T getTargetType() - { - return targetType; - } - - @Override - public int numSourceDimensions() + private DefaultUnaryBlockOperator( DefaultUnaryBlockOperator< S, T > op ) { - return numSourceDimensions; + super( op ); + this.blockProcessor = op.blockProcessor.independentCopy(); } + @SuppressWarnings( "unchecked" ) @Override - public int numTargetDimensions() + public void compute( final BlockSupplier< S > src, final Interval interval, final Object dest ) { - return numTargetDimensions; + blockProcessor.setTargetInterval( interval ); + final Object buf = blockProcessor.getSourceBuffer(); + src.copy( blockProcessor.getSourceInterval(), buf ); + blockProcessor.compute( buf, dest ); } @Override public UnaryBlockOperator< S, T > independentCopy() { - return new DefaultUnaryBlockOperator<>( sourceType, targetType, numSourceDimensions, numTargetDimensions, blockProcessor.independentCopy() ); + return new DefaultUnaryBlockOperator<>( this ); } - private Supplier< UnaryBlockOperator< S, T > > threadSafeSupplier; - - @Override - public UnaryBlockOperator< S, T > threadSafe() + /** + * Get (an instance of) the wrapped {@code BlockProcessor}. + *

+ * Note that this involves an unchecked cast, that is, the returned {@code + * BlockProcessor} will be cast to the {@code I, O} types expected by + * the caller. + *

+ * This is mostly intended for debugging. + * + * @param + * input primitive array type, e.g., float[]. Must correspond to S. + * @param + * output primitive array type, e.g., float[]. Must correspond to T. + * + * @return an instance of the wrapped {@code BlockProcessor} + */ + public < I, O > BlockProcessor< I, O > blockProcessor() { - if ( threadSafeSupplier == null ) - threadSafeSupplier = CloseableThreadLocal.withInitial( this::independentCopy )::get; - return new UnaryBlockOperator< S, T >() - { - @Override - public < I, O > BlockProcessor< I, O > blockProcessor() - { - return threadSafeSupplier.get().blockProcessor(); - } - - @Override - public S getSourceType() - { - return sourceType; - } - - @Override - public T getTargetType() - { - return targetType; - } - - @Override - public int numSourceDimensions() - { - return numSourceDimensions; - } - - @Override - public int numTargetDimensions() - { - return numTargetDimensions; - } - - @Override - public UnaryBlockOperator< S, T > threadSafe() - { - return this; - } - - @Override - public UnaryBlockOperator< S, T > independentCopy() - { - return DefaultUnaryBlockOperator.this.independentCopy().threadSafe(); - } - }; + return Cast.unchecked( blockProcessor ); } - } diff --git a/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java index 09e259d12..368912012 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/PrimitiveBlocksSupplier.java @@ -33,6 +33,7 @@ */ package net.imglib2.algorithm.blocks; +import net.imglib2.Interval; import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.type.NativeType; @@ -58,15 +59,9 @@ public int numDimensions() } @Override - public void copy( final long[] srcPos, final Object dest, final int[] size ) + public void copy( final Interval interval, final Object dest ) { - blocks.copy( srcPos, dest, size ); - } - - @Override - public void copy( final int[] srcPos, final Object dest, final int[] size ) - { - blocks.copy( srcPos, dest, size ); + blocks.copy( interval, dest ); } @Override diff --git a/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java b/src/main/java/net/imglib2/algorithm/blocks/TilingUnaryBlockOperator.java similarity index 60% rename from src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java rename to src/main/java/net/imglib2/algorithm/blocks/TilingUnaryBlockOperator.java index c24714290..b54ddf942 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/TilingBlockSupplier.java +++ b/src/main/java/net/imglib2/algorithm/blocks/TilingUnaryBlockOperator.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,8 @@ */ package net.imglib2.algorithm.blocks; +import net.imglib2.Interval; +import net.imglib2.blocks.BlockInterval; import net.imglib2.blocks.SubArrayCopy; import net.imglib2.blocks.TempArray; import net.imglib2.type.NativeType; @@ -42,17 +44,17 @@ 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}. + * {@code TilingUnaryBlockOperator} fulfills large {@link #compute} requests + * by requesting several smaller blocks from the source {@code BlockSupplier} + * and assembling them into the requested large block. *

* 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}. + * {@link #compute} requests that are smaller or equal to {@code tileSize} are + * passed directly to the source {@code BlockSupplier}. *

* Example use cases: *

    @@ -66,11 +68,11 @@ * pixel type * @param

    * corresponding primitive array type + * + * @see BlockSupplier#tile */ -class TilingBlockSupplier< T extends NativeType< T >, P > extends AbstractBlockSupplier< T > +class TilingUnaryBlockOperator< T extends NativeType< T >, P > extends AbstractUnaryBlockOperator< T, T > { - private final BlockSupplier< T > p0; - private final int[] innerTileSize; private final int[] borderTileSize; private final int[] numTiles; @@ -80,80 +82,76 @@ class TilingBlockSupplier< T extends NativeType< T >, P > extends AbstractBlockS private final SubArrayCopy.Typed< P, P > subArrayCopy; - final int[] tile_pos_in_dest; - final long[] tile_pos_in_src; - final int[] tile_origin; - final int[] tile_size; + private final int[] tile_pos_in_dest; + private final long[] tile_pos_in_src; + private final int[] tile_size; + private final BlockInterval tile_interval_in_src; + private final int[] zero; /** - * Create a {@code BlockSupplier} that handles {@link BlockSupplier#copy} + * Create a {@code UnaryBlockOperator} that handles {@link #compute} * requests by splitting into {@code tileSize} portions that are each - * handled by the given {@code srcSupplier} and assembled into the final + * handled by the source {@code BlockSupplier} and assembled into the final * result. * - * @param srcSupplier - * source {@code BlockSupplier} to wrap. + * @param type + * pixel type (source and target) of this operator + * @param numDimensions + * number of dimensions (source and target) of this operator * @param tileSize - * (maximum) dimensions of a request to the {@code srcSupplier}. + * (maximum) dimensions of a request to the source {@code BlockSupplier}. * {@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 ) + public TilingUnaryBlockOperator( final T type, final int numDimensions, final int... tileSize ) { - this.p0 = srcSupplier; - final int n = srcSupplier.numDimensions(); - innerTileSize = Util.expandArray( tileSize, n ); + super( type, type, numDimensions, numDimensions ); + + innerTileSize = Util.expandArray( tileSize, numDimensions ); innerTileNumElements = Util.safeInt( Intervals.numElements( innerTileSize ) ); - borderTileSize = new int[ n ]; - numTiles = new int[ n ]; + borderTileSize = new int[ numDimensions ]; + numTiles = new int[ numDimensions ]; - final PrimitiveType primitiveType = srcSupplier.getType().getNativeTypeFactory().getPrimitiveType(); + final PrimitiveType primitiveType = type.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 ]; + tile_pos_in_dest = new int[ numDimensions ]; + tile_pos_in_src = new long[ numDimensions ]; + tile_size = new int[ numDimensions ]; + tile_interval_in_src = BlockInterval.wrap( tile_pos_in_src, tile_size ); + zero = new int[ numDimensions ]; } - private TilingBlockSupplier( final TilingBlockSupplier< T, P > s ) + private TilingUnaryBlockOperator( TilingUnaryBlockOperator< T, P > op ) { - p0 = s.p0.independentCopy(); - innerTileSize = s.innerTileSize; - innerTileNumElements = s.innerTileNumElements; - tempArray = s.tempArray.newInstance(); - subArrayCopy = s.subArrayCopy; + super( op ); + + innerTileSize = op.innerTileSize; + innerTileNumElements = op.innerTileNumElements; + tempArray = op.tempArray.newInstance(); + subArrayCopy = op.subArrayCopy; - final int n = numDimensions(); + final int n = op.numTargetDimensions(); 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 ]; + tile_interval_in_src = BlockInterval.wrap( tile_pos_in_src, tile_size ); + zero = op.zero; } @Override - public T getType() + public void compute( final BlockSupplier< T > src, final Interval interval, final Object dest ) { - return p0.getType(); - } + final BlockInterval blockInterval = BlockInterval.asBlockInterval( interval ); + final long[] srcPos = blockInterval.min(); + final int[] size = blockInterval.size(); - @Override - public int numDimensions() - { - return p0.numDimensions(); - } - - @Override - public void copy( final long[] srcPos, final Object dest, final int[] size ) - { - final int n = numDimensions(); + final int n = numTargetDimensions(); boolean singleTile = true; for ( int d = 0; d < n; ++d ) { @@ -164,16 +162,16 @@ public void copy( final long[] srcPos, final Object dest, final int[] size ) } if ( singleTile ) { - p0.copy( srcPos, dest, size ); + src.copy( blockInterval, dest ); } else { final P tile_buf = tempArray.get( innerTileNumElements ); - compute_tiles_recursively( n - 1, srcPos, Cast.unchecked( dest ), size, tile_buf ); + compute_tiles_recursively( n - 1, src, 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 ) { + private void compute_tiles_recursively( final int d, final BlockSupplier< T > src, 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 ) { @@ -182,19 +180,19 @@ private void compute_tiles_recursively( final int d, final long[] srcPos, final 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 ); + src.copy( tile_interval_in_src, tile_buf ); + subArrayCopy.copy( tile_buf, tile_size, zero, dest, dest_size, tile_pos_in_dest, tile_size ); } else { - compute_tiles_recursively( d - 1, srcPos, dest, dest_size, tile_buf ); + compute_tiles_recursively( d - 1, src, srcPos, dest, dest_size, tile_buf ); } } } @Override - public BlockSupplier< T > independentCopy() + public UnaryBlockOperator< T, T > independentCopy() { - return new TilingBlockSupplier<>( this ); + return new TilingUnaryBlockOperator<>( this ); } } diff --git a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java index 0c2f31b91..dfc368e23 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java +++ b/src/main/java/net/imglib2/algorithm/blocks/UnaryBlockOperator.java @@ -33,43 +33,47 @@ */ package net.imglib2.algorithm.blocks; +import net.imglib2.Interval; import net.imglib2.algorithm.blocks.convert.Convert; import net.imglib2.type.NativeType; -import net.imglib2.util.Cast; /** - * Wraps {@code BlockProcessor}, where {@code I} is the primitive array - * type backing ImgLib2 {@code NativeType} {@code S} and {@code O} is the - * primitive array type backing ImgLib2 {@code NativeType} {@code T}. + * A {@code UnaryBlockOperator} computes blocks of {@code NativeType} data + * from blocks of {@code NativeType} data. *

    - * Typically, {@code UnaryBlockOperator} should be used rather than {@link - * BlockProcessor} directly, to avoid mistakes with unchecked (primitive array) - * type casts. + * Use the {@link UnaryBlockOperator#compute(BlockSupplier, Interval, Object)} + * method to compute a block of data and store it into a flat primitive array + * (of the appropriate primitive type corresponding to {@code T}). The input + * block (appropriately sized and positioned to produce the desired output + * {@code Interval}) is read from a {@code BlockSupplier}. + *

    + * Typically, {@code UnaryBlockOperator} are chained to a particular {@code + * BlockSupplier} using {@link BlockSupplier#andThen} (or {@link #applyTo}, + * instead of calling {@code compute()} explicitly. + *

    + * Implementations are not thread-safe in general. Use {@link + * #independentCopy()} to obtain independent instances. * * @param - * source type + * source pixel type * @param - * target type + * target pixel type */ public interface UnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > { /** - * Get (an instance of) the wrapped {@code BlockProcessor}. - *

    - * Note that this involves an unchecked cast, that is, the returned {@code - * BlockProcessor} will be cast to the {@code I, O} types expected by - * the caller. - *

    - * This is mostly intented for internal use, e.g., in {@link BlockAlgoUtils}. + * Compute a block (using {@code src} to provide input data) and store into the given primitive array (of the appropriate type). * - * @param - * input primitive array type, e.g., float[]. Must correspond to S. - * @param - * output primitive array type, e.g., float[]. Must correspond to T. - * - * @return an instance of the wrapped {@code BlockProcessor} + * @param src + * the {@code BlockSupplier} that provides input data + * @param interval + * the output interval to compute + * @param dest + * primitive array to store computation result. Must correspond to {@code T}, for + * example, if {@code T} is {@code UnsignedByteType} then {@code dest} must + * be {@code byte[]}. */ - < I, O > BlockProcessor< I, O > blockProcessor(); + void compute( BlockSupplier< S > src, Interval interval, Object dest ); S getSourceType(); @@ -101,12 +105,6 @@ public interface UnaryBlockOperator< S extends NativeType< S >, T extends Native */ int numTargetDimensions(); - /** - * Get a thread-safe version of this {@code UnaryBlockOperator}. - * (Implemented as a wrapper that makes {@link ThreadLocal} copies). - */ - UnaryBlockOperator< S, T > threadSafe(); - /** * Returns an instance of this {@link UnaryBlockOperator} that can be used * independently, e.g., in another thread or in another place in the same @@ -114,28 +112,22 @@ public interface UnaryBlockOperator< S extends NativeType< S >, T extends Native */ UnaryBlockOperator< S, T > independentCopy(); + /** + * Returns a {@code BlockSupplier} that provide blocks by {@link #compute + * computing} on input blocks from the given {@code BlockSupplier}. + */ + default BlockSupplier< T > applyTo( BlockSupplier< S > blocks ) + { + return new ConcatenatedBlockSupplier<>( blocks, independentCopy() ); + } + /** * Returns a {@code UnaryBlockOperator} that is equivalent to applying * {@code this}, and then applying {@code op} to the result. */ 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() ) { - 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() ) ); + return new ConcatenatedUnaryBlockOperator<>( this, op.independentCopy() ); } /** @@ -145,10 +137,7 @@ default < U extends NativeType< U > > UnaryBlockOperator< S, U > andThen( UnaryB */ default < U extends NativeType< U > > UnaryBlockOperator< U, T > adaptSourceType( U newSourceType, ClampType clamp ) { - if ( newSourceType.getClass().isInstance( getSourceType() ) ) - return Cast.unchecked( this ); - else - return Convert.createOperator( newSourceType, getSourceType(), clamp ).andThen( this ); + return Convert.createOperator( newSourceType, getSourceType(), clamp ).andThen( this ); } /** @@ -158,9 +147,6 @@ default < U extends NativeType< U > > UnaryBlockOperator< U, T > adaptSourceType */ default < U extends NativeType< U > > UnaryBlockOperator< S, U > adaptTargetType( U newTargetType, ClampType clamp ) { - if ( newTargetType.getClass().isInstance( getTargetType() ) ) - return Cast.unchecked( this ); - else - return this.andThen( Convert.createOperator( 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 efff1ad31..922d0032e 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java +++ b/src/main/java/net/imglib2/algorithm/blocks/convert/Convert.java @@ -37,13 +37,15 @@ import java.util.function.Function; import java.util.function.Supplier; +import net.imglib2.Interval; +import net.imglib2.algorithm.blocks.AbstractUnaryBlockOperator; 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; +import net.imglib2.util.Cast; /** * Create {@link UnaryBlockOperator} to convert blocks between standard ImgLib2 {@code Type}s. @@ -170,13 +172,51 @@ UnaryBlockOperator< S, T > createOperator( final S sourceType, final T targetTyp UnaryBlockOperator< S, T > createOperator( final S sourceType, final T targetType, final ClampType clamp ) { if ( Objects.equals( sourceType.getClass(), targetType.getClass() ) ) - return new NoOpUnaryBlockOperator<>(); + return Cast.unchecked( new Identity<>( sourceType, 0 ) ); return new DefaultUnaryBlockOperator<>( sourceType, targetType, 0, 0, new ConvertBlockProcessor<>( sourceType, targetType, clamp ) ); } + // TODO: move to upper level, make public? + static class Identity< T extends NativeType< T > > extends AbstractUnaryBlockOperator< T, T > + { + protected Identity( final T type, final int numDimensions ) + { + super( type, type, numDimensions, numDimensions ); + } + + protected Identity( final AbstractUnaryBlockOperator< T, T > op ) + { + super( op ); + } + + @Override + public void compute( final BlockSupplier< T > src, final Interval interval, final Object dest ) + { + src.copy( interval, dest ); + } + + @Override + public UnaryBlockOperator< T, T > independentCopy() + { + return this; + } + + @Override + public BlockSupplier< T > applyTo( final BlockSupplier< T > blocks ) + { + return blocks; + } + + @Override + public < U extends NativeType< U > > UnaryBlockOperator< T, U > andThen( final UnaryBlockOperator< T, U > op ) + { + return op; + } + } + /** * Create {@link UnaryBlockOperator} to convert blocks between {@code * sourceType} and {@code targetType} with the specified {@code Converter}. 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 a67ce5bd7..bda6bb1a5 100644 --- a/src/main/java/net/imglib2/algorithm/blocks/transform/AbstractTransformProcessor.java +++ b/src/main/java/net/imglib2/algorithm/blocks/transform/AbstractTransformProcessor.java @@ -33,19 +33,13 @@ */ package net.imglib2.algorithm.blocks.transform; -import static net.imglib2.util.Util.safeInt; - import java.util.Arrays; -import java.util.function.Supplier; 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; +import net.imglib2.blocks.BlockInterval; import net.imglib2.type.PrimitiveType; -import net.imglib2.util.Intervals; /** * Abstract base class for {@link Affine3DProcessor} and {@link @@ -96,9 +90,7 @@ abstract class AbstractTransformProcessor< P > extends AbstractBlockProcessor< P @Override public void setTargetInterval( final Interval interval ) { - interval.min( destPos ); - Arrays.setAll( destSize, d -> safeInt( interval.dimension( d ) ) ); - + BlockInterval.wrap( destPos, destSize ).setFrom( interval ); final RealInterval bounds = estimateBounds( interval ); switch ( interpolation ) { diff --git a/src/main/java/net/imglib2/algorithm/blocks/util/BlockProcessorSourceInterval.java b/src/main/java/net/imglib2/algorithm/blocks/util/BlockProcessorSourceInterval.java deleted file mode 100644 index 813c2ccec..000000000 --- a/src/main/java/net/imglib2/algorithm/blocks/util/BlockProcessorSourceInterval.java +++ /dev/null @@ -1,75 +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.util; - -import net.imglib2.Interval; -import net.imglib2.algorithm.blocks.BlockProcessor; - -/** - * Helper class that wraps {@link BlockProcessor#getSourcePos()} and {@link - * BlockProcessor#getSourceSize()} as an {@code Interval}. - */ -public class BlockProcessorSourceInterval implements Interval -{ - private BlockProcessor< ?, ? > p; - - public BlockProcessorSourceInterval( BlockProcessor< ?, ? > blockProcessor ) - { - this.p = blockProcessor; - } - - @Override - public int numDimensions() - { - return p.getSourcePos().length; - } - - @Override - public long min( final int d ) - { - return p.getSourcePos()[ d ]; - } - - @Override - public long max( final int d ) - { - return min( d ) + dimension( d ) - 1; - } - - @Override - public long dimension( final int d ) - { - return p.getSourceSize()[ d ]; - } -} diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull.java index ccf1b92b5..51c20072b 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull.java @@ -123,7 +123,7 @@ public void setUp() { centerFloat = new CenterFloat( downsampleInDim ); centerFloat.setTargetInterval( new FinalInterval( Util.int2long( outputSize ) ) ); - System.arraycopy( centerFloat.getSourceSize(), 0, inputSize, 0, inputSize.length ); + System.arraycopy( centerFloat.getSourceInterval().size(), 0, inputSize, 0, inputSize.length ); inputF = new float[ ( int ) Intervals.numElements( inputSize ) ]; for ( int i = 0; i < inputF.length; i++ ) inputF[ i ] = random.nextFloat(); diff --git a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull2.java b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull2.java index 26490c834..b5e9681bd 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull2.java +++ b/src/test/java/net/imglib2/algorithm/blocks/downsample/DownsampleBenchmarkFull2.java @@ -124,7 +124,7 @@ public void setUp() { halfPixelFloat = new HalfPixelFloat( downsampleInDim ); halfPixelFloat.setTargetInterval( new FinalInterval( Util.int2long( outputSize ) ) ); - System.arraycopy( halfPixelFloat.getSourceSize(), 0, inputSize, 0, inputSize.length ); + System.arraycopy( halfPixelFloat.getSourceInterval().size(), 0, inputSize, 0, inputSize.length ); inputF = new float[ ( int ) Intervals.numElements( inputSize ) ]; for ( int i = 0; i < inputF.length; i++ ) inputF[ i ] = random.nextFloat(); 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 ae0ab159b..60da49cb3 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java +++ b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java @@ -39,12 +39,14 @@ import java.util.concurrent.TimeUnit; import net.imglib2.Cursor; import net.imglib2.FinalInterval; +import net.imglib2.Interval; import net.imglib2.RandomAccessible; 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.ComputationType; +import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator; import net.imglib2.algorithm.blocks.transform.Transform.Interpolation; import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.converter.Converters; @@ -154,17 +156,23 @@ public void blocksnaiveSetup() new RealFloatConverter<>(), new FloatType() ) ); final FloatType type2 = new FloatType(); - processor = Transform.createAffineOperator( type2, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor(); + processor = ( ( DefaultUnaryBlockOperator< ?, ? > ) + Transform.createAffineOperator( type2, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ) + ).blockProcessor(); blocksDouble = PrimitiveBlocks.of( Converters.convert( Views.extendZero( img ), new RealDoubleConverter<>(), new DoubleType() ) ); final DoubleType type1 = new DoubleType(); - processorDouble = Transform.createAffineOperator( type1, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor(); + processorDouble = ( ( DefaultUnaryBlockOperator< ?, ? > ) + Transform.createAffineOperator( type1, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ) + ).blockProcessor(); blocksUnsignedByte = PrimitiveBlocks.of( Views.extendZero( img ) ); final UnsignedByteType type = new UnsignedByteType(); - processorUnsignedByte = Transform.createAffineOperator( type, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor(); + processorUnsignedByte = ( ( DefaultUnaryBlockOperator< ?, ? > ) + Transform.createAffineOperator( type, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ) + ).blockProcessor(); blocksFloat(); blocksDouble(); blocksUnsignedByte(); @@ -179,9 +187,10 @@ public Object blocksFloat() 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 float[] buf = processor.getSourceBuffer(); + blocks.copy( processor.getSourceInterval(), buf ); final float[] dest = new float[ ( int ) Intervals.numElements( size ) ]; - processor.compute( processor.getSourceBuffer(), dest ); + processor.compute( buf, dest ); final RandomAccessibleInterval< FloatType > destImg = ArrayImgs.floats( dest, size[ 0 ], size[ 1 ], size[ 2 ] ); return destImg; } @@ -192,9 +201,10 @@ public Object blocksDouble() long[] max = new long[ size.length ]; Arrays.setAll( max, d -> min[ d ] + size[ d ] - 1 ); processorDouble.setTargetInterval( FinalInterval.wrap( min, max ) ); - blocksDouble.copy( processorDouble.getSourcePos(), processorDouble.getSourceBuffer(), processorDouble.getSourceSize() ); + final double[] buf = processorDouble.getSourceBuffer(); + blocksDouble.copy( processorDouble.getSourceInterval(), buf ); final double[] dest = new double[ ( int ) Intervals.numElements( size ) ]; - processorDouble.compute( processorDouble.getSourceBuffer(), dest ); + processorDouble.compute( buf, dest ); final RandomAccessibleInterval< DoubleType > destImg = ArrayImgs.doubles( dest, size[ 0 ], size[ 1 ], size[ 2 ] ); return destImg; } @@ -205,7 +215,8 @@ public Object blocksUnsignedByte() long[] max = new long[ size.length ]; Arrays.setAll( max, d -> min[ d ] + size[ d ] - 1 ); processorUnsignedByte.setTargetInterval( FinalInterval.wrap( min, max ) ); - blocksUnsignedByte.copy( processorUnsignedByte.getSourcePos(), processorUnsignedByte.getSourceBuffer(), processorUnsignedByte.getSourceSize() ); + final Interval buf = processorUnsignedByte.getSourceInterval(); + blocksUnsignedByte.copy( buf, processorUnsignedByte.getSourceBuffer() ); final byte[] dest = new byte[ ( int ) Intervals.numElements( size ) ]; processorUnsignedByte.compute( processorUnsignedByte.getSourceBuffer(), dest ); final RandomAccessibleInterval< UnsignedByteType > destImg = ArrayImgs.unsignedBytes( dest, size[ 0 ], size[ 1 ], size[ 2 ] ); diff --git a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3DonlyCompute.java b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3DonlyCompute.java index 95d6525e6..987e14778 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3DonlyCompute.java +++ b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3DonlyCompute.java @@ -39,6 +39,7 @@ import java.util.concurrent.TimeUnit; import net.imglib2.FinalInterval; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.transform.Transform.Interpolation; import net.imglib2.blocks.PrimitiveBlocks; import net.imglib2.converter.Converters; @@ -110,13 +111,14 @@ public TransformBenchmark3DonlyCompute() blocksnaiveSetup(); } - PrimitiveBlocks< FloatType > blocks; + BlockSupplier< FloatType > blocks; Affine3DProcessor< float[] > processor; float[] dest; + float[] src; public void blocksnaiveSetup() { - blocks = PrimitiveBlocks.of( + blocks = BlockSupplier.of( Converters.convert( Views.extendZero( img ), new RealFloatConverter<>(), @@ -125,14 +127,15 @@ public void blocksnaiveSetup() 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() ); + src = processor.getSourceBuffer(); + blocks.copy( processor.getSourceInterval(), src ); dest = new float[ ( int ) Intervals.numElements( size ) ]; } @Benchmark public void compute() { - processor.compute( processor.getSourceBuffer(), dest ); + processor.compute( src, dest ); } public static void main( String[] args ) throws RunnerException 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 b85b9d534..e4b19c0ec 100644 --- a/src/test/java/net/imglib2/algorithm/blocks/transform/TransformPlayground3D.java +++ b/src/test/java/net/imglib2/algorithm/blocks/transform/TransformPlayground3D.java @@ -45,6 +45,7 @@ import net.imglib2.RealRandomAccessible; import net.imglib2.algorithm.blocks.BlockSupplier; import net.imglib2.algorithm.blocks.transform.Transform.Interpolation; +import net.imglib2.blocks.BlockInterval; import net.imglib2.img.Img; import net.imglib2.img.array.ArrayImg; import net.imglib2.img.array.ArrayImgFactory; @@ -107,7 +108,7 @@ public static void main( String[] args ) .of( Views.extendZero( img ) ) .andThen( Transform.affine( affine, Interpolation.NLINEAR ) ); final byte[] dest = new byte[ ( int ) Intervals.numElements( size ) ]; - blocks.copy( min, dest, size ); + blocks.copy( BlockInterval.wrap( min, size ), dest ); final RandomAccessibleInterval< UnsignedByteType > destImg = ArrayImgs.unsignedBytes( dest, size[ 0 ], size[ 1 ], size[ 2 ] ); // ----------------------------------------------