diff --git a/src/main/java/net/imglib2/RandomAccessible.java b/src/main/java/net/imglib2/RandomAccessible.java index e42768a23..aa3097da7 100644 --- a/src/main/java/net/imglib2/RandomAccessible.java +++ b/src/main/java/net/imglib2/RandomAccessible.java @@ -34,6 +34,7 @@ package net.imglib2; +import net.imglib2.view.fluent.RandomAccessibleView; import net.imglib2.view.Views; /** @@ -135,10 +136,10 @@ public interface RandomAccessible< T > extends EuclideanSpace, Typed< T > * loops, or called many times!!! Use {@link #randomAccess()} when efficiency * is important. *
- * This method is a short cut for {@code randomAccess().setPositionAndGet( position );} + * This method is a short-cut for {@code randomAccess().setPositionAndGet( position );} * * @param position, length must be ≥ {@link #numDimensions()} - * @return value of the the {@link RandomAccessible} at {@code position}. + * @return value of the {@link RandomAccessible} at {@code position}. */ default T getAt( final long... position ) { @@ -153,10 +154,10 @@ default T getAt( final long... position ) * loops, or called many times!!! Use {@link #randomAccess()} when efficiency * is important. *
- * This method is a short cut for {@code randomAccess().setPositionAndGet( position );} + * This method is a short-cut for {@code randomAccess().setPositionAndGet( position );} * * @param position, length must be ≥ {@link #numDimensions()} - * @return value of the the {@link RandomAccessible} at {@code position}. + * @return value of the {@link RandomAccessible} at {@code position}. */ default T getAt( final int... position ) { @@ -171,16 +172,38 @@ default T getAt( final int... position ) * loops, or called many times!!! Use {@link #randomAccess()} when efficiency * is important. *
- * This method is a short cut for {@code randomAccess().setPositionAndGet( position );} + * This method is a short-cut for {@code randomAccess().setPositionAndGet( position );} * * @param position, {@link Localizable#numDimensions()} must be ≥ {@link #numDimensions()} - * @return value of the the {@link RandomAccessible} at {@code position}. + * @return value of the {@link RandomAccessible} at {@code position}. */ default T getAt( final Localizable position ) { return randomAccess().setPositionAndGet( position ); } + /** + * Provides a gateway for creating light-weight {@link net.imglib2.view.Views + * views} into this {@code RandomAccessible}. + *
+ * A view is itself a {@code RandomAccessible} or {@code + * RandomAccessibleInterval} whose accessors transform coordinates and/or + * values on-the-fly without copying the underlying data. Consecutive + * transformations are concatenated and simplified to provide optimally + * efficient accessors. + *
+ * Note, that accessors provided by a view are read/write. Changing pixels + * in a view changes the underlying image data. (Value converters are an + * exception.) + * + * @return gateway for creating light-weight {@link net.imglib2.view.Views + * views} into this {@code RandomAccessible}. + */ + default RandomAccessibleView< T, ? > view() + { + return RandomAccessibleView.wrap( this ); + } + /* * NB: We cannot have a default implementation here because of * https://bugs.openjdk.org/browse/JDK-7120669 diff --git a/src/main/java/net/imglib2/RandomAccessibleInterval.java b/src/main/java/net/imglib2/RandomAccessibleInterval.java index e3f367e9e..9d73dabff 100644 --- a/src/main/java/net/imglib2/RandomAccessibleInterval.java +++ b/src/main/java/net/imglib2/RandomAccessibleInterval.java @@ -36,6 +36,7 @@ import net.imglib2.util.Intervals; import net.imglib2.view.RandomAccessibleIntervalCursor; +import net.imglib2.view.fluent.RandomAccessibleIntervalView; /** *
@@ -98,4 +99,27 @@ default Object iterationOrder() { return new FlatIterationOrder( this ); } + + /** + * Provides a gateway for creating light-weight {@link net.imglib2.view.Views + * views} into this {@code RandomAccessibleInterval}. + *
+ * A view is itself a {@code RandomAccessibleInterval} or {@code + * RandomAccessible} whose accessors transform coordinates and/or values + * on-the-fly without copying the underlying data. Consecutive + * transformations are concatenated and simplified to provide optimally + * efficient accessors. + *
+ * Note, that accessors provided by a view are read/write. Changing pixels + * in a view changes the underlying image data. (Value converters are an + * exception.) + * + * @return gateway for creating light-weight {@link net.imglib2.view.Views + * views} into this {@code RandomAccessibleInterval}. + */ + @Override + default RandomAccessibleIntervalView< T > view() + { + return RandomAccessibleIntervalView.wrap( this ); + } } diff --git a/src/main/java/net/imglib2/RealRandomAccessible.java b/src/main/java/net/imglib2/RealRandomAccessible.java index 0825ea62f..86477fa80 100644 --- a/src/main/java/net/imglib2/RealRandomAccessible.java +++ b/src/main/java/net/imglib2/RealRandomAccessible.java @@ -34,6 +34,8 @@ package net.imglib2; +import net.imglib2.view.fluent.RealRandomAccessibleView; + /** *
* f:Rn→T @@ -120,6 +122,28 @@ default T getAt( final RealLocalizable position ) return realRandomAccess().setPositionAndGet( position ); } + /** + * Provides a gateway for creating light-weight {@link net.imglib2.view.Views + * views} into this {@code RealRandomAccessible}. + *
+ * A view is itself a {@code RealRandomAccessible} or {@code + * RandomAccessible} whose accessors transform coordinates and/or + * values on-the-fly without copying the underlying data. Consecutive + * transformations are concatenated and simplified to provide optimally + * efficient accessors. + *
+ * Note, that accessors provided by a view are read/write. Changing pixels
+ * in a view changes the underlying image data. (Value converters are an
+ * exception.)
+ *
+ * @return gateway for creating light-weight views into this {@code
+ * RealRandomAccessible}.
+ */
+ default RealRandomAccessibleView< T > realView()
+ {
+ return RealRandomAccessibleView.wrap( this );
+ }
+
/*
* NB: We cannot have a default implementation here because of
* https://bugs.openjdk.org/browse/JDK-7120669
diff --git a/src/main/java/net/imglib2/blocks/Extension.java b/src/main/java/net/imglib2/blocks/Extension.java
index 4c008c23c..7ead383b2 100644
--- a/src/main/java/net/imglib2/blocks/Extension.java
+++ b/src/main/java/net/imglib2/blocks/Extension.java
@@ -33,12 +33,16 @@
*/
package net.imglib2.blocks;
+import static net.imglib2.outofbounds.OutOfBoundsMirrorFactory.Boundary.SINGLE;
+
+import net.imglib2.blocks.ViewNode.ExtensionViewNode;
import net.imglib2.outofbounds.OutOfBoundsBorderFactory;
import net.imglib2.outofbounds.OutOfBoundsConstantValueFactory;
import net.imglib2.outofbounds.OutOfBoundsFactory;
import net.imglib2.outofbounds.OutOfBoundsMirrorFactory;
-
-import static net.imglib2.outofbounds.OutOfBoundsMirrorFactory.Boundary.SINGLE;
+import net.imglib2.outofbounds.OutOfBoundsZeroFactory;
+import net.imglib2.type.operators.SetZero;
+import net.imglib2.util.Cast;
interface Extension
{
@@ -112,4 +116,17 @@ else if ( oobFactory instanceof OutOfBoundsConstantValueFactory )
return new ExtensionImpl.UnknownExtension<>( oobFactory );
}
}
+
+ static Extension of( ExtensionViewNode node )
+ {
+ OutOfBoundsFactory< ?, ? > oobFactory = node.getOutOfBoundsFactory();
+ if ( oobFactory instanceof OutOfBoundsZeroFactory )
+ {
+ final net.imglib2.type.Type< ? > type = Cast.unchecked( node.view().getType() );
+ final SetZero zero = Cast.unchecked( type.createVariable() );
+ zero.setZero();
+ oobFactory = new OutOfBoundsConstantValueFactory<>( zero );
+ }
+ return of( oobFactory );
+ }
}
diff --git a/src/main/java/net/imglib2/blocks/ViewAnalyzer.java b/src/main/java/net/imglib2/blocks/ViewAnalyzer.java
index 802a47aba..9a992b89f 100644
--- a/src/main/java/net/imglib2/blocks/ViewAnalyzer.java
+++ b/src/main/java/net/imglib2/blocks/ViewAnalyzer.java
@@ -50,6 +50,7 @@
import net.imglib2.img.array.ArrayImg;
import net.imglib2.img.cell.AbstractCellImg;
import net.imglib2.img.planar.PlanarImg;
+import net.imglib2.view.fluent.RandomAccessibleView;
import net.imglib2.transform.integer.BoundingBox;
import net.imglib2.transform.integer.MixedTransform;
import net.imglib2.type.NativeType;
@@ -136,6 +137,12 @@ else if ( source instanceof ImgView )
nodes.add( new DefaultViewNode( ViewNode.ViewType.IDENTITY, view ) );
source = view.getSource();
}
+ else if ( source instanceof RandomAccessibleView )
+ {
+ final RandomAccessibleView< ?, ? > view = ( RandomAccessibleView< ?, ? > ) source;
+ nodes.add( new DefaultViewNode( ViewNode.ViewType.IDENTITY, view ) );
+ source = view.delegate();
+ }
// INTERVAL,
else if ( source instanceof IntervalView )
{
diff --git a/src/main/java/net/imglib2/interpolation/Interpolant.java b/src/main/java/net/imglib2/interpolation/Interpolant.java
index e2b6eb3ee..450ebb25a 100644
--- a/src/main/java/net/imglib2/interpolation/Interpolant.java
+++ b/src/main/java/net/imglib2/interpolation/Interpolant.java
@@ -53,7 +53,7 @@ final public class Interpolant< T, F > implements RealRandomAccessible< T >, Vie
protected final int n;
- final InterpolatorFactory< T, F > factory;
+ final InterpolatorFactory< T, ? super F > factory;
/**
*
@@ -79,7 +79,7 @@ public Interpolant( final EuclideanSpace source, final InterpolatorFactory< T, F
* @param factory
* @param n
*/
- public Interpolant( final F source, final InterpolatorFactory< T, F > factory, final int n )
+ public Interpolant( final F source, final InterpolatorFactory< T, ? super F > factory, final int n )
{
this.source = source;
this.factory = factory;
@@ -118,7 +118,7 @@ public T getType()
/**
* @return {@link InterpolatorFactory} used for interpolation
*/
- public InterpolatorFactory< T, F > getInterpolatorFactory()
+ public InterpolatorFactory< T, ? super F > getInterpolatorFactory()
{
return factory;
}
diff --git a/src/main/java/net/imglib2/outofbounds/OutOfBoundsZeroFactory.java b/src/main/java/net/imglib2/outofbounds/OutOfBoundsZeroFactory.java
new file mode 100644
index 000000000..9a187e963
--- /dev/null
+++ b/src/main/java/net/imglib2/outofbounds/OutOfBoundsZeroFactory.java
@@ -0,0 +1,59 @@
+/*-
+ * #%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.outofbounds;
+
+import net.imglib2.Interval;
+import net.imglib2.RandomAccessible;
+import net.imglib2.type.Type;
+import net.imglib2.type.operators.SetZero;
+
+/**
+ * Return the zero value of {@code T} when out of bounds.
+ *
+ * @param
* A view is itself a {@link RandomAccessible} or
* {@link RandomAccessibleInterval} that provides {@link RandomAccess accessors}
* that transform coordinates on-the-fly without copying the underlying data.
@@ -109,7 +108,7 @@ public class Views
* source
* @return
*/
- public static < T, F extends EuclideanSpace > RealRandomAccessible< T > interpolate( final F source, final InterpolatorFactory< T, F > factory )
+ public static < T, F extends EuclideanSpace > RealRandomAccessible< T > interpolate( final F source, final InterpolatorFactory< T, ? super F > factory )
{
return new Interpolant<>( source, factory, source.numDimensions() );
}
diff --git a/src/main/java/net/imglib2/view/fluent/RandomAccessibleIntervalView.java b/src/main/java/net/imglib2/view/fluent/RandomAccessibleIntervalView.java
new file mode 100644
index 000000000..436a0cf15
--- /dev/null
+++ b/src/main/java/net/imglib2/view/fluent/RandomAccessibleIntervalView.java
@@ -0,0 +1,599 @@
+/*-
+ * #%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.view.fluent;
+
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import net.imglib2.Cursor;
+import net.imglib2.FlatIterationOrder;
+import net.imglib2.RandomAccessible;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.converter.Converter;
+import net.imglib2.converter.Converters;
+import net.imglib2.outofbounds.OutOfBoundsBorderFactory;
+import net.imglib2.outofbounds.OutOfBoundsConstantValueFactory;
+import net.imglib2.outofbounds.OutOfBoundsFactory;
+import net.imglib2.outofbounds.OutOfBoundsMirrorFactory;
+import net.imglib2.outofbounds.OutOfBoundsPeriodicFactory;
+import net.imglib2.outofbounds.OutOfBoundsZeroFactory;
+import net.imglib2.stream.LocalizableSpliterator;
+import net.imglib2.type.Type;
+import net.imglib2.type.operators.SetZero;
+import net.imglib2.util.Util;
+import net.imglib2.view.IterableRandomAccessibleInterval;
+import net.imglib2.view.Views;
+
+/**
+ * Gateway for creating light-weight views on a {@code RandomAccessibleInterval}.
+ *
+ * A view is itself a {@code RandomAccessible} or {@code
+ * RandomAccessibleInterval} whose accessors transform coordinates and/or
+ * values on-the-fly without copying the underlying data. Consecutive
+ * transformations are concatenated and simplified to provide optimally
+ * efficient accessors.
+ *
+ * The {@code RandomAccessibleIntervalView} gateway implements {@code
+ * RandomAccessibleInterval}, forwarding all methods to its {@link #delegate}.
+ * Additionally, it provides methods analogous to the {@code static} {@link
+ * Views} methods that operate on its {@link #delegate} and return {@code
+ * RandomAccessibleIntervalView}, {@code RandomAccessibleView}, or {@code
+ * RealRandomAccessibleView} wrappers.
+ *
+ * This provides a fluent API for conveniently chaining {@code Views} methods.
+ * For example
+ *
+ * If this passed {@code RandomAccessibleInterval} already has flat
+ * iteration order then it is returned directly. If not, then it is wrapped
+ * in a {@link IterableRandomAccessibleInterval}.
+ *
+ * @return a view with flat iteration order
+ */
+ default RandomAccessibleIntervalView< T > flatIterable()
+ {
+ return wrap( Views.flatIterable( delegate() ) );
+ }
+
+ /**
+ * Take a (n-1)-dimensional slice of this n-dimensional
+ * {@code RandomAccessible}, by fixing the {@code d} dimension of
+ * coordinates to {@code pos}.
+ *
+ * @param d
+ * coordinate dimension to fix
+ * @param pos
+ * coordinate value to fix {@code d}th dimension to
+ *
+ * @return a view on the given slice
+ */
+ @Override
+ default RandomAccessibleIntervalView< T > slice( int d, long pos )
+ {
+ return wrap( Views.hyperSlice( delegate(), d, pos ) );
+ }
+
+ /**
+ * Create a (n+1)-dimensional view of this n-dimensional
+ * {@code RandomAccessibleInterval}, by replicating values along the added
+ * axis.
+ *
+ * The additional dimension is the last dimension. For example, an XYZ view
+ * is created for an XY source. When accessing an XYZ sample in the view,
+ * the final coordinate is discarded and the source XY sample is accessed.
+ *
+ * @param minOfNewDim
+ * interval min in the added dimension.
+ * @param maxOfNewDim
+ * interval max in the added dimension.
+ *
+ * @return a view with an additional dimension
+ */
+ default RandomAccessibleIntervalView< T > addDimension( long minOfNewDim, long maxOfNewDim )
+ {
+ return wrap( Views.addDimension( delegate(), minOfNewDim, maxOfNewDim ) );
+ }
+
+ /**
+ * Create a view that is translated by the given {@code translation} vector.
+ *
+ * The pixel at coordinates x in this {@code RandomAccessible} has
+ * coordinates (x + translation) in the resulting view.
+ *
+ * @param translation
+ * translation vector
+ *
+ * @return a translated view
+ */
+ @Override
+ default RandomAccessibleIntervalView< T > translate( long... translation )
+ {
+ return wrap( Views.translate( delegate(), translation ) );
+ }
+
+ /**
+ * Create a view that is translated by the inverse of the given {@code
+ * translation} vector.
+ *
+ * The pixel at coordinates x in this {@code RandomAccessible} has
+ * coordinates (x - translation) in the resulting view.
+ *
+ * @param translation
+ * translation vector
+ *
+ * @return an inverse-translated view
+ */
+ @Override
+ default RandomAccessibleIntervalView< T > translateInverse( long... translation )
+ {
+ return wrap( Views.translateInverse( delegate(), translation ) );
+ }
+
+ /**
+ * Create a translated view such that the min (upper left) corner is at the
+ * origin.
+ *
+ * @return a view that is translated to the origin
+ */
+ default RandomAccessibleIntervalView< T > zeroMin()
+ {
+ return wrap( Views.zeroMin( delegate() ) );
+ }
+
+ /**
+ * Sample only every stepdth value of a
+ * source {@link RandomAccessible}. This is effectively an integer scaling
+ * transformation.
+ *
+ * The provided {@code steps} vector is expanded or truncated to the
+ * dimensionality of this {@code RandomAccessible}. When expanding ({@code
+ * steps.length < this.numDimensions()}), the last element is repeated.
+ *
+ * @param steps
+ * the subsampling step sizes
+ *
+ * @return a subsampled view
+ */
+ @Override
+ default RandomAccessibleIntervalView< T > subsample( final long... steps )
+ {
+ return wrap( Views.subsample( delegate(), Util.expandArray( steps, numDimensions() ) ) );
+ }
+
+ /**
+ * Create a view rotated 90 degrees, mapping {@code fromAxis} to {@code
+ * toAxis}.
+ *
+ * For example, {@code fromAxis=0, toAxis=1} means that the {@code X} axis
+ * of this {@code RandomAccessibleInterval} is mapped to the {@code Y} axis
+ * of the rotated view. Correspondingly, the {@code Y} axis is mapped to
+ * {@code -X}. All other axes remain unchanged. This corresponds to a 90
+ * degree clock-wise rotation of this {@code RandomAccessibleInterval} in
+ * the {@code XY} plane.
+ *
+ * Note that if this {@code RandomAccessibleInterval} has its min coordinate
+ * at the origin, the min coordinate of the rotated view will not be at the
+ * origin. To align the min coordinate of the rotated view with the origin,
+ * use {@link #zeroMin()}.
+ *
+ * @param fromAxis
+ * axis index
+ * @param toAxis
+ * axis index that {@code fromAxis} should be rotated to
+ *
+ * @return a view rotated 90 degrees
+ */
+ @Override
+ default RandomAccessibleIntervalView< T > rotate( int fromAxis, int toAxis )
+ {
+ return wrap( Views.rotate( delegate(), fromAxis, toAxis ) );
+ }
+
+ /**
+ * Create a view with permuted axes where the specified {@code fromAxis} to
+ * {@code toAxis} are swapped (while all other axes remain unchanged).
+ *
+ * @param fromAxis
+ * axis index
+ * @param toAxis
+ * axis index that {@code fromAxis} should be swapped with
+ *
+ * @return a view with permuted axes
+ */
+ @Override
+ default RandomAccessibleIntervalView< T > permute( int fromAxis, int toAxis )
+ {
+ return wrap( Views.permute( delegate(), fromAxis, toAxis ) );
+ }
+
+ /**
+ * Create view with permuted axes where the specified {@code fromAxis} is
+ * moved to index {@code toAxis} while the order of other axes is preserved.
+ *
+ * For example, if {@code fromAxis=2, toAxis=4} and the axis order of this
+ * {@code RandomAccessibleInterval} is {@code XYCZT}, the resulting view
+ * will have the axis order {@code XYZTC}.
+ *
+ * @param fromAxis
+ * axis index
+ * @param toAxis
+ * axis index that {@code fromAxis} should be moved to
+ *
+ * @return a view with permuted axes
+ */
+ @Override
+ default RandomAccessibleIntervalView< T > moveAxis( int fromAxis, int toAxis )
+ {
+ return wrap( Views.moveAxis( delegate(), fromAxis, toAxis ) );
+ }
+
+ /**
+ * Invert the {@code axis} with the given index.
+ *
+ * For example, if {@code axis=1}, then coordinate {@code (x,y)} in the
+ * resulting view corresponds to coordinate {@code (x,-y)} in this {@code
+ * RandomAccessibleInterval}.
+ *
+ * Note that the interval boundaries of the view are modified accordingly.
+ * If this {@code RandomAccessibleInterval} is a {@code 10x10} image with
+ * interval {@code (0,0)..(9,9)}, the interval of the view is {@code
+ * (0,-9)..(9,0)}
+ *
+ * @param axis
+ * the axis to invert
+ *
+ * @return a view with {@code axis} inverted
+ */
+ @Override
+ default RandomAccessibleIntervalView< T > invertAxis( int axis )
+ {
+ return wrap( Views.invertAxis( delegate(), axis ) );
+ }
+
+ /**
+ * Extension method to use with {@link #extend} and {@link #expand}. {@code
+ * Extension} instances can be created using static methods {@link #border},
+ * {@link #value}, {@link #mirrorSingle}, etc.
+ *
+ * Usage example:
+ *
+ * Out-of-bounds pixels are created by repeating border pixels.
+ */
+ public static < T > Extension< T > border()
+ {
+ return new Extension<>(new OutOfBoundsBorderFactory<>() );
+ }
+
+ /**
+ * Create {@code Extension} using {@link OutOfBoundsZeroFactory}.
+ *
+ * All out-of-bounds pixels have value zero.
+ */
+ public static < T extends Type< T > & SetZero > Extension< T > zero()
+ {
+ return new Extension<>( new OutOfBoundsZeroFactory< T, RandomAccessibleIntervalView< T > >() );
+ }
+
+ /**
+ * Create {@code Extension} using {@link OutOfBoundsConstantValueFactory}.
+ *
+ * All out-of-bounds pixels have the provided {@code value}.
+ */
+ public static < T > Extension< T > value( T value )
+ {
+ return new Extension<>(new OutOfBoundsConstantValueFactory<>( value ) );
+ }
+
+ /**
+ * Create {@code Extension} using {@link OutOfBoundsMirrorFactory}.
+ *
+ * Out-of-bounds pixels are created by mirroring, where boundary pixels
+ * are not repeated. Note that this requires that all dimensions of the
+ * source must be > 1.
+ */
+ public static < T > Extension< T > mirrorSingle()
+ {
+ return new Extension<>(new OutOfBoundsMirrorFactory<>( OutOfBoundsMirrorFactory.Boundary.SINGLE ) );
+ }
+
+ /**
+ * Create {@code Extension} using {@link OutOfBoundsMirrorFactory}.
+ *
+ * Out-of-bounds pixels are created by mirroring, where boundary pixels
+ * are repeated.
+ */
+ public static < T > Extension< T > mirrorDouble()
+ {
+ return new Extension<>(new OutOfBoundsMirrorFactory<>( OutOfBoundsMirrorFactory.Boundary.DOUBLE ) );
+ }
+
+ /**
+ * Create {@code Extension} using {@link OutOfBoundsPeriodicFactory}.
+ *
+ * Out-of-bounds pixels are created by periodically repeating the source
+ * image.
+ */
+ public static < T > Extension< T > periodic()
+ {
+ return new Extension<>(new OutOfBoundsPeriodicFactory<>() );
+ }
+ }
+
+ /**
+ * Create an unbounded {@link RandomAccessible} view of this {@code
+ * RandomAccessibleInterval} using out-of-bounds extension with the given
+ * {@code extension} method.
+ *
+ * {@link Extension} can be created by one of its static factory methods.
+ * For example
+ *
+ * The provided {@code border} vector is expanded or truncated to the
+ * dimensionality of this {@code RandomAccessibleInterval}. When expanding
+ * ({@code border.length < this.numDimensions()}), the last element is
+ * repeated.
+ *
+ * For example
+ *
+ * Pixel values {@code T} are converted to {@code U} using the given {@code
+ * converter}. A {@code Converter} is equivalent to a {@code BiConsumer
+ * Pixel values {@code T} are converted to {@code U} using {@code
+ * Converter}s created by the given {@code converterSupplier}. A {@code
+ * Converter} is equivalent to a {@code BiConsumer
+ * A view is itself a {@code RandomAccessible} or {@code
+ * RandomAccessibleInterval} whose accessors transform coordinates and/or values
+ * on-the-fly without copying the underlying data. Consecutive transformations
+ * are concatenated and simplified to provide optimally efficient accessors.
+ *
+ * The {@code RandomAccessibleView} gateway implements {@code RandomAccessible},
+ * forwarding all methods to its {@link #delegate}. Additionally, it provides
+ * methods analogous to the {@code static} {@link Views} methods that operate on
+ * its {@link #delegate} and return {@code RandomAccessibleIntervalView}, {@code
+ * RandomAccessibleView}, or {@code RealRandomAccessibleView} wrappers.
+ *
+ * This provides a fluent API for conveniently chaining {@code Views} methods.
+ * For example
+ *
+ * It is the callers responsibility to ensure that the source {@code
+ * RandomAccessible} is defined in the specified {@code interval}.
+ *
+ * For constructing an {@code Interval} from min and max coordinates, min
+ * coordinates and dimensions, by modifying other intervals, etc, see {@link
+ * FinalInterval} and {@link Intervals}.
+ *
+ * @param interval
+ * interval boundaries.
+ *
+ * @return a view on the given interval
+ */
+ default RandomAccessibleIntervalView< T > interval( Interval interval )
+ {
+ return RandomAccessibleIntervalView.wrap( Views.interval( delegate(), interval ) );
+ }
+
+ /**
+ * Take a (n-1)-dimensional slice of this n-dimensional
+ * {@code RandomAccessible}, by fixing the {@code d} dimension of
+ * coordinates to {@code pos}.
+ *
+ * @param d
+ * coordinate dimension to fix
+ * @param pos
+ * coordinate value to fix {@code d}th dimension to
+ *
+ * @return a view on the given slice
+ */
+ default RandomAccessibleView< T, ? > slice( int d, long pos )
+ {
+ return wrap( Views.hyperSlice( delegate(), d, pos ) );
+ }
+
+ /**
+ * Create a (n+1)-dimensional view of this n-dimensional
+ * {@code RandomAccessible}, by replicating values along the added axis.
+ *
+ * The additional dimension is the last dimension. For example, an XYZ view
+ * is created for an XY source. When accessing an XYZ sample in the view,
+ * the final coordinate is discarded and the source XY sample is accessed.
+ *
+ * @return a view with an additional dimension
+ */
+ default RandomAccessibleView< T, ? > addDimension()
+ {
+ return wrap( Views.addDimension( delegate() ) );
+ }
+
+ /**
+ * Create a view that is translated by the given {@code translation} vector.
+ *
+ * The pixel at coordinates x in this {@code RandomAccessible} has
+ * coordinates (x + translation) in the resulting view.
+ *
+ * @param translation
+ * translation vector
+ *
+ * @return a translated view
+ */
+ default RandomAccessibleView< T, ? > translate( long... translation )
+ {
+ return wrap( Views.translate( delegate(), translation ) );
+ }
+
+ /**
+ * Create a view that is translated by the inverse of the given {@code
+ * translation} vector.
+ *
+ * The pixel at coordinates x in this {@code RandomAccessible} has
+ * coordinates (x - translation) in the resulting view.
+ *
+ * @param translation
+ * translation vector
+ *
+ * @return an inverse-translated view
+ */
+ default RandomAccessibleView< T, ? > translateInverse( long... translation )
+ {
+ return wrap( Views.translateInverse( delegate(), translation ) );
+ }
+
+ /**
+ * Sample only every stepdth value of a
+ * source {@link RandomAccessible}. This is effectively an integer scaling
+ * transformation.
+ *
+ * The provided {@code steps} vector is expanded or truncated to the
+ * dimensionality of this {@code RandomAccessible}. When expanding ({@code
+ * steps.length < this.numDimensions()}), the last element is repeated.
+ *
+ * @param steps
+ * the subsampling step sizes
+ *
+ * @return a subsampled view
+ */
+ default RandomAccessibleView< T, ? > subsample( final long... steps )
+ {
+ return wrap( Views.subsample( delegate(), Util.expandArray( steps, numDimensions() ) ) );
+ }
+
+ /**
+ * Create a view rotated 90 degrees, mapping {@code fromAxis} to {@code
+ * toAxis}.
+ *
+ * For example, {@code fromAxis=0, toAxis=1} means that the {@code X} axis
+ * of this {@code RandomAccessible} is mapped to the {@code Y} axis of the
+ * rotated view. Correspondingly, the {@code Y} axis is mapped to {@code
+ * -X}. All other axes remain unchanged. This corresponds to a 90 degree
+ * clock-wise rotation of this {@code RandomAccessible} in the {@code XY}
+ * plane.
+ *
+ * @param fromAxis
+ * axis index
+ * @param toAxis
+ * axis index that {@code fromAxis} should be rotated to
+ *
+ * @return a view rotated 90 degrees
+ */
+ default RandomAccessibleView< T, ? > rotate( int fromAxis, int toAxis )
+ {
+ return wrap( Views.rotate( delegate(), fromAxis, toAxis ) );
+ }
+
+ /**
+ * Create a view with permuted axes where the specified {@code fromAxis} to
+ * {@code toAxis} are swapped (while all other axes remain unchanged).
+ *
+ * @param fromAxis
+ * axis index
+ * @param toAxis
+ * axis index that {@code fromAxis} should be swapped with
+ *
+ * @return a view with permuted axes
+ */
+ default RandomAccessibleView< T, ? > permute( int fromAxis, int toAxis )
+ {
+ return wrap( Views.permute( delegate(), fromAxis, toAxis ) );
+ }
+
+ /**
+ * Create a view with permuted axes where the specified {@code fromAxis} is
+ * moved to index {@code toAxis} while the order of other axes is preserved.
+ *
+ * For example, if {@code fromAxis=2, toAxis=4} and the axis order of this
+ * {@code RandomAccessible} is {@code XYCZT}, the resulting view will have
+ * the axis order {@code XYZTC}.
+ *
+ * @param fromAxis
+ * axis index
+ * @param toAxis
+ * axis index that {@code fromAxis} should be moved to
+ *
+ * @return a view with permuted axes
+ */
+ default RandomAccessibleView< T, ? > moveAxis( int fromAxis, int toAxis )
+ {
+ return wrap( Views.moveAxis( delegate(), fromAxis, toAxis ) );
+ }
+
+ /**
+ * Invert the {@code axis} with the given index.
+ *
+ * For example, if {@code axis=1}, then coordinate {@code (x,y,z)} in the
+ * resulting view corresponds to coordinate {@code (x,-y,z)} in this {@code
+ * RandomAccessible}.
+ *
+ * @param axis
+ * the axis to invert
+ *
+ * @return a view with {@code axis} inverted
+ */
+ default RandomAccessibleView< T, ? > invertAxis( int axis )
+ {
+ return wrap( Views.invertAxis( delegate(), axis ) );
+ }
+
+ /**
+ * Interpolation method to use with {@link #interpolate}. {@code
+ * Interpolation} instances can be created using {@link #nearestNeighbor},
+ * {@link #nLinear}, {@link #clampingNLinear}, or {@link #lanczos}.
+ *
+ * Usage example:
+ *
+ * {@link Interpolation} can be created by one of its static factory
+ * methods. For example
+ *
+ * Pixel values {@code T} are converted to {@code U} using the given {@code
+ * converter}. A {@code Converter} is equivalent to a {@code BiConsumer
+ * Pixel values {@code T} are converted to {@code U} using {@code
+ * Converter}s created by the given {@code converterSupplier}. A {@code
+ * Converter} is equivalent to a {@code BiConsumer
+ * A view is itself a {@code RealRandomAccessible} or {@code RandomAccessible}
+ * whose accessors transform coordinates and/or values on-the-fly without
+ * copying the underlying data. Consecutive transformations are concatenated and
+ * simplified to provide optimally efficient accessors.
+ *
+ * The {@code RealRandomAccessibleView} gateway implements {@code
+ * RealRandomAccessible}, forwarding all methods to its {@link #delegate}.
+ * Additionally, it provides methods analogous to the {@code static} {@link
+ * Views} methods that operate on its {@link #delegate} and return {@code
+ * RandomAccessibleIntervalView}, {@code RandomAccessibleView}, or {@code
+ * RealRandomAccessibleView} wrappers.
+ *
+ * This provides a fluent API for conveniently chaining {@code Views} methods.
+ * For example
+ *
+ * Pixel values {@code T} are converted to {@code U} using the given {@code
+ * converter}. A {@code Converter} is equivalent to a {@code BiConsumer
+ * Pixel values {@code T} are converted to {@code U} using {@code
+ * Converter}s created by the given {@code converterSupplier}. A {@code
+ * Converter} is equivalent to a {@code BiConsumer
+ * {@code RandomAccessibleInterval< IntType > view =
+ * img.view()
+ * .permute( 0, 1 )
+ * .expand( Extension.border(), 5 )
+ * .zeroMin();
+ * }
+ *
+ *
+ * @author Tobias Pietzsch
+ * @author Michael Innerberger
+ * @see Views
+ */
+public interface RandomAccessibleIntervalView< T > extends RandomAccessibleView< T, RandomAccessibleIntervalView< T > >, RandomAccessibleInterval< T >
+{
+ @Override
+ RandomAccessibleInterval< T > delegate();
+
+ static < T > RandomAccessibleIntervalView< T > wrap( final RandomAccessibleInterval< T > delegate )
+ {
+ return () -> delegate;
+ }
+
+ // -- Views methods -------------------------------------------------------
+
+ /**
+ * Enforce {@link FlatIterationOrder} order for this {@code
+ * RandomAccessibleInterval}.
+ *
+ * {@code
+ * RandomAccessible
+ *
+ * @param
+ * {@code
+ * RandomAccessible
+ *
+ * @param extension
+ * the out-of-bounds strategy to use
+ *
+ * @return an extended (unbounded) view
+ */
+ default RandomAccessibleView< T, ? > extend( Extension< T > extension )
+ {
+ return RandomAccessibleView.wrap( Views.extend( this, extension.factory ) );
+ }
+
+ /**
+ * Create an expanded view of this {@code RandomAccessibleInterval} that
+ * using out-of-bounds extension with the given {@code extension} method.
+ *
+ * {@code
+ * // expand by 10 pixels in every dimension
+ * RandomAccessibleInterval
+ *
+ * @param extension
+ * the out-of-bounds strategy to use
+ * @param border
+ * the border to add to the image
+ *
+ * @return an expanded view
+ */
+ default RandomAccessibleIntervalView< T > expand( Extension< T > extension, long... border )
+ {
+ return RandomAccessibleIntervalView.wrap( Views.expand( this, extension.factory, Util.expandArray( border, numDimensions() ) ) );
+ }
+
+ /**
+ * Create a view of this {@code RandomAccessibleInterval} converted to pixel
+ * type {@code U}.
+ *
+ * {@code RandomAccessible< IntType > view =
+ * img.view()
+ * .extend( Extension.mirrorSingle() )
+ * .permute( 0, 1 )
+ * .translate( 10, 10 );
+ * }
+ *
+ *
+ * @author Tobias Pietzsch
+ * @author Michael Innerberger
+ * @see Views
+ */
+public interface RandomAccessibleView< T, V extends RandomAccessibleView< T, V > > extends RandomAccessible< T >
+{
+ RandomAccessible< T > delegate();
+
+ static < T, V extends RandomAccessibleView< T, V > > RandomAccessibleView< T, V > wrap( final RandomAccessible< T > delegate )
+ {
+ return ( RandomAccessibleView< T, V > ) () -> delegate;
+ }
+
+ // -- Views methods -------------------------------------------------------
+
+ /**
+ * Define an interval on this {@code RandomAccessible}.
+ *
+ * {@code
+ * RealRandomAccessible
+ *
+ * @param
+ * {@code
+ * RealRandomAccessible< IntType > interpolated =
+ * img.view()
+ * .extend( Extension.zero() )
+ * .interpolate( Interpolation.lanczos() );
+ * }
+ *
+ *
+ * @param interpolation
+ * the {@link Interpolation} method
+ *
+ * @return an interpolated view
+ */
+ default RealRandomAccessibleView< T > interpolate( final Interpolation< T > interpolation )
+ {
+ return RealRandomAccessibleView.wrap( Views.interpolate( delegate(), interpolation.factory ) );
+ }
+
+ /**
+ * Create a view of this {@code RandomAccessible} converted to pixel type
+ * {@code U}.
+ *
+ * {@code RealRandomAccessible< IntType > view =
+ * img.view()
+ * .extend( Extension.border() )
+ * .interpolate( Interpolation.nLinear() );
+ * }
+ *
+ *
+ * @author Tobias Pietzsch
+ * @author Michael Innerberger
+ * @see Views
+ */
+public interface RealRandomAccessibleView< T > extends RealRandomAccessible< T >
+{
+ RealRandomAccessible< T > delegate();
+
+ static < T > RealRandomAccessibleView< T > wrap( final RealRandomAccessible< T > delegate )
+ {
+ return () -> delegate;
+ }
+
+ // -- Views methods -------------------------------------------------------
+
+ /**
+ * Create a rasterized {@code RandomAccessible} view of this {@code
+ * RealRandomAccessible} by providing {@code RandomAccess} at integer
+ * coordinates.
+ *
+ * @return a rasterized view
+ */
+ default RandomAccessibleView< T, ? > raster()
+ {
+ return RandomAccessibleView.wrap( Views.raster( delegate() ) );
+ }
+
+ /**
+ * Create a view of this {@code RealRandomAccessible} converted to pixel
+ * type {@code U}.
+ *